Browse Source

Added text drawing to gizmo and handle managers
Fixed an issue with blend state caching
Fixed an issue with Gpu parameter retrieval
Fixed an issue with scene axis handle, where negative axes would incorrectly be turned off in certain cases

BearishSun 10 years ago
parent
commit
3bf92297ea

+ 10 - 0
BansheeCore/Include/BsRendererUtility.h

@@ -29,6 +29,16 @@ namespace BansheeEngine
 		 */
 		void setPass(const SPtr<MaterialCore>& material, UINT32 passIdx);
 
+		/**
+		 * @brief	Sets parameters (textures, samplers, buffers) for the currently active pass.
+		 *
+		 * @param	material	Material whose pass' parameters to bind.
+		 * @param	passIdx		Index of the pass in the material.
+		 *					
+		 * @note	Core thread.
+		 */
+		static void setPassParams(const SPtr<MaterialCore>& material, UINT32 passIdx = 0);
+
 		/**
 		 * @brief	Draws the specified mesh.
 		 *

+ 199 - 199
BansheeCore/Source/BsBlendState.cpp

@@ -1,200 +1,200 @@
-#include "BsBlendState.h"
-#include "BsRenderStateManager.h"
-#include "BsRenderAPI.h"
-#include "BsBlendStateRTTI.h"
-#include "BsResources.h"
-
-namespace BansheeEngine
-{
-	bool RENDER_TARGET_BLEND_STATE_DESC::operator == (const RENDER_TARGET_BLEND_STATE_DESC& rhs) const
-	{
-		return blendEnable == rhs.blendEnable &&
-			srcBlend == rhs.srcBlend &&
-			dstBlend == rhs.dstBlend &&
-			blendOp == rhs.blendOp &&
-			srcBlendAlpha == rhs.srcBlendAlpha &&
-			dstBlendAlpha == rhs.dstBlendAlpha &&
-			blendOpAlpha == rhs.blendOpAlpha &&
-			renderTargetWriteMask == rhs.renderTargetWriteMask;
-	}
-
-	bool BLEND_STATE_DESC::operator == (const BLEND_STATE_DESC& rhs) const
-	{
-		bool equals = alphaToCoverageEnable == rhs.alphaToCoverageEnable &&
-			independantBlendEnable == rhs.independantBlendEnable;
-
-		if (equals)
-		{
-			for (UINT32 i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++)
-			{
-				equals |= renderTargetDesc[i] == rhs.renderTargetDesc[i];
-			}
-		}
-
-		return equals;
-	}
-
-	BlendProperties::BlendProperties(const BLEND_STATE_DESC& desc)
-		:mData(desc), mHash(BlendState::generateHash(desc))
-	{ }
-
-	bool BlendProperties::getBlendEnabled(UINT32 renderTargetIdx) const
-	{
-		assert(renderTargetIdx >= 0 && renderTargetIdx < BS_MAX_MULTIPLE_RENDER_TARGETS);
-
-		return mData.renderTargetDesc[renderTargetIdx].blendEnable;
-	}
-
-	BlendFactor BlendProperties::getSrcBlend(UINT32 renderTargetIdx) const
-	{
-		assert(renderTargetIdx >= 0 && renderTargetIdx < BS_MAX_MULTIPLE_RENDER_TARGETS);
-
-		return mData.renderTargetDesc[renderTargetIdx].srcBlend;
-	}
-
-	BlendFactor BlendProperties::getDstBlend(UINT32 renderTargetIdx) const
-	{
-		assert(renderTargetIdx >= 0 && renderTargetIdx < BS_MAX_MULTIPLE_RENDER_TARGETS);
-
-		return mData.renderTargetDesc[renderTargetIdx].dstBlend;
-	}
-
-	BlendOperation BlendProperties::getBlendOperation(UINT32 renderTargetIdx) const
-	{
-		assert(renderTargetIdx >= 0 && renderTargetIdx < BS_MAX_MULTIPLE_RENDER_TARGETS);
-
-		return mData.renderTargetDesc[renderTargetIdx].blendOp;
-	}
-
-	BlendFactor BlendProperties::getAlphaSrcBlend(UINT32 renderTargetIdx) const
-	{
-		assert(renderTargetIdx >= 0 && renderTargetIdx < BS_MAX_MULTIPLE_RENDER_TARGETS);
-
-		return mData.renderTargetDesc[renderTargetIdx].srcBlendAlpha;
-	}
-
-	BlendFactor BlendProperties::getAlphaDstBlend(UINT32 renderTargetIdx) const
-	{
-		assert(renderTargetIdx >= 0 && renderTargetIdx < BS_MAX_MULTIPLE_RENDER_TARGETS);
-
-		return mData.renderTargetDesc[renderTargetIdx].dstBlendAlpha;
-	}
-
-	BlendOperation BlendProperties::getAlphaBlendOperation(UINT32 renderTargetIdx) const
-	{
-		assert(renderTargetIdx >= 0 && renderTargetIdx < BS_MAX_MULTIPLE_RENDER_TARGETS);
-
-		return mData.renderTargetDesc[renderTargetIdx].blendOpAlpha;
-	}
-
-	UINT8 BlendProperties::getRenderTargetWriteMask(UINT32 renderTargetIdx) const
-	{
-		assert(renderTargetIdx >= 0 && renderTargetIdx < BS_MAX_MULTIPLE_RENDER_TARGETS);
-
-		return mData.renderTargetDesc[renderTargetIdx].renderTargetWriteMask;
-	}
-
-	BlendStateCore::BlendStateCore(const BLEND_STATE_DESC& desc, UINT32 id)
-		:mProperties(desc), mId(id)
-	{
-
-	}
-
-	BlendStateCore::~BlendStateCore()
-	{
-
-	}
-
-	void BlendStateCore::initialize()
-	{
-		// Since we cache states it's possible this object was already initialized
-		// (i.e. multiple sim-states can share a single core-state)
-		if (isInitialized())
-			return;
-
-		createInternal();
-		CoreObjectCore::initialize();
-	}
-
-	const BlendProperties& BlendStateCore::getProperties() const
-	{
-		return mProperties;
-	}
-
-	const SPtr<BlendStateCore>& BlendStateCore::getDefault()
-	{
-		return RenderStateCoreManager::instance().getDefaultBlendState();
-	}
-
-	BlendState::BlendState(const BLEND_STATE_DESC& desc)
-		:mProperties(desc), mId(0)
-	{ }
-
-	BlendState::~BlendState()
-	{
-
-	}
-
-	SPtr<BlendStateCore> BlendState::getCore() const
-	{
-		return std::static_pointer_cast<BlendStateCore>(mCoreSpecific);
-	}
-
-	SPtr<CoreObjectCore> BlendState::createCore() const
-	{
-		SPtr<BlendStateCore> core = RenderStateCoreManager::instance()._createBlendState(mProperties.mData);
-		mId = core->getId(); // Accessing core from sim thread is okay here since core ID is immutable
-
-		return core;
-	}
-
-	const BlendProperties& BlendState::getProperties() const
-	{
-		return mProperties;
-	}
-
-	const BlendStatePtr& BlendState::getDefault()
-	{
-		return RenderStateManager::instance().getDefaultBlendState();
-	}
-
-	BlendStatePtr BlendState::create(const BLEND_STATE_DESC& desc)
-	{
-		return RenderStateManager::instance().createBlendState(desc);
-	}
-
-	UINT64 BlendState::generateHash(const BLEND_STATE_DESC& desc)
-	{
-		size_t hash = 0;
-		hash_combine(hash, desc.alphaToCoverageEnable);
-		hash_combine(hash, desc.independantBlendEnable);
-
-		for (UINT32 i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++)
-		{
-			hash_combine(hash, desc.renderTargetDesc[i].blendEnable);
-			hash_combine(hash, (UINT32)desc.renderTargetDesc[i].srcBlend);
-			hash_combine(hash, (UINT32)desc.renderTargetDesc[i].dstBlend);
-			hash_combine(hash, (UINT32)desc.renderTargetDesc[i].blendOp);
-			hash_combine(hash, (UINT32)desc.renderTargetDesc[i].srcBlendAlpha);
-			hash_combine(hash, (UINT32)desc.renderTargetDesc[i].dstBlendAlpha);
-			hash_combine(hash, (UINT32)desc.renderTargetDesc[i].blendOpAlpha);
-			hash_combine(hash, desc.renderTargetDesc[i].renderTargetWriteMask);
-		}
-
-		return (UINT64)hash;
-	}
-
-	/************************************************************************/
-	/* 								RTTI		                     		*/
-	/************************************************************************/
-
-	RTTITypeBase* BlendState::getRTTIStatic()
-	{
-		return BlendStateRTTI::instance();
-	}
-
-	RTTITypeBase* BlendState::getRTTI() const
-	{
-		return BlendState::getRTTIStatic();
-	}
+#include "BsBlendState.h"
+#include "BsRenderStateManager.h"
+#include "BsRenderAPI.h"
+#include "BsBlendStateRTTI.h"
+#include "BsResources.h"
+
+namespace BansheeEngine
+{
+	bool RENDER_TARGET_BLEND_STATE_DESC::operator == (const RENDER_TARGET_BLEND_STATE_DESC& rhs) const
+	{
+		return blendEnable == rhs.blendEnable &&
+			srcBlend == rhs.srcBlend &&
+			dstBlend == rhs.dstBlend &&
+			blendOp == rhs.blendOp &&
+			srcBlendAlpha == rhs.srcBlendAlpha &&
+			dstBlendAlpha == rhs.dstBlendAlpha &&
+			blendOpAlpha == rhs.blendOpAlpha &&
+			renderTargetWriteMask == rhs.renderTargetWriteMask;
+	}
+
+	bool BLEND_STATE_DESC::operator == (const BLEND_STATE_DESC& rhs) const
+	{
+		bool equals = alphaToCoverageEnable == rhs.alphaToCoverageEnable &&
+			independantBlendEnable == rhs.independantBlendEnable;
+
+		if (equals)
+		{
+			for (UINT32 i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++)
+			{
+				equals &= renderTargetDesc[i] == rhs.renderTargetDesc[i];
+			}
+		}
+
+		return equals;
+	}
+
+	BlendProperties::BlendProperties(const BLEND_STATE_DESC& desc)
+		:mData(desc), mHash(BlendState::generateHash(desc))
+	{ }
+
+	bool BlendProperties::getBlendEnabled(UINT32 renderTargetIdx) const
+	{
+		assert(renderTargetIdx >= 0 && renderTargetIdx < BS_MAX_MULTIPLE_RENDER_TARGETS);
+
+		return mData.renderTargetDesc[renderTargetIdx].blendEnable;
+	}
+
+	BlendFactor BlendProperties::getSrcBlend(UINT32 renderTargetIdx) const
+	{
+		assert(renderTargetIdx >= 0 && renderTargetIdx < BS_MAX_MULTIPLE_RENDER_TARGETS);
+
+		return mData.renderTargetDesc[renderTargetIdx].srcBlend;
+	}
+
+	BlendFactor BlendProperties::getDstBlend(UINT32 renderTargetIdx) const
+	{
+		assert(renderTargetIdx >= 0 && renderTargetIdx < BS_MAX_MULTIPLE_RENDER_TARGETS);
+
+		return mData.renderTargetDesc[renderTargetIdx].dstBlend;
+	}
+
+	BlendOperation BlendProperties::getBlendOperation(UINT32 renderTargetIdx) const
+	{
+		assert(renderTargetIdx >= 0 && renderTargetIdx < BS_MAX_MULTIPLE_RENDER_TARGETS);
+
+		return mData.renderTargetDesc[renderTargetIdx].blendOp;
+	}
+
+	BlendFactor BlendProperties::getAlphaSrcBlend(UINT32 renderTargetIdx) const
+	{
+		assert(renderTargetIdx >= 0 && renderTargetIdx < BS_MAX_MULTIPLE_RENDER_TARGETS);
+
+		return mData.renderTargetDesc[renderTargetIdx].srcBlendAlpha;
+	}
+
+	BlendFactor BlendProperties::getAlphaDstBlend(UINT32 renderTargetIdx) const
+	{
+		assert(renderTargetIdx >= 0 && renderTargetIdx < BS_MAX_MULTIPLE_RENDER_TARGETS);
+
+		return mData.renderTargetDesc[renderTargetIdx].dstBlendAlpha;
+	}
+
+	BlendOperation BlendProperties::getAlphaBlendOperation(UINT32 renderTargetIdx) const
+	{
+		assert(renderTargetIdx >= 0 && renderTargetIdx < BS_MAX_MULTIPLE_RENDER_TARGETS);
+
+		return mData.renderTargetDesc[renderTargetIdx].blendOpAlpha;
+	}
+
+	UINT8 BlendProperties::getRenderTargetWriteMask(UINT32 renderTargetIdx) const
+	{
+		assert(renderTargetIdx >= 0 && renderTargetIdx < BS_MAX_MULTIPLE_RENDER_TARGETS);
+
+		return mData.renderTargetDesc[renderTargetIdx].renderTargetWriteMask;
+	}
+
+	BlendStateCore::BlendStateCore(const BLEND_STATE_DESC& desc, UINT32 id)
+		:mProperties(desc), mId(id)
+	{
+
+	}
+
+	BlendStateCore::~BlendStateCore()
+	{
+
+	}
+
+	void BlendStateCore::initialize()
+	{
+		// Since we cache states it's possible this object was already initialized
+		// (i.e. multiple sim-states can share a single core-state)
+		if (isInitialized())
+			return;
+
+		createInternal();
+		CoreObjectCore::initialize();
+	}
+
+	const BlendProperties& BlendStateCore::getProperties() const
+	{
+		return mProperties;
+	}
+
+	const SPtr<BlendStateCore>& BlendStateCore::getDefault()
+	{
+		return RenderStateCoreManager::instance().getDefaultBlendState();
+	}
+
+	BlendState::BlendState(const BLEND_STATE_DESC& desc)
+		:mProperties(desc), mId(0)
+	{ }
+
+	BlendState::~BlendState()
+	{
+
+	}
+
+	SPtr<BlendStateCore> BlendState::getCore() const
+	{
+		return std::static_pointer_cast<BlendStateCore>(mCoreSpecific);
+	}
+
+	SPtr<CoreObjectCore> BlendState::createCore() const
+	{
+		SPtr<BlendStateCore> core = RenderStateCoreManager::instance()._createBlendState(mProperties.mData);
+		mId = core->getId(); // Accessing core from sim thread is okay here since core ID is immutable
+
+		return core;
+	}
+
+	const BlendProperties& BlendState::getProperties() const
+	{
+		return mProperties;
+	}
+
+	const BlendStatePtr& BlendState::getDefault()
+	{
+		return RenderStateManager::instance().getDefaultBlendState();
+	}
+
+	BlendStatePtr BlendState::create(const BLEND_STATE_DESC& desc)
+	{
+		return RenderStateManager::instance().createBlendState(desc);
+	}
+
+	UINT64 BlendState::generateHash(const BLEND_STATE_DESC& desc)
+	{
+		size_t hash = 0;
+		hash_combine(hash, desc.alphaToCoverageEnable);
+		hash_combine(hash, desc.independantBlendEnable);
+
+		for (UINT32 i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++)
+		{
+			hash_combine(hash, desc.renderTargetDesc[i].blendEnable);
+			hash_combine(hash, (UINT32)desc.renderTargetDesc[i].srcBlend);
+			hash_combine(hash, (UINT32)desc.renderTargetDesc[i].dstBlend);
+			hash_combine(hash, (UINT32)desc.renderTargetDesc[i].blendOp);
+			hash_combine(hash, (UINT32)desc.renderTargetDesc[i].srcBlendAlpha);
+			hash_combine(hash, (UINT32)desc.renderTargetDesc[i].dstBlendAlpha);
+			hash_combine(hash, (UINT32)desc.renderTargetDesc[i].blendOpAlpha);
+			hash_combine(hash, desc.renderTargetDesc[i].renderTargetWriteMask);
+		}
+
+		return (UINT64)hash;
+	}
+
+	/************************************************************************/
+	/* 								RTTI		                     		*/
+	/************************************************************************/
+
+	RTTITypeBase* BlendState::getRTTIStatic()
+	{
+		return BlendStateRTTI::instance();
+	}
+
+	RTTITypeBase* BlendState::getRTTI() const
+	{
+		return BlendState::getRTTIStatic();
+	}
 }

+ 563 - 563
BansheeCore/Source/BsGpuParams.cpp

@@ -1,564 +1,564 @@
-#include "BsGpuParams.h"
-#include "BsGpuParamDesc.h"
-#include "BsGpuParamBlockBuffer.h"
-#include "BsVector2.h"
-#include "BsTexture.h"
-#include "BsSamplerState.h"
-#include "BsFrameAlloc.h"
-#include "BsDebug.h"
-#include "BsException.h"
-#include "BsVectorNI.h"
-#include "BsMatrixNxM.h"
-
-namespace BansheeEngine
-{
-	GpuParamsBase::GpuParamsBase(const GpuParamDescPtr& paramDesc, bool transposeMatrices)
-		:mParamDesc(paramDesc), mTransposeMatrices(transposeMatrices), mNumParamBlocks(0), mNumSamplerStates(0),
-		mNumTextures(0), mTextureInfo(nullptr)
-	{
-		for (auto& paramBlock : mParamDesc->paramBlocks)
-		{
-			if ((paramBlock.second.slot + 1) > mNumParamBlocks)
-				mNumParamBlocks = paramBlock.second.slot + 1;
-		}
-
-		for (auto& texture : mParamDesc->textures)
-		{
-			if ((texture.second.slot + 1) > mNumTextures)
-				mNumTextures = texture.second.slot + 1;
-		}
-
-		for (auto& sampler : mParamDesc->samplers)
-		{
-			if ((sampler.second.slot + 1) > mNumSamplerStates)
-				mNumSamplerStates = sampler.second.slot + 1;
-		}
-
-		mTextureInfo = bs_newN<BoundTextureInfo>(mNumTextures);
-	}
-
-	GpuParamsBase::~GpuParamsBase()
-	{
-		bs_deleteN(mTextureInfo, mNumTextures);
-	}
-
-UINT32 GpuParamsBase::getDataParamSize(const String& name) const
-	{
-		GpuParamDataDesc* desc = getParamDesc(name);
-		if(desc != nullptr)
-			return desc->elementSize * 4;
-
-		return 0;
-	}
-
-	bool GpuParamsBase::hasParam(const String& name) const
-	{
-		return getParamDesc(name) != nullptr;
-	}
-
-	bool GpuParamsBase::hasTexture(const String& name) const
-	{
-		auto paramIter = mParamDesc->textures.find(name);
-		if(paramIter != mParamDesc->textures.end())
-			return true;
-
-		return false;
-	}
-
-	bool GpuParamsBase::hasSamplerState(const String& name) const
-	{
-		auto paramIter = mParamDesc->samplers.find(name);
-		if(paramIter != mParamDesc->samplers.end())
-			return true;
-
-		return false;
-	}
-
-	bool GpuParamsBase::hasParamBlock(const String& name) const
-	{
-		auto paramBlockIter = mParamDesc->paramBlocks.find(name);
-		if(paramBlockIter != mParamDesc->paramBlocks.end())
-			return true;
-
-		return false;
-	}
-
-	GpuParamDataDesc* GpuParamsBase::getParamDesc(const String& name) const
-	{
-		auto paramIter = mParamDesc->params.find(name);
-		if (paramIter != mParamDesc->params.end())
-			return &paramIter->second;
-
-		return nullptr;
-	}
-
-	bool GpuParamsBase::isLoadStoreTexture(UINT32 slot) const
-	{
-		if (slot < 0 || slot >= mNumTextures)
-		{
-			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
-				toString(mNumTextures - 1) + ". Requested: " + toString(slot));
-		}
-
-		return mTextureInfo[slot].isLoadStore;
-	}
-
-	void GpuParamsBase::setIsLoadStoreTexture(UINT32 slot, bool isLoadStore)
-	{
-		if (slot < 0 || slot >= mNumTextures)
-		{
-			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
-				toString(mNumTextures - 1) + ". Requested: " + toString(slot));
-		}
-
-		mTextureInfo[slot].isLoadStore = isLoadStore;
-	}
-
-	const TextureSurface& GpuParamsBase::getLoadStoreSurface(UINT32 slot) const
-	{
-		if (slot < 0 || slot >= mNumTextures)
-		{
-			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
-				toString(mNumTextures - 1) + ". Requested: " + toString(slot));
-		}
-
-		return mTextureInfo[slot].surface;
-	}
-
-	void GpuParamsBase::setLoadStoreSurface(UINT32 slot, const TextureSurface& surface) const
-	{
-		if (slot < 0 || slot >= mNumTextures)
-		{
-			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
-				toString(mNumTextures - 1) + ". Requested: " + toString(slot));
-		}
-
-		mTextureInfo[slot].surface = surface;
-	}
-
-	template<bool Core>
-	TGpuParams<Core>::TGpuParams(const GpuParamDescPtr& paramDesc, bool transposeMatrices)
-		:GpuParamsBase(paramDesc, transposeMatrices), mParamBlockBuffers(nullptr), mTextures(nullptr),
-		mSamplerStates(nullptr)
-	{
-		if (mNumParamBlocks > 0)
-			mParamBlockBuffers = bs_newN<ParamsBufferType>(mNumParamBlocks);
-
-		if (mNumTextures > 0)
-			mTextures = bs_newN<TextureType>(mNumTextures);
-
-		if (mNumSamplerStates > 0)
-			mSamplerStates = bs_newN<SamplerType>(mNumSamplerStates);
-	}
-
-	template<bool Core>
-	TGpuParams<Core>::~TGpuParams()
-	{
-		if (mParamBlockBuffers != nullptr)
-			bs_deleteN(mParamBlockBuffers, mNumParamBlocks);
-
-		if (mTextures != nullptr)
-			bs_deleteN(mTextures, mNumTextures);
-
-		if (mSamplerStates != nullptr)
-			bs_deleteN(mSamplerStates, mNumSamplerStates);
-	}
-
-	template<bool Core>
-	void TGpuParams<Core>::setParamBlockBuffer(UINT32 slot, const ParamsBufferType& paramBlockBuffer)
-	{
-		if (slot < 0 || slot >= mNumParamBlocks)
-		{
-			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
-				toString(mNumParamBlocks - 1) + ". Requested: " + toString(slot));
-		}
-
-		mParamBlockBuffers[slot] = paramBlockBuffer;
-
-		_markCoreDirty();
-	}
-
-	template<bool Core>
-	void TGpuParams<Core>::setParamBlockBuffer(const String& name, const ParamsBufferType& paramBlockBuffer)
-	{
-		auto iterFind = mParamDesc->paramBlocks.find(name);
-
-		if (iterFind == mParamDesc->paramBlocks.end())
-		{
-			LOGWRN("Cannot find parameter block with the name: " + name);
-			return;
-		}
-
-		mParamBlockBuffers[iterFind->second.slot] = paramBlockBuffer;
-
-		_markCoreDirty();
-	}
-
-	template<bool Core>
-	template<class T> 
-	void TGpuParams<Core>::getParam(const String& name, TGpuDataParam<T, Core>& output) const
-	{
-		auto iterFind = mParamDesc->params.find(name);
-
-		if (iterFind == mParamDesc->params.end())
-		{
-			output = TGpuDataParam<T, Core>(&iterFind->second, nullptr);
-			LOGWRN("Cannot find parameter with the name '" + name + "'");
-		}
-		else
-			output = TGpuDataParam<T, Core>(&iterFind->second, _getThisPtr());
-	}
-
-	template<bool Core>
-	void TGpuParams<Core>::getStructParam(const String& name, TGpuParamStruct<Core>& output) const
-	{
-		auto iterFind = mParamDesc->params.find(name);
-
-		if (iterFind == mParamDesc->params.end() || iterFind->second.type != GPDT_STRUCT)
-		{
-			output = TGpuParamStruct<Core>(&iterFind->second, nullptr);
-			LOGWRN("Cannot find struct parameter with the name '" + name + "'");
-		}
-		else
-			output = TGpuParamStruct<Core>(&iterFind->second, _getThisPtr());
-	}
-
-	template<bool Core>
-	void TGpuParams<Core>::getTextureParam(const String& name, TGpuParamTexture<Core>& output) const
-	{
-		auto iterFind = mParamDesc->textures.find(name);
-
-		if (iterFind == mParamDesc->textures.end())
-		{
-			output = TGpuParamTexture<Core>(&iterFind->second, nullptr);
-			LOGWRN("Cannot find texture parameter with the name '" + name + "'");
-		}
-		else
-			output = TGpuParamTexture<Core>(&iterFind->second, _getThisPtr());
-	}
-
-	template<bool Core>
-	void TGpuParams<Core>::getLoadStoreTextureParam(const String& name, TGpuParamLoadStoreTexture<Core>& output) const
-	{
-		auto iterFind = mParamDesc->textures.find(name);
-
-		if (iterFind == mParamDesc->textures.end())
-		{
-			output = TGpuParamLoadStoreTexture<Core>(&iterFind->second, nullptr);
-			LOGWRN("Cannot find texture parameter with the name '" + name + "'");
-		}
-		else
-			output = TGpuParamLoadStoreTexture<Core>(&iterFind->second, _getThisPtr());
-	}
-
-	template<bool Core>
-	void TGpuParams<Core>::getSamplerStateParam(const String& name, TGpuParamSampState<Core>& output) const
-	{
-		auto iterFind = mParamDesc->samplers.find(name);
-
-		if (iterFind == mParamDesc->samplers.end())
-		{
-			output = TGpuParamSampState<Core>(&iterFind->second, nullptr);
-			LOGWRN("Cannot find sampler state parameter with the name '" + name + "'");
-		}
-		else
-			output = TGpuParamSampState<Core>(&iterFind->second, _getThisPtr());
-	}
-
-	template<bool Core>
-	typename TGpuParams<Core>::ParamsBufferType TGpuParams<Core>::getParamBlockBuffer(UINT32 slot) const
-	{
-		if (slot < 0 || slot >= mNumParamBlocks)
-		{
-			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
-				toString(mNumParamBlocks - 1) + ". Requested: " + toString(slot));
-		}
-
-		return mParamBlockBuffers[slot];
-	}
-
-	template<bool Core>
-	typename TGpuParams<Core>::TextureType TGpuParams<Core>::getTexture(UINT32 slot)
-	{
-		if (slot < 0 || slot >= mNumTextures)
-		{
-			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
-				toString(mNumTextures - 1) + ". Requested: " + toString(slot));
-		}
-
-		return mTextures[slot];
-	}
-
-	template<bool Core>
-	typename TGpuParams<Core>::SamplerType TGpuParams<Core>::getSamplerState(UINT32 slot)
-	{
-		if (slot < 0 || slot >= mNumSamplerStates)
-		{
-			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
-				toString(mNumSamplerStates - 1) + ". Requested: " + toString(slot));
-		}
-
-		return mSamplerStates[slot];
-	}
-
-	template<bool Core>
-	void TGpuParams<Core>::setTexture(UINT32 slot, const TextureType& texture)
-	{
-		if (slot < 0 || slot >= mNumTextures)
-		{
-			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
-				toString(mNumTextures - 1) + ". Requested: " + toString(slot));
-		}
-
-		mTextures[slot] = texture;
-
-		_markResourcesDirty();
-		_markCoreDirty();
-	}
-
-	template<bool Core>
-	void TGpuParams<Core>::setSamplerState(UINT32 slot, const SamplerType& sampler)
-	{
-		if (slot < 0 || slot >= mNumSamplerStates)
-		{
-			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
-				toString(mNumSamplerStates - 1) + ". Requested: " + toString(slot));
-		}
-
-		mSamplerStates[slot] = sampler;
-
-		_markResourcesDirty();
-		_markCoreDirty();
-	}
-
-	template class TGpuParams < false > ;
-	template class TGpuParams < true > ;
-
-	template BS_CORE_EXPORT void TGpuParams<false>::getParam<float>(const String&, TGpuDataParam<float, false>&) const;
-	template BS_CORE_EXPORT void TGpuParams<false>::getParam<int>(const String&, TGpuDataParam<int, false>&) const;
-	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Color>(const String&, TGpuDataParam<Color, false>&) const;
-	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Vector2>(const String&, TGpuDataParam<Vector2, false>&) const;
-	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Vector3>(const String&, TGpuDataParam<Vector3, false>&) const;
-	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Vector4>(const String&, TGpuDataParam<Vector4, false>&) const;
-	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Vector2I>(const String&, TGpuDataParam<Vector2I, false>&) const;
-	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Vector3I>(const String&, TGpuDataParam<Vector3I, false>&) const;
-	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Vector4I>(const String&, TGpuDataParam<Vector4I, false>&) const;
-	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Matrix2>(const String&, TGpuDataParam<Matrix2, false>&) const;
-	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Matrix2x3>(const String&, TGpuDataParam<Matrix2x3, false>&) const;
-	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Matrix2x4>(const String&, TGpuDataParam<Matrix2x4, false>&) const;
-	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Matrix3>(const String&, TGpuDataParam<Matrix3, false>&) const;
-	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Matrix3x2>(const String&, TGpuDataParam<Matrix3x2, false>&) const;
-	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Matrix3x4>(const String&, TGpuDataParam<Matrix3x4, false>&) const;
-	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Matrix4>(const String&, TGpuDataParam<Matrix4, false>&) const;
-	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Matrix4x2>(const String&, TGpuDataParam<Matrix4x2, false>&) const;
-	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Matrix4x3>(const String&, TGpuDataParam<Matrix4x3, false>&) const;
-
-	template BS_CORE_EXPORT void TGpuParams<true>::getParam<float>(const String&, TGpuDataParam<float, true>&) const;
-	template BS_CORE_EXPORT void TGpuParams<true>::getParam<int>(const String&, TGpuDataParam<int, true>&) const;
-	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Color>(const String&, TGpuDataParam<Color, true>&) const;
-	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Vector2>(const String&, TGpuDataParam<Vector2, true>&) const;
-	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Vector3>(const String&, TGpuDataParam<Vector3, true>&) const;
-	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Vector4>(const String&, TGpuDataParam<Vector4, true>&) const;
-	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Vector2I>(const String&, TGpuDataParam<Vector2I, true>&) const;
-	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Vector3I>(const String&, TGpuDataParam<Vector3I, true>&) const;
-	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Vector4I>(const String&, TGpuDataParam<Vector4I, true>&) const;
-	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Matrix2>(const String&, TGpuDataParam<Matrix2, true>&) const;
-	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Matrix2x3>(const String&, TGpuDataParam<Matrix2x3, true>&) const;
-	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Matrix2x4>(const String&, TGpuDataParam<Matrix2x4, true>&) const;
-	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Matrix3>(const String&, TGpuDataParam<Matrix3, true>&) const;
-	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Matrix3x2>(const String&, TGpuDataParam<Matrix3x2, true>&) const;
-	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Matrix3x4>(const String&, TGpuDataParam<Matrix3x4, true>&) const;
-	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Matrix4>(const String&, TGpuDataParam<Matrix4, true>&) const;
-	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Matrix4x2>(const String&, TGpuDataParam<Matrix4x2, true>&) const;
-	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Matrix4x3>(const String&, TGpuDataParam<Matrix4x3, true>&) const;
-
-	GpuParamsCore::GpuParamsCore(const GpuParamDescPtr& paramDesc, bool transposeMatrices)
-		: TGpuParams(paramDesc, transposeMatrices)
-	{
-
-	}
-
-	SPtr<GpuParamsCore> GpuParamsCore::_getThisPtr() const
-	{
-		return std::static_pointer_cast<GpuParamsCore>(getThisPtr());
-	}
-
-	void GpuParamsCore::updateHardwareBuffers()
-	{
-		for (UINT32 i = 0; i < mNumParamBlocks; i++)
-		{
-			if (mParamBlockBuffers[i] != nullptr)
-			{
-				mParamBlockBuffers[i]->flushToGPU();
-			}
-		}
-	}
-
-	void GpuParamsCore::syncToCore(const CoreSyncData& data)
-	{
-		UINT32 textureInfoSize = mNumTextures * sizeof(BoundTextureInfo);
-		UINT32 paramBufferSize = mNumParamBlocks * sizeof(SPtr<GpuParamBlockBufferCore>);
-		UINT32 textureArraySize = mNumTextures * sizeof(SPtr<TextureCore>);
-		UINT32 samplerArraySize = mNumSamplerStates * sizeof(SPtr<SamplerStateCore>);
-
-		UINT32 totalSize = textureInfoSize + paramBufferSize + textureArraySize + samplerArraySize;
-
-		UINT32 textureInfoOffset = 0;
-		UINT32 paramBufferOffset = textureInfoOffset + textureInfoSize;
-		UINT32 textureArrayOffset = paramBufferOffset + paramBufferSize;
-		UINT32 samplerArrayOffset = textureArrayOffset + textureArraySize;
-
-		assert(data.getBufferSize() == totalSize);
-
-		UINT8* dataPtr = data.getBuffer();
-
-		BoundTextureInfo* textureInfos = (BoundTextureInfo*)(dataPtr + textureInfoOffset);
-		SPtr<GpuParamBlockBufferCore>* paramBuffers = (SPtr<GpuParamBlockBufferCore>*)(dataPtr + paramBufferOffset);
-		SPtr<TextureCore>* textures = (SPtr<TextureCore>*)(dataPtr + textureArrayOffset);
-		SPtr<SamplerStateCore>* samplers = (SPtr<SamplerStateCore>*)(dataPtr + samplerArrayOffset);
-
-		// Copy & destruct
-		for (UINT32 i = 0; i < mNumParamBlocks; i++)
-		{
-			mParamBlockBuffers[i] = paramBuffers[i];
-			paramBuffers[i].~SPtr<GpuParamBlockBufferCore>();
-		}
-
-		for (UINT32 i = 0; i < mNumTextures; i++)
-		{
-			mTextureInfo[i] = textureInfos[i];
-			textureInfos[i].~BoundTextureInfo();
-
-			mTextures[i] = textures[i];
-			textures[i].~SPtr<TextureCore>();
-		}
-
-		for (UINT32 i = 0; i < mNumSamplerStates; i++)
-		{
-			mSamplerStates[i] = samplers[i];
-			samplers[i].~SPtr<SamplerStateCore>();
-		}
-	}
-
-	SPtr<GpuParamsCore> GpuParamsCore::create(const GpuParamDescPtr& paramDesc, bool transposeMatrices)
-	{
-		GpuParamsCore* params = new (bs_alloc<GpuParamsCore>()) GpuParamsCore(paramDesc, transposeMatrices);
-		SPtr<GpuParamsCore> paramsPtr = bs_shared_ptr<GpuParamsCore>(params);
-		paramsPtr->_setThisPtr(paramsPtr);
-
-		return paramsPtr;
-	}
-
-	const GpuDataParamInfos GpuParams::PARAM_SIZES;
-
-	GpuParams::GpuParams(const GpuParamDescPtr& paramDesc, bool transposeMatrices)
-		: TGpuParams(paramDesc, transposeMatrices)
-	{
-
-	}
-
-	SPtr<GpuParams> GpuParams::_getThisPtr() const
-	{
-		return std::static_pointer_cast<GpuParams>(getThisPtr());
-	}
-
-	SPtr<GpuParamsCore> GpuParams::getCore() const
-	{
-		return std::static_pointer_cast<GpuParamsCore>(mCoreSpecific);
-	}
-
-	SPtr<CoreObjectCore> GpuParams::createCore() const
-	{
-		GpuParamsCore* obj = new (bs_alloc<GpuParamsCore>()) GpuParamsCore(mParamDesc, mTransposeMatrices);
-
-		SPtr<CoreObjectCore> coreObj = bs_shared_ptr<GpuParamsCore>(obj);
-		coreObj->_setThisPtr(coreObj);
-
-		return coreObj;
-	}
-
-	void GpuParams::_markCoreDirty()
-	{
-		markCoreDirty();
-	}
-
-	void GpuParams::_markResourcesDirty()
-	{
-		markListenerResourcesDirty();
-	}
-
-	SPtr<GpuParams> GpuParams::create(const GpuParamDescPtr& paramDesc, bool transposeMatrices)
-	{
-		GpuParams* params = new (bs_alloc<GpuParams>()) GpuParams(paramDesc, transposeMatrices);
-		SPtr<GpuParams> paramsPtr = bs_core_ptr<GpuParams>(params);
-		paramsPtr->_setThisPtr(paramsPtr);
-		paramsPtr->initialize();
-		
-		return paramsPtr;
-	}
-
-	CoreSyncData GpuParams::syncToCore(FrameAlloc* allocator)
-	{
-		UINT32 textureInfoSize = mNumTextures * sizeof(BoundTextureInfo);
-		UINT32 paramBufferSize = mNumParamBlocks * sizeof(SPtr<GpuParamBlockBufferCore>);
-		UINT32 textureArraySize = mNumTextures * sizeof(SPtr<TextureCore>);
-		UINT32 samplerArraySize = mNumSamplerStates * sizeof(SPtr<SamplerStateCore>);
-
-		UINT32 totalSize = textureInfoSize + paramBufferSize + textureArraySize + samplerArraySize;
-
-		UINT32 textureInfoOffset = 0;
-		UINT32 paramBufferOffset = textureInfoOffset + textureInfoSize;
-		UINT32 textureArrayOffset = paramBufferOffset + paramBufferSize;
-		UINT32 samplerArrayOffset = textureArrayOffset + textureArraySize;
-
-		UINT8* data = allocator->alloc(totalSize);
-
-		BoundTextureInfo* textureInfos = (BoundTextureInfo*)(data + textureInfoOffset);
-		SPtr<GpuParamBlockBufferCore>* paramBuffers = (SPtr<GpuParamBlockBufferCore>*)(data + paramBufferOffset);
-		SPtr<TextureCore>* textures = (SPtr<TextureCore>*)(data + textureArrayOffset);
-		SPtr<SamplerStateCore>* samplers = (SPtr<SamplerStateCore>*)(data + samplerArrayOffset);
-
-		// Construct & copy
-		for (UINT32 i = 0; i < mNumParamBlocks; i++)
-		{
-			new (&paramBuffers[i]) SPtr<GpuParamBlockBufferCore>();
-
-			if (mParamBlockBuffers[i] != nullptr)
-				paramBuffers[i] = mParamBlockBuffers[i]->getCore();
-		}
-
-		for (UINT32 i = 0; i < mNumTextures; i++)
-		{
-			new (&textureInfos[i]) BoundTextureInfo();
-			textureInfos[i] = mTextureInfo[i];
-
-			new (&textures[i]) SPtr<TextureCore>();
-
-			if (mTextures[i].isLoaded())
-				textures[i] = mTextures[i]->getCore();
-			else
-				textures[i] = nullptr;
-		}
-
-		for (UINT32 i = 0; i < mNumSamplerStates; i++)
-		{
-			new (&samplers[i]) SPtr<SamplerStateCore>();
-
-			if (mSamplerStates[i] != nullptr)
-				samplers[i] = mSamplerStates[i]->getCore();
-			else
-				samplers[i] = nullptr;
-		}
-
-		return CoreSyncData(data, totalSize);
-	}
-
-	void GpuParams::getListenerResources(Vector<HResource>& resources)
-	{
-		for (UINT32 i = 0; i < mNumTextures; i++)
-		{
-			if (mTextures[i] != nullptr)
-				resources.push_back(mTextures[i]);
-		}
-	}
+#include "BsGpuParams.h"
+#include "BsGpuParamDesc.h"
+#include "BsGpuParamBlockBuffer.h"
+#include "BsVector2.h"
+#include "BsTexture.h"
+#include "BsSamplerState.h"
+#include "BsFrameAlloc.h"
+#include "BsDebug.h"
+#include "BsException.h"
+#include "BsVectorNI.h"
+#include "BsMatrixNxM.h"
+
+namespace BansheeEngine
+{
+	GpuParamsBase::GpuParamsBase(const GpuParamDescPtr& paramDesc, bool transposeMatrices)
+		:mParamDesc(paramDesc), mTransposeMatrices(transposeMatrices), mNumParamBlocks(0), mNumSamplerStates(0),
+		mNumTextures(0), mTextureInfo(nullptr)
+	{
+		for (auto& paramBlock : mParamDesc->paramBlocks)
+		{
+			if ((paramBlock.second.slot + 1) > mNumParamBlocks)
+				mNumParamBlocks = paramBlock.second.slot + 1;
+		}
+
+		for (auto& texture : mParamDesc->textures)
+		{
+			if ((texture.second.slot + 1) > mNumTextures)
+				mNumTextures = texture.second.slot + 1;
+		}
+
+		for (auto& sampler : mParamDesc->samplers)
+		{
+			if ((sampler.second.slot + 1) > mNumSamplerStates)
+				mNumSamplerStates = sampler.second.slot + 1;
+		}
+
+		mTextureInfo = bs_newN<BoundTextureInfo>(mNumTextures);
+	}
+
+	GpuParamsBase::~GpuParamsBase()
+	{
+		bs_deleteN(mTextureInfo, mNumTextures);
+	}
+
+UINT32 GpuParamsBase::getDataParamSize(const String& name) const
+	{
+		GpuParamDataDesc* desc = getParamDesc(name);
+		if(desc != nullptr)
+			return desc->elementSize * 4;
+
+		return 0;
+	}
+
+	bool GpuParamsBase::hasParam(const String& name) const
+	{
+		return getParamDesc(name) != nullptr;
+	}
+
+	bool GpuParamsBase::hasTexture(const String& name) const
+	{
+		auto paramIter = mParamDesc->textures.find(name);
+		if(paramIter != mParamDesc->textures.end())
+			return true;
+
+		return false;
+	}
+
+	bool GpuParamsBase::hasSamplerState(const String& name) const
+	{
+		auto paramIter = mParamDesc->samplers.find(name);
+		if(paramIter != mParamDesc->samplers.end())
+			return true;
+
+		return false;
+	}
+
+	bool GpuParamsBase::hasParamBlock(const String& name) const
+	{
+		auto paramBlockIter = mParamDesc->paramBlocks.find(name);
+		if(paramBlockIter != mParamDesc->paramBlocks.end())
+			return true;
+
+		return false;
+	}
+
+	GpuParamDataDesc* GpuParamsBase::getParamDesc(const String& name) const
+	{
+		auto paramIter = mParamDesc->params.find(name);
+		if (paramIter != mParamDesc->params.end())
+			return &paramIter->second;
+
+		return nullptr;
+	}
+
+	bool GpuParamsBase::isLoadStoreTexture(UINT32 slot) const
+	{
+		if (slot < 0 || slot >= mNumTextures)
+		{
+			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
+				toString(mNumTextures - 1) + ". Requested: " + toString(slot));
+		}
+
+		return mTextureInfo[slot].isLoadStore;
+	}
+
+	void GpuParamsBase::setIsLoadStoreTexture(UINT32 slot, bool isLoadStore)
+	{
+		if (slot < 0 || slot >= mNumTextures)
+		{
+			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
+				toString(mNumTextures - 1) + ". Requested: " + toString(slot));
+		}
+
+		mTextureInfo[slot].isLoadStore = isLoadStore;
+	}
+
+	const TextureSurface& GpuParamsBase::getLoadStoreSurface(UINT32 slot) const
+	{
+		if (slot < 0 || slot >= mNumTextures)
+		{
+			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
+				toString(mNumTextures - 1) + ". Requested: " + toString(slot));
+		}
+
+		return mTextureInfo[slot].surface;
+	}
+
+	void GpuParamsBase::setLoadStoreSurface(UINT32 slot, const TextureSurface& surface) const
+	{
+		if (slot < 0 || slot >= mNumTextures)
+		{
+			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
+				toString(mNumTextures - 1) + ". Requested: " + toString(slot));
+		}
+
+		mTextureInfo[slot].surface = surface;
+	}
+
+	template<bool Core>
+	TGpuParams<Core>::TGpuParams(const GpuParamDescPtr& paramDesc, bool transposeMatrices)
+		:GpuParamsBase(paramDesc, transposeMatrices), mParamBlockBuffers(nullptr), mTextures(nullptr),
+		mSamplerStates(nullptr)
+	{
+		if (mNumParamBlocks > 0)
+			mParamBlockBuffers = bs_newN<ParamsBufferType>(mNumParamBlocks);
+
+		if (mNumTextures > 0)
+			mTextures = bs_newN<TextureType>(mNumTextures);
+
+		if (mNumSamplerStates > 0)
+			mSamplerStates = bs_newN<SamplerType>(mNumSamplerStates);
+	}
+
+	template<bool Core>
+	TGpuParams<Core>::~TGpuParams()
+	{
+		if (mParamBlockBuffers != nullptr)
+			bs_deleteN(mParamBlockBuffers, mNumParamBlocks);
+
+		if (mTextures != nullptr)
+			bs_deleteN(mTextures, mNumTextures);
+
+		if (mSamplerStates != nullptr)
+			bs_deleteN(mSamplerStates, mNumSamplerStates);
+	}
+
+	template<bool Core>
+	void TGpuParams<Core>::setParamBlockBuffer(UINT32 slot, const ParamsBufferType& paramBlockBuffer)
+	{
+		if (slot < 0 || slot >= mNumParamBlocks)
+		{
+			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
+				toString(mNumParamBlocks - 1) + ". Requested: " + toString(slot));
+		}
+
+		mParamBlockBuffers[slot] = paramBlockBuffer;
+
+		_markCoreDirty();
+	}
+
+	template<bool Core>
+	void TGpuParams<Core>::setParamBlockBuffer(const String& name, const ParamsBufferType& paramBlockBuffer)
+	{
+		auto iterFind = mParamDesc->paramBlocks.find(name);
+
+		if (iterFind == mParamDesc->paramBlocks.end())
+		{
+			LOGWRN("Cannot find parameter block with the name: " + name);
+			return;
+		}
+
+		mParamBlockBuffers[iterFind->second.slot] = paramBlockBuffer;
+
+		_markCoreDirty();
+	}
+
+	template<bool Core>
+	template<class T> 
+	void TGpuParams<Core>::getParam(const String& name, TGpuDataParam<T, Core>& output) const
+	{
+		auto iterFind = mParamDesc->params.find(name);
+
+		if (iterFind == mParamDesc->params.end())
+		{
+			output = TGpuDataParam<T, Core>(nullptr, nullptr);
+			LOGWRN("Cannot find parameter with the name '" + name + "'");
+		}
+		else
+			output = TGpuDataParam<T, Core>(&iterFind->second, _getThisPtr());
+	}
+
+	template<bool Core>
+	void TGpuParams<Core>::getStructParam(const String& name, TGpuParamStruct<Core>& output) const
+	{
+		auto iterFind = mParamDesc->params.find(name);
+
+		if (iterFind == mParamDesc->params.end() || iterFind->second.type != GPDT_STRUCT)
+		{
+			output = TGpuParamStruct<Core>(nullptr, nullptr);
+			LOGWRN("Cannot find struct parameter with the name '" + name + "'");
+		}
+		else
+			output = TGpuParamStruct<Core>(&iterFind->second, _getThisPtr());
+	}
+
+	template<bool Core>
+	void TGpuParams<Core>::getTextureParam(const String& name, TGpuParamTexture<Core>& output) const
+	{
+		auto iterFind = mParamDesc->textures.find(name);
+
+		if (iterFind == mParamDesc->textures.end())
+		{
+			output = TGpuParamTexture<Core>(nullptr, nullptr);
+			LOGWRN("Cannot find texture parameter with the name '" + name + "'");
+		}
+		else
+			output = TGpuParamTexture<Core>(&iterFind->second, _getThisPtr());
+	}
+
+	template<bool Core>
+	void TGpuParams<Core>::getLoadStoreTextureParam(const String& name, TGpuParamLoadStoreTexture<Core>& output) const
+	{
+		auto iterFind = mParamDesc->textures.find(name);
+
+		if (iterFind == mParamDesc->textures.end())
+		{
+			output = TGpuParamLoadStoreTexture<Core>(nullptr, nullptr);
+			LOGWRN("Cannot find texture parameter with the name '" + name + "'");
+		}
+		else
+			output = TGpuParamLoadStoreTexture<Core>(&iterFind->second, _getThisPtr());
+	}
+
+	template<bool Core>
+	void TGpuParams<Core>::getSamplerStateParam(const String& name, TGpuParamSampState<Core>& output) const
+	{
+		auto iterFind = mParamDesc->samplers.find(name);
+
+		if (iterFind == mParamDesc->samplers.end())
+		{
+			output = TGpuParamSampState<Core>(nullptr, nullptr);
+			LOGWRN("Cannot find sampler state parameter with the name '" + name + "'");
+		}
+		else
+			output = TGpuParamSampState<Core>(&iterFind->second, _getThisPtr());
+	}
+
+	template<bool Core>
+	typename TGpuParams<Core>::ParamsBufferType TGpuParams<Core>::getParamBlockBuffer(UINT32 slot) const
+	{
+		if (slot < 0 || slot >= mNumParamBlocks)
+		{
+			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
+				toString(mNumParamBlocks - 1) + ". Requested: " + toString(slot));
+		}
+
+		return mParamBlockBuffers[slot];
+	}
+
+	template<bool Core>
+	typename TGpuParams<Core>::TextureType TGpuParams<Core>::getTexture(UINT32 slot)
+	{
+		if (slot < 0 || slot >= mNumTextures)
+		{
+			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
+				toString(mNumTextures - 1) + ". Requested: " + toString(slot));
+		}
+
+		return mTextures[slot];
+	}
+
+	template<bool Core>
+	typename TGpuParams<Core>::SamplerType TGpuParams<Core>::getSamplerState(UINT32 slot)
+	{
+		if (slot < 0 || slot >= mNumSamplerStates)
+		{
+			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
+				toString(mNumSamplerStates - 1) + ". Requested: " + toString(slot));
+		}
+
+		return mSamplerStates[slot];
+	}
+
+	template<bool Core>
+	void TGpuParams<Core>::setTexture(UINT32 slot, const TextureType& texture)
+	{
+		if (slot < 0 || slot >= mNumTextures)
+		{
+			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
+				toString(mNumTextures - 1) + ". Requested: " + toString(slot));
+		}
+
+		mTextures[slot] = texture;
+
+		_markResourcesDirty();
+		_markCoreDirty();
+	}
+
+	template<bool Core>
+	void TGpuParams<Core>::setSamplerState(UINT32 slot, const SamplerType& sampler)
+	{
+		if (slot < 0 || slot >= mNumSamplerStates)
+		{
+			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
+				toString(mNumSamplerStates - 1) + ". Requested: " + toString(slot));
+		}
+
+		mSamplerStates[slot] = sampler;
+
+		_markResourcesDirty();
+		_markCoreDirty();
+	}
+
+	template class TGpuParams < false > ;
+	template class TGpuParams < true > ;
+
+	template BS_CORE_EXPORT void TGpuParams<false>::getParam<float>(const String&, TGpuDataParam<float, false>&) const;
+	template BS_CORE_EXPORT void TGpuParams<false>::getParam<int>(const String&, TGpuDataParam<int, false>&) const;
+	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Color>(const String&, TGpuDataParam<Color, false>&) const;
+	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Vector2>(const String&, TGpuDataParam<Vector2, false>&) const;
+	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Vector3>(const String&, TGpuDataParam<Vector3, false>&) const;
+	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Vector4>(const String&, TGpuDataParam<Vector4, false>&) const;
+	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Vector2I>(const String&, TGpuDataParam<Vector2I, false>&) const;
+	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Vector3I>(const String&, TGpuDataParam<Vector3I, false>&) const;
+	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Vector4I>(const String&, TGpuDataParam<Vector4I, false>&) const;
+	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Matrix2>(const String&, TGpuDataParam<Matrix2, false>&) const;
+	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Matrix2x3>(const String&, TGpuDataParam<Matrix2x3, false>&) const;
+	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Matrix2x4>(const String&, TGpuDataParam<Matrix2x4, false>&) const;
+	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Matrix3>(const String&, TGpuDataParam<Matrix3, false>&) const;
+	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Matrix3x2>(const String&, TGpuDataParam<Matrix3x2, false>&) const;
+	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Matrix3x4>(const String&, TGpuDataParam<Matrix3x4, false>&) const;
+	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Matrix4>(const String&, TGpuDataParam<Matrix4, false>&) const;
+	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Matrix4x2>(const String&, TGpuDataParam<Matrix4x2, false>&) const;
+	template BS_CORE_EXPORT void TGpuParams<false>::getParam<Matrix4x3>(const String&, TGpuDataParam<Matrix4x3, false>&) const;
+
+	template BS_CORE_EXPORT void TGpuParams<true>::getParam<float>(const String&, TGpuDataParam<float, true>&) const;
+	template BS_CORE_EXPORT void TGpuParams<true>::getParam<int>(const String&, TGpuDataParam<int, true>&) const;
+	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Color>(const String&, TGpuDataParam<Color, true>&) const;
+	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Vector2>(const String&, TGpuDataParam<Vector2, true>&) const;
+	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Vector3>(const String&, TGpuDataParam<Vector3, true>&) const;
+	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Vector4>(const String&, TGpuDataParam<Vector4, true>&) const;
+	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Vector2I>(const String&, TGpuDataParam<Vector2I, true>&) const;
+	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Vector3I>(const String&, TGpuDataParam<Vector3I, true>&) const;
+	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Vector4I>(const String&, TGpuDataParam<Vector4I, true>&) const;
+	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Matrix2>(const String&, TGpuDataParam<Matrix2, true>&) const;
+	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Matrix2x3>(const String&, TGpuDataParam<Matrix2x3, true>&) const;
+	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Matrix2x4>(const String&, TGpuDataParam<Matrix2x4, true>&) const;
+	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Matrix3>(const String&, TGpuDataParam<Matrix3, true>&) const;
+	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Matrix3x2>(const String&, TGpuDataParam<Matrix3x2, true>&) const;
+	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Matrix3x4>(const String&, TGpuDataParam<Matrix3x4, true>&) const;
+	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Matrix4>(const String&, TGpuDataParam<Matrix4, true>&) const;
+	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Matrix4x2>(const String&, TGpuDataParam<Matrix4x2, true>&) const;
+	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Matrix4x3>(const String&, TGpuDataParam<Matrix4x3, true>&) const;
+
+	GpuParamsCore::GpuParamsCore(const GpuParamDescPtr& paramDesc, bool transposeMatrices)
+		: TGpuParams(paramDesc, transposeMatrices)
+	{
+
+	}
+
+	SPtr<GpuParamsCore> GpuParamsCore::_getThisPtr() const
+	{
+		return std::static_pointer_cast<GpuParamsCore>(getThisPtr());
+	}
+
+	void GpuParamsCore::updateHardwareBuffers()
+	{
+		for (UINT32 i = 0; i < mNumParamBlocks; i++)
+		{
+			if (mParamBlockBuffers[i] != nullptr)
+			{
+				mParamBlockBuffers[i]->flushToGPU();
+			}
+		}
+	}
+
+	void GpuParamsCore::syncToCore(const CoreSyncData& data)
+	{
+		UINT32 textureInfoSize = mNumTextures * sizeof(BoundTextureInfo);
+		UINT32 paramBufferSize = mNumParamBlocks * sizeof(SPtr<GpuParamBlockBufferCore>);
+		UINT32 textureArraySize = mNumTextures * sizeof(SPtr<TextureCore>);
+		UINT32 samplerArraySize = mNumSamplerStates * sizeof(SPtr<SamplerStateCore>);
+
+		UINT32 totalSize = textureInfoSize + paramBufferSize + textureArraySize + samplerArraySize;
+
+		UINT32 textureInfoOffset = 0;
+		UINT32 paramBufferOffset = textureInfoOffset + textureInfoSize;
+		UINT32 textureArrayOffset = paramBufferOffset + paramBufferSize;
+		UINT32 samplerArrayOffset = textureArrayOffset + textureArraySize;
+
+		assert(data.getBufferSize() == totalSize);
+
+		UINT8* dataPtr = data.getBuffer();
+
+		BoundTextureInfo* textureInfos = (BoundTextureInfo*)(dataPtr + textureInfoOffset);
+		SPtr<GpuParamBlockBufferCore>* paramBuffers = (SPtr<GpuParamBlockBufferCore>*)(dataPtr + paramBufferOffset);
+		SPtr<TextureCore>* textures = (SPtr<TextureCore>*)(dataPtr + textureArrayOffset);
+		SPtr<SamplerStateCore>* samplers = (SPtr<SamplerStateCore>*)(dataPtr + samplerArrayOffset);
+
+		// Copy & destruct
+		for (UINT32 i = 0; i < mNumParamBlocks; i++)
+		{
+			mParamBlockBuffers[i] = paramBuffers[i];
+			paramBuffers[i].~SPtr<GpuParamBlockBufferCore>();
+		}
+
+		for (UINT32 i = 0; i < mNumTextures; i++)
+		{
+			mTextureInfo[i] = textureInfos[i];
+			textureInfos[i].~BoundTextureInfo();
+
+			mTextures[i] = textures[i];
+			textures[i].~SPtr<TextureCore>();
+		}
+
+		for (UINT32 i = 0; i < mNumSamplerStates; i++)
+		{
+			mSamplerStates[i] = samplers[i];
+			samplers[i].~SPtr<SamplerStateCore>();
+		}
+	}
+
+	SPtr<GpuParamsCore> GpuParamsCore::create(const GpuParamDescPtr& paramDesc, bool transposeMatrices)
+	{
+		GpuParamsCore* params = new (bs_alloc<GpuParamsCore>()) GpuParamsCore(paramDesc, transposeMatrices);
+		SPtr<GpuParamsCore> paramsPtr = bs_shared_ptr<GpuParamsCore>(params);
+		paramsPtr->_setThisPtr(paramsPtr);
+
+		return paramsPtr;
+	}
+
+	const GpuDataParamInfos GpuParams::PARAM_SIZES;
+
+	GpuParams::GpuParams(const GpuParamDescPtr& paramDesc, bool transposeMatrices)
+		: TGpuParams(paramDesc, transposeMatrices)
+	{
+
+	}
+
+	SPtr<GpuParams> GpuParams::_getThisPtr() const
+	{
+		return std::static_pointer_cast<GpuParams>(getThisPtr());
+	}
+
+	SPtr<GpuParamsCore> GpuParams::getCore() const
+	{
+		return std::static_pointer_cast<GpuParamsCore>(mCoreSpecific);
+	}
+
+	SPtr<CoreObjectCore> GpuParams::createCore() const
+	{
+		GpuParamsCore* obj = new (bs_alloc<GpuParamsCore>()) GpuParamsCore(mParamDesc, mTransposeMatrices);
+
+		SPtr<CoreObjectCore> coreObj = bs_shared_ptr<GpuParamsCore>(obj);
+		coreObj->_setThisPtr(coreObj);
+
+		return coreObj;
+	}
+
+	void GpuParams::_markCoreDirty()
+	{
+		markCoreDirty();
+	}
+
+	void GpuParams::_markResourcesDirty()
+	{
+		markListenerResourcesDirty();
+	}
+
+	SPtr<GpuParams> GpuParams::create(const GpuParamDescPtr& paramDesc, bool transposeMatrices)
+	{
+		GpuParams* params = new (bs_alloc<GpuParams>()) GpuParams(paramDesc, transposeMatrices);
+		SPtr<GpuParams> paramsPtr = bs_core_ptr<GpuParams>(params);
+		paramsPtr->_setThisPtr(paramsPtr);
+		paramsPtr->initialize();
+		
+		return paramsPtr;
+	}
+
+	CoreSyncData GpuParams::syncToCore(FrameAlloc* allocator)
+	{
+		UINT32 textureInfoSize = mNumTextures * sizeof(BoundTextureInfo);
+		UINT32 paramBufferSize = mNumParamBlocks * sizeof(SPtr<GpuParamBlockBufferCore>);
+		UINT32 textureArraySize = mNumTextures * sizeof(SPtr<TextureCore>);
+		UINT32 samplerArraySize = mNumSamplerStates * sizeof(SPtr<SamplerStateCore>);
+
+		UINT32 totalSize = textureInfoSize + paramBufferSize + textureArraySize + samplerArraySize;
+
+		UINT32 textureInfoOffset = 0;
+		UINT32 paramBufferOffset = textureInfoOffset + textureInfoSize;
+		UINT32 textureArrayOffset = paramBufferOffset + paramBufferSize;
+		UINT32 samplerArrayOffset = textureArrayOffset + textureArraySize;
+
+		UINT8* data = allocator->alloc(totalSize);
+
+		BoundTextureInfo* textureInfos = (BoundTextureInfo*)(data + textureInfoOffset);
+		SPtr<GpuParamBlockBufferCore>* paramBuffers = (SPtr<GpuParamBlockBufferCore>*)(data + paramBufferOffset);
+		SPtr<TextureCore>* textures = (SPtr<TextureCore>*)(data + textureArrayOffset);
+		SPtr<SamplerStateCore>* samplers = (SPtr<SamplerStateCore>*)(data + samplerArrayOffset);
+
+		// Construct & copy
+		for (UINT32 i = 0; i < mNumParamBlocks; i++)
+		{
+			new (&paramBuffers[i]) SPtr<GpuParamBlockBufferCore>();
+
+			if (mParamBlockBuffers[i] != nullptr)
+				paramBuffers[i] = mParamBlockBuffers[i]->getCore();
+		}
+
+		for (UINT32 i = 0; i < mNumTextures; i++)
+		{
+			new (&textureInfos[i]) BoundTextureInfo();
+			textureInfos[i] = mTextureInfo[i];
+
+			new (&textures[i]) SPtr<TextureCore>();
+
+			if (mTextures[i].isLoaded())
+				textures[i] = mTextures[i]->getCore();
+			else
+				textures[i] = nullptr;
+		}
+
+		for (UINT32 i = 0; i < mNumSamplerStates; i++)
+		{
+			new (&samplers[i]) SPtr<SamplerStateCore>();
+
+			if (mSamplerStates[i] != nullptr)
+				samplers[i] = mSamplerStates[i]->getCore();
+			else
+				samplers[i] = nullptr;
+		}
+
+		return CoreSyncData(data, totalSize);
+	}
+
+	void GpuParams::getListenerResources(Vector<HResource>& resources)
+	{
+		for (UINT32 i = 0; i < mNumTextures; i++)
+		{
+			if (mTextures[i] != nullptr)
+				resources.push_back(mTextures[i]);
+		}
+	}
 }

+ 271 - 200
BansheeCore/Source/BsRendererUtility.cpp

@@ -1,201 +1,272 @@
-#include "BsRendererUtility.h"
-#include "BsRenderAPI.h"
-#include "BsMesh.h"
-#include "BsVertexDataDesc.h"
-#include "BsMaterial.h"
-#include "BsPass.h"
-#include "BsBlendState.h"
-#include "BsDepthStencilState.h"
-#include "BsRasterizerState.h"
-
-namespace BansheeEngine
-{
-	RendererUtility::RendererUtility()
-	{
-		VertexDataDescPtr vertexDesc = bs_shared_ptr_new<VertexDataDesc>();
-		vertexDesc->addVertElem(VET_FLOAT3, VES_POSITION);
-		vertexDesc->addVertElem(VET_FLOAT2, VES_TEXCOORD);
-
-		mFullScreenQuadMesh = MeshCore::create(4, 6, vertexDesc);
-	}
-
-	RendererUtility::~RendererUtility()
-	{
-		
-	}
-
-	void RendererUtility::setPass(const SPtr<MaterialCore>& material, UINT32 passIdx)
-	{
-		RenderAPICore& rs = RenderAPICore::instance();
-
-		SPtr<PassCore> pass = material->getPass(passIdx);
-		SPtr<PassParametersCore> passParams = material->getPassParameters(passIdx);
-
-		struct StageData
-		{
-			GpuProgramType type;
-			bool enable;
-			SPtr<GpuParamsCore> params;
-			SPtr<GpuProgramCore> program;
-		};
-
-		const UINT32 numStages = 6;
-		StageData stages[numStages] =
-		{
-			{
-				GPT_VERTEX_PROGRAM, pass->hasVertexProgram(),
-				passParams->mVertParams, pass->getVertexProgram()
-			},
-			{
-				GPT_FRAGMENT_PROGRAM, pass->hasFragmentProgram(),
-				passParams->mFragParams, pass->getFragmentProgram()
-			},
-			{
-				GPT_GEOMETRY_PROGRAM, pass->hasGeometryProgram(),
-				passParams->mGeomParams, pass->getGeometryProgram()
-			},
-			{
-				GPT_HULL_PROGRAM, pass->hasHullProgram(),
-				passParams->mHullParams, pass->getHullProgram()
-			},
-			{
-				GPT_DOMAIN_PROGRAM, pass->hasDomainProgram(),
-				passParams->mDomainParams, pass->getDomainProgram()
-			},
-			{
-				GPT_COMPUTE_PROGRAM, pass->hasComputeProgram(),
-				passParams->mComputeParams, pass->getComputeProgram()
-			}
-		};
-
-		for (UINT32 i = 0; i < numStages; i++)
-		{
-			const StageData& stage = stages[i];
-
-			if (stage.enable)
-			{
-				rs.bindGpuProgram(stage.program);
-				rs.setGpuParams(stage.type, stage.params);
-
-			}
-			else
-				rs.unbindGpuProgram(stage.type);
-		}
-
-		// Set up non-texture related pass settings
-		if (pass->getBlendState() != nullptr)
-			rs.setBlendState(pass->getBlendState());
-		else
-			rs.setBlendState(BlendStateCore::getDefault());
-
-		if (pass->getDepthStencilState() != nullptr)
-			rs.setDepthStencilState(pass->getDepthStencilState(), pass->getStencilRefValue());
-		else
-			rs.setDepthStencilState(DepthStencilStateCore::getDefault(), pass->getStencilRefValue());
-
-		if (pass->getRasterizerState() != nullptr)
-			rs.setRasterizerState(pass->getRasterizerState());
-		else
-			rs.setRasterizerState(RasterizerStateCore::getDefault());
-	}
-
-	void RendererUtility::draw(const SPtr<MeshCoreBase>& mesh, const SubMesh& subMesh)
-	{
-		RenderAPICore& rs = RenderAPICore::instance();
-		const MeshProperties& meshProps = mesh->getProperties();
-		std::shared_ptr<VertexData> vertexData = mesh->getVertexData();
-
-		rs.setVertexDeclaration(vertexData->vertexDeclaration);
-		auto& vertexBuffers = vertexData->getBuffers();
-
-		if (vertexBuffers.size() > 0)
-		{
-			SPtr<VertexBufferCore> buffers[MAX_BOUND_VERTEX_BUFFERS];
-
-			UINT32 endSlot = 0;
-			UINT32 startSlot = MAX_BOUND_VERTEX_BUFFERS;
-			for (auto iter = vertexBuffers.begin(); iter != vertexBuffers.end(); ++iter)
-			{
-				if (iter->first >= MAX_BOUND_VERTEX_BUFFERS)
-					BS_EXCEPT(InvalidParametersException, "Buffer index out of range");
-
-				startSlot = std::min(iter->first, startSlot);
-				endSlot = std::max(iter->first, endSlot);
-			}
-
-			for (auto iter = vertexBuffers.begin(); iter != vertexBuffers.end(); ++iter)
-			{
-				buffers[iter->first - startSlot] = iter->second;
-			}
-
-			rs.setVertexBuffers(startSlot, buffers, endSlot - startSlot + 1);
-		}
-
-		rs.setDrawOperation(subMesh.drawOp);
-
-		SPtr<IndexBufferCore> indexBuffer = mesh->getIndexBuffer();
-
-		UINT32 indexCount = subMesh.indexCount;
-
-		rs.setIndexBuffer(indexBuffer);
-		rs.drawIndexed(subMesh.indexOffset + mesh->getIndexOffset(), indexCount, mesh->getVertexOffset(), vertexData->vertexCount);
-
-		mesh->_notifyUsedOnGPU();
-	}
-
-	void RendererUtility::drawScreenQuad(const ViewportCore& viewport, const Rect2& uv, const Vector2I& textureSize)
-	{
-		// Note: Consider drawing the quad using a single large triangle for possibly better performance
-		Rect2I viewArea = viewport.getArea();
-
-		Vector3 vertices[4];
-		vertices[0] = Vector3((float)viewArea.x, (float)viewArea.y, 0.0f);
-		vertices[1] = Vector3((float)viewArea.x + (float)viewArea.width, (float)viewArea.y, 0.0f);
-		vertices[2] = Vector3((float)viewArea.x, (float)viewArea.y + (float)viewArea.height, 0.0f);
-		vertices[3] = Vector3((float)viewArea.x + (float)viewArea.width, (float)viewArea.y + (float)viewArea.height, 0.0f);
-
-		Vector2 uvs[4];
-		uvs[0] = Vector2(uv.x, uv.y);
-		uvs[1] = Vector2(uv.x + uv.width, uv.y);
-		uvs[2] = Vector2(uv.x, uv.y + uv.height);
-		uvs[3] = Vector2(uv.x + uv.width, uv.y + uv.height);
-
-		auto targetProps = viewport.getTarget()->getProperties();;
-		RenderAPICore& rapi = RenderAPICore::instance();
-		for (int i = 0; i < 4; i++)
-		{
-			vertices[i].x = -1.0f + 2.0f * (vertices[i].x + rapi.getHorizontalTexelOffset()) / targetProps.getWidth();
-			vertices[i].y = 1.0f - 2.0f * (vertices[i].y + rapi.getVerticalTexelOffset()) / targetProps.getHeight();
-
-			uvs[i].x /= (float)textureSize.x;
-			uvs[i].y /= (float)textureSize.y;
-		}
-
-		SPtr<VertexDataDesc> vertexDesc = mFullScreenQuadMesh->getVertexDesc();
-		MeshDataPtr meshData = bs_shared_ptr_new<MeshData>(4, 6, vertexDesc);
-
-		auto vecIter = meshData->getVec3DataIter(VES_POSITION);
-		for (UINT32 i = 0; i < 4; i++)
-			vecIter.addValue(vertices[i]);
-
-		auto uvIter = meshData->getVec2DataIter(VES_TEXCOORD);
-		for (UINT32 i = 0; i < 4; i++)
-			uvIter.addValue(uvs[i]);
-
-		auto indices = meshData->getIndices32();
-		indices[0] = 0;
-		indices[1] = 1;
-		indices[2] = 2;
-		indices[3] = 1;
-		indices[4] = 3;
-		indices[5] = 2;
-
-		mFullScreenQuadMesh->writeSubresource(0, *meshData, true, false);
-		draw(mFullScreenQuadMesh, mFullScreenQuadMesh->getProperties().getSubMesh());
-	}
-
-	RendererUtility& gRendererUtility()
-	{
-		return RendererUtility::instance();
-	}
+#include "BsRendererUtility.h"
+#include "BsRenderAPI.h"
+#include "BsMesh.h"
+#include "BsVertexDataDesc.h"
+#include "BsMaterial.h"
+#include "BsPass.h"
+#include "BsBlendState.h"
+#include "BsDepthStencilState.h"
+#include "BsRasterizerState.h"
+#include "BsGpuParams.h"
+#include "BsGpuParamDesc.h"
+
+namespace BansheeEngine
+{
+	RendererUtility::RendererUtility()
+	{
+		VertexDataDescPtr vertexDesc = bs_shared_ptr_new<VertexDataDesc>();
+		vertexDesc->addVertElem(VET_FLOAT3, VES_POSITION);
+		vertexDesc->addVertElem(VET_FLOAT2, VES_TEXCOORD);
+
+		mFullScreenQuadMesh = MeshCore::create(4, 6, vertexDesc);
+	}
+
+	RendererUtility::~RendererUtility()
+	{
+		
+	}
+
+	void RendererUtility::setPass(const SPtr<MaterialCore>& material, UINT32 passIdx)
+	{
+		RenderAPICore& rs = RenderAPICore::instance();
+
+		SPtr<PassCore> pass = material->getPass(passIdx);
+		SPtr<PassParametersCore> passParams = material->getPassParameters(passIdx);
+
+		struct StageData
+		{
+			GpuProgramType type;
+			bool enable;
+			SPtr<GpuParamsCore> params;
+			SPtr<GpuProgramCore> program;
+		};
+
+		const UINT32 numStages = 6;
+		StageData stages[numStages] =
+		{
+			{
+				GPT_VERTEX_PROGRAM, pass->hasVertexProgram(),
+				passParams->mVertParams, pass->getVertexProgram()
+			},
+			{
+				GPT_FRAGMENT_PROGRAM, pass->hasFragmentProgram(),
+				passParams->mFragParams, pass->getFragmentProgram()
+			},
+			{
+				GPT_GEOMETRY_PROGRAM, pass->hasGeometryProgram(),
+				passParams->mGeomParams, pass->getGeometryProgram()
+			},
+			{
+				GPT_HULL_PROGRAM, pass->hasHullProgram(),
+				passParams->mHullParams, pass->getHullProgram()
+			},
+			{
+				GPT_DOMAIN_PROGRAM, pass->hasDomainProgram(),
+				passParams->mDomainParams, pass->getDomainProgram()
+			},
+			{
+				GPT_COMPUTE_PROGRAM, pass->hasComputeProgram(),
+				passParams->mComputeParams, pass->getComputeProgram()
+			}
+		};
+
+		for (UINT32 i = 0; i < numStages; i++)
+		{
+			const StageData& stage = stages[i];
+
+			if (stage.enable)
+			{
+				rs.bindGpuProgram(stage.program);
+				rs.setGpuParams(stage.type, stage.params);
+
+			}
+			else
+				rs.unbindGpuProgram(stage.type);
+		}
+
+		// Set up non-texture related pass settings
+		if (pass->getBlendState() != nullptr)
+			rs.setBlendState(pass->getBlendState());
+		else
+			rs.setBlendState(BlendStateCore::getDefault());
+
+		if (pass->getDepthStencilState() != nullptr)
+			rs.setDepthStencilState(pass->getDepthStencilState(), pass->getStencilRefValue());
+		else
+			rs.setDepthStencilState(DepthStencilStateCore::getDefault(), pass->getStencilRefValue());
+
+		if (pass->getRasterizerState() != nullptr)
+			rs.setRasterizerState(pass->getRasterizerState());
+		else
+			rs.setRasterizerState(RasterizerStateCore::getDefault());
+	}
+
+	void RendererUtility::setPassParams(const SPtr<MaterialCore>& material, UINT32 passIdx)
+	{
+		const SPtr<PassParametersCore>& passParams = material->getPassParameters(passIdx);
+
+		RenderAPICore& rs = RenderAPICore::instance();
+
+		struct StageData
+		{
+			GpuProgramType type;
+			SPtr<GpuParamsCore> params;
+		};
+
+		const UINT32 numStages = 6;
+		StageData stages[numStages] =
+		{
+			{ GPT_VERTEX_PROGRAM, passParams->mVertParams },
+			{ GPT_FRAGMENT_PROGRAM, passParams->mFragParams },
+			{ GPT_GEOMETRY_PROGRAM, passParams->mGeomParams },
+			{ GPT_HULL_PROGRAM, passParams->mHullParams },
+			{ GPT_DOMAIN_PROGRAM, passParams->mDomainParams },
+			{ GPT_COMPUTE_PROGRAM, passParams->mComputeParams }
+		};
+
+		for (UINT32 i = 0; i < numStages; i++)
+		{
+			const StageData& stage = stages[i];
+
+			SPtr<GpuParamsCore> params = stage.params;
+			if (params == nullptr)
+				continue;
+
+			const GpuParamDesc& paramDesc = params->getParamDesc();
+
+			for (auto iter = paramDesc.samplers.begin(); iter != paramDesc.samplers.end(); ++iter)
+			{
+				SPtr<SamplerStateCore> samplerState = params->getSamplerState(iter->second.slot);
+
+				if (samplerState == nullptr)
+					rs.setSamplerState(stage.type, iter->second.slot, SamplerStateCore::getDefault());
+				else
+					rs.setSamplerState(stage.type, iter->second.slot, samplerState);
+			}
+
+			for (auto iter = paramDesc.textures.begin(); iter != paramDesc.textures.end(); ++iter)
+			{
+				SPtr<TextureCore> texture = params->getTexture(iter->second.slot);
+
+				if (!params->isLoadStoreTexture(iter->second.slot))
+				{
+					if (texture == nullptr)
+						rs.setTexture(stage.type, iter->second.slot, false, nullptr);
+					else
+						rs.setTexture(stage.type, iter->second.slot, true, texture);
+				}
+				else
+				{
+					const TextureSurface& surface = params->getLoadStoreSurface(iter->second.slot);
+
+					if (texture == nullptr)
+						rs.setLoadStoreTexture(stage.type, iter->second.slot, false, nullptr, surface);
+					else
+						rs.setLoadStoreTexture(stage.type, iter->second.slot, true, texture, surface);
+				}
+			}
+
+			rs.setConstantBuffers(stage.type, params);
+		}
+	}
+
+	void RendererUtility::draw(const SPtr<MeshCoreBase>& mesh, const SubMesh& subMesh)
+	{
+		RenderAPICore& rs = RenderAPICore::instance();
+		const MeshProperties& meshProps = mesh->getProperties();
+		std::shared_ptr<VertexData> vertexData = mesh->getVertexData();
+
+		rs.setVertexDeclaration(vertexData->vertexDeclaration);
+		auto& vertexBuffers = vertexData->getBuffers();
+
+		if (vertexBuffers.size() > 0)
+		{
+			SPtr<VertexBufferCore> buffers[MAX_BOUND_VERTEX_BUFFERS];
+
+			UINT32 endSlot = 0;
+			UINT32 startSlot = MAX_BOUND_VERTEX_BUFFERS;
+			for (auto iter = vertexBuffers.begin(); iter != vertexBuffers.end(); ++iter)
+			{
+				if (iter->first >= MAX_BOUND_VERTEX_BUFFERS)
+					BS_EXCEPT(InvalidParametersException, "Buffer index out of range");
+
+				startSlot = std::min(iter->first, startSlot);
+				endSlot = std::max(iter->first, endSlot);
+			}
+
+			for (auto iter = vertexBuffers.begin(); iter != vertexBuffers.end(); ++iter)
+			{
+				buffers[iter->first - startSlot] = iter->second;
+			}
+
+			rs.setVertexBuffers(startSlot, buffers, endSlot - startSlot + 1);
+		}
+
+		rs.setDrawOperation(subMesh.drawOp);
+
+		SPtr<IndexBufferCore> indexBuffer = mesh->getIndexBuffer();
+
+		UINT32 indexCount = subMesh.indexCount;
+
+		rs.setIndexBuffer(indexBuffer);
+		rs.drawIndexed(subMesh.indexOffset + mesh->getIndexOffset(), indexCount, mesh->getVertexOffset(), vertexData->vertexCount);
+
+		mesh->_notifyUsedOnGPU();
+	}
+
+	void RendererUtility::drawScreenQuad(const ViewportCore& viewport, const Rect2& uv, const Vector2I& textureSize)
+	{
+		// Note: Consider drawing the quad using a single large triangle for possibly better performance
+		Rect2I viewArea = viewport.getArea();
+
+		Vector3 vertices[4];
+		vertices[0] = Vector3((float)viewArea.x, (float)viewArea.y, 0.0f);
+		vertices[1] = Vector3((float)viewArea.x + (float)viewArea.width, (float)viewArea.y, 0.0f);
+		vertices[2] = Vector3((float)viewArea.x, (float)viewArea.y + (float)viewArea.height, 0.0f);
+		vertices[3] = Vector3((float)viewArea.x + (float)viewArea.width, (float)viewArea.y + (float)viewArea.height, 0.0f);
+
+		Vector2 uvs[4];
+		uvs[0] = Vector2(uv.x, uv.y);
+		uvs[1] = Vector2(uv.x + uv.width, uv.y);
+		uvs[2] = Vector2(uv.x, uv.y + uv.height);
+		uvs[3] = Vector2(uv.x + uv.width, uv.y + uv.height);
+
+		auto targetProps = viewport.getTarget()->getProperties();;
+		RenderAPICore& rapi = RenderAPICore::instance();
+		for (int i = 0; i < 4; i++)
+		{
+			vertices[i].x = -1.0f + 2.0f * (vertices[i].x + rapi.getHorizontalTexelOffset()) / targetProps.getWidth();
+			vertices[i].y = 1.0f - 2.0f * (vertices[i].y + rapi.getVerticalTexelOffset()) / targetProps.getHeight();
+
+			uvs[i].x /= (float)textureSize.x;
+			uvs[i].y /= (float)textureSize.y;
+		}
+
+		SPtr<VertexDataDesc> vertexDesc = mFullScreenQuadMesh->getVertexDesc();
+		MeshDataPtr meshData = bs_shared_ptr_new<MeshData>(4, 6, vertexDesc);
+
+		auto vecIter = meshData->getVec3DataIter(VES_POSITION);
+		for (UINT32 i = 0; i < 4; i++)
+			vecIter.addValue(vertices[i]);
+
+		auto uvIter = meshData->getVec2DataIter(VES_TEXCOORD);
+		for (UINT32 i = 0; i < 4; i++)
+			uvIter.addValue(uvs[i]);
+
+		auto indices = meshData->getIndices32();
+		indices[0] = 0;
+		indices[1] = 1;
+		indices[2] = 2;
+		indices[3] = 1;
+		indices[4] = 3;
+		indices[5] = 2;
+
+		mFullScreenQuadMesh->writeSubresource(0, *meshData, true, false);
+		draw(mFullScreenQuadMesh, mFullScreenQuadMesh->getProperties().getSubMesh());
+	}
+
+	RendererUtility& gRendererUtility()
+	{
+		return RendererUtility::instance();
+	}
 }

+ 9 - 0
BansheeEditor/Include/BsBuiltinEditorResources.h

@@ -80,6 +80,9 @@ namespace BansheeEngine
 		 */
 		const HGUISkin& getSkin() const { return mSkin; }
 
+		/** Returns the default font used by the editor. */
+		const HFont& getDefaultFont() const { return mDefaultFont; }
+
 		/**
 		 * @brief	Creates a material used for docking drop overlay used by the editor.
 		 */
@@ -135,6 +138,9 @@ namespace BansheeEngine
 		 */
 		HMaterial createSolidHandleMat() const;
 
+		/** Creates a material used for rendering text for gizmos and handles. */
+		HMaterial createTextGizmoMat() const;
+
 		/** Creates a material used for clearing the alpha channel of the handle rendering texture. */
 		HMaterial createHandleClearAlphaMat() const;
 
@@ -253,11 +259,13 @@ namespace BansheeEngine
 		HShader mShaderGizmoIcon;
 		HShader mShaderGizmoPicking;
 		HShader mShaderGizmoAlphaPicking;
+		HShader mShaderGizmoText;
 		HShader mShaderHandleSolid;
 		HShader mShaderHandleWire;
 		HShader mShaderHandleClearAlpha;
 		HShader mShaderSelection;
 
+		HFont mDefaultFont;
 		HGUISkin mSkin;
 
 		ResourceManifestPtr mResourceManifest;
@@ -491,6 +499,7 @@ namespace BansheeEngine
 		static const WString ShaderIconGizmoFile;
 		static const WString ShaderGizmoPickingFile;
 		static const WString ShaderGizmoPickingAlphaFile;
+		static const WString ShaderTextGizmoFile;
 		static const WString ShaderSelectionFile;
 
 		static const WString EmptyShaderCodeFile;

+ 60 - 8
BansheeEditor/Include/BsGizmoManager.h

@@ -153,6 +153,16 @@ namespace BansheeEngine
 		 */
 		void drawIcon(Vector3 position, HSpriteTexture image, bool fixedScale);
 
+		/**
+		 * Draws a mesh representing 2D text with the specified properties. 
+		 *
+		 * @param[in]	position	Position to render the text at. Text will be centered around this point.
+		 * @param[in]	text		Text to draw.
+		 * @param[in]	font		Font to use for rendering the text's characters.
+		 * @param[in]	fontSize	Size of the characters, in points.
+		 */
+		void drawText(const Vector3& position, const WString& text, const HFont& font, UINT32 fontSize = 16);
+
 		/**
 		 * @brief	Updates all the gizmo meshes to reflect all draw calls submitted since "clearGizmos".
 		 *
@@ -199,7 +209,7 @@ namespace BansheeEngine
 		 */
 		enum class GizmoMaterial
 		{
-			Solid, Wire, Picking
+			Solid, Wire, Picking, PickingAlpha, Text
 		};
 
 		/**
@@ -285,6 +295,17 @@ namespace BansheeEngine
 			HSpriteTexture texture;
 		};
 
+		/**
+		 * @brief	Data required for rendering text.
+		 */
+		struct TextData : public CommonData
+		{
+			Vector3 position;
+			WString text;
+			HFont font;
+			UINT32 fontSize;
+		};
+
 		/**
 		 * @brief	Stores how many icons use a specific texture.
 		 */
@@ -302,6 +323,7 @@ namespace BansheeEngine
 			SPtr<MaterialCore> solidMat;
 			SPtr<MaterialCore> wireMat;
 			SPtr<MaterialCore> iconMat;
+			SPtr<MaterialCore> textMat;
 			SPtr<MaterialCore> pickingMat;
 			SPtr<MaterialCore> alphaPickingMat;
 		};
@@ -378,6 +400,7 @@ namespace BansheeEngine
 		Vector<WireArcData> mWireArcData;
 		Vector<FrustumData> mFrustumData;
 		Vector<IconData> mIconData;
+		Vector<TextData> mTextData;
 		Map<UINT32, HSceneObject> mIdxToSceneObjectMap;
 
 		Vector<DrawHelper::ShapeMeshData> mActiveMeshes;
@@ -439,6 +462,16 @@ namespace BansheeEngine
 			GpuParamTextureCore mTexture[2];
 		};
 
+		/**
+		 * @brief	Text gizmo material and parameter handles.
+		 */
+		struct TextMaterialData
+		{
+			SPtr<MaterialCore> mat;
+			GpuParamMat4Core mViewProj;
+			GpuParamTextureCore mTexture;
+		};
+
 		/**
 		 * @brief	Gizmo material and parameter handles used for picking.
 		 */
@@ -460,6 +493,24 @@ namespace BansheeEngine
 			GpuParamTextureCore mTexture;
 		};
 
+		/** Type of mesh that can be drawn. */
+		enum class MeshType
+		{
+			Solid, Wire, Text
+		};
+
+		/** Data about a mesh rendered by the draw manager. */
+		struct MeshData
+		{
+			MeshData(const SPtr<MeshCoreBase>& mesh, SPtr<TextureCore> texture, MeshType type)
+				:mesh(mesh), texture(texture), type(type)
+			{ }
+
+			SPtr<MeshCoreBase> mesh;
+			SPtr<TextureCore> texture;
+			MeshType type;
+		};
+
 		struct PrivatelyConstuct { };
 
 	public:
@@ -484,9 +535,11 @@ namespace BansheeEngine
 		 * @param	projMatrix	Projection matrix of the camera we are rendering with.
 		 * @param	viewDir		View direction of the camera we are rendering with.
 		 * @param	mesh		Mesh to render. This is normally the solid or wireframe gizmo mesh.
+		 * @param	texture		Texture to apply to the material, if the material supports a texture.
 		 * @param	material	Material to use for rendering. This is normally the solid, wireframe or picking material.
 		 */
-		void renderGizmos(Matrix4 viewMatrix, Matrix4 projMatrix, Vector3 viewDir, SPtr<MeshCoreBase> mesh, GizmoManager::GizmoMaterial material);
+		void renderGizmos(const Matrix4& viewMatrix, const Matrix4& projMatrix, const Vector3& viewDir, 
+			const SPtr<MeshCoreBase>& mesh, const SPtr<TextureCore>& texture, GizmoManager::GizmoMaterial material);
 
 		/**
 		 * @brief	Renders the icon gizmo mesh using the provided parameters.
@@ -503,20 +556,18 @@ namespace BansheeEngine
 		 *			updating the camera or meshes on the sim thread.
 		 *
 		 * @param	camera			Sets the camera all rendering will be performed to.
-		 * @param	solidMesh		Mesh containing solid gizmos.
-		 * @param	wireMesh		Mesh containing wireframe gizmos.
+		 * @param	meshes			Meshes to render.
 		 * @param	iconMesh		Mesh containing icon meshes.
 		 * @param	iconRenderData	Icon render data outlining which parts of the icon mesh use which textures.
 		 */
-		void updateData(const SPtr<CameraCore>& camera, const SPtr<MeshCoreBase>& solidMesh, const SPtr<MeshCoreBase>& wireMesh,
-			const SPtr<MeshCoreBase>& iconMesh, const GizmoManager::IconRenderDataVecPtr& iconRenderData);
+		void updateData(const SPtr<CameraCore>& camera, const Vector<MeshData>& meshes, const SPtr<MeshCoreBase>& iconMesh, 
+			const GizmoManager::IconRenderDataVecPtr& iconRenderData);
 
 		static const float PICKING_ALPHA_CUTOFF;
 
 		SPtr<CameraCore> mCamera;
 
-		SPtr<MeshCoreBase> mSolidMesh;
-		SPtr<MeshCoreBase> mWireMesh;
+		Vector<MeshData> mMeshes;
 		SPtr<MeshCoreBase> mIconMesh;
 		GizmoManager::IconRenderDataVecPtr mIconRenderData;
 
@@ -524,6 +575,7 @@ namespace BansheeEngine
 		SolidMaterialData mSolidMaterial;
 		WireMaterialData mWireMaterial;
 		IconMaterialData mIconMaterial;
+		TextMaterialData mTextMaterial;
 
 		PickingMaterialData mPickingMaterial;
 		AlphaPickingMaterialData mAlphaPickingMaterial;

+ 32 - 9
BansheeEditor/Include/BsHandleDrawManager.h

@@ -146,6 +146,17 @@ namespace BansheeEngine
 		 */
 		void drawRect(const Rect3& area, float size = 1.0f);
 
+		/**
+		 * Draws a mesh representing 2D text with the specified properties. 
+		 *
+		 * @param[in]	position	Position to render the text at. Text will be centered around this point.
+		 * @param[in]	text		Text to draw.
+		 * @param[in]	font		Font to use for rendering the text's characters.
+		 * @param[in]	fontSize	Size of the characters, in points.
+		 * @param[in]	size		Uniform scale of the rendered mesh.
+		 */
+		void drawText(const Vector3& position, const WString& text, const HFont& font, UINT32 fontSize = 16, float size = 1.0f);
+
 		/**	Queues all the handle draw commands queued since the last call to clear() for rendering. */
 		void draw(const CameraPtr& camera);
 
@@ -160,10 +171,11 @@ namespace BansheeEngine
 		 *
 		 * @param[in]	wireMat		Material used for drawing the wireframe objects.
 		 * @param[in]	solidMat	Material used for drawing the solid objects.
+		 *@param[in]	textMat		Material used for drawing the text.
 		 * @param[in]	clearMat	Material used for clearing the alpha channel in the empty areas.
 		 */
 		void initializeCore(const SPtr<MaterialCore>& wireMat, const SPtr<MaterialCore>& solidMat, 
-			const SPtr<MaterialCore>& clearMat);
+			const SPtr<MaterialCore>& textMat, const SPtr<MaterialCore>& clearMat);
 
 		/** Destroys the core thread portion of the draw manager. */
 		void destroyCore(HandleDrawManagerCore* core);
@@ -190,15 +202,23 @@ namespace BansheeEngine
 		struct SolidMaterialData
 		{
 			SPtr<MaterialCore> mat;
-			GpuParamMat4Core mViewProj;
-			GpuParamVec4Core mViewDir;
+			GpuParamMat4Core viewProj;
+			GpuParamVec4Core viewDir;
 		};
 
 		/**	Contains information about the material used for drawing wireframe objects and its parameters. */
 		struct WireMaterialData
 		{
 			SPtr<MaterialCore> mat;
-			GpuParamMat4Core mViewProj;
+			GpuParamMat4Core viewProj;
+		};
+
+		/**	Contains information about the material used for drawing text and its parameters. */
+		struct TextMaterialData
+		{
+			SPtr<MaterialCore> mat;
+			GpuParamMat4Core viewProj;
+			GpuParamTextureCore texture;
 		};
 
 		/**	Contains information about the material used for clearing the alpha channel in the empty areas. */
@@ -210,17 +230,18 @@ namespace BansheeEngine
 		/** Type of mesh that can be drawn. */
 		enum class MeshType
 		{
-			Solid, Wire
+			Solid, Wire, Text
 		};
 
 		/** Data about a mesh rendered by the draw manager. */
 		struct MeshData
 		{
-			MeshData(const SPtr<MeshCoreBase>& mesh, MeshType type)
-				:mesh(mesh), type(type)
+			MeshData(const SPtr<MeshCoreBase>& mesh, SPtr<TextureCore> texture, MeshType type)
+				:mesh(mesh), texture(texture), type(type)
 			{ }
 
 			SPtr<MeshCoreBase> mesh;
+			SPtr<TextureCore> texture;
 			MeshType type;
 		};
 
@@ -245,10 +266,11 @@ namespace BansheeEngine
 		 *
 		 * @param[in]	wireMat		Material used for drawing the wireframe objects.
 		 * @param[in]	solidMat	Material used for drawing the solid objects.
+		 * @param[in]	textMat		Material used for drawing the text.
 		 * @param[in]	clearMat	Material used for clearing the alpha channel in the empty areas.
 		 */
-		void initialize(const SPtr<MaterialCore>& wireMat, const SPtr<MaterialCore>& solidMat,
-			const SPtr<MaterialCore>& clearMat);
+		void initialize(const SPtr<MaterialCore>& wireMat, const SPtr<MaterialCore>& solidMat, 
+			const SPtr<MaterialCore>& textMat, const SPtr<MaterialCore>& clearMat);
 
 		/**
 		 * Queues new data for rendering.
@@ -269,6 +291,7 @@ namespace BansheeEngine
 		// Immutable
 		SolidMaterialData mSolidMaterial;
 		WireMaterialData mWireMaterial;
+		TextMaterialData mTextMaterial;
 		WireMaterialData mClearMaterial;
 	};
 }

+ 8 - 0
BansheeEditor/Source/BsBuiltinEditorResources.cpp

@@ -270,6 +270,7 @@ namespace BansheeEngine
 	const WString BuiltinEditorResources::ShaderIconGizmoFile = L"IconGizmo.bsl";
 	const WString BuiltinEditorResources::ShaderGizmoPickingFile = L"GizmoPicking.bsl";
 	const WString BuiltinEditorResources::ShaderGizmoPickingAlphaFile = L"GizmoPickingAlpha.bsl";
+	const WString BuiltinEditorResources::ShaderTextGizmoFile = L"TextGizmo.bsl";
 	const WString BuiltinEditorResources::ShaderSelectionFile = L"Selection.bsl";
 
 	/************************************************************************/
@@ -340,11 +341,13 @@ namespace BansheeEngine
 		mShaderGizmoIcon = getShader(ShaderIconGizmoFile);
 		mShaderGizmoPicking = getShader(ShaderGizmoPickingFile);
 		mShaderGizmoAlphaPicking = getShader(ShaderGizmoPickingAlphaFile);
+		mShaderGizmoText = getShader(ShaderTextGizmoFile);
 		mShaderHandleSolid = getShader(ShaderSolidHandleFile);
 		mShaderHandleClearAlpha = getShader(ShaderHandleClearAlphaFile);
 		mShaderHandleWire = getShader(ShaderWireHandleFile);
 		mShaderSelection = getShader(ShaderSelectionFile);
 
+		mDefaultFont = gResources().load<Font>(BuiltinDataFolder + (DefaultAAFontFilename + L".asset"));
 		mSkin = gResources().load<GUISkin>(BuiltinDataFolder + (GUISkinFile + L".asset"));
 	}
 
@@ -1958,6 +1961,11 @@ namespace BansheeEngine
 		return Material::create(mShaderHandleWire);
 	}
 
+	HMaterial BuiltinEditorResources::createTextGizmoMat() const
+	{
+		return Material::create(mShaderGizmoText);
+	}
+
 	HMaterial BuiltinEditorResources::createSolidHandleMat() const
 	{
 		return Material::create(mShaderHandleSolid);

+ 118 - 30
BansheeEditor/Source/BsGizmoManager.cpp

@@ -48,6 +48,7 @@ namespace BansheeEngine
 		HMaterial solidMaterial = BuiltinEditorResources::instance().createSolidGizmoMat();
 		HMaterial wireMaterial = BuiltinEditorResources::instance().createWireGizmoMat();
 		HMaterial iconMaterial = BuiltinEditorResources::instance().createIconGizmoMat();
+		HMaterial textMaterial = BuiltinEditorResources::instance().createTextGizmoMat();
 		HMaterial pickingMaterial = BuiltinEditorResources::instance().createGizmoPickingMat();
 		HMaterial alphaPickingMaterial = BuiltinEditorResources::instance().createAlphaGizmoPickingMat();
 
@@ -56,6 +57,7 @@ namespace BansheeEngine
 		initData.solidMat = solidMaterial->getCore();
 		initData.wireMat = wireMaterial->getCore();
 		initData.iconMat = iconMaterial->getCore();
+		initData.textMat = textMaterial->getCore();
 		initData.pickingMat = pickingMaterial->getCore();
 		initData.alphaPickingMat = alphaPickingMaterial->getCore();
 
@@ -271,6 +273,29 @@ namespace BansheeEngine
 		mIdxToSceneObjectMap[iconData.idx] = mActiveSO;
 	}
 
+	void GizmoManager::drawText(const Vector3& position, const WString& text, const HFont& font, UINT32 fontSize)
+	{
+		HFont myFont = font;
+		if (myFont == nullptr)
+			myFont = BuiltinEditorResources::instance().getDefaultFont();
+
+		mTextData.push_back(TextData());
+		TextData& textData = mTextData.back();
+
+		textData.idx = mCurrentIdx++;
+		textData.position = position;
+		textData.text = text;
+		textData.font = myFont;
+		textData.fontSize = fontSize;
+		textData.color = mColor;
+		textData.transform = mTransform;
+		textData.sceneObject = mActiveSO;
+		textData.pickable = mPickable;
+
+		mDrawHelper->text(position, text, myFont, fontSize);
+		mIdxToSceneObjectMap[textData.idx] = mActiveSO;
+	}
+
 	void GizmoManager::update(const CameraPtr& camera)
 	{
 		mDrawHelper->clearMeshes(mActiveMeshes);
@@ -281,36 +306,40 @@ namespace BansheeEngine
 
 		IconRenderDataVecPtr iconRenderData;
 
-		mDrawHelper->buildMeshes();
+		mDrawHelper->buildMeshes(DrawHelper::SortType::BackToFront, camera->getPosition());
 		mActiveMeshes = mDrawHelper->getMeshes();
 
-		SPtr<MeshCoreBase> solidMesh = nullptr;
-		SPtr<MeshCoreBase> wireMesh = nullptr;
+		Vector<GizmoManagerCore::MeshData> proxyData;
 		for (auto& meshData : mActiveMeshes)
 		{
+			SPtr<TextureCore> tex;
+			if (meshData.texture.isLoaded())
+				tex = meshData.texture->getCore();
+
 			if (meshData.type == DrawHelper::MeshType::Solid)
 			{
-				if (solidMesh == nullptr)
-					solidMesh = meshData.mesh->getCore();
+				proxyData.push_back(GizmoManagerCore::MeshData(
+					meshData.mesh->getCore(), tex, GizmoManagerCore::MeshType::Solid));
 			}
-			else // Wire
+			else if (meshData.type == DrawHelper::MeshType::Wire)
 			{
-				if (wireMesh == nullptr)
-					wireMesh = meshData.mesh->getCore();
+				proxyData.push_back(GizmoManagerCore::MeshData(
+					meshData.mesh->getCore(), tex, GizmoManagerCore::MeshType::Wire));
+			}
+			else // Text
+			{
+				proxyData.push_back(GizmoManagerCore::MeshData(
+					meshData.mesh->getCore(), tex, GizmoManagerCore::MeshType::Text));
 			}
 		}
 
-		// Since there is no sorting used with draw helper meshes we only expect up to two of them,
-		// one for solids, one for wireframe
-		assert(mActiveMeshes.size() <= 2);
-
 		mIconMesh = buildIconMesh(camera, mIconData, false, iconRenderData);
 		SPtr<MeshCoreBase> iconMesh = mIconMesh->getCore();
 
 		GizmoManagerCore* core = mCore.load(std::memory_order_relaxed);
 
 		gCoreAccessor().queueCommand(std::bind(&GizmoManagerCore::updateData, core, camera->getCore(),
-			solidMesh, wireMesh, iconMesh, iconRenderData));
+			proxyData, iconMesh, iconRenderData));
 	}
 
 	void GizmoManager::renderForPicking(const CameraPtr& camera, std::function<Color(UINT32)> idxToColorCallback)
@@ -410,6 +439,18 @@ namespace BansheeEngine
 				frustumDataEntry.near, frustumDataEntry.far);
 		}
 
+		for (auto& textDataEntry : mTextData)
+		{
+			if (!textDataEntry.pickable)
+				continue;
+
+			mPickingDrawHelper->setColor(idxToColorCallback(textDataEntry.idx));
+			mPickingDrawHelper->setTransform(textDataEntry.transform);
+
+			mPickingDrawHelper->text(textDataEntry.position, textDataEntry.text, textDataEntry.font,
+				textDataEntry.fontSize);
+		}
+
 		for (auto& iconDataEntry : mIconData)
 		{
 			if (!iconDataEntry.pickable)
@@ -419,7 +460,7 @@ namespace BansheeEngine
 			iconData.back().color = idxToColorCallback(iconDataEntry.idx);
 		}
 
-		mPickingDrawHelper->buildMeshes();
+		mPickingDrawHelper->buildMeshes(DrawHelper::SortType::BackToFront, camera->getPosition());
 		const Vector<DrawHelper::ShapeMeshData>& meshes = mPickingDrawHelper->getMeshes();
 
 		TransientMeshPtr iconMesh = buildIconMesh(camera, iconData, true, iconRenderData);
@@ -433,15 +474,19 @@ namespace BansheeEngine
 
 		for (auto& meshData : meshes)
 		{
-			if (meshData.type == DrawHelper::MeshType::Solid)
+			SPtr<TextureCore> tex;
+			if (meshData.texture.isLoaded())
+				tex = meshData.texture->getCore();
+
+			if(meshData.type == DrawHelper::MeshType::Text)
 			{
-				gCoreAccessor().queueCommand(std::bind(&GizmoManagerCore::renderGizmos,
-					core, viewMat, projMat, camera->getForward(), meshData.mesh->getCore(), GizmoMaterial::Picking));
+				gCoreAccessor().queueCommand(std::bind(&GizmoManagerCore::renderGizmos, core, viewMat, projMat,
+					camera->getForward(), meshData.mesh->getCore(), tex, GizmoMaterial::PickingAlpha));
 			}
-			else // Wire
+			else
 			{
-				gCoreAccessor().queueCommand(std::bind(&GizmoManagerCore::renderGizmos,
-					core, viewMat, projMat, camera->getForward(), meshData.mesh->getCore(), GizmoMaterial::Picking));
+				gCoreAccessor().queueCommand(std::bind(&GizmoManagerCore::renderGizmos, core, viewMat, projMat,
+					camera->getForward(), meshData.mesh->getCore(), tex, GizmoMaterial::Picking));
 			}
 		}
 
@@ -464,6 +509,7 @@ namespace BansheeEngine
 		mWireDiscData.clear();
 		mWireArcData.clear();
 		mFrustumData.clear();
+		mTextData.clear();
 		mIconData.clear();
 		mIdxToSceneObjectMap.clear();
 
@@ -485,7 +531,8 @@ namespace BansheeEngine
 		GizmoManagerCore* core = mCore.load(std::memory_order_relaxed);
 		IconRenderDataVecPtr iconRenderData = bs_shared_ptr_new<IconRenderDataVec>();
 		
-		gCoreAccessor().queueCommand(std::bind(&GizmoManagerCore::updateData, core, nullptr, nullptr, nullptr, nullptr, iconRenderData));
+		gCoreAccessor().queueCommand(std::bind(&GizmoManagerCore::updateData, core, 
+			nullptr, Vector<GizmoManagerCore::MeshData>(), nullptr, iconRenderData));
 	}
 
 	TransientMeshPtr GizmoManager::buildIconMesh(const CameraPtr& camera, const Vector<IconData>& iconData,
@@ -724,6 +771,7 @@ namespace BansheeEngine
 
 		mSolidMaterial.mat = initData.solidMat;
 		mWireMaterial.mat = initData.wireMat;
+		mTextMaterial.mat = initData.textMat;
 		mIconMaterial.mat = initData.iconMat;
 		mPickingMaterial.mat = initData.pickingMat;
 		mAlphaPickingMaterial.mat = initData.alphaPickingMat;
@@ -783,9 +831,20 @@ namespace BansheeEngine
 			mAlphaPickingMaterial.mFragParams->getParam("alphaCutoff", alphaCutoffParam);
 			alphaCutoffParam.set(PICKING_ALPHA_CUTOFF);
 		}
+
+		{
+			SPtr<MaterialCore> mat = mTextMaterial.mat;
+
+			SPtr<PassParametersCore> passParams = mat->getPassParameters(0);
+			SPtr<GpuParamsCore> vertParams = passParams->mVertParams;
+			SPtr<GpuParamsCore> fragParams = passParams->mFragParams;
+
+			vertParams->getParam("matViewProj", mTextMaterial.mViewProj);
+			fragParams->getTextureParam("mainTexture", mTextMaterial.mTexture);
+		}
 	}
 
-	void GizmoManagerCore::updateData(const SPtr<CameraCore>& camera, const SPtr<MeshCoreBase>& solidMesh, const SPtr<MeshCoreBase>& wireMesh,
+	void GizmoManagerCore::updateData(const SPtr<CameraCore>& camera, const Vector<MeshData>& meshes, 
 		const SPtr<MeshCoreBase>& iconMesh, const GizmoManager::IconRenderDataVecPtr& iconRenderData)
 	{
 		if (mCamera != camera)
@@ -799,8 +858,7 @@ namespace BansheeEngine
 		}
 
 		mCamera = camera;
-		mSolidMesh = solidMesh;
-		mWireMesh = wireMesh;
+		mMeshes = meshes;
 		mIconMesh = iconMesh;
 		mIconRenderData = iconRenderData;
 	}
@@ -823,17 +881,32 @@ namespace BansheeEngine
 		screenArea.width = (int)(normArea.width * width);
 		screenArea.height = (int)(normArea.height * height);
 
-		if (mSolidMesh != nullptr)
-			renderGizmos(mCamera->getViewMatrix(), mCamera->getProjectionMatrixRS(), mCamera->getForward(), mSolidMesh, GizmoManager::GizmoMaterial::Solid);
+		for (auto& meshData : mMeshes)
+		{
+			GizmoManager::GizmoMaterial material = GizmoManager::GizmoMaterial::Solid;
+			switch(meshData.type)
+			{
+			case MeshType::Solid:
+				material = GizmoManager::GizmoMaterial::Solid;
+				break;
+			case MeshType::Wire:
+				material = GizmoManager::GizmoMaterial::Wire;
+				break;
+			case MeshType::Text:
+				material = GizmoManager::GizmoMaterial::Text;
+				break;
+			}
 
-		if (mWireMesh != nullptr)
-			renderGizmos(mCamera->getViewMatrix(), mCamera->getProjectionMatrixRS(), mCamera->getForward(), mWireMesh, GizmoManager::GizmoMaterial::Wire);
+			renderGizmos(mCamera->getViewMatrix(), mCamera->getProjectionMatrixRS(), mCamera->getForward(), 
+				meshData.mesh, meshData.texture, material);
+		}
 
 		if (mIconMesh != nullptr)
 			renderIconGizmos(screenArea, mIconMesh, mIconRenderData, false);
 	}
 
-	void GizmoManagerCore::renderGizmos(Matrix4 viewMatrix, Matrix4 projMatrix, Vector3 viewDir, SPtr<MeshCoreBase> mesh, GizmoManager::GizmoMaterial material)
+	void GizmoManagerCore::renderGizmos(const Matrix4& viewMatrix, const Matrix4& projMatrix, const Vector3& viewDir, 
+		const SPtr<MeshCoreBase>& mesh, const SPtr<TextureCore>& texture, GizmoManager::GizmoMaterial material)
 	{
 		THROW_IF_NOT_CORE_THREAD;
 
@@ -845,17 +918,32 @@ namespace BansheeEngine
 			mSolidMaterial.mViewProj.set(viewProjMat);
 			mSolidMaterial.mViewDir.set((Vector4)viewDir);
 			gRendererUtility().setPass(mSolidMaterial.mat, 0);
+			gRendererUtility().setPassParams(mSolidMaterial.mat);
 			break;
 		case GizmoManager::GizmoMaterial::Wire:
 			mWireMaterial.mViewProj.set(viewProjMat);
 			gRendererUtility().setPass(mWireMaterial.mat, 0);
+			gRendererUtility().setPassParams(mWireMaterial.mat);
 			break;
 		case GizmoManager::GizmoMaterial::Picking:
 			mPickingMaterial.mViewProj.set(viewProjMat);
 			gRendererUtility().setPass(mPickingMaterial.mat, 0);
+			gRendererUtility().setPassParams(mPickingMaterial.mat);
+			break;
+		case GizmoManager::GizmoMaterial::PickingAlpha:
+			mAlphaPickingMaterial.mViewProj.set(viewProjMat);
+			mAlphaPickingMaterial.mTexture.set(texture);
+			gRendererUtility().setPass(mAlphaPickingMaterial.mat, 0);
+			gRendererUtility().setPassParams(mAlphaPickingMaterial.mat);
+			break;
+		case GizmoManager::GizmoMaterial::Text:
+			mTextMaterial.mViewProj.set(viewProjMat);
+			mTextMaterial.mTexture.set(texture);
+
+			gRendererUtility().setPass(mTextMaterial.mat, 0);
+			gRendererUtility().setPassParams(mTextMaterial.mat);
 			break;
 		}
-		
 		gRendererUtility().draw(mesh, mesh->getProperties().getSubMesh(0));
 	}
 

+ 67 - 16
BansheeEditor/Source/BsHandleDrawManager.cpp

@@ -8,8 +8,9 @@
 #include "BsTransientMesh.h"
 #include "BsCamera.h"
 #include "BsRendererUtility.h"
-#include "BsSceneObject.h"
+#include "BsTexture.h"
 #include "BsTime.h"
+#include "BsRenderAPI.h"
 
 using namespace std::placeholders;
 
@@ -27,16 +28,18 @@ namespace BansheeEngine
 
 		HMaterial solidMaterial = BuiltinEditorResources::instance().createSolidHandleMat();
 		HMaterial wireMaterial = BuiltinEditorResources::instance().createWireHandleMat();
+		HMaterial textMaterial = BuiltinEditorResources::instance().createTextGizmoMat();
 		HMaterial clearMaterial = BuiltinEditorResources::instance().createHandleClearAlphaMat();
 
 		SPtr<MaterialCore> solidMaterialProxy = solidMaterial->getCore();
 		SPtr<MaterialCore> wireMaterialProxy = wireMaterial->getCore();
+		SPtr<MaterialCore> textMaterialProxy = textMaterial->getCore();
 		SPtr<MaterialCore> clearMaterialProxy = clearMaterial->getCore();
 
 		mCore.store(bs_new<HandleDrawManagerCore>(HandleDrawManagerCore::PrivatelyConstruct()), std::memory_order_release);
 
 		gCoreAccessor().queueCommand(std::bind(&HandleDrawManager::initializeCore, this, 
-			wireMaterialProxy, solidMaterialProxy, clearMaterialProxy));
+			wireMaterialProxy, solidMaterialProxy, textMaterialProxy, clearMaterialProxy));
 	}
 
 	HandleDrawManager::~HandleDrawManager()
@@ -48,11 +51,11 @@ namespace BansheeEngine
 	}
 
 	void HandleDrawManager::initializeCore(const SPtr<MaterialCore>& wireMat, const SPtr<MaterialCore>& solidMat, 
-		const SPtr<MaterialCore>& clearMat)
+		const SPtr<MaterialCore>& textMat, const SPtr<MaterialCore>& clearMat)
 	{
 		THROW_IF_NOT_CORE_THREAD;
 
-		mCore.load(std::memory_order_acquire)->initialize(wireMat, solidMat, clearMat);
+		mCore.load(std::memory_order_acquire)->initialize(wireMat, solidMat, textMat, clearMat);
 	}
 
 	void HandleDrawManager::destroyCore(HandleDrawManagerCore* core)
@@ -165,6 +168,18 @@ namespace BansheeEngine
 		mDrawHelper->rectangle(area);
 	}
 
+	void HandleDrawManager::drawText(const Vector3& position, const WString& text, const HFont& font, UINT32 fontSize, float size)
+	{
+		Matrix4 scale = Matrix4::scaling(size);
+		mDrawHelper->setTransform(mTransform * scale);
+
+		HFont myFont = font;
+		if (myFont == nullptr)
+			myFont = BuiltinEditorResources::instance().getDefaultFont();
+
+		mDrawHelper->text(position, text, myFont, fontSize);
+	}
+
 	void HandleDrawManager::draw(const CameraPtr& camera)
 	{
 		HandleDrawManagerCore* core = mCore.load(std::memory_order_relaxed);
@@ -187,15 +202,24 @@ namespace BansheeEngine
 		Vector<HandleDrawManagerCore::MeshData> proxyData;
 		for (auto& meshData : meshes)
 		{
+			SPtr<TextureCore> tex;
+			if (meshData.texture.isLoaded())
+				tex = meshData.texture->getCore();
+
 			if (meshData.type == DrawHelper::MeshType::Solid)
 			{
 				proxyData.push_back(HandleDrawManagerCore::MeshData(
-					meshData.mesh->getCore(), HandleDrawManagerCore::MeshType::Solid));
+					meshData.mesh->getCore(), tex, HandleDrawManagerCore::MeshType::Solid));
+			}
+			else if (meshData.type == DrawHelper::MeshType::Wire)
+			{
+				proxyData.push_back(HandleDrawManagerCore::MeshData(
+					meshData.mesh->getCore(), tex, HandleDrawManagerCore::MeshType::Wire));
 			}
-			else // Wire
+			else // Text
 			{
 				proxyData.push_back(HandleDrawManagerCore::MeshData(
-					meshData.mesh->getCore(), HandleDrawManagerCore::MeshType::Wire));
+					meshData.mesh->getCore(), tex, HandleDrawManagerCore::MeshType::Text));
 			}
 		}
 
@@ -221,13 +245,13 @@ namespace BansheeEngine
 	}
 
 	void HandleDrawManagerCore::initialize(const SPtr<MaterialCore>& wireMat, const SPtr<MaterialCore>& solidMat, 
-		const SPtr<MaterialCore>& clearMat)
+		const SPtr<MaterialCore>& textMat, const SPtr<MaterialCore>& clearMat)
 	{
 		{
 			mWireMaterial.mat = wireMat;
 			SPtr<GpuParamsCore> vertParams = wireMat->getPassParameters(0)->mVertParams;
 
-			vertParams->getParam("matViewProj", mWireMaterial.mViewProj);
+			vertParams->getParam("matViewProj", mWireMaterial.viewProj);
 		}
 
 		{
@@ -235,8 +259,17 @@ namespace BansheeEngine
 			SPtr<GpuParamsCore> vertParams = solidMat->getPassParameters(0)->mVertParams;
 			SPtr<GpuParamsCore> fragParams = solidMat->getPassParameters(0)->mFragParams;
 
-			vertParams->getParam("matViewProj", mSolidMaterial.mViewProj);
-			fragParams->getParam("viewDir", mSolidMaterial.mViewDir);
+			vertParams->getParam("matViewProj", mSolidMaterial.viewProj);
+			fragParams->getParam("viewDir", mSolidMaterial.viewDir);
+		}
+		{
+			mTextMaterial.mat = textMat;
+
+			SPtr<GpuParamsCore> vertParams = textMat->getPassParameters(0)->mVertParams;
+			SPtr<GpuParamsCore> fragParams = textMat->getPassParameters(0)->mFragParams;
+
+			vertParams->getParam("matViewProj", mTextMaterial.viewProj);
+			fragParams->getTextureParam("mainTexture", mTextMaterial.texture);
 		}
 
 		{
@@ -287,9 +320,10 @@ namespace BansheeEngine
 		screenArea.height = (int)(normArea.height * height);
 
 		Matrix4 viewProjMat = camera->getProjectionMatrixRS() * camera->getViewMatrix();
-		mSolidMaterial.mViewProj.set(viewProjMat);
-		mSolidMaterial.mViewDir.set((Vector4)camera->getForward());
-		mWireMaterial.mViewProj.set(viewProjMat);
+		mSolidMaterial.viewProj.set(viewProjMat);
+		mSolidMaterial.viewDir.set((Vector4)camera->getForward());
+		mWireMaterial.viewProj.set(viewProjMat);
+		mTextMaterial.viewProj.set(viewProjMat);
 
 		MeshType currentType = MeshType::Solid;
 		if (meshes.size() > 0)
@@ -298,8 +332,13 @@ namespace BansheeEngine
 
 			if (currentType == MeshType::Solid)
 				gRendererUtility().setPass(mSolidMaterial.mat, 0);
-			else
+			else if(currentType == MeshType::Wire)
 				gRendererUtility().setPass(mWireMaterial.mat, 0);
+			else
+			{
+				mTextMaterial.texture.set(meshes[0].texture);
+				gRendererUtility().setPass(mTextMaterial.mat, 0);
+			}
 		}
 
 		for (auto& meshData : meshes)
@@ -307,9 +346,21 @@ namespace BansheeEngine
 			if (currentType != meshData.type)
 			{
 				if (meshData.type == MeshType::Solid)
+				{
 					gRendererUtility().setPass(mSolidMaterial.mat, 0);
-				else
+					gRendererUtility().setPassParams(mSolidMaterial.mat); // TODO - This call shouldn't be necessary, calling set() on parameters should be enough
+				}
+				else if (meshData.type == MeshType::Wire)
+				{
 					gRendererUtility().setPass(mWireMaterial.mat, 0);
+					gRendererUtility().setPassParams(mWireMaterial.mat); // TODO - This call shouldn't be necessary, calling set() on parameters should be enough
+				}
+				else
+				{
+					mTextMaterial.texture.set(meshData.texture);
+					gRendererUtility().setPass(mTextMaterial.mat, 0);
+					gRendererUtility().setPassParams(mTextMaterial.mat); // TODO - This call shouldn't be necessary, calling set() on parameters should be enough
+				}
 
 				currentType = meshData.type;
 			}

+ 5 - 4
BansheeEngine/Include/BsDrawHelper.h

@@ -41,6 +41,7 @@ namespace BansheeEngine
 		{
 			TransientMeshPtr mesh;
 			MeshType type;
+			HTexture texture;
 		};
 
 		DrawHelper();
@@ -126,10 +127,10 @@ namespace BansheeEngine
 		/**
 		 * Records a mesh representing 2D text with the specified properties in the internal draw queue. 
 		 *
-		 * @param[in]	position		Position to render the text at. Text will be centered around this point.
-		 * @param[in]	text			Text to draw.
-		 * @param[in]	font			Font to use for rendering the text's characters.
-		 * @param[in]	size			Size of the text, in points.
+		 * @param[in]	position	Position to render the text at. Text will be centered around this point.
+		 * @param[in]	text		Text to draw.
+		 * @param[in]	font		Font to use for rendering the text's characters.
+		 * @param[in]	size		Size of the characters, in points.
 		 */
 		void text(const Vector3& position, const WString& text, const HFont& font, UINT32 size = 10);
 

+ 29 - 17
BansheeEngine/Source/BsDrawHelper.cpp

@@ -7,6 +7,7 @@
 #include "BsShapeMeshes3D.h"
 #include "BsTextData.h"
 #include "BsVector2.h"
+#include "BsQuaternion.h"
 
 namespace BansheeEngine
 {
@@ -660,23 +661,13 @@ namespace BansheeEngine
 				Batch& currentBatch = batches.back();
 
 				HTexture texture;
-				bool startNewBatch = false;
-				if(allShapes[i].meshType != currentBatch.type)
+				if (allShapes[i].meshType == MeshType::Text)
 				{
-					startNewBatch = true;
-				}
-				else
-				{
-					if(allShapes[i].meshType == MeshType::Text)
-					{
-						TextRenderData& renderData = textRenderData[allShapes[i].textIdx];
-						texture = renderData.textData->getTextureForPage(renderData.page);
-
-						if (texture != currentBatch.texture)
-							startNewBatch = true;
-					}
+					TextRenderData& renderData = textRenderData[allShapes[i].textIdx];
+					texture = renderData.textData->getTextureForPage(renderData.page);
 				}
 
+				bool startNewBatch = allShapes[i].meshType != currentBatch.type || texture != currentBatch.texture;
 				if (startNewBatch)
 				{
 					currentBatch.endIdx = i - 1;
@@ -951,18 +942,38 @@ namespace BansheeEngine
 						quadOffset += writtenQuads;
 					}
 
+					Vector3 translation = text2DData.transform.getTranslation();
+					
+					Vector2 accum;
+					for (UINT32 j = 0; j < shapeData.numVertices; j++)
+						accum += tempVertices[j];
+
+					Vector2 center2D = accum / (float)shapeData.numVertices;
+					Vector3 lookAt = Vector3::normalize(reference - translation);
+
+					Quaternion rotation;
+					rotation.lookRotation(lookAt, Vector3::UNIT_Y);
+
+					float scale = translation.distance(reference) * 0.0025f; // 0.0025 = arbitrary scale to make the text look okay in world space
+
+					// Scale by negative because we want to flip the vertices (they're upside down because GUI shader expects them as such)
+					Matrix4 transform = Matrix4::TRS(translation, rotation, Vector3::ONE);
+
 					for (UINT32 j = 0; j < shapeData.numVertices; j++)
 					{
-						Vector3 localPos(tempVertices[j].x, tempVertices[j].y, 0.0f);
-						Vector3 worldPos = text2DData.transform.multiplyAffine(localPos);
+						Vector2 localPos2D = tempVertices[j] - center2D;
+						localPos2D = localPos2D * -scale;
+
+						Vector3 localPos(localPos2D.x, localPos2D.y, 0.0f);
+						Vector3 worldPos = transform.multiplyAffine(localPos);
 
 						positionIter.addValue(worldPos);
 						uvIter.addValue(tempUVs[j]);
 						colorIter.addValue(text2DData.color.getAsRGBA());
 					}
 
-					bs_stack_free(tempVertices);
 					bs_stack_free(tempUVs);
+					bs_stack_free(tempVertices);
 
 					curVertexOffset += shapeData.numVertices;
 					curIndexOffet += shapeData.numIndices;
@@ -972,6 +983,7 @@ namespace BansheeEngine
 				ShapeMeshData& newMesh = mMeshes.back();
 				newMesh.mesh = mTextMeshHeap->alloc(meshData, DOT_TRIANGLE_LIST);
 				newMesh.type = MeshType::Text;
+				newMesh.texture = batch.texture;
 			}
 		}
 

+ 21 - 1
MBansheeEditor/Scene/Gizmos.cs

@@ -1,4 +1,5 @@
-using System.Runtime.CompilerServices;
+using System;
+using System.Runtime.CompilerServices;
 using BansheeEngine;
 
 namespace BansheeEditor
@@ -144,6 +145,22 @@ namespace BansheeEditor
             Internal_DrawIcon(ref position, image, fixedScale);
         }
 
+        /// <summary>
+        /// Draws camera aligned text at the specified position.
+        /// </summary>
+        /// <param name="position">World position to center the text on.</param>
+        /// <param name="text">String to draw.</param>
+        /// <param name="font">Font used for drawing the characters.</param>
+        /// <param name="size">Size of the characters, in points.</param>
+        public static void DrawText(Vector3 position, string text, Font font = null, int size = 16)
+        {
+            IntPtr scriptFont = IntPtr.Zero;
+            if (font != null)
+                scriptFont = font.GetCachedPtr();
+
+            Internal_DrawText(ref position, text, scriptFont, size);
+        }
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetColor(ref Color color);
 
@@ -183,5 +200,8 @@ namespace BansheeEditor
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_DrawIcon(ref Vector3 position, SpriteTexture image, bool fixedScale);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_DrawText(ref Vector3 position, string text, IntPtr font, int size);
     }
 }

+ 25 - 2
MBansheeEditor/Scene/HandleDrawing.cs

@@ -145,7 +145,8 @@ namespace BansheeEditor
         /// <param name="amountAngle">Length of the arc.</param>
         /// <param name="size">Uniform scale to apply on top of the existing transform. Primarily used for maintaining
         ///                    handle size regardless of distance from camera.</param>
-        public static void DrawArc(Vector3 position, Vector3 normal, float radius, Degree startAngle, Degree amountAngle, float size = 1.0f)
+        public static void DrawArc(Vector3 position, Vector3 normal, float radius, Degree startAngle, Degree amountAngle,
+            float size = 1.0f)
         {
             Internal_DrawArc(ref position, ref normal, radius, ref startAngle, ref amountAngle, size);
         }
@@ -160,7 +161,8 @@ namespace BansheeEditor
         /// <param name="amountAngle">Length of the arc.</param>
         /// <param name="size">Uniform scale to apply on top of the existing transform. Primarily used for maintaining
         ///                    handle size regardless of distance from camera.</param>
-        public static void DrawWireArc(Vector3 position, Vector3 normal, float radius, Degree startAngle, Degree amountAngle, float size = 1.0f)
+        public static void DrawWireArc(Vector3 position, Vector3 normal, float radius, Degree startAngle,
+            Degree amountAngle, float size = 1.0f)
         {
             Internal_DrawWireArc(ref position, ref normal, radius, ref startAngle, ref amountAngle, size);
         }
@@ -180,6 +182,24 @@ namespace BansheeEditor
             Internal_DrawRect(ref center, ref axisHorz, ref axisVert, area.ExtentHorz, area.ExtentVert, size);
         }
 
+        /// <summary>
+        /// Draws camera aligned text at the specified position.
+        /// </summary>
+        /// <param name="position">World position to center the text on.</param>
+        /// <param name="text">String to draw.</param>
+        /// <param name="font">Font used for drawing the characters.</param>
+        /// <param name="fontSize">Size of the characters, in points.</param>
+        /// <param name="size">Uniform scale to apply on top of the existing transform. Primarily used for maintaining
+        ///                    handle size regardless of distance from camera.</param>
+        public static void DrawText(Vector3 position, string text, Font font = null, int fontSize = 16, float size = 1.0f)
+        {
+            IntPtr scriptFont = IntPtr.Zero;
+            if (font != null)
+                scriptFont = font.GetCachedPtr();
+
+            Internal_DrawText(ref position, text, scriptFont, fontSize, size);
+        }
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetColor(ref Color color);
 
@@ -221,5 +241,8 @@ namespace BansheeEditor
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_DrawRect(ref Vector3 center, ref Vector3 axisH, ref Vector3 axisV, float extentH, float extentV, float size);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_DrawText(ref Vector3 position, string text, IntPtr font, int fontSize, float size);
     }
 }

+ 2 - 2
MBansheeEditor/Scene/SceneAxesHandle.cs

@@ -78,8 +78,8 @@ namespace BansheeEditor
             zAxis.Enabled = MathEx.Abs(Vector3.Dot(cameraForward, Vector3.ZAxis)) < DISABLE_THRESHOLD;
 
             xNegAxis.Enabled = MathEx.Abs(Vector3.Dot(cameraForward, Vector3.XAxis)) < DISABLE_THRESHOLD;
-            xNegAxis.Enabled = MathEx.Abs(Vector3.Dot(cameraForward, Vector3.YAxis)) < DISABLE_THRESHOLD;
-            xNegAxis.Enabled = MathEx.Abs(Vector3.Dot(cameraForward, Vector3.ZAxis)) < DISABLE_THRESHOLD;
+            yNegAxis.Enabled = MathEx.Abs(Vector3.Dot(cameraForward, Vector3.YAxis)) < DISABLE_THRESHOLD;
+            zNegAxis.Enabled = MathEx.Abs(Vector3.Dot(cameraForward, Vector3.ZAxis)) < DISABLE_THRESHOLD;
 
             Vector3 freeAxisOffset = new Vector3(-BOX_EXTENT, -BOX_EXTENT, 0.2f);
             projTypePlane.Rotation = Quaternion.Identity;

+ 1 - 0
SBansheeEditor/Include/BsScriptGizmos.h

@@ -33,5 +33,6 @@ namespace BansheeEngine
 		static void internal_DrawWireArc(Vector3* position, Vector3* normal, float radius, float startAngle, float amountAngle);
 		static void internal_DrawFrustum(Vector3* position, float aspect, Degree* FOV, float near, float far);
 		static void internal_DrawIcon(Vector3* position, MonoObject* image, bool fixedScale);
+		static void internal_DrawText(Vector3* position, MonoString* text, ScriptFont* font, int size);
 	};
 }

+ 1 - 0
SBansheeEditor/Include/BsScriptHandleDrawing.h

@@ -36,5 +36,6 @@ namespace BansheeEngine
 		static void internal_DrawArc(Vector3* position, Vector3* normal, float radius, Degree* startAngle, Degree* amountAngle, float size);
 		static void internal_DrawWireArc(Vector3* position, Vector3* normal, float radius, Degree* startAngle, Degree* amountAngle, float size);
 		static void internal_DrawRect(Vector3* center, Vector3* horzAxis, Vector3* vertAxis, float extentH, float extentV, float size);
+		static void internal_DrawText(Vector3* position, MonoString* text, ScriptFont* font, int fontSize, float size);
 	};
 }

+ 14 - 1
SBansheeEditor/Source/BsScriptGizmos.cpp

@@ -2,8 +2,9 @@
 #include "BsScriptMeta.h"
 #include "BsMonoClass.h"
 #include "BsScriptSpriteTexture.h"
-#include "BsSpriteTexture.h"
 #include "BsGizmoManager.h"
+#include "BsMonoUtil.h"
+#include "BsScriptFont.h"
 
 namespace BansheeEngine
 {
@@ -22,6 +23,7 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_DrawLine", &ScriptGizmos::internal_DrawLine);
 		metaData.scriptClass->addInternalCall("Internal_DrawFrustum", &ScriptGizmos::internal_DrawFrustum);
 		metaData.scriptClass->addInternalCall("Internal_DrawIcon", &ScriptGizmos::internal_DrawIcon);
+		metaData.scriptClass->addInternalCall("Internal_DrawText", &ScriptGizmos::internal_DrawText);
 	}
 
 	void ScriptGizmos::internal_SetColor(Color* color)
@@ -93,4 +95,15 @@ namespace BansheeEngine
 
 		GizmoManager::instance().drawIcon(*position, nativeTexture, fixedScale);
 	}
+
+	void ScriptGizmos::internal_DrawText(Vector3* position, MonoString* text, ScriptFont* font, int size)
+	{
+		WString nativeText = MonoUtil::monoToWString(text);
+
+		HFont fontHandle;
+		if (font != nullptr)
+			fontHandle = font->getHandle();
+
+		GizmoManager::instance().drawText(*position, nativeText, fontHandle, size);
+	}
 }

+ 14 - 2
SBansheeEditor/Source/BsScriptHandleDrawing.cpp

@@ -1,10 +1,10 @@
 #include "BsScriptHandleDrawing.h"
 #include "BsScriptMeta.h"
 #include "BsMonoClass.h"
-#include "BsScriptSpriteTexture.h"
-#include "BsSpriteTexture.h"
 #include "BsHandleManager.h"
 #include "BsHandleDrawManager.h"
+#include "BsScriptFont.h"
+#include "BsMonoUtil.h"
 
 namespace BansheeEngine
 {
@@ -24,6 +24,7 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_DrawArc", &ScriptHandleDrawing::internal_DrawArc);
 		metaData.scriptClass->addInternalCall("Internal_DrawWireArc", &ScriptHandleDrawing::internal_DrawWireArc);
 		metaData.scriptClass->addInternalCall("Internal_DrawRect", &ScriptHandleDrawing::internal_DrawRect);
+		metaData.scriptClass->addInternalCall("Internal_DrawText", &ScriptHandleDrawing::internal_DrawText);
 	}
 
 	void ScriptHandleDrawing::internal_SetColor(Color* color)
@@ -99,4 +100,15 @@ namespace BansheeEngine
 		Rect3 area(*center, axes, extents);
 		HandleManager::instance().getDrawManager().drawRect(area, size);
 	}
+
+	void ScriptHandleDrawing::internal_DrawText(Vector3* position, MonoString* text, ScriptFont* font, int fontSize, float size)
+	{
+		WString nativeText = MonoUtil::monoToWString(text);
+
+		HFont fontHandle;
+		if (font != nullptr)
+			fontHandle = font->getHandle();
+
+		HandleManager::instance().getDrawManager().drawText(*position, nativeText, fontHandle, fontSize, size);
+	}
 }