#pragma once #include "BsCorePrerequisites.h" #include "BsResource.h" #include "BsIResourceListener.h" #include "BsMaterialParam.h" #include "BsVector2.h" #include "BsVector3.h" #include "BsVector4.h" #include "BsMatrix3.h" #include "BsMatrix4.h" namespace BansheeEngine { /** @addtogroup Implementation * @{ */ class MaterialParams; /** Helper class containing parameters for all types of GPU programs used in a pass. */ template class TPassParameters { public: typedef typename TGpuParamsPtrType::Type GpuParamsType; /** * Returns a set of GPU parameters based on an index. * * @note Useful when needing to iterate over all sets of GPU parameters. */ GpuParamsType& getParamByIdx(UINT32 idx) { GpuParamsType* paramArray[] = { &mVertParams, &mFragParams, &mGeomParams, &mHullParams, &mDomainParams, &mComputeParams }; return *paramArray[idx]; } /** * Sets GPU parameters based on an index. * * @note Useful when needing to iterate over all sets of GPU parameters. */ void setParamByIdx(UINT32 idx, const GpuParamsType& params) { GpuParamsType* paramArray[] = { &mVertParams, &mFragParams, &mGeomParams, &mHullParams, &mDomainParams, &mComputeParams }; (*paramArray[idx]) = params; } GpuParamsType mVertParams; GpuParamsType mFragParams; GpuParamsType mGeomParams; GpuParamsType mHullParams; GpuParamsType mDomainParams; GpuParamsType mComputeParams; }; template struct TGpuParamBlockBufferPtrType { }; template<> struct TGpuParamBlockBufferPtrType { typedef SPtr Type; }; template<> struct TGpuParamBlockBufferPtrType { typedef SPtr Type; }; template struct TGpuProgramType { }; template<> struct TGpuProgramType { typedef GpuProgramPtr Type; }; template<> struct TGpuProgramType { typedef SPtr Type; }; /** Contains sim thread pass parameters for each shader stage. */ class BS_CORE_EXPORT PassParameters : public TPassParameters { public: static const UINT32 NUM_PARAMS; }; /** Contains core thread pass parameters for each shader stage. */ class BS_CORE_EXPORT PassParametersCore : public TPassParameters { public: static const UINT32 NUM_PARAMS; }; /** * Material that controls how objects are rendered. It is represented by a shader and parameters used to set up that * shader. It provides a simple interface for manipulating the parameters. */ class BS_CORE_EXPORT MaterialBase { public: /** Data used to described a structure defined within a shader. */ struct StructData { StructData() :size(0), data(nullptr) { } StructData(UINT32 _size) :size(_size) { data = std::shared_ptr(bs_alloc(_size), &bs_free); } /** * Writes the specified data to the internal buffer. Caller must ensure size of the provided buffer is correct. */ void write(void* _data) { memcpy(data.get(), _data, size); } std::shared_ptr data; UINT32 size; }; virtual ~MaterialBase() { } protected: /** Retrieves a list of all shader GPU parameters, and the GPU program variable names they map to. */ const Map& getValidParamNames() const { return mValidParams; } /** @copydoc CoreObject::markCoreDirty */ virtual void _markCoreDirty() { } /** @copydoc CoreObject::markDependenciesDirty */ virtual void _markDependenciesDirty() { } /** @copydoc IResourceListener::markResourcesDirty */ virtual void _markResourcesDirty() { } /** Returns all GPU parameter descriptions in the specified technique. */ static Vector getAllParamDescs(const SPtr& technique); /** Returns all GPU parameter descriptions in the specified technique. */ static Vector getAllParamDescs(const SPtr& technique); Set mValidShareableParamBlocks; Map mValidParams; // Also maps Shader param name -> gpu variable name }; /** @copydoc MaterialBase */ template class BS_CORE_EXPORT TMaterial : public MaterialBase { public: template struct TPassType {}; template<> struct TPassType < false > { typedef SPtr Type; }; template<> struct TPassType < true > { typedef SPtr Type; }; template struct TTechniqueType {}; template<> struct TTechniqueType < false > { typedef SPtr Type; }; template<> struct TTechniqueType < true > { typedef SPtr Type; }; template struct TShaderType {}; template<> struct TShaderType < false > { typedef HShader Type; }; template<> struct TShaderType < true > { typedef SPtr Type; }; template struct TGpuParamBlockBufferType {}; template<> struct TGpuParamBlockBufferType < false > { typedef GpuParamBlockBuffer Type; }; template<> struct TGpuParamBlockBufferType < true > { typedef GpuParamBlockBufferCore Type; }; template struct TPassParamsType {}; template<> struct TPassParamsType < false > { typedef PassParameters Type; }; template<> struct TPassParamsType < true > { typedef PassParametersCore Type; }; typedef typename TGpuParamsPtrType::Type GpuParamsType; typedef typename TGpuParamTextureType::Type TextureType; typedef typename TGpuParamSamplerStateType::Type SamplerStateType; typedef typename TGpuParamBlockBufferPtrType::Type ParamBlockPtrType; typedef typename TGpuParamBlockBufferType::Type ParamBlockType; typedef typename TGpuProgramType::Type GpuProgramType; typedef typename TPassType::Type PassType; typedef typename TTechniqueType::Type TechniqueType; typedef typename TShaderType::Type ShaderType; typedef typename TPassParamsType::Type PassParamsType; virtual ~TMaterial() { } /** Returns the currently active shader. */ ShaderType getShader() const { return mShader; } /** Returns the number of passes that are used by the shader used in the material. */ UINT32 getNumPasses() const; /** Retrieves a specific shader pass. */ PassType getPass(UINT32 passIdx) const; /** * Assigns a float value to the shader parameter with the specified name. * * Optionally if the parameter is an array you may provide an array index to assign the value to. */ void setFloat(const String& name, float value, UINT32 arrayIdx = 0) { return getParamFloat(name).set(value, arrayIdx); } /** * Assigns a color to the shader parameter with the specified name. * * Optionally if the parameter is an array you may provide an array index to assign the value to. */ void setColor(const String& name, const Color& value, UINT32 arrayIdx = 0) { return getParamColor(name).set(value, arrayIdx); } /** * Assigns a 2D vector to the shader parameter with the specified name. * * Optionally if the parameter is an array you may provide an array index to assign the value to. */ void setVec2(const String& name, const Vector2& value, UINT32 arrayIdx = 0) { return getParamVec2(name).set(value, arrayIdx); } /** * Assigns a 3D vector to the shader parameter with the specified name. * * Optionally if the parameter is an array you may provide an array index to assign the value to. */ void setVec3(const String& name, const Vector3& value, UINT32 arrayIdx = 0) { return getParamVec3(name).set(value, arrayIdx); } /** * Assigns a 4D vector to the shader parameter with the specified name. * * Optionally if the parameter is an array you may provide an array index to assign the value to. */ void setVec4(const String& name, const Vector4& value, UINT32 arrayIdx = 0) { return getParamVec4(name).set(value, arrayIdx); } /** * Assigns a 3x3 matrix to the shader parameter with the specified name. * * Optionally if the parameter is an array you may provide an array index to assign the value to. */ void setMat3(const String& name, const Matrix3& value, UINT32 arrayIdx = 0) { return getParamMat3(name).set(value, arrayIdx); } /** * Assigns a 4x4 matrix to the shader parameter with the specified name. * * Optionally if the parameter is an array you may provide an array index to assign the value to. */ void setMat4(const String& name, const Matrix4& value, UINT32 arrayIdx = 0) { return getParamMat4(name).set(value, arrayIdx); } /** * Assigns a structure to the shader parameter with the specified name. * * Structure is provided as a raw buffer and caller must ensure structure in buffer matches what the shader expects. * * Optionally if the parameter is an array you may provide an array index to assign the value to. */ void setStructData(const String& name, void* value, UINT32 size, UINT32 arrayIdx = 0) { return getParamStruct(name).set(value, size, arrayIdx); } /** Assigns a texture to the shader parameter with the specified name. */ void setTexture(const String& name, const TextureType& value) { return getParamTexture(name).set(value); } /** Assigns a texture to be used for random load/store operations to the shader parameter with the specified name. */ void setLoadStoreTexture(const String& name, const TextureType& value, const TextureSurface& surface) { return getParamLoadStoreTexture(name).set(value, surface); } /** Assigns a sampler state to the shader parameter with the specified name. */ void setSamplerState(const String& name, const SamplerStateType& value) { return getParamSamplerState(name).set(value); } /** * Returns a float value assigned with the parameter with the specified name. * * Optionally if the parameter is an array you may provide an array index you which to retrieve. */ float getFloat(const String& name, UINT32 arrayIdx = 0) const { return getParamFloat(name).get(arrayIdx); } /** * Returns a color assigned with the parameter with the specified name. * * Optionally if the parameter is an array you may provide an array index you which to retrieve. */ Color getColor(const String& name, UINT32 arrayIdx = 0) const { return getParamColor(name).get(arrayIdx); } /** * Returns a 2D vector assigned with the parameter with the specified name. * * Optionally if the parameter is an array you may provide an array index you which to retrieve. */ Vector2 getVec2(const String& name, UINT32 arrayIdx = 0) const { return getParamVec2(name).get(arrayIdx); } /** * Returns a 3D vector assigned with the parameter with the specified name. * * Optionally if the parameter is an array you may provide an array index you which to retrieve. */ Vector3 getVec3(const String& name, UINT32 arrayIdx = 0) const { return getParamVec3(name).get(arrayIdx); } /** * Returns a 4D vector assigned with the parameter with the specified name. * * Optionally if the parameter is an array you may provide an array index you which to retrieve. */ Vector4 getVec4(const String& name, UINT32 arrayIdx = 0) const { return getParamVec4(name).get(arrayIdx); } /** * Returns a 3x3 matrix assigned with the parameter with the specified name. * * Optionally if the parameter is an array you may provide an array index you which to retrieve. */ Matrix3 getMat3(const String& name, UINT32 arrayIdx = 0) const { return getParamMat3(name).get(arrayIdx); } /** * Returns a 4x4 matrix assigned with the parameter with the specified name. * * Optionally if the parameter is an array you may provide an array index you which to retrieve. */ Matrix4 getMat4(const String& name, UINT32 arrayIdx = 0) const { return getParamMat4(name).get(arrayIdx); } /** Returns a texture assigned with the parameter with the specified name. */ TextureType getTexture(const String& name) const { return getParamTexture(name).get(); } /** Returns a sampler state assigned with the parameter with the specified name. */ SamplerStateType getSamplerState(const String& name) const { return getParamSamplerState(name).get(); } /** * Returns a buffer representing a structure assigned to the parameter with the specified name. * * Optionally if the parameter is an array you may provide an array index you which to retrieve. */ MaterialBase::StructData getStructData(const String& name, UINT32 arrayIdx = 0) const { TMaterialParamStruct structParam = getParamStruct(name); MaterialBase::StructData data(structParam.getElementSize()); structParam.get(data.data.get(), structParam.getElementSize(), arrayIdx); return data; } /** * Returns a float GPU parameter. This parameter may be used for more efficiently getting/setting GPU parameter * values than calling Material::get* / Material::set* methods. * * @note * Expected behavior is that you would retrieve this parameter when initially constructing the material, and then * use it throughout material lifetime to assign and retrieve parameter values. * @note * If material shader changes this handle will be invalidated. */ TMaterialDataParam getParamFloat(const String& name) const { TMaterialDataParam gpuParam; getParam(name, gpuParam); return gpuParam; } /** * Returns a color GPU parameter. This parameter may be used for more efficiently getting/setting GPU parameter * values than calling Material::get* / Material::set* methods. * * @note * Expected behavior is that you would retrieve this parameter when initially constructing the material, * and then use it throughout material lifetime to assign and retrieve parameter values. * @note * If material shader changes this handle will be invalidated. */ TMaterialDataParam getParamColor(const String& name) const { TMaterialDataParam gpuParam; getParam(name, gpuParam); return gpuParam; } /** * Returns a 2D vector GPU parameter. This parameter may be used for more efficiently getting/setting GPU parameter * values than calling Material::get* / Material::set* methods. * * @note * Expected behavior is that you would retrieve this parameter when initially constructing the material, and then * use it throughout material lifetime to assign and retrieve parameter values. * @note * If material shader changes this handle will be invalidated. */ TMaterialDataParam getParamVec2(const String& name) const { TMaterialDataParam gpuParam; getParam(name, gpuParam); return gpuParam; } /** * Returns a 3D vector GPU parameter. This parameter may be used for more efficiently getting/setting GPU parameter * values than calling Material::get* / Material::set* methods. * * @note * Expected behavior is that you would retrieve this parameter when initially constructing the material, and then * use it throughout material lifetime to assign and retrieve parameter values. * @note * If material shader changes this handle will be invalidated. */ TMaterialDataParam getParamVec3(const String& name) const { TMaterialDataParam gpuParam; getParam(name, gpuParam); return gpuParam; } /** * Returns a 4D vector GPU parameter. This parameter may be used for more efficiently getting/setting GPU parameter * values than calling Material::get* / Material::set* methods. * * @note * Expected behavior is that you would retrieve this parameter when initially constructing the material, and then * use it throughout material lifetime to assign and retrieve parameter values. * @note * If material shader changes this handle will be invalidated. */ TMaterialDataParam getParamVec4(const String& name) const { TMaterialDataParam gpuParam; getParam(name, gpuParam); return gpuParam; } /** * Returns a 3x3 matrix GPU parameter. This parameter may be used for more efficiently getting/setting GPU * parameter values than calling Material::get* / Material::set* methods. * * @note * Expected behavior is that you would retrieve this parameter when initially constructing the material, and then * use it throughout material lifetime to assign and retrieve parameter values. * @note * If material shader changes this handle will be invalidated. */ TMaterialDataParam getParamMat3(const String& name) const { TMaterialDataParam gpuParam; getParam(name, gpuParam); return gpuParam; } /** * Returns a 4x4 matrix GPU parameter. This parameter may be used for more efficiently getting/setting GPU parameter * values than calling Material::get* / Material::set* methods. * * @note * Expected behavior is that you would retrieve this parameter when initially constructing the material, and then * use it throughout material lifetime to assign and retrieve parameter values. * @note * If material shader changes this handle will be invalidated. */ TMaterialDataParam getParamMat4(const String& name) const { TMaterialDataParam gpuParam; getParam(name, gpuParam); return gpuParam; } /** * Returns a structure GPU parameter. This parameter may be used for more efficiently getting/setting GPU parameter * values than calling Material::get* / Material::set* methods. * * @note * Expected behavior is that you would retrieve this parameter when initially constructing the material, and then * use it throughout material lifetime to assign and retrieve parameter values. * @note * If material shader changes this handle will be invalidated. */ TMaterialParamStruct getParamStruct(const String& name) const; /** * Returns a texture GPU parameter. This parameter may be used for more efficiently getting/setting GPU parameter * values than calling Material::get* / Material::set* methods. * * @note * Expected behavior is that you would retrieve this parameter when initially constructing the material, and then * use it throughout material lifetime to assign and retrieve parameter values. * @note * If material shader changes this handle will be invalidated. */ TMaterialParamTexture getParamTexture(const String& name) const; /** * Returns a GPU parameter for binding a load/store texture. This parameter may be used for more efficiently * getting/setting GPU parameter values than calling Material::get* / Material::set* methods. * * @note * Expected behavior is that you would retrieve this parameter when initially constructing the material, and then * use it throughout material lifetime to assign and retrieve parameter values. * @note * If material shader changes this handle will be invalidated. */ TMaterialParamLoadStoreTexture getParamLoadStoreTexture(const String& name) const; /** * Returns a sampler state GPU parameter. This parameter may be used for more efficiently getting/setting GPU * parameter values than calling Material::get* / Material::set* methods. * * @note * Expected behavior is that you would retrieve this parameter when initially constructing the material, and then * use it throughout material lifetime to assign and retrieve parameter values. * @note * If material shader changes this handle will be invalidated. */ TMaterialParamSampState getParamSamplerState(const String& name) const; /** Returns a set of parameters for all GPU programs in the specified shader pass. */ SPtr getPassParameters(UINT32 passIdx) const { return mParametersPerPass[passIdx]; } /** * Assign a parameter block buffer with the specified name. * * @note * Parameter block buffers can be used as quick way of setting multiple parameters on a material at once, or * potentially sharing parameters between multiple materials. This reduces driver overhead as the parameters * in the buffers need only be set once and then reused multiple times. */ void setParamBlockBuffer(const String& name, const ParamBlockPtrType& paramBlock); /** * Allows you to retrieve a handle to a parameter that you can then use for quickly setting and retrieving parameter * data. This allows you to set/get parameter data without all the cost of extra lookups otherwise required. * * @note * All of these handles will be invalidated if material shader ever changes. It is up to the caller to keep track * of that. */ template void getParam(const String& name, TMaterialDataParam& output) const; protected: /** * Creates a material param out of multiple GPU params. Caller must ensure all GPU params reference the same * parameter. */ template TMaterialDataParam createDataParam(const String& name, const SPtr>>& gpuParams) const { return TMaterialDataParam(name, getCachedParams(), gpuParams); } /** * Creates a material param out of multiple GPU params. Caller must ensure all GPU params reference the same * parameter. */ template TMaterialDataParam createDataParam(const String& name, const SPtr>>& gpuParams) const { return TMaterialDataParam(gpuParams); } /** * Creates a material param out of multiple GPU params. Caller must ensure all GPU params reference the same * parameter. */ TMaterialParamStruct createStructParam(const String& name, const SPtr>>& gpuParams) const { return TMaterialParamStruct(name, getCachedParams(), gpuParams); } /** * Creates a material param out of multiple GPU params. Caller must ensure all GPU params reference the same * parameter. */ TMaterialParamStruct createStructParam(const String& name, const SPtr>>& gpuParams) const { return TMaterialParamStruct(gpuParams); } /** * Creates a material param out of multiple GPU params. Caller must ensure all GPU params reference the same * parameter. */ TMaterialParamTexture createTextureParam(const String& name, const SPtr>>& gpuParams) const { return TMaterialParamTexture(name, getCachedParams(), gpuParams); } /** * Creates a material param out of multiple GPU params. Caller must ensure all GPU params reference the same * parameter. */ TMaterialParamTexture createTextureParam(const String& name, const SPtr>>& gpuParams) const { return TMaterialParamTexture(gpuParams); } /** * Creates a material param out of multiple GPU params. Caller must ensure all GPU params reference the same * parameter. */ TMaterialParamLoadStoreTexture createLoadStoreTextureParam(const String& name, const SPtr>>& gpuParams) const { return TMaterialParamLoadStoreTexture(name, getCachedParams(), gpuParams); } /** * Creates a material param out of multiple GPU params. Caller must ensure all GPU params reference the same * parameter. */ TMaterialParamLoadStoreTexture createLoadStoreTextureParam(const String& name, const SPtr>>& gpuParams) const { return TMaterialParamLoadStoreTexture(gpuParams); } /** * Creates a material param out of multiple GPU params. Caller must ensure all GPU params reference the same * parameter. */ TMaterialParamSampState createSamplerStateParam(const String& name, const SPtr>>& gpuParams) const { return TMaterialParamSampState(name, getCachedParams(), gpuParams); } /** * Creates a material param out of multiple GPU params. Caller must ensure all GPU params reference the same * parameter. */ TMaterialParamSampState createSamplerStateParam(const String& name, const SPtr>>& gpuParams) const { return TMaterialParamSampState(gpuParams); } /** * Assigns a value from a raw buffer to the parameter with the specified name. Buffer must be of sizeof(T) * * numElements size and initialized. * * @note Provided parameter must exist, no checking is done. */ template void setParamValue(const String& name, UINT8* buffer, UINT32 numElements); /** Called during initialization, creates enough space to cache all parameters (not used on core thread). */ void createCachedParams(const SPtr& shader) { /* Do nothing */} /** Called during initialization, creates enough space to cache all parameters. */ virtual void createCachedParams(const HShader& shader) { } /** Returns a list of all values assigned to material parameters. */ virtual SPtr getCachedParams() const { return nullptr; } /** * Initializes the material by using the best technique from the currently set shader. Shader must contain the * technique that matches the current renderer and render system. */ void initBestTechnique(); /** Assigns all the default parameters specified in the shader to the material. */ void initDefaultParameters(); /** Throw an exception if no shader is set, or no acceptable technique was found. */ void throwIfNotInitialized() const; Vector> mParametersPerPass; ShaderType mShader; TechniqueType mBestTechnique; }; /** @} */ /** @addtogroup Material * @{ */ /** @cond INTERNAL */ /** @copydoc MaterialBase */ class BS_CORE_EXPORT MaterialCore : public CoreObjectCore, public TMaterial { public: ~MaterialCore() { } /** @copydoc Material::setShader */ void setShader(const SPtr& shader); /** Creates a new material with the specified shader. */ static SPtr create(const SPtr& shader); private: friend class Material; MaterialCore() { } MaterialCore(const SPtr& shader); MaterialCore(const SPtr& shader, const SPtr& bestTechnique, const Set& validShareableParamBlocks, const Map& validParams, const Vector>& passParams); /** @copydoc CoreObjectCore::syncToCore */ void syncToCore(const CoreSyncData& data) override; }; /** @endcond */ /** @copydoc MaterialBase */ class BS_CORE_EXPORT Material : public Resource, public TMaterial, public IResourceListener { public: ~Material() { } /** * Sets a shader that will be used by the material. Best technique within the provided shader will be used for the * material. * * @note * Shader must be set before doing any other operations with the material. * @note * After setting the shader if change any systems that a shader technique is dependent upon (render system, * renderer, etc), you will need to call this method again on all your Materials to make sure technique used is * updated. */ void setShader(const HShader& shader); /** Retrieves an implementation of a material usable only from the core thread. */ SPtr getCore() const; /** @copydoc CoreObject::initialize */ void initialize() override; /** Creates a deep copy of the material and returns the new object. */ HMaterial Material::clone(); /** * Creates a new empty material. * * @note Make sure you call Material::setShader before using it. */ static HMaterial create(); /** Creates a new material with the specified shader. */ static HMaterial create(const HShader& shader); private: friend class MaterialManager; Material(); Material(const HShader& shader); /** @copydoc CoreObject::createCore */ SPtr createCore() const override; /** @copydoc CoreObject::syncToCore */ CoreSyncData syncToCore(FrameAlloc* allocator) override; /** @copydoc CoreObject::getCoreDependencies */ void getCoreDependencies(Vector& dependencies) override; /** @copydoc CoreObject::markCoreDirty */ void _markCoreDirty() override; /** @copydoc CoreObject::markDependenciesDirty */ void _markDependenciesDirty() override; /** @copydoc IResourceListener::markResourcesDirty */ void _markResourcesDirty() override; /** @copydoc IResourceListener::getListenerResources */ void getListenerResources(Vector& resources) override; /** @copydoc IResourceListener::notifyResourceLoaded */ void notifyResourceLoaded(const HResource& resource) override; /** @copydoc IResourceListener::notifyResourceChanged */ void notifyResourceChanged(const HResource& resource) override; /** @copydoc Resource::getResourceDependencies */ void getResourceDependencies(FrameVector& dependencies) const override; /** Performs material initialization when all resources are ready. */ void initializeIfLoaded(); /** @copydoc Material::createCachedParams */ void createCachedParams(const HShader& shader) override; /** @copydoc Material::getCachedParams */ SPtr getCachedParams() const override { return mCachedParams; } /** * Uses the provided list of parameters to try to set every parameter in this material. Parameter whose name, type * or size don't match are ignored and will not be set. */ void setParams(const SPtr& params); UINT32 mLoadFlags; SPtr mCachedParams; /************************************************************************/ /* RTTI */ /************************************************************************/ public: friend class MaterialRTTI; static RTTITypeBase* getRTTIStatic(); virtual RTTITypeBase* getRTTI() const override; }; /** @} */ }