Просмотр исходного кода

Update inspector as selection changes
Update inspector as SceneObject components are added or removed

Marko Pintera 10 лет назад
Родитель
Сommit
06a238cab0

+ 71 - 5
BansheeEditor/Include/BsHandleManager.h

@@ -6,27 +6,97 @@
 
 namespace BansheeEngine
 {
+	/**
+	 * @brief	The central place for interacting with and drawing handles.
+	 */
 	class BS_ED_EXPORT HandleManager : public Module<HandleManager>
 	{
 	public:
 		HandleManager();
 		virtual ~HandleManager();
 
+		/**
+		 * @brief	To be called every frame. Updates interactable handle sliders based on provided input
+		 *			and queues handles for drawing.
+		 *
+		 * @param	camera		Camera that the input positions are relative to, and destination to draw the handles to.
+		 * @param	inputPos	Position of the pointer, relative to the provided camera viewport.
+		 * @param	inputDelta	Determines pointer movement since last call to this method.
+		 */
 		void update(const CameraHandlerPtr& camera, const Vector2I& inputPos, const Vector2I& inputDelta);
+
+		/**
+		 * @brief	Select a handle slider at the specified location, if there is any under the pointer. Makes
+		 *			the selected slider active and draggable.
+		 *
+		 * @param	camera		Camera that the input positions are relative to, and destination to draw the handles to.
+		 * @param	inputPos	Position of the pointer, relative to the provided camera viewport.
+		 */
 		void trySelect(const CameraHandlerPtr& camera, const Vector2I& inputPos);
+
+		/**
+		 * @brief	Clears the currently selected/active handle slider.
+		 */
 		void clearSelection();
+
+		/**
+		 * @brief	Is any handle slider selected/active.
+		 */
 		bool isHandleActive() const;
 
+		/**
+		 * @brief	Returns the manager that can be used for interacting with handle sliders.
+		 */
 		HandleSliderManager& getSliderManager() const { return *mSliderManager; }
+
+		/**
+		 * @brief	Returns the manager that can be used for drawing handle geometry.
+		 */
 		HandleDrawManager& getDrawManager() const { return *mDrawManager; }
 
+		/**
+		 * @brief	Returns the uniform size for a handle rendered in @p camera, at the world
+		 *			position @p handlePos. The handles will be scaled so that they appear
+		 *			the same size regardless of distance from camera.
+		 */
 		float getHandleSize(const CameraHandlerPtr& camera, const Vector3& handlePos) const;
 
+		/**
+		 * @brief	Sets the default handle size. This controls the uniform scale returned from
+		 *			::getHandleSize method.
+		 */
 		void setDefaultHandleSize(float value) { mDefaultHandleSize = value; }
+
+		/**
+		 * @brief	Sets editor settings that will be used for controlling various 
+		 *			handle behaviour.
+		 */
 		void setSettings(const EditorSettingsPtr& settings);
 
 	protected:
-		void updateFromProjectSettings();
+		/**
+		 * @brief	Updates the internal properties from editor settings.
+		 */
+		void updateFromEditorSettings();
+
+		/**
+		 * @brief	Called during handle update. Allows handle sliders to be created or 
+		 *			destroyed before any input is handled.
+		 */
+		virtual void refreshHandles() = 0;
+
+		/**
+		 * @brief	Called during handle update after handle input is processed.
+		 *			Allows implementation to respond to delta values calculated in sliders
+		 *			due to input.
+		 */
+		virtual void triggerHandles() = 0;
+
+		/**
+		 * @brief	Called during handle update. Allows implementation to
+		 *			queue handle draw commands.
+		 */
+		virtual void queueDrawCommands() = 0;
 
 		HandleSliderManager* mSliderManager;
 		HandleDrawManager* mDrawManager;
@@ -35,9 +105,5 @@ namespace BansheeEngine
 
 		EditorSettingsPtr mSettings;
 		UINT32 mSettingsHash;
-
-		virtual void refreshHandles() = 0;
-		virtual void triggerHandles() = 0;
-		virtual void queueDrawCommands() = 0;
 	};
 }

+ 1 - 0
BansheeEditor/Include/BsSelection.h

@@ -23,6 +23,7 @@ namespace BansheeEngine
 		void clearSceneSelection();
 		void clearResourceSelection();
 
+		Event<void(const Vector<HSceneObject>&, const Vector<Path>&)> onSelectionChanged;
 	private:
 		void sceneSelectionChanged();
 		void resourceSelectionChanged();

+ 3 - 3
BansheeEditor/Source/BsHandleManager.cpp

@@ -28,7 +28,7 @@ namespace BansheeEngine
 	void HandleManager::update(const CameraHandlerPtr& camera, const Vector2I& inputPos, const Vector2I& inputDelta)
 	{
 		if (mSettings != nullptr && mSettingsHash != mSettings->getHash())
-			updateFromProjectSettings();
+			updateFromEditorSettings();
 
 		refreshHandles();
 		mSliderManager->update(camera, inputPos, inputDelta);
@@ -42,10 +42,10 @@ namespace BansheeEngine
 	{
 		mSettings = settings;
 
-		updateFromProjectSettings();
+		updateFromEditorSettings();
 	}
 
-	void HandleManager::updateFromProjectSettings()
+	void HandleManager::updateFromEditorSettings()
 	{
 		setDefaultHandleSize(mSettings->getHandleSize());
 

+ 14 - 0
BansheeEditor/Source/BsSelection.cpp

@@ -34,6 +34,8 @@ namespace BansheeEngine
 		GUISceneTreeView* sceneTreeView = SceneTreeViewLocator::instance();
 		if (sceneTreeView != nullptr)
 			sceneTreeView->setSelection(sceneObjects);
+
+		onSelectionChanged(mSelectedSceneObjects, Vector<Path>());
 	}
 
 	const Vector<Path>& Selection::getResourcePaths() const
@@ -44,6 +46,8 @@ namespace BansheeEngine
 	void Selection::setResourcePaths(const Vector<Path>& paths)
 	{
 		mSelectedResourcePaths = paths;
+
+		onSelectionChanged(Vector<HSceneObject>(), mSelectedResourcePaths);
 	}
 
 	Vector<String> Selection::getResourceUUIDs() const
@@ -75,6 +79,8 @@ namespace BansheeEngine
 		GUIResourceTreeView* resourceTreeView = ResourceTreeViewLocator::instance();
 		if (resourceTreeView != nullptr)
 			resourceTreeView->setSelection(mSelectedResourcePaths);
+
+		onSelectionChanged(Vector<HSceneObject>(), mSelectedResourcePaths);
 	}
 
 	void Selection::clearSceneSelection()
@@ -91,13 +97,21 @@ namespace BansheeEngine
 	{
 		GUISceneTreeView* sceneTreeView = SceneTreeViewLocator::instance();
 		if (sceneTreeView != nullptr)
+		{
 			mSelectedSceneObjects = sceneTreeView->getSelection();
+
+			onSelectionChanged(mSelectedSceneObjects, Vector<Path>());
+		}
 	}
 
 	void Selection::resourceSelectionChanged()
 	{
 		GUIResourceTreeView* resourceTreeView = ResourceTreeViewLocator::instance();
 		if (resourceTreeView != nullptr)
+		{
 			mSelectedResourcePaths = resourceTreeView->getSelection();
+
+			onSelectionChanged(Vector<HSceneObject>(), mSelectedResourcePaths);
+		}
 	}
 }

+ 141 - 17
MBansheeEditor/Inspector/InspectorWindow.cs

@@ -6,15 +6,31 @@ namespace BansheeEditor
 {
     internal sealed class InspectorWindow : EditorWindow
     {
-        private class InspectorData
+        private enum InspectorType
+        {
+            SceneObject,
+            Resource,
+            Multiple,
+            None
+        }
+
+        private class InspectorComponent
         {
             public GUIComponentFoldout foldout;
             public GUIPanel panel;
             public Inspector inspector;
             public bool expanded = true;
+            public UInt64 instanceId;
+        }
+
+        private class InspectorResource
+        {
+            public GUIPanel panel;
+            public Inspector inspector;
         }
 
-        private List<InspectorData> inspectorData = new List<InspectorData>();
+        private List<InspectorComponent> inspectorComponents = new List<InspectorComponent>();
+        private InspectorResource inspectorResource;
         private GUIScrollArea inspectorScrollArea;
         private GUILayout inspectorLayout;
 
@@ -32,6 +48,9 @@ namespace BansheeEditor
         private GUIFloatField soScaleY;
         private GUIFloatField soScaleZ;
 
+        private InspectorType currentType = InspectorType.None;
+        private Resource activeResource;
+
         [MenuItem("Windows/Inspector", ButtonModifier.CtrlAlt, ButtonCode.I)]
         private static void OpenInspectorWindow()
         {
@@ -43,15 +62,37 @@ namespace BansheeEditor
             return "Inspector";
         }
 
-        internal void SetObjectToInspect(SceneObject so)
+        private void SetObjectToInspect(String resourcePath)
         {
-            Clear();
+            activeResource = ProjectLibrary.Load<Resource>(resourcePath);
 
-            activeSO = so;
+            if (activeResource == null)
+                return;
 
-            if (activeSO == null)
+            currentType = InspectorType.Resource;
+
+            inspectorScrollArea = new GUIScrollArea();
+            GUI.AddElement(inspectorScrollArea);
+            inspectorLayout = inspectorScrollArea.Layout;
+
+            inspectorResource = new InspectorResource();
+            inspectorResource.panel = inspectorLayout.AddPanel();
+
+            inspectorResource.inspector = GetInspector(activeResource.GetType());
+            inspectorResource.inspector.Initialize(this, inspectorResource.panel, activeResource);
+            inspectorResource.inspector.Refresh();
+
+            inspectorLayout.AddFlexibleSpace();
+        }
+
+        private void SetObjectToInspect(SceneObject so)
+        {
+            if (so == null)
                 return;
 
+            currentType = InspectorType.SceneObject;
+            activeSO = so;
+
             inspectorScrollArea = new GUIScrollArea();
             GUI.AddElement(inspectorScrollArea);
             inspectorLayout = inspectorScrollArea.Layout;
@@ -64,7 +105,8 @@ namespace BansheeEditor
             Component[] allComponents = so.GetComponents();
             for (int i = 0; i < allComponents.Length; i++)
             {
-                InspectorData data = new InspectorData();
+                InspectorComponent data = new InspectorComponent();
+                data.instanceId = allComponents[i].InstanceId;
 
                 data.foldout = new GUIComponentFoldout(allComponents[i].GetType().Name);
                 inspectorLayout.AddElement(data.foldout);
@@ -76,15 +118,15 @@ namespace BansheeEditor
                 data.foldout.SetExpanded(true);
                 data.foldout.OnToggled += (bool expanded) => OnComponentFoldoutToggled(data, expanded);
 
-                inspectorData.Add(data);
+                inspectorComponents.Add(data);
 
-                inspectorData[i].inspector.Refresh();
+                inspectorComponents[i].inspector.Refresh();
             }
 
             inspectorLayout.AddFlexibleSpace();
         }
 
-        private void OnComponentFoldoutToggled(InspectorData inspectorData, bool expanded)
+        private void OnComponentFoldoutToggled(InspectorComponent inspectorData, bool expanded)
         {
             inspectorData.expanded = expanded;
             inspectorData.inspector.SetVisible(expanded);
@@ -160,6 +202,8 @@ namespace BansheeEditor
             scaleLayout.AddSpace(10);
             scaleLayout.AddElement(soScaleZ);
             scaleLayout.AddFlexibleSpace();
+
+            inspectorLayout.AddSpace(15);
         }
 
         private void RefreshSceneObjectFields(bool forceUpdate)
@@ -230,13 +274,84 @@ namespace BansheeEditor
             soScaleZ.Value = scale.z;
         }
 
+        private void OnInitialize()
+        {
+            Selection.OnSelectionChanged += OnSelectionChanged;
+        }
+
+        private void OnDestroy()
+        {
+            Selection.OnSelectionChanged -= OnSelectionChanged;
+        }
+
         private void OnEditorUpdate()
         {
-            RefreshSceneObjectFields(false);
+            if (currentType == InspectorType.SceneObject)
+            {
+                Component[] allComponents = activeSO.GetComponents();
+                bool requiresRebuild = allComponents.Length != inspectorComponents.Count;
+
+                if (!requiresRebuild)
+                {
+                    for (int i = 0; i < inspectorComponents.Count; i++)
+                    {
+                        if (inspectorComponents[i].instanceId != allComponents[i].InstanceId)
+                        {
+                            requiresRebuild = true;
+                            break;
+                        }
+                    }
+                }
 
-            for (int i = 0; i < inspectorData.Count; i++)
+                if (requiresRebuild)
+                    SetObjectToInspect(activeSO);
+                else
+                {
+                    RefreshSceneObjectFields(false);
+
+                    for (int i = 0; i < inspectorComponents.Count; i++)
+                    {
+                        inspectorComponents[i].inspector.Refresh();
+                    }
+                }
+            }
+            else if (currentType == InspectorType.Resource)
             {
-                inspectorData[i].inspector.Refresh();
+                inspectorResource.inspector.Refresh();
+            }
+        }
+
+        private void OnSelectionChanged(SceneObject[] objects, string[] paths)
+        {
+            Clear();
+
+            if (objects.Length == 0 && paths.Length == 0)
+            {
+                currentType = InspectorType.None;
+                inspectorScrollArea = new GUIScrollArea();
+                GUI.AddElement(inspectorScrollArea);
+                inspectorLayout = inspectorScrollArea.Layout;
+                inspectorLayout.AddElement(new GUILabel("No object selected"));
+                inspectorLayout.AddFlexibleSpace();
+            }
+            else if ((objects.Length + paths.Length) > 1)
+            {
+                currentType = InspectorType.None;
+                inspectorScrollArea = new GUIScrollArea();
+                GUI.AddElement(inspectorScrollArea);
+                inspectorLayout = inspectorScrollArea.Layout;
+                inspectorLayout.AddElement(new GUILabel("Multiple objects selected"));
+                inspectorLayout.AddFlexibleSpace();
+            }
+            else if (objects.Length == 1)
+            {
+                Debug.Log("Object selected: " + objects[0].Name);
+                SetObjectToInspect(objects[0]);
+            }
+            else if (paths.Length == 1)
+            {
+                Debug.Log("Path selected: " + paths[0]);
+                SetObjectToInspect(paths[0]);
             }
         }
 
@@ -247,13 +362,19 @@ namespace BansheeEditor
 
         internal void Clear()
         {
-            for (int i = 0; i < inspectorData.Count; i++)
+            for (int i = 0; i < inspectorComponents.Count; i++)
             {
-                inspectorData[i].foldout.Destroy();
-                inspectorData[i].inspector.Destroy();
+                inspectorComponents[i].foldout.Destroy();
+                inspectorComponents[i].inspector.Destroy();
             }
 
-            inspectorData.Clear();
+            inspectorComponents.Clear();
+
+            if (inspectorResource != null)
+            {
+                inspectorResource.inspector.Destroy();
+                inspectorResource = null;
+            }
 
             if (inspectorScrollArea != null)
             {
@@ -274,6 +395,9 @@ namespace BansheeEditor
             soScaleX = null;
             soScaleY = null;
             soScaleZ = null;
+
+            activeResource = null;
+            currentType = InspectorType.None;
         }
 
         private void OnPositionChanged(int idx, float value)

+ 10 - 1
MBansheeEditor/Selection.cs

@@ -1,10 +1,13 @@
-using System.Runtime.CompilerServices;
+using System;
+using System.Runtime.CompilerServices;
 using BansheeEngine;
 
 namespace BansheeEditor
 {
     public sealed class Selection
     {
+        public static Action<SceneObject[], string[]> OnSelectionChanged;
+
         public static SceneObject[] sceneObjects
         {
             get
@@ -47,6 +50,12 @@ namespace BansheeEditor
             }
         }
 
+        private static void Internal_TriggerSelectionChanged(SceneObject[] objects, string[] paths)
+        {
+            if (OnSelectionChanged != null)
+                OnSelectionChanged(objects, paths);
+        }
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         internal static extern void Internal_GetSceneObjectSelection(out SceneObject[] selection);
 

+ 3 - 0
MBansheeEngine/GUI/GUILayout.cs

@@ -14,6 +14,9 @@ namespace BansheeEngine
 
         public void InsertElement(int index, GUIElement element)
         {
+            if(index < 0 || index > GetNumChildren())
+                throw new ArgumentOutOfRangeException("index", index, "Index out of range.");
+
             if (element != null)
                 Internal_InsertElement(mCachedPtr, index, element.mCachedPtr);
         }

+ 11 - 1
MBansheeEngine/GameObject.cs

@@ -1,6 +1,16 @@
-namespace BansheeEngine
+using System;
+using System.Runtime.CompilerServices;
+
+namespace BansheeEngine
 {
     public class GameObject : ScriptObject
     {
+        public UInt64 InstanceId
+        {
+            get { return Internal_GetInstanceId(mCachedPtr); }
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern UInt64 Internal_GetInstanceId(IntPtr thisPtr);
     }
 }

+ 5 - 5
SBansheeEditor/Include/BsScriptEditorWindow.h

@@ -45,10 +45,10 @@ namespace BansheeEngine
 		void onFocusChanged(bool inFocus);
 		void onAssemblyRefreshStarted();
 
-		void _onManagedInstanceDeleted();
-		ScriptObjectBackup beginRefresh();
-		void endRefresh(const ScriptObjectBackup& backupData);
-		MonoObject* _createManagedInstance(bool construct);
+		void _onManagedInstanceDeleted() override;
+		ScriptObjectBackup beginRefresh() override;
+		void endRefresh(const ScriptObjectBackup& backupData) override;
+		MonoObject* _createManagedInstance(bool construct) override;
 
 		String mName;
 		ScriptEditorWidget* mEditorWidget;
@@ -79,7 +79,7 @@ namespace BansheeEngine
 		~ScriptEditorWidget();
 
 		bool createManagedInstance();
-		void update();
+		void update() override;
 		void reloadMonoTypes(MonoClass* windowClass);
 		void triggerOnInitialize();
 		void triggerOnDestroy();

+ 13 - 1
SBansheeEditor/Include/BsScriptSelection.h

@@ -8,9 +8,16 @@ namespace BansheeEngine
 	class BS_SCR_BED_EXPORT ScriptSelection : public ScriptObject<ScriptSelection>
 	{
 	public:
-		SCRIPT_OBJ(EDITOR_ASSEMBLY, "BansheeEditor", "Selection")
+		SCRIPT_OBJ(EDITOR_ASSEMBLY, "BansheeEditor", "Selection");
+
+		static void startUp();
+		static void shutDown();
 
 	private:
+		ScriptSelection(MonoObject* instance);
+
+		static void onSelectionChanged(const Vector<HSceneObject>& sceneObjects, const Vector<Path>& resPaths);
+
 		static void internal_GetSceneObjectSelection(MonoArray** selection);
 		static void internal_SetSceneObjectSelection(MonoArray* selection);
 
@@ -19,5 +26,10 @@ namespace BansheeEngine
 
 		static void internal_GetResourcePathSelection(MonoArray** selection);
 		static void internal_SetResourcePathSelection(MonoArray* selection);
+
+		typedef void(__stdcall *OnSelectionChangedThunkDef) (MonoArray*, MonoArray*, MonoException**);
+		static OnSelectionChangedThunkDef OnSelectionChangedThunk;
+
+		static HEvent OnSelectionChangedConn;
 	};
 }

+ 4 - 1
SBansheeEditor/Source/BsEditorScriptManager.cpp

@@ -16,7 +16,8 @@
 #include "BsTime.h"
 #include "BsMath.h"
 #include "BsEditorApplication.h"
-#include <BsTestOutput.h>
+#include "BsScriptSelection.h"
+#include "BsTestOutput.h"
 
 namespace BansheeEngine
 {
@@ -36,6 +37,7 @@ namespace BansheeEngine
 		ScriptProjectLibrary::startUp();
 		MenuItemManager::startUp(ScriptAssemblyManager::instance());
 		ScriptFolderMonitorManager::startUp();
+		ScriptSelection::startUp();
 
 		mOnDomainLoadConn = ScriptObjectManager::instance().onRefreshDomainLoaded.connect(std::bind(&EditorScriptManager::loadMonoTypes, this));
 		mOnAssemblyRefreshDoneConn = ScriptObjectManager::instance().onRefreshComplete.connect(std::bind(&EditorScriptManager::onAssemblyRefreshDone, this));
@@ -58,6 +60,7 @@ namespace BansheeEngine
 		mOnDomainLoadConn.disconnect();
 		mOnAssemblyRefreshDoneConn.disconnect();
 
+		ScriptSelection::shutDown();
 		ScriptFolderMonitorManager::shutDown();
 		MenuItemManager::shutDown();
 		ScriptProjectLibrary::shutDown();

+ 47 - 0
SBansheeEditor/Source/BsScriptSelection.cpp

@@ -1,6 +1,7 @@
 #include "BsScriptSelection.h"
 #include "BsScriptMeta.h"
 #include "BsMonoClass.h"
+#include "BsMonoMethod.h"
 #include "BsSelection.h"
 #include "BsScriptSceneObject.h"
 #include "BsMonoUtil.h"
@@ -8,6 +9,15 @@
 
 namespace BansheeEngine
 {
+	ScriptSelection::OnSelectionChangedThunkDef ScriptSelection::OnSelectionChangedThunk;
+	HEvent ScriptSelection::OnSelectionChangedConn;
+
+	ScriptSelection::ScriptSelection(MonoObject* instance)
+		:ScriptObject(instance)
+	{
+		
+	}
+
 	void ScriptSelection::initRuntimeData()
 	{
 		metaData.scriptClass->addInternalCall("Internal_GetSceneObjectSelection", &ScriptSelection::internal_GetSceneObjectSelection);
@@ -16,6 +26,8 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_SetResourceUUIDSelection", &ScriptSelection::internal_SetResourceUUIDSelection);
 		metaData.scriptClass->addInternalCall("Internal_GetResourcePathSelection", &ScriptSelection::internal_GetResourcePathSelection);
 		metaData.scriptClass->addInternalCall("Internal_SetResourcePathSelection", &ScriptSelection::internal_SetResourcePathSelection);
+
+		OnSelectionChangedThunk = (OnSelectionChangedThunkDef)metaData.scriptClass->getMethod("Internal_TriggerSelectionChanged", 2)->getThunk();
 	}
 
 	void ScriptSelection::internal_GetSceneObjectSelection(MonoArray** selection)
@@ -126,4 +138,39 @@ namespace BansheeEngine
 
 		Selection::instance().setResourcePaths(paths);
 	}
+
+
+	void ScriptSelection::startUp()
+	{
+		OnSelectionChangedConn = Selection::instance().onSelectionChanged.connect(&ScriptSelection::onSelectionChanged);
+	}
+
+	void ScriptSelection::shutDown()
+	{
+		OnSelectionChangedConn.disconnect();
+	}
+
+	void ScriptSelection::onSelectionChanged(const Vector<HSceneObject>& sceneObjects, const Vector<Path>& resPaths)
+	{
+		UINT32 numObjects = (UINT32)sceneObjects.size();
+		ScriptArray scriptObjects = ScriptArray::create<ScriptSceneObject>(numObjects);
+		for (UINT32 i = 0; i < numObjects; i++)
+		{
+			// TODO - This bit is commonly used, I should add a method in ScriptGameObjectManager
+			ScriptSceneObject* scriptSceneObject = ScriptGameObjectManager::instance().getScriptSceneObject(sceneObjects[i]);
+			if (scriptSceneObject == nullptr)
+				scriptSceneObject = ScriptGameObjectManager::instance().createScriptSceneObject(sceneObjects[i]);
+
+			scriptObjects.set(i, scriptSceneObject->getManagedInstance());
+		}
+
+		UINT32 numPaths = (UINT32)resPaths.size();
+		ScriptArray scriptPaths = ScriptArray::create<String>(numPaths);
+		for (UINT32 i = 0; i < numPaths; i++)
+			scriptObjects.set(i, resPaths[i].toString());
+
+		MonoArray* monoObjects = scriptObjects.getInternal();
+		MonoArray* monoPaths = scriptPaths.getInternal();
+		MonoUtil::invokeThunk(OnSelectionChangedThunk, monoObjects, monoPaths);
+	}
 }

+ 6 - 9
SBansheeEngine/Include/BsScriptGameObject.h

@@ -14,8 +14,8 @@ namespace BansheeEngine
 		virtual HGameObject getNativeHandle() const = 0;
 		virtual void setNativeHandle(const HGameObject& gameObject) = 0;
 
-		virtual ScriptObjectBackup beginRefresh();
-		virtual void endRefresh(const ScriptObjectBackup& backupData);
+		virtual ScriptObjectBackup beginRefresh() override;
+		virtual void endRefresh(const ScriptObjectBackup& backupData) override;
 
 	protected:
 		bool mRefreshInProgress;
@@ -24,14 +24,11 @@ namespace BansheeEngine
 	class BS_SCR_BE_EXPORT ScriptGameObject : public ScriptObject<ScriptGameObject, ScriptGameObjectBase>
 	{
 	public:
-		static String getAssemblyName() { return ENGINE_ASSEMBLY; }
-		static String getNamespace() { return "BansheeEngine"; }
-		static String getTypeName() { return "GameObject"; }
-		static void initRuntimeData() { }
+		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "GameObject")
 
 	private:
-		ScriptGameObject(MonoObject* instance)
-			:ScriptObject(instance)
-		{ }
+		ScriptGameObject(MonoObject* instance);
+
+		static UINT64 internal_getInstanceId(ScriptGameObject* nativeInstance);
 	};
 }

+ 3 - 3
SBansheeEngine/Include/BsScriptSceneObject.h

@@ -14,8 +14,8 @@ namespace BansheeEngine
 
 		static bool checkIfDestroyed(ScriptSceneObject* nativeInstance);
 
-		virtual HGameObject getNativeHandle() const { return mSceneObject; }
-		virtual void setNativeHandle(const HGameObject& gameObject);
+		virtual HGameObject getNativeHandle() const override { return mSceneObject; }
+		virtual void setNativeHandle(const HGameObject& gameObject) override;
 
 		HSceneObject getNativeSceneObject() const { return mSceneObject; }
 
@@ -66,7 +66,7 @@ namespace BansheeEngine
 		
 		ScriptSceneObject(MonoObject* instance, const HSceneObject& sceneObject);
 
-		void _onManagedInstanceDeleted();
+		void _onManagedInstanceDeleted() override;
 
 		HSceneObject mSceneObject;
 	};

+ 15 - 0
SBansheeEngine/Source/BsScriptGameObject.cpp

@@ -1,4 +1,5 @@
 #include "BsScriptGameObject.h"
+#include "BsDebug.h"
 
 namespace BansheeEngine
 {
@@ -19,4 +20,18 @@ namespace BansheeEngine
 
 		PersistentScriptObjectBase::endRefresh(backupData);
 	}
+
+	ScriptGameObject::ScriptGameObject(MonoObject* instance)
+		:ScriptObject(instance)
+	{ }
+
+	void ScriptGameObject::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_GetInstanceId", &ScriptGameObject::internal_getInstanceId);
+	}
+
+	UINT64 ScriptGameObject::internal_getInstanceId(ScriptGameObject* nativeInstance)
+	{
+		return nativeInstance->getNativeHandle().getInstanceId();
+	}
 }

+ 41 - 25
TODO.txt

@@ -11,7 +11,6 @@ Modal windows are set up as persistent but I don't serialize their internal data
 ----------------------------------------------------------------------
 C# Material/Shader:
 
-TODO - Material/Shader has no color type so I cannot know when to display normal vector and when color in inspector
 TODO - Implement param block and sampler support
 TODO - When creating a Material without a shader, a default one should be used, at least in editor
 TODO - Setting Material array parameters isn't possible from C#
@@ -58,9 +57,14 @@ Code quality improvements:
 ----------------------------------------------------------------------
 Polish stage 1
 
+Test inspector selection, selecting a resource and adding/removing component updates
+Showing the inspector causes a considerable slowdown (maybe stuff gets refreshed too often?)
+Crash when showing the inspector (invalid index in Layout.InsertElement)
+
 Handle seems to lag behind the selected mesh
 ProjectLibrary seems to import some files on every start-up
 Crash on shutdown in mono_gchandle_free
+Material/Shader has no color type so I cannot know when to display normal vector and when color in inspector
 
 First screenshot work:
 - Inspector change contents on selection (and make sure the selected object/component looks okay)
@@ -80,10 +84,12 @@ First screenshot work:
 SceneTreeView
  - Hook up ping effect so it triggers when I select a resource or sceneobject
  - See if it needs other enhancements (rename, delete all work properly? etc.)
+ - Add copy/cut/paste/duplicate (with context menu)
 
 Finish up inspector
  - Do I handle the case of updating the inspector when component is added or removed?
  - Hook it up to Selection changes so it shows inspector for current component/resource
+ - GUI TextureField similar to ResourceField but it displays the texture it has assigned
 
 Need a way to add scene objects and components (and remove them)
  - Components adding should be only done by drag and dropping scripts to inspector (undoable)
@@ -92,10 +98,12 @@ Need a way to add scene objects and components (and remove them)
  - Deleting them should be doable by context menu in Hierarchy and Del keystroke (undoable)
 
 Add shortcut keys for view/move/rotate/scale
-Add "focus on object" key (F)
+Add "focus on object" key (F) - animate it: rotate camera towards then speed towards while zooming in
 Ortographic camera views (+ gizmo in scene view corner that shows camera orientation)
 Drag to select in scene view
 
+Replace "minimize" button in tabbed title bar with maximize and make sure it works
+
 Will need a status bar:
  - Displays last error message
  - Opens up console on click
@@ -112,12 +120,14 @@ Later:
  - Undo/Redo when breaking or reverting a scene object
 
 ----------------------------------------------------------------------
-Project window
-
-Later:
- - Might need to improve search (need to test). Do multiple search keywords work properly?
- - Consider delaying search until user stops pressing keys (so not to have thousands of search results in the initial stages)
- - Save & restore scroll position when Refresh happens
+Simple stuff
+ - Inject an icon into an .exe (Win32 specific)
+ - C# wrapper for GUISkin (and a way to assign the current skin to a window)
+ - Move all the code files into subfolders so their hierarchy is similar to VS filters
+ - Font doesn't have a C# interface
+ - Get rid of PoolAlloc and other unused allocators (plus fix bs_new and others which have weird overloads)
+ - Get rid of event callback from HString and figure out a better way
+ - Splash screen
 
 ----------------------------------------------------------------------
 Resources
@@ -138,27 +148,16 @@ Resources
    - Copy all the resources marked with the flag mentioned above to \Data subfolder in the output folder, preserving the same asset structure
 
 ----------------------------------------------------------------------
-Simple stuff
+Project window
 
- - Inject an icon into an .exe (Win32 specific)
- - C# wrapper for GUISkin (and a way to assign the current skin to a window)
- - Move all the code files into subfolders so their hierarchy is similar to VS filters
- - Font doesn't have a C# interface
- - Get rid of PoolAlloc and other unused allocators (plus fix bs_new and others which have weird overloads)
- - Get rid of event callback from HString and figure out a better way
- - GUI TextureField similar to ResourceField but it displays the texture it has assigned
- - Splash screen
+Later:
+ - Might need to improve search (need to test). Do multiple search keywords work properly?
+ - Consider delaying search until user stops pressing keys (so not to have thousands of search results in the initial stages)
+ - Save & restore scroll position when Refresh happens
 
 ----------------------------------------------------------------------
 Handles
 
-When scaling using center make sure to offset the object before scale
-
-Rotate handle:
- - How to handle local/global with rotate handle?
-   - This maybe just determines initial rotation of the handle?
-   - I don't think my code properly handles rotation handle transforms (e.g. arc drawing)
-
 Ideally free scale handle indicator should always render and be interactable and never be hidden by axis scale indicators (Not high priority)
 
 Later:
@@ -168,7 +167,6 @@ Later:
 Include files:
 
 Test:
- - Try preprocessing using one RenderAPi and then load the shaders using another and see if they're created normally
  - Test if default values work
  - Test project library dependant resources (e.g. changing an include and seeing if shader is reimported)
 
@@ -180,6 +178,24 @@ Test:
  - Handle snapping
  - Multi-select Move/Rotate/scale
 
+----------------------------------------------------------------------
+Undo/Redo C#
+
+UndoRedo class
+ - RegisterCommand(cmd, operationName)
+ - pushGroup
+ - popGroup
+ - undo
+ - redo
+ - clear
+
+RecordObjectCommand
+ - Saves the entire object and at the end of the frame performs a diff of the object to actually generate the undo operation
+ - Must work for scene objects, components and resources
+SetParentCommand - For reparenting scene objects
+AddComponentCommand
+DestroyCommand - for destroying scene objects or components
+
 ----------------------------------------------------------------------
 Other