瀏覽代碼

WIP: On-demand 3D viewport drawing
- Enabled on-demand drawing for scene camera
- Notify to redraw when camera moves/changes
- Notify to redraw when scene is marked as dirty
- Notify to redraw when handle sliders are interacted with
- Toggle normal drawing when entering/exiting play mode

BearishSun 6 年之前
父節點
當前提交
5329e98bb3

+ 4 - 6
Source/EditorCore/Handles/BsHandleManager.cpp

@@ -11,8 +11,6 @@
 namespace bs
 {
 	HandleManager::HandleManager()
-		: mSliderManager(nullptr), mDrawManager(nullptr), mInputStarted(false), mSettingsHash(0xFFFFFFFF)
-		, mLastDrawFrameIdx((UINT64)-1)
 	{
 		mSliderManager = bs_new<HandleSliderManager>();
 		mDrawManager = bs_new<HandleDrawManager>();
@@ -35,18 +33,18 @@ namespace bs
 		mInputStarted = true;
 	}
 
-	void HandleManager::updateInput(const SPtr<Camera>& camera, const Vector2I& inputPos, const Vector2I& inputDelta)
+	bool HandleManager::updateInput(const SPtr<Camera>& camera, const Vector2I& inputPos, const Vector2I& inputDelta)
 	{
 		if(!mInputStarted)
 		{
 			BS_LOG(Warning, Editor, "Updating handle input without calling beginInput() first. Input won't be processed.");
-			return;
+			return false;
 		}
 
 		if (mSettings != nullptr && mSettingsHash != mSettings->getHash())
 			updateFromEditorSettings();
 
-		mSliderManager->update(camera, inputPos, inputDelta);
+		return mSliderManager->update(camera, inputPos, inputDelta);
 	}
 
 	void HandleManager::endInput()
@@ -82,7 +80,7 @@ namespace bs
 		mSettingsHash = mSettings->getHash();
 	}
 
-	void HandleManager::trySelect(const SPtr<Camera>& camera, const Vector2I& inputPos)
+	bool HandleManager::trySelect(const SPtr<Camera>& camera, const Vector2I& inputPos)
 	{
 		return mSliderManager->trySelect(camera, inputPos);
 	}

+ 9 - 7
Source/EditorCore/Handles/BsHandleManager.h

@@ -32,8 +32,9 @@ namespace bs
 		 * @param[in]	camera		Camera that the input positions are relative to.
 		 * @param[in]	inputPos	Position of the pointer, relative to the provided camera viewport.
 		 * @param[in]	inputDelta	Determines pointer movement since last call to this method.
+		 * @return					True if handle slider hover state changed, false otherwise.
 		 */
-		void updateInput(const SPtr<Camera>& camera, const Vector2I& inputPos, const Vector2I& inputDelta);
+		bool updateInput(const SPtr<Camera>& camera, const Vector2I& inputPos, const Vector2I& inputDelta);
 
 		/** 
 		 * Triggers handle post-input callbacks. Must be called after all updateInput() calls and after beginInput().
@@ -54,8 +55,9 @@ namespace bs
 		 *
 		 * @param[in]	camera		Camera that the input positions are relative to, and destination to draw the handles to.
 		 * @param[in]	inputPos	Position of the pointer, relative to the provided camera viewport.
+		 * @return					True if handle slider active state changed, false otherwise.
 		 */
-		void trySelect(const SPtr<Camera>& camera, const Vector2I& inputPos);
+		bool trySelect(const SPtr<Camera>& camera, const Vector2I& inputPos);
 
 		/**	Clears the currently selected/active handle slider for the specified camera. */
 		void clearSelection(const SPtr<Camera>& camera);
@@ -97,15 +99,15 @@ namespace bs
 		/** Called during handle update. Allows implementation to queue handle draw commands. */
 		virtual void queueDrawCommands() = 0;
 
-		HandleSliderManager* mSliderManager;
-		HandleDrawManager* mDrawManager;
+		HandleSliderManager* mSliderManager = nullptr;
+		HandleDrawManager* mDrawManager = nullptr;
 
 		float mDefaultHandleSize = 20.0f;
-		bool mInputStarted;
+		bool mInputStarted = false;
 
 		SPtr<EditorSettings> mSettings;
-		UINT32 mSettingsHash;
-		UINT64 mLastDrawFrameIdx;
+		UINT32 mSettingsHash = 0xFFFFFFFF;
+		UINT64 mLastDrawFrameIdx = (UINT64)-1;
 	};
 
 	/** @} */

+ 13 - 2
Source/EditorCore/Handles/BsHandleSliderManager.cpp

@@ -9,7 +9,7 @@ using namespace std::placeholders;
 
 namespace bs
 {
-	void HandleSliderManager::update(const SPtr<Camera>& camera, const Vector2I& inputPos, const Vector2I& inputDelta)
+	bool HandleSliderManager::update(const SPtr<Camera>& camera, const Vector2I& inputPos, const Vector2I& inputDelta)
 	{
 		for (auto& slider : mSliders)
 		{
@@ -44,19 +44,26 @@ namespace bs
 					state.hoverSlider = newHoverSlider;
 					state.hoverSlider->setHover();
 				}
+
+				return true;
 			}
 		}
+
+		return false;
 	}
 
-	void HandleSliderManager::trySelect(const SPtr<Camera>& camera, const Vector2I& inputPos)
+	bool HandleSliderManager::trySelect(const SPtr<Camera>& camera, const Vector2I& inputPos)
 	{
 		HandleSlider* newActiveSlider = findUnderCursor(camera, inputPos);
 
+		bool stateChanged = false;
 		StatePerCamera& state = mStates[camera->getInternalID()];
 		if (state.hoverSlider != nullptr)
 		{
 			state.hoverSlider->setInactive();
 			state.hoverSlider = nullptr;
+
+			stateChanged = true;
 		}
 
 		if (newActiveSlider != state.activeSlider)
@@ -72,7 +79,11 @@ namespace bs
 				state.activeSlider = newActiveSlider;
 				state.activeSlider->setActive(camera, inputPos);
 			}
+
+			return true;
 		}
+
+		return stateChanged;
 	}
 
 	bool HandleSliderManager::isSliderActive(const SPtr<Camera>& camera) const

+ 4 - 2
Source/EditorCore/Handles/BsHandleSliderManager.h

@@ -28,16 +28,18 @@ namespace bs
 		 * @param[in]	camera		Camera through which we're interacting with sliders.
 		 * @param[in]	inputPos	Position of the pointer.
 		 * @param[in]	inputDelta	Movement of the pointer since last frame.
+		 * @return					True if slider state changed, false otherwise.
 		 */
-		void update(const SPtr<Camera>& camera, const Vector2I& inputPos, const Vector2I& inputDelta);
+		bool update(const SPtr<Camera>& camera, const Vector2I& inputPos, const Vector2I& inputDelta);
 
 		/**
 		 * Attempts to select (activate) a slider at the specified position.
 		 *
 		 * @param[in]	camera		Camera through which we're interacting with sliders.
 		 * @param[in]	inputPos	Position of the pointer.
+		 * @return					True if handle slider state changed, false otherwise.
 		 */
-		void trySelect(const SPtr<Camera>& camera, const Vector2I& inputPos);
+		bool trySelect(const SPtr<Camera>& camera, const Vector2I& inputPos);
 
 		/** Clears the active slider (deactivates it) for the specified camera. */
 		void clearSelection(const SPtr<Camera>& camera);

+ 55 - 3
Source/EditorManaged/General/EditorApplication.cs

@@ -284,12 +284,29 @@ namespace bs.Editor
                         log.Refresh();
                 }
 
+                ToggleOnDemandDrawing(false);
                 ToggleToolbarItem("Play", true);
             };
 
-            PlayInEditor.OnStopped += () => ToggleToolbarItem("Play", false);
-            PlayInEditor.OnPaused += () => ToggleToolbarItem("Pause", true);
-            PlayInEditor.OnUnpaused += () => ToggleToolbarItem("Pause", false);
+            PlayInEditor.OnStopped += () =>
+            {
+                ToggleOnDemandDrawing(true);
+                ToggleToolbarItem("Play", false);
+            };
+
+            PlayInEditor.OnPaused += () =>
+            {
+                ToggleOnDemandDrawing(true);
+                ToggleToolbarItem("Pause", true);
+            };
+
+            PlayInEditor.OnUnpaused += () =>
+            {
+                ToggleOnDemandDrawing(false);
+                ToggleToolbarItem("Pause", false);
+            };
+
+            Selection.OnSelectionChanged += OnSelectionChanged;
 
             // Register controls
             InputConfiguration inputConfig = VirtualInput.KeyConfig;
@@ -348,6 +365,13 @@ namespace bs.Editor
             hierarcyWindow?.SaveHierarchyState(EditorSceneData);
         }
 
+        /// <summary>
+        /// Triggered whenever object or resource selection changes.
+        /// </summary>
+        private static void OnSelectionChanged(SceneObject[] sceneObjects, string[] resourcePaths)
+        {
+            NotifyNeedsRedraw();
+        }
 
         /// <summary>
         /// Triggered when the scene has been loaded.
@@ -817,6 +841,7 @@ namespace bs.Editor
         public static void SetSceneDirty()
         {
             SetSceneDirty(true);
+            NotifyNeedsRedraw();
         }
 
         /// <summary>
@@ -842,6 +867,33 @@ namespace bs.Editor
             return persistentData.dirtyResources.ContainsKey(resource.UUID);
         }
 
+        /// <summary>
+        /// Notifies the system that the 3D viewports should be redrawn.
+        /// </summary>
+        public static void NotifyNeedsRedraw()
+        {
+            SceneWindow sceneWindow = EditorWindow.GetWindow<SceneWindow>();
+            sceneWindow?.NotifyNeedsRedraw();
+
+            GameWindow gameWindow = EditorWindow.GetWindow<GameWindow>();
+            gameWindow?.NotifyNeedsRedraw();
+        }
+
+        /// <summary>
+        /// Enables or disables on-demand drawing for 3D viewports. When enabled the viewports will only be
+        /// redrawn when <see cref="NotifyNeedsRedraw"/> is called. If disabled the viewport will be redrawn
+        /// every frame.
+        /// </summary>
+        /// <param name="enabled">True to enable on-demand drawing, false otherwise.</param>
+        public static void ToggleOnDemandDrawing(bool enabled)
+        {
+            SceneWindow sceneWindow = EditorWindow.GetWindow<SceneWindow>();
+            sceneWindow?.ToggleOnDemandDrawing(enabled);
+
+            GameWindow gameWindow = EditorWindow.GetWindow<GameWindow>();
+            gameWindow?.ToggleOnDemandDrawing(enabled);
+        }
+
         /// <summary>
         /// Checks does the path represent a native resource.
         /// </summary>

+ 26 - 0
Source/EditorManaged/Windows/GameWindow.cs

@@ -160,6 +160,32 @@ namespace bs.Editor
             EditorApplication.MainRenderTarget = null;
         }
 
+        /// <summary>
+        /// Notifies the system that the 3D viewport should be redrawn.
+        /// </summary>
+        internal void NotifyNeedsRedraw()
+        {
+            Camera camera = Scene.Camera;
+            camera?.NotifyNeedsRedraw();
+        }
+
+        /// <summary>
+        /// Enables or disables on-demand drawing. When enabled the 3D viewport will only be redrawn when
+        /// <see cref="NotifyNeedsRedraw"/> is called. If disabled the viewport will be redrawn every frame.
+        /// </summary>
+        /// <param name="enabled">True to enable on-demand drawing, false otherwise.</param>
+        internal void ToggleOnDemandDrawing(bool enabled)
+        {
+            Camera camera = Scene.Camera;
+            if (camera == null)
+                return;
+
+            if (enabled)
+                camera.Flags = CameraFlag.OnDemand;
+            else
+                camera.Flags = new CameraFlag();
+        }
+
         /// <summary>
         /// Creates or rebuilds the main render texture. Should be called at least once before using the
         /// game window. Should be called whenever the window is resized.

+ 36 - 0
Source/EditorManaged/Windows/Scene/SceneCamera.cs

@@ -89,6 +89,8 @@ namespace bs.Editor
                 camera.OrthoHeight = value.orthographicSize;
                 camera.FieldOfView = value.fieldOfView;
                 camera.Viewport.ClearColor = value.backgroundColor;
+
+                NotifyNeedsRedraw();
             }
         }
 
@@ -170,6 +172,30 @@ namespace bs.Editor
             SetState(state);
         }
 
+        /// <summary>
+        /// Notifies the system that the 3D viewport should be redrawn.
+        /// </summary>
+        internal void NotifyNeedsRedraw()
+        {
+            camera?.NotifyNeedsRedraw();
+        }
+
+        /// <summary>
+        /// Enables or disables on-demand drawing. When enabled the 3D viewport will only be redrawn when
+        /// <see cref="NotifyNeedsRedraw"/> is called. If disabled the viewport will be redrawn every frame.
+        /// </summary>
+        /// <param name="enabled">True to enable on-demand drawing, false otherwise.</param>
+        internal void ToggleOnDemandDrawing(bool enabled)
+        {
+            if (camera == null)
+                return;
+
+            if (enabled)
+                camera.Flags = CameraFlag.OnDemand;
+            else
+                camera.Flags = new CameraFlag();
+        }
+
         #endregion
 
         #region Private methods
@@ -193,6 +219,8 @@ namespace bs.Editor
             horizontalAxis = new VirtualAxis(HorizontalAxisBinding);
             verticalAxis = new VirtualAxis(VerticalAxisBinding);
             scrollAxis = new VirtualAxis(ScrollAxisBinding);
+
+            NotifyNeedsRedraw();
         }
 
         private void OnUpdate()
@@ -289,6 +317,8 @@ namespace bs.Editor
                         Vector3 velocity = direction * currentSpeed;
                         SceneObject.Move(velocity * frameDelta);
                     }
+
+                    NotifyNeedsRedraw();
                 }
 
                 // Pan
@@ -301,6 +331,8 @@ namespace bs.Editor
                     direction = camera.SceneObject.Rotation.Rotate(direction);
 
                     SceneObject.Move(direction * MoveSettings.panSpeed * frameDelta);
+
+                    NotifyNeedsRedraw();
                 }
             }
             else
@@ -338,6 +370,8 @@ namespace bs.Editor
                             if (oldOrthoHeight != orthoHeight)
                                 camera.OrthoHeight = orthoHeight;
                         }
+
+                        NotifyNeedsRedraw();
                     }
                 }
             }
@@ -456,6 +490,8 @@ namespace bs.Editor
 
             camera.NearClipPlane = near;
             camera.FarClipPlane = far;
+
+            NotifyNeedsRedraw();
         }
 
         /// <summary>

+ 8 - 6
Source/EditorManaged/Windows/Scene/SceneHandles.cs

@@ -49,9 +49,10 @@ namespace bs.Editor
         /// </summary>
         /// <param name="pointerPos">Position of the pointer relative to the scene camera viewport.</param>
         /// <param name="inputDelta">Movement of the pointer since last frame.</param>
-        internal void UpdateInput(Vector2I pointerPos, Vector2I inputDelta)
+        /// <returns>True if the state of any handle sliders changed, false otherwise.</returns>
+        internal bool UpdateInput(Vector2I pointerPos, Vector2I inputDelta)
         {
-            Internal_UpdateInput(mCachedPtr, ref pointerPos, ref inputDelta);
+            return Internal_UpdateInput(mCachedPtr, ref pointerPos, ref inputDelta);
         }
 
         /// <summary>
@@ -66,9 +67,10 @@ namespace bs.Editor
         /// Selects a handle under the pointer position.
         /// </summary>
         /// <param name="pointerPos">Position of the pointer relative to the target camera's viewport.</param>
-        internal void TrySelect(Vector2I pointerPos)
+        /// <returns>True if the state of any handle sliders changed, false otherwise.</returns>
+        internal bool TrySelect(Vector2I pointerPos)
         {
-            Internal_TrySelect(mCachedPtr, ref pointerPos);
+            return Internal_TrySelect(mCachedPtr, ref pointerPos);
         }
 
         /// <summary>
@@ -98,13 +100,13 @@ namespace bs.Editor
         private static extern void Internal_EndInput();
 
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_UpdateInput(IntPtr thisPtr, ref Vector2I pointerPos, ref Vector2I inputDelta);
+        private static extern bool Internal_UpdateInput(IntPtr thisPtr, ref Vector2I pointerPos, ref Vector2I inputDelta);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_Draw(IntPtr thisPtr);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_TrySelect(IntPtr thisPtr, ref Vector2I pointerPos);
+        private static extern bool Internal_TrySelect(IntPtr thisPtr, ref Vector2I pointerPos);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern bool Internal_IsActive(IntPtr thisPtr);

+ 33 - 2
Source/EditorManaged/Windows/Scene/SceneWindow.cs

@@ -606,7 +606,10 @@ namespace bs.Editor
             {
                 dragResult = EndDragSelection();
                 if (sceneHandles.IsActive())
+                {
                     sceneHandles.ClearSelection();
+                    NotifyNeedsRedraw();
+                }
 
                 if (sceneAxesGUI.IsActive())
                     sceneAxesGUI.ClearSelection();
@@ -736,7 +739,10 @@ namespace bs.Editor
                         if (sceneAxesGUIBounds.Contains(scenePos))
                             sceneAxesGUI.TrySelect(scenePos);
                         else
-                            sceneHandles.TrySelect(scenePos);
+                        {
+                            if(sceneHandles.TrySelect(scenePos))
+                                NotifyNeedsRedraw();
+                        }
                     }
                     else if (Input.IsPointerButtonHeld(PointerButton.Left) && !handleActive && !dragActive &&
                              draggedSO == null && scenePos != mouseDownPosition)
@@ -764,11 +770,15 @@ namespace bs.Editor
             if (AllowViewportInput)
             {
                 SceneHandles.BeginInput();
-                sceneHandles.UpdateInput(scenePos, Input.PointerDelta);
+                if(sceneHandles.UpdateInput(scenePos, Input.PointerDelta))
+                    NotifyNeedsRedraw();
                 sceneAxesGUI.UpdateInput(scenePos);
                 SceneHandles.EndInput();
             }
 
+            if(sceneHandles.IsActive())
+                NotifyNeedsRedraw();
+
             sceneHandles.Draw();
             sceneAxesGUI.Draw();
 
@@ -796,6 +806,7 @@ namespace bs.Editor
             if (!inFocus)
             {
                 sceneHandles.ClearSelection();
+                NotifyNeedsRedraw();
             }
         }
 
@@ -967,6 +978,7 @@ namespace bs.Editor
                 camera.Priority = 2;
                 camera.Viewport.ClearColor = ClearColor;
                 camera.Layers = UInt64.MaxValue & ~SceneAxesHandle.LAYER; // Don't draw scene axes in this camera
+                camera.Flags = CameraFlag.OnDemand;
 
                 sceneCamera = sceneCameraSO.AddComponent<SceneCamera>();
 
@@ -994,6 +1006,25 @@ namespace bs.Editor
             // render target destroy/create cycle for every single pixel.
 
             camera.AspectRatio = width / (float)height;
+            camera.NotifyNeedsRedraw();
+        }
+
+        /// <summary>
+        /// Notifies the system that the 3D viewport should be redrawn.
+        /// </summary>
+        internal void NotifyNeedsRedraw()
+        {
+            sceneCamera?.NotifyNeedsRedraw();
+        }
+
+        /// <summary>
+        /// Enables or disables on-demand drawing. When enabled the 3D viewport will only be redrawn when
+        /// <see cref="NotifyNeedsRedraw"/> is called. If disabled the viewport will be redrawn every frame.
+        /// </summary>
+        /// <param name="enabled">True to enable on-demand drawing, false otherwise.</param>
+        internal void ToggleOnDemandDrawing(bool enabled)
+        {
+            sceneCamera?.ToggleOnDemandDrawing(enabled);
         }
 
         /// <summary>

+ 4 - 4
Source/EditorScript/Wrappers/BsScriptSceneHandles.cpp

@@ -102,7 +102,7 @@ namespace bs
 		HandleManager::instance().endInput();
 	}
 
-	void ScriptSceneHandles::internal_UpdateInput(ScriptSceneHandles* thisPtr, Vector2I* inputPos, Vector2I* inputDelta)
+	bool ScriptSceneHandles::internal_UpdateInput(ScriptSceneHandles* thisPtr, Vector2I* inputPos, Vector2I* inputDelta)
 	{
 		// If mouse wrapped around last frame then we need to compensate for the jump amount
 		Vector2I realDelta = *inputDelta - thisPtr->mMouseDeltaCompensate;
@@ -111,12 +111,12 @@ namespace bs
 		if (HandleManager::instance().isHandleActive(thisPtr->mCamera->_getCamera()))
 			thisPtr->mMouseDeltaCompensate = thisPtr->wrapCursorToWindow();
 
-		HandleManager::instance().updateInput(thisPtr->mCamera->_getCamera(), *inputPos, realDelta);
+		return HandleManager::instance().updateInput(thisPtr->mCamera->_getCamera(), *inputPos, realDelta);
 	}
 
-	void ScriptSceneHandles::internal_TrySelect(ScriptSceneHandles* thisPtr, Vector2I* inputPos)
+	bool ScriptSceneHandles::internal_TrySelect(ScriptSceneHandles* thisPtr, Vector2I* inputPos)
 	{
-		HandleManager::instance().trySelect(thisPtr->mCamera->_getCamera(), *inputPos);
+		return HandleManager::instance().trySelect(thisPtr->mCamera->_getCamera(), *inputPos);
 	}
 
 	bool ScriptSceneHandles::internal_IsActive(ScriptSceneHandles* thisPtr)

+ 2 - 2
Source/EditorScript/Wrappers/BsScriptSceneHandles.h

@@ -44,8 +44,8 @@ namespace bs
 		static void internal_Draw(ScriptSceneHandles* thisPtr);
 		static void internal_BeginInput();
 		static void internal_EndInput();
-		static void internal_UpdateInput(ScriptSceneHandles* thisPtr, Vector2I* inputPos, Vector2I* inputDelta);
-		static void internal_TrySelect(ScriptSceneHandles* thisPtr, Vector2I* inputPos);
+		static bool internal_UpdateInput(ScriptSceneHandles* thisPtr, Vector2I* inputPos, Vector2I* inputDelta);
+		static bool internal_TrySelect(ScriptSceneHandles* thisPtr, Vector2I* inputPos);
 		static bool internal_IsActive(ScriptSceneHandles* thisPtr);
 		static void internal_ClearSelection(ScriptSceneHandles* thisPtr);
 	};

+ 1 - 1
Source/bsf

@@ -1 +1 @@
-Subproject commit 90c5277d04ef7104ce4ead4f6b28a63db1288764
+Subproject commit 2bd8a37787b988956afb0fb9662e3fc5a88aa3ad