Sfoglia il codice sorgente

GUI input bridging and GUIRenderTexture added and working

Marko Pintera 12 anni fa
parent
commit
bc31d6ca47

+ 2 - 0
BansheeEngine/BansheeEngine.vcxproj

@@ -246,6 +246,7 @@
     <ClInclude Include="Include\BsGUIInputTool.h" />
     <ClInclude Include="Include\BsGUIInputBox.h" />
     <ClInclude Include="Include\BsGUIOptions.h" />
+    <ClInclude Include="Include\BsGUIRenderTexture.h" />
     <ClInclude Include="Include\BsGUITextInputEvent.h" />
     <ClInclude Include="Include\BsGUIInputCaret.h" />
     <ClInclude Include="Include\BsGUIInputSelection.h" />
@@ -312,6 +313,7 @@
     <ClCompile Include="Source\BsGUIElementBase.cpp" />
     <ClCompile Include="Source\BsGUIInputBox.cpp" />
     <ClCompile Include="Source\BsGUIOptions.cpp" />
+    <ClCompile Include="Source\BsGUIRenderTexture.cpp" />
     <ClCompile Include="Source\BsGUITextInputEvent.cpp" />
     <ClCompile Include="Source\BsGUIInputCaret.cpp" />
     <ClCompile Include="Source\BsGUIInputSelection.cpp" />

+ 6 - 0
BansheeEngine/BansheeEngine.vcxproj.filters

@@ -228,6 +228,9 @@
     <ClInclude Include="Include\BsGUIOptions.h">
       <Filter>Header Files\GUI</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsGUIRenderTexture.h">
+      <Filter>Header Files\GUI</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsGUIElement.cpp">
@@ -404,5 +407,8 @@
     <ClCompile Include="Source\BsGUILayoutOptions.cpp">
       <Filter>Source Files\GUI</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsGUIRenderTexture.cpp">
+      <Filter>Source Files\GUI</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 9 - 7
BansheeEngine/Include/BsGUIManager.h

@@ -85,20 +85,22 @@ namespace BansheeEngine
 		void addSelectiveInputElement(const GUIElement* element);
 
 		/**
-		 * @brief	Allows you to bridge GUI input from a GUI element into a widget.
+		 * @brief	Allows you to bridge GUI input from a GUI element into another render target.
 		 *
-		 * @param	widget 	The widget for which to bridge input.
-		 * @param	element	The element from which to bridge input. Input will be transformed according to this
-		 * 					elements position and size. Provide nullptr if you want to remove a bridge for the specified widget.
+		 * @param	renderTex 	The render target to which to bridge the input.
+		 * @param	element		The element from which to bridge input. Input will be transformed according to this
+		 * 						elements position and size. Provide nullptr if you want to remove a bridge for the specified widget.
 		 * 					
 		 * @note	This is useful if you use render textures, where your GUI is rendered off-
 		 * 			screen. In such case you need to display the render texture within another GUIElement
 		 * 			in a GUIWidget, but have no way of sending input to the render texture (normally
-		 * 			input is only sent to render windows). This allows you to change that.
+		 * 			input is only sent to render windows). This allows you to change that - any GUIWidget
+		 * 			using the bridged render texture as a render target will then receive input when mouse
+		 * 			is over the specified element.
 		 * 			
 		 *			Bridged element needs to remove itself as the bridge when it is destroyed.
 		 */
-		void setInputBridge(const GUIWidget* widget, const GUIElement* element);
+		void setInputBridge(const CM::RenderTexture* renderTex, const GUIElement* element);
 
 		boost::signal<void(GUIWidget*, GUIElement*, const GUIMouseEvent&)> mouseEventFilter;
 		boost::signal<void(GUIWidget*, GUIElement*, const GUITextInputEvent&)> textInputEventFilter;
@@ -160,7 +162,7 @@ namespace BansheeEngine
 		CM::Map<const GUIWidget*, SelectiveInputData>::type mSelectiveInputData;
 		std::function<void()> mOnOutsideClickCallback;
 
-		CM::Map<const GUIWidget*, const GUIElement*>::type mInputBridge;
+		CM::Map<const CM::RenderTexture*, const GUIElement*>::type mInputBridge;
 
 		boost::signals::connection mOnCursorMovedConn;
 		boost::signals::connection mOnCursorPressedConn;

+ 28 - 0
BansheeEngine/Include/BsGUIRenderTexture.h

@@ -0,0 +1,28 @@
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsGUITexture.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Allows you to display a render texture in the GUI.
+	 * 			
+	 * @note	Has the same functionality as GUITexture, but also forwards any input to the control
+	 * 			to underlying GUI elements.
+	 */
+	class BS_EXPORT GUIRenderTexture : public GUITexture
+	{
+	public:
+		static const CM::String& getGUITypeName();
+
+		static GUIRenderTexture* create(GUIWidget& parent, const CM::RenderTexturePtr& texture, const GUIElementStyle* style = nullptr);
+		static GUIRenderTexture* create(GUIWidget& parent, const CM::RenderTexturePtr& texture, const GUIOptions& layoutOptions, const GUIElementStyle* style = nullptr);
+
+	protected:
+		GUIRenderTexture(GUIWidget& parent, const GUIElementStyle* style, const CM::RenderTexturePtr& texture, const GUILayoutOptions& layoutOptions);
+		virtual ~GUIRenderTexture();
+
+		const CM::RenderTexture* mSourceTexture;
+	};
+}

+ 2 - 0
BansheeEngine/Include/BsGUITexture.h

@@ -25,6 +25,8 @@ namespace BansheeEngine
 			GUIImageScaleMode scale = GUIImageScaleMode::StretchToFit, const GUIElementStyle* style = nullptr);
 		static GUITexture* create(GUIWidget& parent, GUIImageScaleMode scale = GUIImageScaleMode::StretchToFit, const GUIElementStyle* style = nullptr);
 		static GUITexture* create(GUIWidget& parent, const GUIOptions& layoutOptions, GUIImageScaleMode scale = GUIImageScaleMode::StretchToFit, const GUIElementStyle* style = nullptr);
+
+		void setTexture(const SpriteTexturePtr& texture);
 	protected:
 		ImageSprite* mImageSprite;
 		IMAGE_SPRITE_DESC mDesc;

+ 17 - 8
BansheeEngine/Source/BsGUIManager.cpp

@@ -1126,12 +1126,12 @@ namespace BansheeEngine
 		mSelectiveInputData[&element->_getParentWidget()].elements.insert(element);
 	}
 
-	void GUIManager::setInputBridge(const GUIWidget* widget, const GUIElement* element)
+	void GUIManager::setInputBridge(const CM::RenderTexture* renderTex, const GUIElement* element)
 	{
 		if(element == nullptr)
-			mInputBridge.erase(widget);
+			mInputBridge.erase(renderTex);
 		else
-			mInputBridge[widget] = element;
+			mInputBridge[renderTex] = element;
 	}
 
 	GUIMouseButton GUIManager::buttonToGUIButton(PositionalInputEventButton cursorButton) const
@@ -1162,7 +1162,12 @@ namespace BansheeEngine
 
 	Int2 GUIManager::windowToBridgedCoords(const GUIWidget& widget, const Int2& windowPos) const
 	{
-		auto iterFind = mInputBridge.find(&widget);
+		// This cast might not be valid (the render target could be a window), but we only really need to cast
+		// so that mInputBridge map allows us to search through it - we don't access anything unless the target is bridged
+		// (in which case we know it is a RenderTexture)
+		const RenderTexture* renderTexture = static_cast<const RenderTexture*>(widget.getTarget()->getTarget().get());
+
+		auto iterFind = mInputBridge.find(renderTexture);
 		if(iterFind != mInputBridge.end()) // Widget input is bridged, which means we need to transform the coordinates
 		{
 			const GUIElement* bridgeElement = iterFind->second;
@@ -1171,13 +1176,13 @@ namespace BansheeEngine
 
 			Vector4 vecLocalPos = worldTfrm.inverse() * Vector4((float)windowPos.x, (float)windowPos.y, 0.0f, 1.0f);
 			Rect bridgeBounds = bridgeElement->getBounds();
-			Rect actualBounds = widget.getBounds();
 
+			// Find coordinates relative to the bridge element
 			float x = vecLocalPos.x - (float)bridgeBounds.x;
 			float y = vecLocalPos.y - (float)bridgeBounds.y;
 
-			float scaleX = actualBounds.width / (float)bridgeBounds.width;
-			float scaleY = actualBounds.height / (float)bridgeBounds.height;
+			float scaleX = renderTexture->getWidth() / (float)bridgeBounds.width;
+			float scaleY = renderTexture->getHeight() / (float)bridgeBounds.height;
 
 			return Int2(Math::RoundToInt(x * scaleX), Math::RoundToInt(y * scaleY));
 		}
@@ -1187,8 +1192,12 @@ namespace BansheeEngine
 
 	const CM::RenderWindow* GUIManager::getWidgetWindow(const GUIWidget& widget) const
 	{
-		auto iterFind = mInputBridge.find(&widget);
+		// This cast might not be valid (the render target could be a window), but we only really need to cast
+		// so that mInputBridge map allows us to search through it - we don't access anything unless the target is bridged
+		// (in which case we know it is a RenderTexture)
+		const RenderTexture* renderTexture = static_cast<const RenderTexture*>(widget.getTarget()->getTarget().get());
 
+		auto iterFind = mInputBridge.find(renderTexture);
 		if(iterFind != mInputBridge.end())
 		{
 			GUIWidget& parentWidget = iterFind->second->_getParentWidget();

+ 51 - 0
BansheeEngine/Source/BsGUIRenderTexture.cpp

@@ -0,0 +1,51 @@
+#include "BsGUIRenderTexture.h"
+#include "BsGUIWidget.h"
+#include "BsGUISkin.h"
+#include "BsGUIManager.h"
+#include "CmRenderTexture.h"
+#include "BsSpriteTexture.h"
+
+using namespace CamelotFramework;
+
+namespace BansheeEngine
+{
+	const String& GUIRenderTexture::getGUITypeName()
+	{
+		static String name = "RenderTexture";
+		return name;
+	}
+
+	GUIRenderTexture::GUIRenderTexture(GUIWidget& parent, const GUIElementStyle* style, const RenderTexturePtr& texture, const GUILayoutOptions& layoutOptions)
+		:GUITexture(parent, style, nullptr, GUIImageScaleMode::StretchToFit, layoutOptions), mSourceTexture(texture.get())
+	{
+		setTexture(std::make_shared<SpriteTexture>(texture->getBindableColorTexture()));
+		GUIManager::instance().setInputBridge(mSourceTexture, this);
+	}
+
+	GUIRenderTexture::~GUIRenderTexture()
+	{
+		GUIManager::instance().setInputBridge(mSourceTexture, nullptr);
+	}
+
+	GUIRenderTexture* GUIRenderTexture::create(GUIWidget& parent, const RenderTexturePtr& texture, const GUIElementStyle* style)
+	{
+		if(style == nullptr)
+		{
+			const GUISkin& skin = parent.getSkin();
+			style = skin.getStyle(getGUITypeName());
+		}
+
+		return new (cm_alloc<GUIRenderTexture, PoolAlloc>()) GUIRenderTexture(parent, style, texture, GUILayoutOptions::create(style));
+	}
+
+	GUIRenderTexture* GUIRenderTexture::create(GUIWidget& parent, const RenderTexturePtr& texture, const GUIOptions& layoutOptions, const GUIElementStyle* style)
+	{
+		if(style == nullptr)
+		{
+			const GUISkin& skin = parent.getSkin();
+			style = skin.getStyle(getGUITypeName());
+		}
+
+		return new (cm_alloc<GUIRenderTexture, PoolAlloc>()) GUIRenderTexture(parent, style, texture, GUILayoutOptions::create(layoutOptions, style));
+	}
+}

+ 6 - 0
BansheeEngine/Source/BsGUITexture.cpp

@@ -84,6 +84,12 @@ namespace BansheeEngine
 		return new (cm_alloc<GUITexture, PoolAlloc>()) GUITexture(parent, style, nullptr, scale, GUILayoutOptions::create(layoutOptions, style));
 	}
 
+	void GUITexture::setTexture(const SpriteTexturePtr& texture)
+	{
+		mDesc.texture = texture;
+		markContentAsDirty();
+	}
+
 	UINT32 GUITexture::getNumRenderElements() const
 	{
 		return mImageSprite->getNumRenderElements();

+ 2 - 2
CamelotClient/Source/CmTestTextSprite.cpp

@@ -13,6 +13,7 @@
 #include "BsSpriteTexture.h"
 #include "BsEngineGUI.h"
 #include "BsGUITexture.h"
+#include "BsGUIRenderTexture.h"
 #include "BsGUIArea.h"
 #include "BsGUILayout.h"
 #include "BsGUISpace.h"
@@ -44,8 +45,7 @@ namespace CamelotFramework
 
 		GUIArea* area = GUIArea::createStretchedXY(*this, 0, 0, 0, 0);
 
-		SpriteTexturePtr spriteTex = std::make_shared<SpriteTexture>(sceneView->getBindableColorTexture());
-		area->getLayout().addElement(GUITexture::create(*this, GUIOptions(GUIOption::fixedWidth(800), GUIOption::fixedHeight(600)), spriteTex));
+		area->getLayout().addElement(GUIRenderTexture::create(*this, sceneView, GUIOptions(GUIOption::fixedWidth(800), GUIOption::fixedHeight(600))));
 		mLabel = GUILabel::create(*this, HString(L""));
 		area->getLayout().addElement(mLabel);