Просмотр исходного кода

We can now set params through Material and apply the material

Marko Pintera 13 лет назад
Родитель
Сommit
6f9755d324

+ 34 - 0
CamelotRenderer/Include/CmGpuProgramParams.h

@@ -610,6 +610,14 @@ namespace CamelotEngine {
 		@param vec The value to set
 		*/
 		void _writeRawConstant(size_t physicalIndex, const Vector3& vec);
+		/** Write a 2-element floating-point parameter to the program via Vector2.
+		@note You can use these methods if you have already derived the physical
+		constant buffer location, for a slight speed improvement over using
+		the named / logical index versions.
+		@param physicalIndex The physical buffer index at which to place the parameter 
+		@param vec The value to set
+		*/
+		void _writeRawConstant(size_t physicalIndex, const Vector2& vec);
 		/** Write a Matrix4 parameter to the program.
 		@note You can use these methods if you have already derived the physical
 		constant buffer location, for a slight speed improvement over using
@@ -627,6 +635,15 @@ namespace CamelotEngine {
 		@param numEntries Number of Matrix4 entries
 		*/
 		void _writeRawConstant(size_t physicalIndex, const Matrix4* m, size_t numEntries);
+		/** Write a Matrix3 parameter to the program.
+		@note You can use these methods if you have already derived the physical
+		constant buffer location, for a slight speed improvement over using
+		the named / logical index versions.
+		@param physicalIndex The physical buffer index at which to place the parameter 
+		@param m The value to set
+		@param elementCount actual element count used with shader
+		*/
+		void _writeRawConstant(size_t physicalIndex, const Matrix3& m, size_t elementCount);
 		/** Write a ColourValue parameter to the program.
 		@note You can use these methods if you have already derived the physical
 		constant buffer location, for a slight speed improvement over using
@@ -785,6 +802,13 @@ namespace CamelotEngine {
 		@param vec The value to set
 		*/
 		void setNamedConstant(const String& name, const Vector3& vec);
+		/** Sets a Vector2 parameter to the program.
+		@note
+		This named option will only work if you are using a parameters object created
+		from a high-level program (HighLevelGpuProgram).
+		@param vec The value to set
+		*/
+		void setNamedConstant(const String& name, const Vector2& vec);
 		/** Sets a Matrix4 parameter to the program.
 		@param name The name of the parameter
 		@param m The value to set
@@ -798,6 +822,11 @@ namespace CamelotEngine {
 		@param numEntries Number of Matrix4 entries
 		*/
 		void setNamedConstant(const String& name, const Matrix4* m, size_t numEntries);
+		/** Sets a Matrix3 parameter to the program.
+		@param name The name of the parameter
+		@param m The value to set
+		*/
+		void setNamedConstant(const String& name, const Matrix3& m);
 		/** Sets a multiple value constant floating-point parameter to the program.
 		@par
 		Some systems only allow constants to be set on certain boundaries, 
@@ -859,6 +888,11 @@ namespace CamelotEngine {
 		void setNamedConstant(const String& name, const int *val, size_t count, 
 			size_t multiple = 4);
 
+		/**
+		 * @brief	Returns true if a named constant with the specified name exists.
+		 */
+		bool hasNamedConstant(const String& name) const;
+
 		/** Find a constant definition for a named parameter.
 		@remarks
 		This method returns null if the named parameter did not exist, unlike

+ 49 - 6
CamelotRenderer/Include/CmMaterial.h

@@ -6,17 +6,31 @@ namespace CamelotEngine
 {
 	class Material
 	{
-		// Required for initialization
+		struct ParamsPerPass
+		{
+			GpuProgramParametersPtr mVertParams;
+			GpuProgramParametersPtr mFragParams;
+			GpuProgramParametersPtr mGeomParams;
+		};
+
+		/**
+		 * @brief	Sets a shader that will be used by the material. 
+		 * 			Shaders best technique will be retrieved and used in all subsequent Material
+		 * 			operations. 
+		 * 			You need to call this method before doing any other operations with this class.
+		 * 			After setting the shader if change any systems that a shader technique is defendant upon (render system, renderer, ...)
+		 * 			you will need to call this method again on all your Materials to make sure technique used is updated.
+		 */
 		void setShader(ShaderPtr shader);
 
 		void setTexture(const String& name, TexturePtr value);
 		void setFloat(const String& name, float value);
 		void setColor(const String& name, const Color& value);
-		void setVec(const String& name, const Vector2& value);
-		void setVec(const String& name, const Vector3& value);
-		void setVec(const String& name, const Vector4& value);
-		void setMat(const String& name, const Matrix3& value);
-		void setMat(const String& name, const Matrix4& value);
+		void setVec2(const String& name, const Vector2& value);
+		void setVec3(const String& name, const Vector3& value);
+		void setVec4(const String& name, const Vector4& value);
+		void setMat3(const String& name, const Matrix3& value);
+		void setMat4(const String& name, const Matrix4& value);
 
 		/**
 		 * @brief	Use the provided pass for rendering of all following objects.
@@ -27,7 +41,36 @@ namespace CamelotEngine
 
 	private:
 		ShaderPtr mShader;
+		TechniquePtr mBestTechnique;
+		vector<ParamsPerPass>::type mParameters;
 
 		void throwIfNotInitialized() const;
+
+		template <typename T>
+		void setParam(const String& name, T& value)
+		{
+			for(auto iter = mParameters.begin(); iter != mParameters.end(); ++iter)
+			{
+				ParamsPerPass params = *iter;
+
+				if(params.mVertParams)
+				{
+					if(params.mVertParams->hasNamedConstant(name))
+						params.mVertParams->setNamedConstant(name, value);
+				}
+
+				if(params.mFragParams)
+				{
+					if(params.mFragParams->hasNamedConstant(name))
+						params.mFragParams->setNamedConstant(name, value);
+				}
+
+				if(params.mGeomParams)
+				{
+					if(params.mGeomParams->hasNamedConstant(name))
+						params.mGeomParams->setNamedConstant(name, value);
+				}
+			}
+		}
 	};
 }

+ 2 - 0
CamelotRenderer/Include/CmPrerequisites.h

@@ -70,6 +70,7 @@ namespace CamelotEngine {
     class Color;
     class GpuProgram;
     class GpuProgramManager;
+	class GpuProgramParameters;
     class HardwareIndexBuffer;
     class HardwareOcclusionQuery;
     class HardwareVertexBuffer;
@@ -121,6 +122,7 @@ namespace CamelotEngine {
 namespace CamelotEngine
 {
 	typedef std::shared_ptr<GpuProgram> GpuProgramPtr;
+	typedef std::shared_ptr<GpuProgramParameters> GpuProgramParametersPtr;
 	typedef std::shared_ptr<HighLevelGpuProgram> HighLevelGpuProgramPtr;
 	typedef std::shared_ptr<HardwarePixelBuffer> HardwarePixelBufferPtr;
 	typedef std::shared_ptr<VertexDeclaration> VertexDeclarationPtr;

+ 1 - 0
CamelotRenderer/Include/CmTechnique.h

@@ -11,6 +11,7 @@ namespace CamelotEngine
 
 		void addPass(PassPtr pass);
 		void removePass(UINT32 idx);
+		PassPtr getPass(UINT32 idx);
 
 		UINT32 getNumPasses() const { return mPasses.size(); }
 

+ 3 - 3
CamelotRenderer/Include/CmVertexDeclarationRTTI.h

@@ -12,7 +12,7 @@ namespace CamelotEngine
 		VertexElement& getElement(VertexDeclaration* obj, UINT32 idx)
 		{
 			auto iter = obj->mElementList.begin();
-			for(int i = 0; i < idx; i++)
+			for(UINT32 i = 0; i < idx; i++)
 				++iter;
 
 			return *iter;
@@ -21,7 +21,7 @@ namespace CamelotEngine
 		void setElement(VertexDeclaration* obj, UINT32 idx, VertexElement& data)
 		{
 			auto iter = obj->mElementList.begin();
-			for(int i = 0; i < idx; i++)
+			for(UINT32 i = 0; i < idx; i++)
 				++iter;
 
 			*iter = data;
@@ -34,7 +34,7 @@ namespace CamelotEngine
 
 		void setElementArraySize(VertexDeclaration* obj, UINT32 size)
 		{
-			for(int i = obj->mElementList.size(); i < size; i++)
+			for(UINT32 i = obj->mElementList.size(); i < size; i++)
 				obj->mElementList.push_back(VertexElement());
 		}
 

+ 45 - 0
CamelotRenderer/Source/CmGpuProgramParams.cpp

@@ -27,6 +27,8 @@ THE SOFTWARE.
 */
 #include "CmGpuProgramParams.h"
 #include "CmMatrix4.h"
+#include "CmMatrix3.h"
+#include "CmVector2.h"
 #include "CmVector3.h"
 #include "CmVector4.h"
 #include "CmTexture.h"
@@ -295,6 +297,11 @@ namespace CamelotEngine
 		_writeRawConstants(physicalIndex, vec.ptr(), 3);		
 	}
 	//-----------------------------------------------------------------------------
+	void GpuProgramParameters::_writeRawConstant(size_t physicalIndex, const Vector2& vec)
+	{
+		_writeRawConstants(physicalIndex, vec.ptr(), 2);		
+	}
+	//-----------------------------------------------------------------------------
 	void GpuProgramParameters::_writeRawConstant(size_t physicalIndex, const Matrix4& m,size_t elementCount)
 	{
 
@@ -329,6 +336,21 @@ namespace CamelotEngine
 		}
 
 
+	}
+	//-----------------------------------------------------------------------------
+	void GpuProgramParameters::_writeRawConstant(size_t physicalIndex, const Matrix3& m,size_t elementCount)
+	{
+		// remember, raw content access uses raw float count rather than float4
+		if (mTransposeMatrices)
+		{
+			Matrix3 t = m.Transpose();
+			_writeRawConstants(physicalIndex, t[0], elementCount>9?9:elementCount);
+		}
+		else
+		{
+			_writeRawConstants(physicalIndex, m[0], elementCount>9?9:elementCount);
+		}
+
 	}
 	//-----------------------------------------------------------------------------
 	void GpuProgramParameters::_writeRawConstant(size_t physicalIndex, 
@@ -645,6 +667,11 @@ namespace CamelotEngine
 
 	}
 	//-----------------------------------------------------------------------------
+	bool GpuProgramParameters::hasNamedConstant(const String& name) const
+	{
+		return _findNamedConstantDefinition(name) != nullptr;
+	}
+	//-----------------------------------------------------------------------------
 	const GpuConstantDefinition* 
 		GpuProgramParameters::_findNamedConstantDefinition(const String& name, 
 		bool throwExceptionIfNotFound) const
@@ -723,6 +750,15 @@ namespace CamelotEngine
 			_writeRawConstant(def->physicalIndex, vec);
 	}
 	//---------------------------------------------------------------------------
+	void GpuProgramParameters::setNamedConstant(const String& name, const Vector2& vec)
+	{
+		// look up, and throw an exception if we're not ignoring missing
+		const GpuConstantDefinition* def = 
+			_findNamedConstantDefinition(name, !mIgnoreMissingParams);
+		if (def)
+			_writeRawConstant(def->physicalIndex, vec);
+	}
+	//---------------------------------------------------------------------------
 	void GpuProgramParameters::setNamedConstant(const String& name, const Matrix4& m)
 	{
 		// look up, and throw an exception if we're not ignoring missing
@@ -742,6 +778,15 @@ namespace CamelotEngine
 			_writeRawConstant(def->physicalIndex, m, numEntries);
 	}
 	//---------------------------------------------------------------------------
+	void GpuProgramParameters::setNamedConstant(const String& name, const Matrix3& m)
+	{
+		// look up, and throw an exception if we're not ignoring missing
+		const GpuConstantDefinition* def = 
+			_findNamedConstantDefinition(name, !mIgnoreMissingParams);
+		if (def)
+			_writeRawConstant(def->physicalIndex, m, def->elementSize);
+	}
+	//---------------------------------------------------------------------------
 	void GpuProgramParameters::setNamedConstant(const String& name, 
 		const float *val, size_t count, size_t multiple)
 	{

+ 80 - 6
CamelotRenderer/Source/CmMaterial.cpp

@@ -2,12 +2,49 @@
 #include "CmException.h"
 #include "CmShader.h"
 #include "CmTechnique.h"
+#include "CmPass.h"
+#include "CmRenderSystemManager.h"
+#include "CmRenderSystem.h"
+#include "CmGpuProgramParams.h"
+#include "CmGpuProgram.h"
 
 namespace CamelotEngine
 {
 	void Material::setShader(ShaderPtr shader)
 	{
 		mShader = shader;
+
+		mBestTechnique = nullptr;
+		mParameters.clear();
+
+		if(shader)
+		{
+			mBestTechnique = shader->getBestTechnique();
+
+			if(mBestTechnique)
+			{
+				for(UINT32 i = 0; i < mBestTechnique->getNumPasses(); i++)
+				{
+					PassPtr curPass = mBestTechnique->getPass(i);
+
+					ParamsPerPass params;
+
+					GpuProgramPtr vertProgram = curPass->getVertexProgram();
+					if(vertProgram)
+						params.mVertParams = vertProgram->createParameters();
+
+					GpuProgramPtr fragProgram = curPass->getFragmentProgram();
+					if(fragProgram)
+						params.mFragParams = fragProgram->createParameters();
+
+					GpuProgramPtr geomProgram = curPass->getGeometryProgram();
+					if(geomProgram)
+						params.mGeomParams = geomProgram->createParameters();	
+
+					mParameters.push_back(params);
+				}
+			}
+		}
 	}
 
 	void Material::throwIfNotInitialized() const
@@ -16,46 +53,59 @@ namespace CamelotEngine
 		{
 			CM_EXCEPT(InternalErrorException, "Material does not have shader set.");
 		}
+
+		if(mBestTechnique == nullptr)
+		{
+			CM_EXCEPT(InternalErrorException, "Shader does not contain a supported technique.");
+		}
 	}
 
 	void Material::setTexture(const String& name, TexturePtr value)
 	{
 		throwIfNotInitialized();
+		setParam(name, value);
 	}
 
 	void Material::setFloat(const String& name, float value)
 	{
 		throwIfNotInitialized();
+		setParam(name, value);
 	}
 
 	void Material::setColor(const String& name, const Color& value)
 	{
 		throwIfNotInitialized();
+		setParam(name, value);
 	}
 
-	void Material::setVec(const String& name, const Vector2& value)
+	void Material::setVec2(const String& name, const Vector2& value)
 	{
 		throwIfNotInitialized();
+		setParam(name, value);
 	}
 
-	void Material::setVec(const String& name, const Vector3& value)
+	void Material::setVec3(const String& name, const Vector3& value)
 	{
 		throwIfNotInitialized();
+		setParam(name, value);
 	}
 
-	void Material::setVec(const String& name, const Vector4& value)
+	void Material::setVec4(const String& name, const Vector4& value)
 	{
 		throwIfNotInitialized();
+		setParam(name, value);
 	}
 
-	void Material::setMat(const String& name, const Matrix3& value)
+	void Material::setMat3(const String& name, const Matrix3& value)
 	{
 		throwIfNotInitialized();
+		setParam(name, value);
 	}
 
-	void Material::setMat(const String& name, const Matrix4& value)
+	void Material::setMat4(const String& name, const Matrix4& value)
 	{
 		throwIfNotInitialized();
+		setParam(name, value);
 	}
 
 	UINT32 Material::getNumPasses() const
@@ -69,7 +119,31 @@ namespace CamelotEngine
 	{
 		throwIfNotInitialized();
 
-		// TODO - It's going to be very important to minimize the amount of texture (and less importantly) constant changes
+		// TODO - I need to take care to minimize shader and shader constant (especially texture) changes
+		RenderSystem* renderSystem = RenderSystemManager::getActive();
+
+		PassPtr curPass = mBestTechnique->getPass(passIdx);
+		ParamsPerPass params = mParameters[passIdx];
+
+		GpuProgramPtr vertProgram = curPass->getVertexProgram();
+		if(vertProgram)
+		{
+			renderSystem->bindGpuProgram(vertProgram->_getBindingDelegate());
+			renderSystem->bindGpuProgramParameters(GPT_VERTEX_PROGRAM, params.mVertParams, GPV_ALL);
+		}
+
+		GpuProgramPtr fragProgram = curPass->getFragmentProgram();
+		if(fragProgram)
+		{
+			renderSystem->bindGpuProgram(fragProgram->_getBindingDelegate());
+			renderSystem->bindGpuProgramParameters(GPT_FRAGMENT_PROGRAM, params.mFragParams, GPV_ALL);
+		}
 
+		GpuProgramPtr geomProgram = curPass->getGeometryProgram();
+		if(geomProgram)
+		{
+			renderSystem->bindGpuProgram(geomProgram->_getBindingDelegate());
+			renderSystem->bindGpuProgramParameters(GPT_GEOMETRY_PROGRAM, params.mGeomParams, GPV_ALL);
+		}	
 	}
 }

+ 2 - 0
CamelotRenderer/Source/CmShader.cpp

@@ -52,7 +52,9 @@ namespace CamelotEngine
 		for(auto iter = mTechniques.begin(); iter != mTechniques.end(); ++iter)
 		{
 			if((*iter)->isSupported())
+			{
 				return *iter;
+			}
 		}
 
 		CM_EXCEPT(InternalErrorException, "No techniques are supported!");

+ 8 - 0
CamelotRenderer/Source/CmTechnique.cpp

@@ -34,6 +34,14 @@ namespace CamelotEngine
 		mPasses.erase(iter);
 	}
 
+	PassPtr Technique::getPass(UINT32 idx)
+	{
+		if(idx < 0 || idx >= mPasses.size())
+			CM_EXCEPT(InvalidParametersException, "Index out of range: " + toString(idx));
+
+		return mPasses[idx];
+	}
+
 	bool Technique::isSupported() const
 	{
 		if(RenderSystemManager::getActive()->getName() == mRenderSystem &&