Index: media/d3d9Shader.xml =================================================================== --- media/d3d9Shader.xml (revision 0) +++ media/d3d9Shader.xml (revision 0) @@ -0,0 +1,11 @@ + + + + + + + + + + + Index: media/glShader.xml =================================================================== --- media/glShader.xml (revision 0) +++ media/glShader.xml (revision 0) @@ -0,0 +1,11 @@ + + + + + + + + + + + Index: media/d3d8Shader.xml =================================================================== --- media/d3d8Shader.xml (revision 0) +++ media/d3d8Shader.xml (revision 0) @@ -0,0 +1,10 @@ + + + + + + + + + + Index: source/Irrlicht/CNullDriver.h =================================================================== --- source/Irrlicht/CNullDriver.h (revision 3488) +++ source/Irrlicht/CNullDriver.h (working copy) @@ -21,6 +21,7 @@ #include "SVertexIndex.h" #include "SLight.h" #include "SExposedVideoData.h" +#include "SUniqueXmlShader.h" namespace irr { @@ -569,6 +570,34 @@ E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, s32 userData=0); + //! Reads all required shaders from an xml file which references shader files. + virtual s32 getXMLMaterialType(io::IXMLReaderUTF8* xmlShaderFile, + const io::path& xmlShaderFileName, + bool& ForceHighLevelShaders, + s32 baseMaterial, + IShaderConstantSetCallBack* callback, + s32 userData); + + //! Reads all required shaders from an xml file which references shader files. + virtual s32 getXMLMaterialType(const io::path& xmlShaderFileName, + bool& ForceHighLevelShaders, + s32 baseMaterial = -1, + IShaderConstantSetCallBack* callback = 0, + s32 userData = 0); + + //! clears the cache of xmlShaders, doesnt delete the shaders and callbacks though + virtual void clearXMLShaderCache(); + + //! Returns how many XML shaders there are + //! \return xml shader count + virtual u32 getXMLShaderCount() const; + + //! Returns an XML shader material type. + //! \param idx: Zero based index of the light. Note: first indices correspond + //! to EMT enums + //! \return Material Type. + virtual s32 getXMLShaderByIndex(u32 idx) const; + //! Returns a pointer to the mesh manipulator. virtual scene::IMeshManipulator* getMeshManipulator(); @@ -596,6 +625,10 @@ //! looks if the image is already loaded virtual video::ITexture* findTexture(const io::path& filename); + //! looks if the image is already loaded + virtual s32 findXMLShader(const io::path& filename, s32 baseMaterial, bool highLevel, + video::IShaderConstantSetCallBack* callback = 0, bool uniqueCallBack = false); + //! Set/unset a clipping plane. //! There are at least 6 clipping planes available for the user to set at will. //! \param index: The plane index. Must be between 0 and MaxUserClipPlanes. @@ -793,6 +826,7 @@ core::array SurfaceWriter; core::array Lights; core::array MaterialRenderers; + core::array xmlShaderCache; //core::array HWBufferLinks; core::map< const scene::IMeshBuffer* , SHWBufferLink* > HWBufferMap; Index: source/Irrlicht/Irrlicht-gcc.cbp =================================================================== --- source/Irrlicht/Irrlicht-gcc.cbp (revision 3488) +++ source/Irrlicht/Irrlicht-gcc.cbp (working copy) @@ -430,6 +430,7 @@ + @@ -456,6 +457,7 @@ + @@ -570,6 +572,7 @@ + @@ -667,6 +670,7 @@ + Index: source/Irrlicht/CNullDriver.cpp =================================================================== --- source/Irrlicht/CNullDriver.cpp (revision 3488) +++ source/Irrlicht/CNullDriver.cpp (working copy) @@ -14,6 +14,8 @@ #include "IAnimatedMeshSceneNode.h" #include "CMeshManipulator.h" #include "CColorConverter.h" +#include "EDefaultShaderConstants.h" +#include "IDefaultShaderCallBack.h" namespace irr @@ -197,6 +199,8 @@ InitMaterial2D.TextureLayer[i].TextureWrapV=video::ETC_REPEAT; } OverrideMaterial2D=InitMaterial2D; + + clearXMLShaderCache(); } @@ -2269,7 +2273,387 @@ return result; } +//! clears the cache of xmlShaders, doesnt delete the shaders and callbacks though +void CNullDriver::clearXMLShaderCache() +{ + xmlShaderCache.set_used(0); + SUniqueXmlShader temp; + temp.highLevel = false; + temp.cb = 0; + for (u32 i=0; igetAbsolutePath(filename); + if (baseMaterial!=-1) + { + if (uniqueCallBack) + { + for (u32 i=EMT_COUNT; icreateXMLReaderUTF8(xmlShaderFileName); + if (!xmlShaderFile) + { + os::Printer::log("Could not open shader xml file", + xmlShaderFileName, ELL_WARNING); + } + } + + result = getXMLMaterialType( + xmlShaderFile, xmlShaderFileName, ForceHighLevelShaders, + baseMaterial, callback, userData); + + if (xmlShaderFile) + xmlShaderFile->drop(); + + return result; +} + +void readXMLUntilElement(io::IXMLReaderUTF8* xml) { + bool notEnd; + do + { + notEnd = xml->read(); + } + while (xml->getNodeType()!=io::EXN_ELEMENT&¬End); +} + +//! Reads all required shaders from an xml file which references shader files. +s32 CNullDriver::getXMLMaterialType(io::IXMLReaderUTF8* xmlShaderFile, + const io::path& xmlShaderFileName, + bool& ForceHighLevelShaders, + s32 baseMaterial, + IShaderConstantSetCallBack* callback, + s32 userData) +{ + if (!queryFeature(video::EVDF_VERTEX_SHADER_1_1) && + !queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)) + { + os::Printer::log("WARNING: Vertex shaders disabled "\ + "because of missing driver/hardware support.", ELL_WARNING); + return -1; + } + if (!queryFeature(video::EVDF_PIXEL_SHADER_1_1) && + !queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)) + { + os::Printer::log("WARNING: Pixel shaders disabled "\ + "because of missing driver/hardware support.", ELL_WARNING); + return -1; + } + + if (!xmlShaderFile) + { + return -1; + } + + readXMLUntilElement(xmlShaderFile); + if (core::stringc(xmlShaderFile->getNodeName())!="irrlichtShader") + { + return -1; + } + + core::stringc temp; + core::stringc vsFile = ""; + core::stringc psFile = ""; + core::stringc gsFile = ""; + core::stringc vsFileLow = ""; + core::stringc psFileLow = ""; + E_VERTEX_SHADER_TYPE vst = EVST_VS_1_1; + E_PIXEL_SHADER_TYPE pst = EPST_PS_1_1; + E_GEOMETRY_SHADER_TYPE gst = EGST_GS_4_0; + core::stringc vsEntry = ""; + core::stringc psEntry = ""; + s32 fixedFnFallBack = -1; + E_MATERIAL_TYPE baseMaterialXmlH; + E_MATERIAL_TYPE baseMaterialXmlL; + + readXMLUntilElement(xmlShaderFile); + // No matter if or fallback there are at least 3 attributes + if (xmlShaderFile->getAttributeCount()<4) + { + return -1; + } + bool failAtHighLevel = false; + if (core::stringc(xmlShaderFile->getNodeName())=="shaderCode"&&ForceHighLevelShaders) + { + if (!((core::stringc(xmlShaderFile->getAttributeValueSafe("Type"))=="GLSL"&&getDriverType()==EDT_OPENGL)|| + (core::stringc(xmlShaderFile->getAttributeValueSafe("Type"))=="HLSL"&&getDriverType()==EDT_DIRECT3D9))) + { + os::Printer::log("The driver is not appropriate for shader type ", + core::stringc(xmlShaderFile->getAttributeValueSafe("Type")), ELL_WARNING); + return -1; + } + vsFile = xmlShaderFile->getAttributeValueSafe("vsFile"); + psFile = xmlShaderFile->getAttributeValueSafe("psFile"); + gsFile = xmlShaderFile->getAttributeValueSafe("gsFile"); + vsEntry = xmlShaderFile->getAttributeValueSafe("vsEntryPoint"); + psEntry = xmlShaderFile->getAttributeValueSafe("psEntryPoint"); + temp = xmlShaderFile->getAttributeValueSafe("vsTarget"); + for (u32 i=0; igetAttributeValueSafe("psTarget"); + for (u32 i=0; igetAttributeValueSafe("gsTarget"); + for (u32 i=0; igetAttributeValueSafe("fixedFnFallBack"); + for (u32 i=0; igetAttributeValueSafe("baseMaterial"); + for (u32 i=0; igetNodeName())=="shaderCodeFallBack") + { + if (!((core::stringc(xmlShaderFile->getAttributeValueSafe("Type"))=="ARB"&&getDriverType()==EDT_OPENGL)|| + (core::stringc(xmlShaderFile->getAttributeValueSafe("Type"))=="DXASM"&&(getDriverType()==EDT_DIRECT3D9||getDriverType()==EDT_DIRECT3D8)))) + { + os::Printer::log("The driver is not appropriate for shader type ", + core::stringc(xmlShaderFile->getAttributeValueSafe("Type")), ELL_WARNING); + return -1; + } + vsFileLow = xmlShaderFile->getAttributeValueSafe("vsFile"); + psFileLow = xmlShaderFile->getAttributeValueSafe("psFile"); + ForceHighLevelShaders = false; //! make sure + temp = xmlShaderFile->getAttributeValueSafe("fixedFnFallBack"); + for (u32 i=0; igetAttributeValueSafe("baseMaterial"); + for (u32 i=0; igetNodeName())=="shaderCodeFallBack") + { + if (!((core::stringc(xmlShaderFile->getAttributeValueSafe("Type"))=="ARB"&&getDriverType()==EDT_OPENGL)|| + (core::stringc(xmlShaderFile->getAttributeValueSafe("Type"))=="DXASM"&&(getDriverType()==EDT_DIRECT3D9||getDriverType()==EDT_DIRECT3D8)))) + { + os::Printer::log("The driver is not appropriate for shader type ", + core::stringc(xmlShaderFile->getAttributeValueSafe("Type")), ELL_WARNING); + return -1; + } + vsFileLow = xmlShaderFile->getAttributeValueSafe("vsFile"); + psFileLow = xmlShaderFile->getAttributeValueSafe("psFile"); + temp = xmlShaderFile->getAttributeValueSafe("fixedFnFallBack"); + for (u32 i=0; igetAttributeValueSafe("baseMaterial"); + for (u32 i=0; i node blocks are missing in the shader xml.", ELL_WARNING); + return -1; + } + ForceHighLevelShaders = false; + } + + readXMLUntilElement(xmlShaderFile); + if (core::stringc(xmlShaderFile->getNodeName())!="passParameters") { + readXMLUntilElement(xmlShaderFile); + if (core::stringc(xmlShaderFile->getNodeName())!="passParameters") + return -1; + } + + u32 edscFlags = 0; + core::array registers; + SDefaultShaderConstantRegisters tempReg; + for (u32 i=0; iread()) { + if (xmlShaderFile->getNodeType()==io::EXN_ELEMENT) + { + for (u32 i=0; igetNodeName())==DEFAULT_SHADER_CONSTANTS_NAMES[i]) + { + edscFlags |= (1 << i); + registers[i].Name = xmlShaderFile->getAttributeValueSafe("name"); + registers[i].Register = xmlShaderFile->getAttributeValueAsInt("register"); + if (core::stringc(xmlShaderFile->getAttributeValueSafe("shader"))=="vertex") + registers[i].pixelOrVertex = false; + else + registers[i].pixelOrVertex = true; + break; + } + } + } + } + IDefaultShaderCallBack* cb = new IDefaultShaderCallBack(edscFlags,registers,callback); + s32 newMaterialType = 0; + if (ForceHighLevelShaders) + { + newMaterialType = addHighLevelShaderMaterialFromFiles(vsFile,vsEntry.c_str(),vst,psFile,psEntry.c_str(),pst, + gsFile,"geomMain",gst,scene::EPT_TRIANGLES,scene::EPT_TRIANGLE_STRIP,0, + cb,baseMaterial!=-1 ? ((E_MATERIAL_TYPE)baseMaterial):baseMaterialXmlH,userData); + if (newMaterialType==-1) + ForceHighLevelShaders=false; + else + { + cb->setHighorLowLevel(ForceHighLevelShaders); + SUniqueXmlShader tempSUXS; + tempSUXS.filename = FileSystem->getAbsolutePath(xmlShaderFileName); + tempSUXS.baseMaterial = baseMaterial!=-1 ? ((E_MATERIAL_TYPE)baseMaterial):baseMaterialXmlH; + tempSUXS.cb = callback; + tempSUXS.highLevel = true; + tempSUXS.MaterialType = newMaterialType; + xmlShaderCache.push_back(tempSUXS); + cb->drop(); + return newMaterialType; + } + } + if (!ForceHighLevelShaders) //! DO NOT change into an "else" + { + newMaterialType = addShaderMaterialFromFiles(vsFileLow,psFileLow,cb,baseMaterial!=-1 ? ((E_MATERIAL_TYPE)baseMaterial):baseMaterialXmlL,userData); + cb->setHighorLowLevel(ForceHighLevelShaders); + if (newMaterialType!=-1) { + SUniqueXmlShader tempSUXS; + tempSUXS.filename = FileSystem->getAbsolutePath(xmlShaderFileName); + tempSUXS.baseMaterial = baseMaterial!=-1 ? ((E_MATERIAL_TYPE)baseMaterial):baseMaterialXmlL; + tempSUXS.cb = callback; + tempSUXS.highLevel = false; + tempSUXS.MaterialType = newMaterialType; + xmlShaderCache.push_back(tempSUXS); + cb->drop(); + return newMaterialType; + } + } + + return fixedFnFallBack; +} + //! Creates a render target texture. ITexture* CNullDriver::addRenderTargetTexture(const core::dimension2d& size, const io::path&name, const ECOLOR_FORMAT format) Index: source/Irrlicht/CDefaultShaderCallBack.cpp =================================================================== --- source/Irrlicht/CDefaultShaderCallBack.cpp (revision 0) +++ source/Irrlicht/CDefaultShaderCallBack.cpp (revision 0) @@ -0,0 +1,273 @@ +#include "SMaterial.h" +#include "IDefaultShaderCallBack.h" +#include "IMaterialRendererServices.h" +#include "IVideoDriver.h" +#include "matrix4.h" +#include "ICameraSceneNode.h" + +namespace irr +{ +namespace video +{ + + +IDefaultShaderCallBack::IDefaultShaderCallBack(u32 flags, core::array registers, IShaderConstantSetCallBack* callback) + : edscFlags(flags), Registers(registers), callBack(callback), highOrLowLevel(true) +{ + if (callBack) + callBack->grab(); +} + +IDefaultShaderCallBack::~IDefaultShaderCallBack() +{ + if (callBack) + callBack->drop(); +} + +void IDefaultShaderCallBack::OnSetMaterial(const SMaterial& material) +{ + if (callBack) + callBack->OnSetMaterial(material); +} + +void setConstant(bool highOrLowLevel,video::IMaterialRendererServices* services,float* pointer,u32 size,SDefaultShaderConstantRegisters Register) { + if (highOrLowLevel) + { + if (Register.pixelOrVertex) + services->setPixelShaderConstant(Register.Name.c_str(),pointer,size); + else + services->setVertexShaderConstant(Register.Name.c_str(),pointer,size); + } + else + { + if (Register.pixelOrVertex) + services->setPixelShaderConstant(pointer,Register.Register,size/4); + else + services->setVertexShaderConstant(pointer,Register.Register,size/4); + } +} + +void IDefaultShaderCallBack::OnSetConstants(video::IMaterialRendererServices* services, + s32 userData) +{ + video::IVideoDriver* driver = services->getVideoDriver(); + + for (u32 i=0; igetTransform(video::ETS_WORLD); + setConstant(highOrLowLevel,services,mat.pointer(),16,Registers[i]); + } + else if (edscFlags & (1 << EDSC_VIEW_TFORM)) { + core::matrix4 mat = driver->getTransform(video::ETS_VIEW); + setConstant(highOrLowLevel,services,mat.pointer(),16,Registers[i]); + } + else if (edscFlags & (1 << EDSC_PROJ_TFORM)) { + core::matrix4 mat = driver->getTransform(video::ETS_PROJECTION); + setConstant(highOrLowLevel,services,mat.pointer(),16,Registers[i]); + } + else if (edscFlags & (1 << EDSC_VIEW_PROJ_TFORM)) { + core::matrix4 mat = driver->getTransform(video::ETS_PROJECTION); + mat *= driver->getTransform(video::ETS_VIEW); + setConstant(highOrLowLevel,services,mat.pointer(),16,Registers[i]); + } + else if (edscFlags & (1 << EDSC_WORLD_VIEW_PROJ_TFORM)) { + core::matrix4 mat = driver->getTransform(video::ETS_PROJECTION); + mat *= driver->getTransform(video::ETS_VIEW); + mat *= driver->getTransform(video::ETS_WORLD); + setConstant(highOrLowLevel,services,mat.pointer(),16,Registers[i]); + } + else if (edscFlags & (1 << EDSC_WORLD_TFORM_INV)) { + core::matrix4 mat = driver->getTransform(video::ETS_WORLD); + mat.makeInverse(); + setConstant(highOrLowLevel,services,mat.pointer(),16,Registers[i]); + } + else if (edscFlags & (1 << EDSC_VIEW_TFORM_INV)) { + core::matrix4 mat = driver->getTransform(video::ETS_VIEW); + mat.makeInverse(); + setConstant(highOrLowLevel,services,mat.pointer(),16,Registers[i]); + } + else if (edscFlags & (1 << EDSC_PROJ_TFORM_INV)) { + core::matrix4 mat = driver->getTransform(video::ETS_PROJECTION); + mat.makeInverse(); + setConstant(highOrLowLevel,services,mat.pointer(),16,Registers[i]); + } + else if (edscFlags & (1 << EDSC_VIEW_PROJ_TFORM_INV)) { + core::matrix4 mat = driver->getTransform(video::ETS_PROJECTION); + mat *= driver->getTransform(video::ETS_VIEW); + mat.makeInverse(); + setConstant(highOrLowLevel,services,mat.pointer(),16,Registers[i]); + } + else if (edscFlags & (1 << EDSC_WORLD_VIEW_PROJ_TFORM_INV)) { + core::matrix4 mat = driver->getTransform(video::ETS_PROJECTION); + mat *= driver->getTransform(video::ETS_VIEW); + mat *= driver->getTransform(video::ETS_WORLD); + mat.makeInverse(); + setConstant(highOrLowLevel,services,mat.pointer(),16,Registers[i]); + } + else if (edscFlags & (1 << EDSC_WORLD_TRANSPOSED)) { + core::matrix4 mat = driver->getTransform(video::ETS_WORLD); + mat = mat.getTransposed(); + setConstant(highOrLowLevel,services,mat.pointer(),16,Registers[i]); + } + else if (edscFlags & (1 << EDSC_VIEW_TRANSPOSED)) { + core::matrix4 mat = driver->getTransform(video::ETS_VIEW); + mat = mat.getTransposed(); + setConstant(highOrLowLevel,services,mat.pointer(),16,Registers[i]); + } + else if (edscFlags & (1 << EDSC_PROJ_TRANSPOSED)) { + core::matrix4 mat = driver->getTransform(video::ETS_PROJECTION); + mat = mat.getTransposed(); + setConstant(highOrLowLevel,services,mat.pointer(),16,Registers[i]); + } + else if (edscFlags & (1 << EDSC_VIEW_PROJ_TRANSPOSED)) { + core::matrix4 mat = driver->getTransform(video::ETS_PROJECTION); + mat *= driver->getTransform(video::ETS_VIEW); + mat = mat.getTransposed(); + setConstant(highOrLowLevel,services,mat.pointer(),16,Registers[i]); + } + else if (edscFlags & (1 << EDSC_WORLD_VIEW_PROJ_TRANSPOSED)) { + core::matrix4 mat = driver->getTransform(video::ETS_PROJECTION); + mat *= driver->getTransform(video::ETS_VIEW); + mat *= driver->getTransform(video::ETS_WORLD); + mat = mat.getTransposed(); + setConstant(highOrLowLevel,services,mat.pointer(),16,Registers[i]); + } + else if (edscFlags & (1 << EDSC_WORLD_TRANSPOSED_INV)) { + core::matrix4 mat = driver->getTransform(video::ETS_WORLD); + mat = mat.getTransposed(); + mat.makeInverse(); + setConstant(highOrLowLevel,services,mat.pointer(),16,Registers[i]); + } + else if (edscFlags & (1 << EDSC_VIEW_TRANSPOSED_INV)) { + core::matrix4 mat = driver->getTransform(video::ETS_VIEW); + mat = mat.getTransposed(); + mat.makeInverse(); + setConstant(highOrLowLevel,services,mat.pointer(),16,Registers[i]); + } + else if (edscFlags & (1 << EDSC_PROJ_TRANSPOSED_INV)) { + core::matrix4 mat = driver->getTransform(video::ETS_PROJECTION); + mat = mat.getTransposed(); + mat.makeInverse(); + setConstant(highOrLowLevel,services,mat.pointer(),16,Registers[i]); + } + else if (edscFlags & (1 << EDSC_VIEW_PROJ_TRANSPOSED_INV)) { + core::matrix4 mat = driver->getTransform(video::ETS_PROJECTION); + mat *= driver->getTransform(video::ETS_VIEW); + mat = mat.getTransposed(); + mat.makeInverse(); + setConstant(highOrLowLevel,services,mat.pointer(),16,Registers[i]); + } + else if (edscFlags & (1 << EDSC_WORLD_VIEW_PROJ_TRANSPOSED_INV)) { + core::matrix4 mat = driver->getTransform(video::ETS_PROJECTION); + mat *= driver->getTransform(video::ETS_VIEW); + mat *= driver->getTransform(video::ETS_WORLD); + mat = mat.getTransposed(); + mat.makeInverse(); + setConstant(highOrLowLevel,services,mat.pointer(),16,Registers[i]); + } + //! HighLevel only + else if (edscFlags & (1 << EDSC_FRAME_BUFFER_SIZE)) + { + core::dimension2df fbSize = core::dimension2df(driver->getCurrentRenderTargetSize().Width,driver->getCurrentRenderTargetSize().Height); + if (Registers[i].pixelOrVertex) + services->setPixelShaderConstant(Registers[i].Name.c_str(),&fbSize.Width,2); + else + services->setVertexShaderConstant(Registers[i].Name.c_str(),&fbSize.Width,2); + } + else if (edscFlags & (1 << EDSC_CAMERA_FAR_DISTANCE)) + { + core::matrix4 mat = driver->getTransform(video::ETS_PROJECTION); + f32 farDist; + if (mat.isOrthogonal()) + { + if (mat[10]>0.f) // Left Handed + farDist = 1.f/mat[10]-mat[14]/mat[10]; + else // Right Handed + farDist = mat[14]/mat[10]-1.f/mat[10]; + } + else + { + if (mat[10]>0.f) // Left Handed + farDist = -mat[14]/(mat[10]-1.f); + else // Right Handed + farDist = mat[14]/(mat[10]+1.f); + } + if (Registers[i].pixelOrVertex) + services->setPixelShaderConstant(Registers[i].Name.c_str(),&farDist,1); + else + services->setVertexShaderConstant(Registers[i].Name.c_str(),&farDist,1); + } + else if (edscFlags & (1 << EDSC_TEX0)) + { + s32 texIdx = 0; + if (Registers[i].pixelOrVertex) + services->setPixelShaderConstant(Registers[i].Name.c_str(),(f32*)&texIdx,1); + else + services->setVertexShaderConstant(Registers[i].Name.c_str(),(f32*)&texIdx,1); + } + else if (edscFlags & (1 << EDSC_TEX1)) + { + s32 texIdx = 1; + if (Registers[i].pixelOrVertex) + services->setPixelShaderConstant(Registers[i].Name.c_str(),(f32*)&texIdx,1); + else + services->setVertexShaderConstant(Registers[i].Name.c_str(),(f32*)&texIdx,1); + } + else if (edscFlags & (1 << EDSC_TEX2)) + { + s32 texIdx = 2; + if (Registers[i].pixelOrVertex) + services->setPixelShaderConstant(Registers[i].Name.c_str(),(f32*)&texIdx,1); + else + services->setVertexShaderConstant(Registers[i].Name.c_str(),(f32*)&texIdx,1); + } + else if (edscFlags & (1 << EDSC_TEX3)) + { + s32 texIdx = 3; + if (Registers[i].pixelOrVertex) + services->setPixelShaderConstant(Registers[i].Name.c_str(),(f32*)&texIdx,1); + else + services->setVertexShaderConstant(Registers[i].Name.c_str(),(f32*)&texIdx,1); + } + else if (edscFlags & (1 << EDSC_TEX4)) + { + s32 texIdx = 4; + if (Registers[i].pixelOrVertex) + services->setPixelShaderConstant(Registers[i].Name.c_str(),(f32*)&texIdx,1); + else + services->setVertexShaderConstant(Registers[i].Name.c_str(),(f32*)&texIdx,1); + } + else if (edscFlags & (1 << EDSC_TEX5)) + { + s32 texIdx = 5; + if (Registers[i].pixelOrVertex) + services->setPixelShaderConstant(Registers[i].Name.c_str(),(f32*)&texIdx,1); + else + services->setVertexShaderConstant(Registers[i].Name.c_str(),(f32*)&texIdx,1); + } + else if (edscFlags & (1 << EDSC_TEX6)) + { + s32 texIdx = 6; + if (Registers[i].pixelOrVertex) + services->setPixelShaderConstant(Registers[i].Name.c_str(),(f32*)&texIdx,1); + else + services->setVertexShaderConstant(Registers[i].Name.c_str(),(f32*)&texIdx,1); + } + else if (edscFlags & (1 << EDSC_TEX7)) + { + s32 texIdx = 7; + if (Registers[i].pixelOrVertex) + services->setPixelShaderConstant(Registers[i].Name.c_str(),(f32*)&texIdx,1); + else + services->setVertexShaderConstant(Registers[i].Name.c_str(),(f32*)&texIdx,1); + } + } + + if (callBack) + callBack->OnSetConstants(services,userData); +} + + +} // end namespace video +} // end namespace irr Index: include/SUniqueXmlShader.h =================================================================== --- include/SUniqueXmlShader.h (revision 0) +++ include/SUniqueXmlShader.h (revision 0) @@ -0,0 +1,24 @@ +#ifndef __S_UNIQUE_XML_SHADER_H_INCLUDED__ +#define __S_UNIQUE_XML_SHADER_H_INCLUDED__ + +#include "irrTypes.h" +//#include "irrString.h" + +namespace irr +{ +namespace video +{ + +struct SUniqueXmlShader +{ + io::path filename; + video::E_MATERIAL_TYPE baseMaterial; + video::IShaderConstantSetCallBack* cb; + bool highLevel; + s32 MaterialType; +}; + +} // end namespace video +} // end namespace irr + +#endif // __S_UNIQUE_XML_SHADER_H_INCLUDED__ Index: include/IGPUProgrammingServices.h =================================================================== --- include/IGPUProgrammingServices.h (revision 3488) +++ include/IGPUProgrammingServices.h (working copy) @@ -9,6 +9,7 @@ #include "EMaterialTypes.h" #include "EPrimitiveTypes.h" #include "path.h" +#include "IFileSystem.h" namespace irr { @@ -357,6 +358,47 @@ IShaderConstantSetCallBack* callback = 0, E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, s32 userData = 0) = 0; + + //! Reads all required shaders from an xml file which references shader files. + /** \param xmlShaderFileName: XML file name containing the parameters to + set up shader programs. Set to 0 if no shader shall be created. + \param baseMaterial: baseMaterial + \param IShaderConstantSetCallBack: A callback will be created by irrlicht + anyway, but the user specified callback will be called after that. Set to 0 + if you do not wish for an extra custom callback. + \param ForceHighLevelShaders: if true AND the xml file specifies a high level + shader AND the hardware allows, a high level shader will be created. If false + AND the xml file defines a low level shader, a low level shader will be created. + The reference is used to return whether a high level shader has been created + \param userData: a user data int. This int can be set to any value and + will be set as parameter in the callback method when calling + OnSetConstants(). In this way it is easily possible to use the same + callback method for multiple materials and distinguish between them + during the call. + \return Returns the number of the material type which can be set in + SMaterial::MaterialType to use the renderer. -1 is returned if an + error occured. -1 is returned for example if a vertex or pixel shader + program could not be compiled, the error strings are then printed out + into the error log, and can be catched with a custom event receiver. */ + virtual s32 getXMLMaterialType(const io::path& xmlShaderFileName, + bool& ForceHighLevelShaders, + s32 baseMaterial = -1, + IShaderConstantSetCallBack* callback = 0, + s32 userData = 0) = 0; + + + //! clears the cache of xmlShaders, doesnt delete the shaders and callbacks though + virtual void clearXMLShaderCache() = 0; + + //! Returns how many XML shaders there are + //! \return xml shader count + virtual u32 getXMLShaderCount() const = 0; + + //! Returns an XML shader material type. + //! \param idx: Zero based index of the light. Note: first indices correspond + //! to EMT enums + //! \return Material Type. + virtual s32 getXMLShaderByIndex(u32 idx) const = 0; }; Index: include/irrlicht.h =================================================================== --- include/irrlicht.h (revision 3488) +++ include/irrlicht.h (working copy) @@ -39,6 +39,7 @@ #include "dimension2d.h" #include "ECullingTypes.h" #include "EDebugSceneTypes.h" +#include "EDefaultShaderConstants.h" #include "EDriverFeatures.h" #include "EDriverTypes.h" #include "EGUIAlignment.h" @@ -64,6 +65,7 @@ #include "IBoneSceneNode.h" #include "ICameraSceneNode.h" #include "ICursorControl.h" +#include "IDefaultShaderCallBack.h" #include "IDummyTransformationSceneNode.h" #include "IDynamicMeshBuffer.h" #include "IEventReceiver.h" @@ -178,6 +180,7 @@ #include "SParticle.h" #include "SSharedMeshBuffer.h" #include "SSkinMeshBuffer.h" +#include "SUniqueXmlShader.h" #include "SVertexIndex.h" #include "SViewFrustum.h" #include "triangle3d.h" Index: include/EMaterialTypes.h =================================================================== --- include/EMaterialTypes.h (revision 3488) +++ include/EMaterialTypes.h (working copy) @@ -192,6 +192,9 @@ /** Using only first texture. Generic blending method. */ EMT_ONETEXTURE_BLEND, + //! Tells how many built in materials there are + EMT_COUNT, + //! This value is not used. It only forces this enumeration to compile to 32 bit. EMT_FORCE_32BIT = 0x7fffffff }; Index: include/IDefaultShaderCallBack.h =================================================================== --- include/IDefaultShaderCallBack.h (revision 0) +++ include/IDefaultShaderCallBack.h (revision 0) @@ -0,0 +1,38 @@ +#ifndef __I_DEFAULT_SHADER_CALLBACK_H_INCLUDED__ +#define __I_DEFAULT_SHADER_CALLBACK_H_INCLUDED__ + +#include "EDefaultShaderConstants.h" +#include "irrArray.h" +#include "IShaderConstantSetCallBack.h" +#include "ISceneManager.h" + +namespace irr +{ +namespace video +{ + + +class IDefaultShaderCallBack : public IShaderConstantSetCallBack +{ +private: + + u32 edscFlags; + core::array Registers; + IShaderConstantSetCallBack* callBack; + bool highOrLowLevel; + +public: + + IDefaultShaderCallBack(u32 flags, core::array registers, IShaderConstantSetCallBack* callback=0); + ~IDefaultShaderCallBack(); + + void OnSetMaterial(const SMaterial& material); + void OnSetConstants(video::IMaterialRendererServices* services,s32 userData); + void setHighorLowLevel(bool level) {highOrLowLevel=level;} +}; + + +} // end namespace video +} // end namespace irr + +#endif Index: include/EDefaultShaderConstants.h =================================================================== --- include/EDefaultShaderConstants.h (revision 0) +++ include/EDefaultShaderConstants.h (revision 0) @@ -0,0 +1,98 @@ +#ifndef __E_DEFAULT_SHADER_CONSTANTS_H_INCLUDED__ +#define __E_DEFAULT_SHADER_CONSTANTS_H_INCLUDED__ + +#include "irrTypes.h" +#include "irrString.h" + +namespace irr +{ +namespace video +{ + +struct SDefaultShaderConstantRegisters +{ + int Register; + core::stringc Name; + bool pixelOrVertex; +}; + +//! Default Shader Constants enumeration to be passed by the IDefaultShaderCallBack +enum E_DEFAULT_SHADER_CONSTANTS +{ + EDSC_WORLD_TFORM = 0, + EDSC_VIEW_TFORM, + EDSC_PROJ_TFORM, + EDSC_VIEW_PROJ_TFORM, + EDSC_WORLD_VIEW_PROJ_TFORM, + EDSC_WORLD_TFORM_INV, + EDSC_VIEW_TFORM_INV, + EDSC_PROJ_TFORM_INV, + EDSC_VIEW_PROJ_TFORM_INV, + EDSC_WORLD_VIEW_PROJ_TFORM_INV, + EDSC_WORLD_TRANSPOSED, + EDSC_VIEW_TRANSPOSED, + EDSC_PROJ_TRANSPOSED, + EDSC_VIEW_PROJ_TRANSPOSED, + EDSC_WORLD_VIEW_PROJ_TRANSPOSED, + EDSC_WORLD_TRANSPOSED_INV, + EDSC_VIEW_TRANSPOSED_INV, + EDSC_PROJ_TRANSPOSED_INV, + EDSC_VIEW_PROJ_TRANSPOSED_INV, + EDSC_WORLD_VIEW_PROJ_TRANSPOSED_INV, + EDSC_FRAME_BUFFER_SIZE, + EDSC_CAMERA_FAR_DISTANCE, + EDSC_TEX0, + EDSC_TEX1, + EDSC_TEX2, + EDSC_TEX3, + EDSC_TEX4, + EDSC_TEX5, + EDSC_TEX6, + EDSC_TEX7, + + //! This is not a type, but a value indicating how many types there are. + EDSC_COUNT, + EDSC_FORCE_32BIT = 0x7fffffff +}; + +//! Names for all vertex shader types, each entry corresponds to a E_DEFAULT_SHADER_CONSTANTS entry. +const c8* const DEFAULT_SHADER_CONSTANTS_NAMES[] = { + "worldTrans", + "viewTrans", + "projTrans", + "viewProjTrans", + "worldViewProjTrans", + "worldTransInv", + "viewTransInv", + "projTransInv", + "viewProjTransInv", + "worldViewProjTransInv", + "worldTransposed", + "viewTransposed", + "projTransposed", + "viewProjTransposed", + "worldViewProjTransposed", + "worldTransposedInv", + "viewTransposedInv", + "projTransposedInv", + "viewProjTransposedInv", + "worldViewProjTransposedInv", + "frameBufferSize", + "camFarDistance", + "tex0", + "tex1", + "tex2", + "tex3", + "tex4", + "tex5", + "tex6", + "tex7", + 0 }; + + +} // end namespace video +} // end namespace irr + +#endif // __E_DEFAULT_SHADER_CONSTANTS_H_INCLUDED__ + + Index: examples/26.XMLShaders/main.cpp =================================================================== --- examples/26.XMLShaders/main.cpp (revision 0) +++ examples/26.XMLShaders/main.cpp (revision 0) @@ -0,0 +1,272 @@ +/** Example 026 XML Shaders + +This tutorial shows how to use an XML file to load shaders for D3D8, D3D9, +and OpenGL with the engine and use the default shader callback to pass global +parameters such as transform matrices. It also shows how to pass your own custom +constants on top of the default callback. + +This tutorial does not explain how irrlicht handles shaders, look in example 010. + +At first, we need to include all headers and do the stuff we always do, like in +nearly all other tutorials: +*/ +#include +#include +#include "driverChoice.h" + +using namespace irr; + +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + +/* +If you look at the code for example 010 you can see that this callback doesn't +pass the transform matrices, irrlicht does it automatically. + +However in this case we need to pass some custom, non standard variables and +constants, to do this we create a shader callback that is used on top of the +irrlicht callback (and gets called by it). +*/ + +IrrlichtDevice* device = 0; +bool UseHighLevelShaders = false; + +class MyShaderCallBack : public video::IShaderConstantSetCallBack +{ +public: + + virtual void OnSetConstants(video::IMaterialRendererServices* services, + s32 userData) + { + video::IVideoDriver* driver = services->getVideoDriver(); + + // set camera position + + core::vector3df pos = device->getSceneManager()-> + getActiveCamera()->getAbsolutePosition(); + + if (UseHighLevelShaders) + services->setVertexShaderConstant("mLightPos", reinterpret_cast(&pos), 3); + else + services->setVertexShaderConstant(reinterpret_cast(&pos), 8, 1); + + // set light color + + video::SColorf col(0.0f,1.0f,1.0f,0.0f); + + if (UseHighLevelShaders) + services->setVertexShaderConstant("mLightColor", + reinterpret_cast(&col), 4); + else + services->setVertexShaderConstant(reinterpret_cast(&col), 9, 1); + + } +}; + + + +int main() +{ + // ask user for driver + video::E_DRIVER_TYPE driverType=driverChoiceConsole(); + if (driverType==video::EDT_COUNT) + return 1; + + // ask the user if we should use high level shaders for this example + if (driverType == video::EDT_DIRECT3D9 || + driverType == video::EDT_OPENGL) + { + char i; + printf("Please press 'y' if you want to use high level shaders.\n"); + std::cin >> i; + if (i == 'y') + UseHighLevelShaders = true; + } + + // create device + + device = createDevice(driverType, core::dimension2d(640, 480)); + + if (device == 0) + return 1; // could not create selected driver. + + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + gui::IGUIEnvironment* gui = device->getGUIEnvironment(); + + /* + If you notice the only consideration we must take is what driver we are using + as to which xml we are going to use + */ + + io::path xmlFileName; // filename for the XML shader file + + switch(driverType) + { + case video::EDT_DIRECT3D8: + xmlFileName = "../../media/d3d8Shader.xml"; + break; + case video::EDT_DIRECT3D9: + xmlFileName = "../../media/d3d9Shader.xml"; + break; + + case video::EDT_OPENGL: + xmlFileName = "../../media/glShader.xml"; + break; + } + + /* + Now lets create the new materials. As you maybe know from previous + examples, a material type in the Irrlicht engine is set by simply + changing the MaterialType value in the SMaterial struct. And this value + is just a simple 32 bit value, like video::EMT_SOLID. So we only need + the engine to create a new value for us which we can set there. To do + this, we get a pointer to the IGPUProgrammingServices and call + addShaderMaterialFromXML(), which returns such a new 32 bit value. + That's all. + + However there is one more compulsory parameter, ForceHighLevelShaders + which you must set. It takes a reference and changes the bool if a + High Level Shader couldn't be created. + + To demonstrate this, we create two materials with a different base + material, one with EMT_SOLID and one with EMT_TRANSPARENT_ADD_COLOR. + + The last material is here to prove that there are fake xmlShaders + already created for fixed function materials + */ + + // create materials + + video::IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices(); + s32 newMaterialType1 = 0; + s32 newMaterialType2 = 0; + s32 newMaterialType3 = video::EMT_TRANSPARENT_ADD_COLOR; // will change to EMT_SOLID + + if (gpu) + { + MyShaderCallBack* mc = new MyShaderCallBack(); + + newMaterialType1 = gpu->getXMLMaterialType(xmlFileName, UseHighLevelShaders, video::EMT_SOLID, mc); + + newMaterialType2 = gpu->getXMLMaterialType(xmlFileName, UseHighLevelShaders, video::EMT_TRANSPARENT_ADD_COLOR, mc); + + newMaterialType3 = gpu->getXMLMaterialType("solid", UseHighLevelShaders); + + mc->drop(); + } + + /* + Now it's time for testing the materials. We create a test cube and set + the material we created. In addition, we add a text scene node to the + cube and a rotation animator to make it look more interesting and + important. + */ + + // create test scene node 1, with the new created material type 1 + + scene::ISceneNode* node = smgr->addCubeSceneNode(50); + node->setPosition(core::vector3df(0,0,0)); + node->setMaterialTexture(0, driver->getTexture("../../media/wall.bmp")); + node->setMaterialFlag(video::EMF_LIGHTING, false); + node->setMaterialType((video::E_MATERIAL_TYPE)newMaterialType1); + + scene::ISceneNodeAnimator* anim = smgr->createRotationAnimator( + core::vector3df(0,0.3f,0)); + node->addAnimator(anim); + anim->drop(); + + /* + Same for the second cube, but with the second material we created. + */ + + // create test scene node 2, with the new created material type 2 + + node = smgr->addCubeSceneNode(50); + node->setPosition(core::vector3df(0,-10,50)); + node->setMaterialTexture(0, driver->getTexture("../../media/wall.bmp")); + node->setMaterialFlag(video::EMF_LIGHTING, false); + node->setMaterialType((video::E_MATERIAL_TYPE)newMaterialType2); + + anim = smgr->createRotationAnimator(core::vector3df(0,0.3f,0)); + node->addAnimator(anim); + anim->drop(); + + /* + Then we add a third cube without a shader on it, to be able to compare + the cubes. + */ + + // add a scene node with no shader + + node = smgr->addCubeSceneNode(50); + node->setPosition(core::vector3df(0,50,25)); + node->setMaterialTexture(0, driver->getTexture("../../media/wall.bmp")); + node->setMaterialFlag(video::EMF_LIGHTING, false); + node->setMaterialType((video::E_MATERIAL_TYPE)newMaterialType3); + + /* + And last, we add a skybox and a user controlled camera to the scene. + For the skybox textures, we disable mipmap generation, because we don't + need mipmaps on it. + */ + + // add a nice skybox + + driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); + + smgr->addSkyBoxSceneNode( + driver->getTexture("../../media/irrlicht2_up.jpg"), + driver->getTexture("../../media/irrlicht2_dn.jpg"), + driver->getTexture("../../media/irrlicht2_lf.jpg"), + driver->getTexture("../../media/irrlicht2_rt.jpg"), + driver->getTexture("../../media/irrlicht2_ft.jpg"), + driver->getTexture("../../media/irrlicht2_bk.jpg")); + + driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true); + + // add a camera and disable the mouse cursor + + scene::ICameraSceneNode* cam = smgr->addCameraSceneNodeFPS(); + cam->setPosition(core::vector3df(-100,50,100)); + cam->setTarget(core::vector3df(0,0,0)); + device->getCursorControl()->setVisible(false); + + /* + Now draw everything. That's all. + */ + + int lastFPS = -1; + + while(device->run()) + if (device->isWindowActive()) + { + driver->beginScene(true, true, video::SColor(255,0,0,0)); + smgr->drawAll(); + driver->endScene(); + + int fps = driver->getFPS(); + + if (lastFPS != fps) + { + core::stringw str = L"Irrlicht Engine - Vertex and pixel shader example ["; + str += driver->getName(); + str += "] FPS:"; + str += fps; + + device->setWindowCaption(str.c_str()); + lastFPS = fps; + } + } + + device->drop(); + + return 0; +} + Index: examples/26.XMLShaders/XMLShaders.layout =================================================================== --- examples/26.XMLShaders/XMLShaders.layout (revision 0) +++ examples/26.XMLShaders/XMLShaders.layout (revision 0) @@ -0,0 +1,7 @@ + + + + + + + Index: examples/26.XMLShaders/Makefile =================================================================== --- examples/26.XMLShaders/Makefile (revision 0) +++ examples/26.XMLShaders/Makefile (revision 0) @@ -0,0 +1,38 @@ +# Makefile for Irrlicht Examples +# It's usually sufficient to change just the target name and source file list +# and be sure that CXX is set to a valid compiler +Target = 26.XMLShaders +Sources = main.cpp + +# general compiler settings +CPPFLAGS = -I../../include -I/usr/X11R6/include +CXXFLAGS = -O3 -ffast-math +#CXXFLAGS = -g -Wall + +#default target is Linux +all: all_linux + +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif + +# target specific settings +all_linux: LDFLAGS = -L/usr/X11R6/lib$(LIBSELECT) -L../../lib/Linux -lIrrlicht -lGL -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32: LDFLAGS = -L../../lib/Win32-gcc -lIrrlicht -lopengl32 -lm +all_win32 clean_win32: SYSTEM=Win32-gcc +all_win32 clean_win32: SUF=.exe +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = ../../bin/$(SYSTEM)/$(Target)$(SUF) + +all_linux all_win32: + $(warning Building...) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(Sources) -o $(DESTPATH) $(LDFLAGS) + +clean: clean_linux clean_win32 + $(warning Cleaning...) + +clean_linux clean_win32: + @$(RM) $(DESTPATH) + +.PHONY: all all_win32 clean clean_linux clean_win32 Index: examples/26.XMLShaders/XMLShaders.cbp =================================================================== --- examples/26.XMLShaders/XMLShaders.cbp (revision 0) +++ examples/26.XMLShaders/XMLShaders.cbp (revision 0) @@ -0,0 +1,58 @@ + + + + + +