Jelajahi Sumber

Update scene view render target size whenever the view size changes

Marko Pintera 11 tahun lalu
induk
melakukan
3d1ffd9d09

+ 23 - 0
BansheeCore/Include/BsViewport.h

@@ -31,6 +31,11 @@ namespace BansheeEngine
          */
         RenderTargetPtr getTarget() const { return mTarget; }
 
+		/**
+		 * @brief	Sets the render target the viewport will be associated with.
+		 */
+		void setTarget(const RenderTargetPtr& target) { mTarget = target; markCoreDirty(); }
+
         /**
          * @brief	Gets the normalized x coordinate of the viewport, in [0, 1] range.
          */
@@ -129,7 +134,23 @@ namespace BansheeEngine
 		 * @brief	Makes an exact copy of this viewport.
 		 */
 		Viewport clone();
+
+		/**
+		 * @brief	Checks is the core dirty flag set. This is used by external systems 
+		 *			to know when internal data has changed and core thread potentially needs to be notified.
+		 */
+		bool _isCoreDirty() const { return mCoreDirtyFlags != 0; }
+
+		/**
+		 * @brief	Marks the core dirty flag as clean.
+		 */
+		void _markCoreClean() { mCoreDirtyFlags = 0; }
     protected:
+		/**
+		 * @brief	Marks the core data as dirty, signaling that the core thread needs an updated version.
+		 */
+		void markCoreDirty() { mCoreDirtyFlags = 0xFFFFFFFF; }
+
         RenderTargetPtr mTarget;
 
 		RectF mNormArea;
@@ -142,6 +163,8 @@ namespace BansheeEngine
 		float mDepthClearValue;
 		UINT16 mStencilClearValue;
 
+		UINT32 mCoreDirtyFlags; /**< True when internal data has changed and core thread wasn't yet informed. */
+
 		static const Color DEFAULT_CLEAR_COLOR;
     };
 }

+ 1 - 1
BansheeCore/Source/BsCoreObject.cpp

@@ -31,7 +31,7 @@ namespace BansheeEngine
 		if(!mThis.expired())
 		{
 			BS_EXCEPT(InternalErrorException, "Shared pointer to this object still has active references but " \
-				"the object is being deleted? You shouldn't delete CoreGpuObjects manually.");
+				"the object is being deleted? You shouldn't delete CoreObjects manually.");
 		}
 #endif
 

+ 10 - 2
BansheeCore/Source/BsRenderWindow.cpp

@@ -7,9 +7,17 @@
 namespace BansheeEngine 
 {
     RenderWindow::RenderWindow(const RENDER_WINDOW_DESC& desc)
-        : RenderTarget(), mIsFullScreen(false), mDesc(desc), mHasFocus(false), mLeft(0), mTop(0), mHidden(false)
+		: RenderTarget(), mIsFullScreen(false), mDesc(desc), mHasFocus(false), mLeft(0), mTop(0), mHidden(false)
     {
-
+		mWidth = desc.videoMode.getWidth();
+		mHeight = desc.videoMode.getHeight();
+		mHwGamma = desc.gamma;
+		mVSync = desc.vsync;
+		mMultisampleCount = desc.multisampleCount;
+		mLeft = desc.left; 
+		mTop = desc.top;
+		mIsFullScreen = desc.fullscreen;
+		mHidden = desc.hidden;
     }
 
 	RenderWindow::~RenderWindow() 

+ 8 - 2
BansheeCore/Source/BsViewport.cpp

@@ -11,14 +11,14 @@ namespace BansheeEngine
 
 	Viewport::Viewport()
 		:mTarget(nullptr), mClearColor(DEFAULT_CLEAR_COLOR), mRequiresColorClear(true), mRequiresDepthClear(true), 
-		mRequiresStencilClear(false), mStencilClearValue(0), mDepthClearValue(1.0f)
+		mRequiresStencilClear(false), mStencilClearValue(0), mDepthClearValue(1.0f), mCoreDirtyFlags(0xFFFFFFFF)
 	{
 
 	}
 
     Viewport::Viewport(const RenderTargetPtr& target, float x, float y, float width, float height)
          :mTarget(target), mNormArea(x, y, width, height), mClearColor(DEFAULT_CLEAR_COLOR), mRequiresColorClear(true), 
-		 mRequiresDepthClear(true), mRequiresStencilClear(false), mStencilClearValue(0), mDepthClearValue(1.0f)
+		 mRequiresDepthClear(true), mRequiresStencilClear(false), mStencilClearValue(0), mDepthClearValue(1.0f), mCoreDirtyFlags(0xFFFFFFFF)
     {
 
     }
@@ -33,6 +33,8 @@ namespace BansheeEngine
         mNormArea.y = y;
         mNormArea.width = width;
         mNormArea.height = height;
+
+		markCoreDirty();
     }
 
 	RectI Viewport::getArea() const
@@ -54,6 +56,8 @@ namespace BansheeEngine
 		mRequiresColorClear = colorClear;
 		mRequiresDepthClear = depthClear;
 		mRequiresStencilClear = stencilClear;
+
+		markCoreDirty();
 	}
 
 	void Viewport::setClearValues(const Color& clearColor, float clearDepth, UINT16 clearStencil)
@@ -61,6 +65,8 @@ namespace BansheeEngine
 		mClearColor = clearColor;
 		mDepthClearValue = clearDepth;
 		mStencilClearValue = clearStencil;
+
+		markCoreDirty();
 	}
 
 	INT32 Viewport::getX() const 

+ 3 - 0
BansheeEditor/Include/BsSceneEditorWidget.h

@@ -21,10 +21,13 @@ namespace BansheeEngine
 	protected:
 		void doOnResized(UINT32 width, UINT32 height);
 
+		void updateRenderTexture(UINT32 width, UINT32 height);
+
 	private:
 		static SceneEditorWidget* Instance;
 
 		RenderTexturePtr mSceneRenderTarget;
+		GUIRenderTexture* mGUIRenderTexture;
 		HCamera mCamera;
 	};
 }

+ 47 - 29
BansheeEditor/Source/BsSceneEditorWidget.cpp

@@ -18,33 +18,9 @@ namespace BansheeEngine
 	SceneEditorWidget* SceneEditorWidget::Instance = nullptr;
 
 	SceneEditorWidget::SceneEditorWidget(const ConstructPrivately& dummy, EditorWidgetContainer& parentContainer)
-		:EditorWidget<SceneEditorWidget>(HString(L"SceneEditorWidget"), parentContainer)
+		:EditorWidget<SceneEditorWidget>(HString(L"SceneEditorWidget"), parentContainer), mGUIRenderTexture(nullptr)
 	{
-		GUILayout& layout = mContent->getLayout();
-
-		UINT32 width = 200; // TODO - Use proper width/height once I have texture resize working. Have some mininum limit (e.g. 4x4)
-		UINT32 height = 200;
-		
-		mSceneRenderTarget = RenderTexture::create(TEX_TYPE_2D, width, height);
-		mSceneRenderTarget->setPriority(1);
-
-		HSceneObject sceneCameraSO = SceneObject::create("SceneCamera");
-		mCamera = sceneCameraSO->addComponent<Camera>(mSceneRenderTarget, 0.0f, 0.0f, 1.0f, 1.0f);
-
-		sceneCameraSO->setPosition(Vector3(0, 0, 0));
-		sceneCameraSO->lookAt(Vector3(0, 0, -3));
-
-		// DEBUG ONLY
-		sceneCameraSO->setPosition(Vector3(-130.0f, 140.0f, 650.0f));
-		sceneCameraSO->lookAt(Vector3(0, 0, 0));
-
-		mCamera->setPriority(1);
-		mCamera->setNearClipDistance(5);
-		mCamera->setAspectRatio(width / (float)height);
-
-		sceneCameraSO->addComponent<SceneCameraController>();
-
-		layout.addElement(GUIRenderTexture::create(mSceneRenderTarget));
+		updateRenderTexture(getWidth(), getHeight());
 	}
 
 	SceneEditorWidget::~SceneEditorWidget()
@@ -61,10 +37,52 @@ namespace BansheeEngine
 	{
 		EditorWidget::doOnResized(width, height);
 
-		// TODO - Need to resize render texture as the widget resizes
+		updateRenderTexture(width, height);
+	}
+
+	void SceneEditorWidget::updateRenderTexture(UINT32 width, UINT32 height)
+	{
+		width = std::max(20U, width);
+		height = std::max(20U, height);
+
+		if (mSceneRenderTarget != nullptr)
+			mSceneRenderTarget->destroy();
+
+		mSceneRenderTarget = RenderTexture::create(TEX_TYPE_2D, width, height);
+		mSceneRenderTarget->setPriority(1);
+
+		if (mCamera == nullptr)
+		{
+			HSceneObject sceneCameraSO = SceneObject::create("SceneCamera");
+			mCamera = sceneCameraSO->addComponent<Camera>(mSceneRenderTarget, 0.0f, 0.0f, 1.0f, 1.0f);
+
+			sceneCameraSO->setPosition(Vector3(0, 0, 0));
+			sceneCameraSO->lookAt(Vector3(0, 0, -3));
+
+			// DEBUG ONLY
+			sceneCameraSO->setPosition(Vector3(-130.0f, 140.0f, 650.0f));
+			sceneCameraSO->lookAt(Vector3(0, 0, 0));
 
-		//mSceneRenderTarget->set
-		//mCamera->setAspectRatio(getWidth() / getHeight());
+			mCamera->setPriority(1);
+			mCamera->setNearClipDistance(5);
+
+			sceneCameraSO->addComponent<SceneCameraController>();
+
+			GUILayout& layout = mContent->getLayout();
+
+			mGUIRenderTexture = GUIRenderTexture::create(mSceneRenderTarget);
+			layout.addElement(mGUIRenderTexture);
+		}
+		else
+		{
+			mCamera->getViewport()->setTarget(mSceneRenderTarget);
+			mGUIRenderTexture->setRenderTexture(mSceneRenderTarget);
+		}
+
+		// TODO - Consider only doing the resize once user stops resizing the widget in order to reduce constant
+		// render target destroy/create cycle for every little pixel.
+
+		mCamera->setAspectRatio(width / (float)height);
 	}
 
 	SceneEditorWidget* SceneEditorWidget::instance()

+ 2 - 2
BansheeEngine/Include/BsCamera.h

@@ -285,12 +285,12 @@ namespace BansheeEngine
 		 * @brief	Checks is the core dirty flag set. This is used by external systems 
 		 *			to know when internal data has changed and core thread potentially needs to be notified.
 		 */
-		bool _isCoreDirty() const { return mCoreDirtyFlags != 0; }
+		bool _isCoreDirty() const { return mCoreDirtyFlags != 0 || mViewport->_isCoreDirty(); }
 
 		/**
 		 * @brief	Marks the core dirty flag as clean.
 		 */
-		void _markCoreClean() { mCoreDirtyFlags = 0; }
+		void _markCoreClean() { mCoreDirtyFlags = 0; mViewport->_markCoreClean(); }
 
 		/**
 		 * @brief	Creates a new core proxy from the currently set options. Core proxies ensure

+ 6 - 1
BansheeEngine/Include/BsGUIRenderTexture.h

@@ -41,6 +41,11 @@ namespace BansheeEngine
 		 */
 		static GUIRenderTexture* create(const RenderTexturePtr& texture, const GUIOptions& layoutOptions, const String& styleName = StringUtil::BLANK);
 
+		/**
+		 * @brief	Changes the active render texture whose contents to display in the GUI element.
+		 */
+		void setRenderTexture(const RenderTexturePtr& texture);
+
 	protected:
 		GUIRenderTexture(const String& styleName, const RenderTexturePtr& texture, const GUILayoutOptions& layoutOptions);
 		virtual ~GUIRenderTexture();
@@ -50,6 +55,6 @@ namespace BansheeEngine
 		 */
 		virtual void updateRenderElementsInternal();
 
-		const RenderTexture* mSourceTexture;
+		RenderTexturePtr mSourceTexture;
 	};
 }

+ 1 - 0
BansheeEngine/Include/BsPrerequisites.h

@@ -48,6 +48,7 @@ namespace BansheeEngine
 	class GUIScrollBarHorz;
 	class GUIScrollArea;
 	class GUISkin;
+	class GUIRenderTexture;
 	struct GUIElementStyle;
 	class GUIMouseEvent;
 	class GUITextInputEvent;

+ 31 - 10
BansheeEngine/Source/BsGUIRenderTexture.cpp

@@ -14,21 +14,15 @@ namespace BansheeEngine
 	}
 
 	GUIRenderTexture::GUIRenderTexture(const String& styleName, const RenderTexturePtr& texture, const GUILayoutOptions& layoutOptions)
-		:GUITexture(styleName, HSpriteTexture(), GUIImageScaleMode::StretchToFit, layoutOptions), mSourceTexture(texture.get())
+		:GUITexture(styleName, HSpriteTexture(), GUIImageScaleMode::StretchToFit, layoutOptions)
 	{
-		if(mSourceTexture->requiresTextureFlipping())
-		{
-			mDesc.uvOffset = Vector2(0.0f, 1.0f);
-			mDesc.uvScale = Vector2(1.0f, -1.0f);
-		}
-
-		setTexture(SpriteTexture::create(texture->getBindableColorTexture()));
-		GUIManager::instance().setInputBridge(mSourceTexture, this);
+		setRenderTexture(texture);
 	}
 
 	GUIRenderTexture::~GUIRenderTexture()
 	{
-		GUIManager::instance().setInputBridge(mSourceTexture, nullptr);
+		if (mSourceTexture != nullptr)
+			GUIManager::instance().setInputBridge(mSourceTexture.get(), nullptr);
 	}
 
 	GUIRenderTexture* GUIRenderTexture::create(const RenderTexturePtr& texture, const String& styleName)
@@ -41,6 +35,33 @@ namespace BansheeEngine
 		return new (bs_alloc<GUIRenderTexture, PoolAlloc>()) GUIRenderTexture(getStyleName<GUIRenderTexture>(styleName), texture, GUILayoutOptions::create(layoutOptions));
 	}
 
+	void GUIRenderTexture::setRenderTexture(const RenderTexturePtr& texture)
+	{
+		if (mSourceTexture != nullptr)
+			GUIManager::instance().setInputBridge(mSourceTexture.get(), nullptr);
+
+		mSourceTexture = texture;
+
+		if (mSourceTexture != nullptr)
+		{
+			if (mSourceTexture->requiresTextureFlipping())
+			{
+				mDesc.uvOffset = Vector2(0.0f, 1.0f);
+				mDesc.uvScale = Vector2(1.0f, -1.0f);
+			}
+
+			setTexture(SpriteTexture::create(texture->getBindableColorTexture()));
+
+			GUIManager::instance().setInputBridge(mSourceTexture.get(), this);
+		}
+		else
+		{
+			setTexture(SpriteTexture::create(HTexture()));
+		}
+
+		markContentAsDirty();
+	}
+
 	void GUIRenderTexture::updateRenderElementsInternal()
 	{		
 		if(mActiveTexture != nullptr && mActiveTexture.isLoaded())

+ 30 - 5
SceneView.txt

@@ -1,9 +1,5 @@
-I get an error when serializing a material
- - I'm assuming its because one shader block is renderer manager and not created at the time of serialization
-
 Resizing SceneView requires a resize() method on RenderTexture
  - Add resize() method to RenderTexture and normal Texture
-Add a basic 3D model so SceneView actually displays something
 
 Think about how gizmos will be rendered
  - Both quad icon-like ones
@@ -16,4 +12,33 @@ Picking
  - Result is returned via async op
  - Needs to support multi-select where I draw a rectangle on screen
  - NOTE: I will also need to render gizmos which I assume will all be within a single buffer. This might require special care since normally I can color each buffer with a different color, which won't work in this case.
-     - Similar issue might happen with particles and other systems
+     - Similar issue might happen with particles and other systems
+
+
+--------------------------
+
+RenderTarget (and in turn, Viewport) make data available to sim thread, even though that data can be arbitrarily modified from the core thread
+
+Stuff that needs to be synchronized:
+ mIsFullscreen
+ mWidth
+ mHeight
+ mHidden
+ mTop
+ mLeft
+ mHasFocus
+ (more? check)
+
+Core thread should have up to date access as it has now.
+Sim thread should only get updated data next frame.
+ - Ensure this happens before any RenderWindowManager events
+
+-------------
+
+Option:
+ - Keep two copies of data in RenderTarget/RenderTexture/RenderWindow
+ - Whenever stuff gets modified from core thread a notification is sent to RenderTargetManager which queues an update to refresh the sim thread data
+ - Core thread data is updated from sim thread as normal
+
+How will the external methods know which version of data to use?
+ - TODO