Browse Source

Added better selected element management to scene and resource TreeViews

Marko Pintera 11 years ago
parent
commit
0269741e02

+ 5 - 0
BansheeEditor/Include/BsGUIResourceTreeView.h

@@ -44,6 +44,10 @@ namespace BansheeEngine
 			const String& editBoxStyle = StringUtil::BLANK, const String& dragHighlightStyle = StringUtil::BLANK, 
 			const String& dragSepHighlightStyle = StringUtil::BLANK);
 
+		Vector<Path> getSelection() const;
+		void setSelection(const Vector<Path>& paths);
+
+		Event<void()> onSelectionChanged;
 
 	protected:
 		virtual ~GUIResourceTreeView();
@@ -77,6 +81,7 @@ namespace BansheeEngine
 		virtual void dragAndDropEnded(TreeElement* overTreeElement);
 		virtual void dragAndDropFinalize();
 		virtual bool _acceptDragAndDrop(const Vector2I position, UINT32 typeId) const;
+		virtual void selectionChanged();
 
 		void updateFromProjectLibraryEntry(ResourceTreeElement* treeElement, const ProjectLibrary::LibraryEntry* libraryEntry);
 		ResourceTreeElement* addTreeElement(ResourceTreeElement* parent, const Path& fullPath);

+ 4 - 0
BansheeEditor/Include/BsGUISceneTreeView.h

@@ -42,7 +42,10 @@ namespace BansheeEngine
 			const String& editBoxStyle = StringUtil::BLANK, const String& dragHighlightStyle = StringUtil::BLANK, 
 			const String& dragSepHighlightStyle = StringUtil::BLANK);
 
+		Vector<HSceneObject> getSelection() const;
+		void setSelection(const Vector<HSceneObject>& objects);
 
+		Event<void()> onSelectionChanged;
 	protected:
 		virtual ~GUISceneTreeView();
 
@@ -65,6 +68,7 @@ namespace BansheeEngine
 		virtual void dragAndDropEnded(TreeElement* overTreeElement);
 		virtual void dragAndDropFinalize();
 		virtual bool _acceptDragAndDrop(const Vector2I position, UINT32 typeId) const;
+		virtual void selectionChanged();
 
 		void deleteTreeElementInternal(TreeElement* element);
 	};

+ 2 - 0
BansheeEditor/Include/BsGUITreeView.h

@@ -147,12 +147,14 @@ namespace BansheeEngine
 		virtual void dragAndDropStart() = 0;
 		virtual void dragAndDropEnded(TreeElement* overTreeElement) = 0;
 		virtual void dragAndDropFinalize() = 0;
+		virtual void selectionChanged() { }
 
 		bool isSelectionActive() const;
 		void selectElement(TreeElement* element);
 		void unselectElement(TreeElement* element);
 		void unselectAll();
 
+		void expandToElement(TreeElement* element);
 		void expandElement(TreeElement* element);
 		void collapseElement(TreeElement* element);
 

+ 45 - 0
BansheeEditor/Source/BsGUIResourceTreeView.cpp

@@ -463,6 +463,51 @@ namespace BansheeEngine
 		return typeId == (UINT32)DragAndDropType::Resources;
 	}
 
+	void GUIResourceTreeView::selectionChanged()
+	{
+		onSelectionChanged();
+	}
+
+	Vector<Path> GUIResourceTreeView::getSelection() const
+	{
+		Vector<Path> selectedPaths;
+		for (auto& selectedElem : mSelectedElements)
+		{
+			ResourceTreeElement* resTreeElement = static_cast<ResourceTreeElement*>(selectedElem.element);
+
+			selectedPaths.push_back(resTreeElement->mFullPath);
+		}
+
+		return selectedPaths;
+	}
+
+	void GUIResourceTreeView::setSelection(const Vector<Path>& paths)
+	{
+		ResourceTreeElement& root = mRootElement;
+
+		Stack<ResourceTreeElement*> todo;
+		todo.push(&mRootElement);
+
+		while (!todo.empty())
+		{
+			ResourceTreeElement* currentElem = todo.top();
+			todo.pop();
+
+			auto iterFind = std::find(paths.begin(), paths.end(), currentElem->mFullPath);
+			if (iterFind != paths.end())
+			{
+				expandToElement(currentElem);
+				selectElement(currentElem);
+			}
+
+			for (auto& child : currentElem->mChildren)
+			{
+				ResourceTreeElement* sceneChild = static_cast<ResourceTreeElement*>(child);
+				todo.push(sceneChild);
+			}
+		}
+	}
+
 	const String& GUIResourceTreeView::getGUITypeName()
 	{
 		static String typeName = "ResourceTreeView";

+ 45 - 0
BansheeEditor/Source/BsGUISceneTreeView.cpp

@@ -260,6 +260,51 @@ namespace BansheeEngine
 		return typeId == (UINT32)DragAndDropType::SceneObject;
 	}
 
+	void GUISceneTreeView::selectionChanged()
+	{
+		onSelectionChanged();
+	}
+
+	Vector<HSceneObject> GUISceneTreeView::getSelection() const
+	{
+		Vector<HSceneObject> selectedSOs;
+		for (auto& selectedElem : mSelectedElements)
+		{
+			SceneTreeElement* sceneTreeElement = static_cast<SceneTreeElement*>(selectedElem.element);
+
+			selectedSOs.push_back(sceneTreeElement->mSceneObject);
+		}
+
+		return selectedSOs;
+	}
+
+	void GUISceneTreeView::setSelection(const Vector<HSceneObject>& objects)
+	{
+		SceneTreeElement& root = mRootElement;
+
+		Stack<SceneTreeElement*> todo;
+		todo.push(&mRootElement);
+
+		while (!todo.empty())
+		{
+			SceneTreeElement* currentElem = todo.top();
+			todo.pop();
+
+			auto iterFind = std::find(objects.begin(), objects.end(), currentElem->mSceneObject);
+			if (iterFind != objects.end())
+			{
+				expandToElement(currentElem);
+				selectElement(currentElem);
+			}
+
+			for (auto& child : currentElem->mChildren)
+			{
+				SceneTreeElement* sceneChild = static_cast<SceneTreeElement*>(child);
+				todo.push(sceneChild);
+			}
+		}
+	}
+
 	const String& GUISceneTreeView::getGUITypeName()
 	{
 		static String typeName = "SceneTreeView";

+ 31 - 0
BansheeEditor/Source/BsGUITreeView.cpp

@@ -503,6 +503,8 @@ namespace BansheeEngine
 
 			mSelectedElements.push_back(SelectedElement(element, background));
 			mIsElementSelected = true;
+
+			selectionChanged();
 		}
 	}
 
@@ -518,6 +520,8 @@ namespace BansheeEngine
 
 			mSelectedElements.erase(iterFind);
 			markContentAsDirty();
+
+			selectionChanged();
 		}
 
 		mIsElementSelected = mSelectedElements.size() > 0;
@@ -535,6 +539,33 @@ namespace BansheeEngine
 		mIsElementSelected = false;
 
 		markContentAsDirty();
+
+		selectionChanged();
+	}
+
+	void GUITreeView::expandToElement(TreeElement* element)
+	{
+		if (element->mIsVisible || element->mParent == nullptr)
+			return;
+
+		Stack<TreeElement*> todo;
+
+		TreeElement* parent = element->mParent;
+		while (parent != nullptr && !parent->mIsVisible)
+		{
+			if (!parent->mIsExpanded)
+				todo.push(parent);
+
+			parent = parent->mParent;
+		}
+
+		while (!todo.empty())
+		{
+			TreeElement* curElement = todo.top();
+			todo.pop();
+
+			expandElement(curElement);
+		}
 	}
 
 	void GUITreeView::expandElement(TreeElement* element)

+ 44 - 7
SceneView.txt

@@ -2,10 +2,19 @@
 TODO:
  - Core thread gets stuck on shutdown when OpenGL is used...Somewhere in kernel
 
+CONCRETE TASK:
+ - SceneView editor window: Add a way to detect exact mouse position on the render texture
+ - Extend SceneTreeView and ResourceTreeView that have events that occurr when selection changes
+    - Events need to return SceneObject, Resource or Path (an array of any of those if needed)
+ - Extend SceneTreeView and ResourceTreeView so that they have setSelection method accepting SceneObject/Resource-Path arrays
+ - Similar to how I have onRenderViewport callback in Renderer have another one that gets triggered from core thread
+   - Hook up gizmo rendering there
+ - Hook up gizmo manager to ScenePicking so gizmos are considered when picking
+   - I'll likely need to update GizmoManager so I can query gizmo SceneObject based on gizmo index
+
 IMMEDIATE:
  - SceneGrid is very ugly. Consider using default lines for now and come back with a better approach later.
    - Potentially enable line AA?
- - In Picking code I don't set main texture when rendering with alpha
  - Picking code is completely untested and will likely need major fixing
  - Disable DX9 for editor as I will likely want to use geometry shaders for icon rendering, and possibly new AA line shader
    - Or just use MeshHeap and update the icon/lines every frame?
@@ -13,9 +22,7 @@ IMMEDIATE:
 
  GIZMO TODO:
   - IMPORTANT: Gizmo rendering happens in update() but it should happen whenever scene view is being rendered as the render target isn't set anywhere
-  - Add a method that renders gizmos for picking
   - Figure out how to deal with builtin components like Camera and Renderable (e.g. how will they have gizmos since they're not managed components?)
-  - Don't forget to call clearGizmos every frame
 
 LATER:
  - Need a way to render text for gizmos and handles, and in scene in general
@@ -39,8 +46,38 @@ TODO - Think about this
 See for inspiration: http://docs.unity3d.com/ScriptReference/Handles.html
 
 ----------------------------------------------------------------------
-Rendering selection
+SelectionRenderer
+
+Retrieve a list of selected objects from SelectionManager
+Find ones with Renderable components
+Retrieve Meshes, and world transforms from them
+Draw that same mesh with either a wireframe or a grayed out shader with a slight depth bias
+
+----------------------------------------------------------------------
+SceneView editor flow:
+  Hook up gizmo, handle and selection rendering methods to be executed after the scene is rendered
+  Calculate mouse coords manually relative to the window and to the render texture GUI element
+     - Don't use GUI events as we require more precise control (do we?)
+
+  Detect mouse clicks on the scene render target
+      Forward those mouse coordinates to HandleManager
+      It checks if screen ray intersects any handles and returns the handle if it does
+         If handle is found it is activated and method returns
+         Otherwise we mark the coordinates as selection start
+
+  Detect mouse drag on the scene render target
+    - If we have an active handle
+         Forward mouse coordinates to the active handle so it can do its thing
+         return
+    - Otherwise its assumed we are dragging a selection
+         Update selection endpoint and send it to ScenePicking
+         Use Selection to select picked objects if any
+         return
 
-Get the mesh from the selected Renderable
-Draw that same mesh again using a shader that grays out the original
-The second mesh will likely need to use depth bias (sloped depth bias too?)
+  Detect mouse release on scene render target
+     If we have an active handle
+        Clear active handle
+        return
+     Otheriwse its assumed we are dragging a selection
+        Do nothing
+        return