Exemplo n.º 1
0
	//-----------------------------------------------------------------------------------
	GpuProgramPtr ShaderManager::createGpuProgram(const String& name, const String& code, HlmsDatablock* dataBlock)
	{
		HighLevelGpuProgramPtr gpuProgram = HighLevelGpuProgramManager::getSingleton().createProgram(name,
			ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, dataBlock->getLanguage(), dataBlock->getShaderType());

		gpuProgram->setParameter("entry_point", "main");

		gpuProgram->setSource(code);

		if (dataBlock->getLanguage() == "hlsl")
		{
			// HLSL program requires specific target profile settings - we have to split the profile string.
			const StringVector& profilesList = dataBlock->getProfileList();
			StringVector::const_iterator it = profilesList.begin();
			StringVector::const_iterator itEnd = profilesList.end();

			for (; it != itEnd; ++it)
			{
				if (GpuProgramManager::getSingleton().isSyntaxSupported(*it))
				{
					gpuProgram->setParameter("target", *it);
					break;
				}
			}
		}
		
		gpuProgram->load();

		// Case an error occurred.
		if (gpuProgram->hasCompileError())
		{
			gpuProgram.setNull();
			return GpuProgramPtr(gpuProgram);
		}

		return gpuProgram;
	}
//-----------------------------------------------------------------------------
GpuProgramPtr ProgramManager::createGpuProgram(Program* shaderProgram, 
											   ProgramWriter* programWriter,
											   const String& language,
											   const String& profiles,
											   const StringVector& profilesList,
											   const String& cachePath)
{

	
#if OGRE_PLATFORM == OGRE_PLATFORM_ANDROID
	Ogre::StringSerialiser sourceCodeStringStream;
#else
	std::stringstream sourceCodeStringStream;
#endif
	_StringHash stringHash;
	uint32 programHashCode;
	String programName;

	// Generate source code.
	programWriter->writeSourceCode(sourceCodeStringStream, shaderProgram);

	// Generate program hash code.
	programHashCode = static_cast<uint32>(stringHash(sourceCodeStringStream.str()));

	// Generate program name.
	programName = StringConverter::toString(programHashCode);
	
	if (shaderProgram->getType() == GPT_VERTEX_PROGRAM)
	{
		programName += "_VS";
	}
	else if (shaderProgram->getType() == GPT_FRAGMENT_PROGRAM)
	{
		programName += "_FS";
	}

	HighLevelGpuProgramPtr pGpuProgram;

	// Try to get program by name.
	pGpuProgram = HighLevelGpuProgramManager::getSingleton().getByName(programName);

	// Case the program doesn't exist yet.
	if (pGpuProgram.isNull())
	{
		// Create new GPU program.
		pGpuProgram = HighLevelGpuProgramManager::getSingleton().createProgram(programName,
			ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, language, shaderProgram->getType());

		// Case cache directory specified -> create program from file.
		if (cachePath.empty() == false)
		{
			const String  programFullName = programName + "." + language;
			const String  programFileName = cachePath + programFullName;	
			std::ifstream programFile;
			bool		  writeFile = true;


			// Check if program file already exist.
			programFile.open(programFileName.c_str());

			// Case no matching file found -> we have to write it.
			if (!programFile)
			{			
				writeFile = true;
			}
			else
			{
				writeFile = false;
				programFile.close();
			}

			// Case we have to write the program to a file.
			if (writeFile)
			{
				std::ofstream outFile(programFileName.c_str());

				if (!outFile)
					return GpuProgramPtr();

				outFile << sourceCodeStringStream.str();
				outFile.close();
			}

			pGpuProgram->setSourceFile(programFullName);
		}

		// No cache directory specified -> create program from system memory.
		else
		{
			pGpuProgram->setSource(sourceCodeStringStream.str());
		}
		
		
		pGpuProgram->setParameter("entry_point", shaderProgram->getEntryPointFunction()->getName());

		// HLSL program requires specific target profile settings - we have to split the profile string.
		if (language == "hlsl")
		{
			StringVector::const_iterator it = profilesList.begin();
			StringVector::const_iterator itEnd = profilesList.end();
			
			for (; it != itEnd; ++it)
			{
				if (GpuProgramManager::getSingleton().isSyntaxSupported(*it))
				{
					pGpuProgram->setParameter("target", *it);
					break;
				}
			}
		}
		
		pGpuProgram->setParameter("profiles", profiles);
		pGpuProgram->load();
	
		// Case an error occurred.
		if (pGpuProgram->hasCompileError())
		{
			pGpuProgram.setNull();
			return GpuProgramPtr(pGpuProgram);
		}

		// Add the created GPU program to local cache.
		if (pGpuProgram->getType() == GPT_VERTEX_PROGRAM)
		{
			mVertexShaderMap[programName] = pGpuProgram;			
		}
		else if (pGpuProgram->getType() == GPT_FRAGMENT_PROGRAM)
		{
			mFragmentShaderMap[programName] = pGpuProgram;	
		}				
	}
	
	return GpuProgramPtr(pGpuProgram);
}
Exemplo n.º 3
0
//-----------------------------------------------------------------------------
GpuProgramPtr ProgramManager::createGpuProgram(Program* shaderProgram, 
                                               ProgramWriter* programWriter,
                                               const String& language,
                                               const String& profiles,
                                               const StringVector& profilesList,
                                               const String& cachePath)
{
    stringstream sourceCodeStringStream;

    // Generate source code.
    programWriter->writeSourceCode(sourceCodeStringStream, shaderProgram);
    String source = sourceCodeStringStream.str();

    // Generate program name.
    String programName = generateHash(source);

    if (shaderProgram->getType() == GPT_VERTEX_PROGRAM)
    {
        programName += "_VS";
    }
    else if (shaderProgram->getType() == GPT_FRAGMENT_PROGRAM)
    {
        programName += "_FS";
    }

    // Try to get program by name.
    HighLevelGpuProgramPtr pGpuProgram =
        HighLevelGpuProgramManager::getSingleton().getByName(
            programName, ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME);

    if(pGpuProgram) {
        return static_pointer_cast<GpuProgram>(pGpuProgram);
    }

    // Case the program doesn't exist yet.
    // Create new GPU program.
    pGpuProgram = HighLevelGpuProgramManager::getSingleton().createProgram(programName,
        ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME, language, shaderProgram->getType());

    // Case cache directory specified -> create program from file.
    if (!cachePath.empty())
    {
        const String  programFullName = programName + "." + language;
        const String  programFileName = cachePath + programFullName;
        std::ifstream programFile;

        // Check if program file already exist.
        programFile.open(programFileName.c_str());

        // Case we have to write the program to a file.
        if (!programFile)
        {
            std::ofstream outFile(programFileName.c_str());

            if (!outFile)
                return GpuProgramPtr();

            outFile << source;
            outFile.close();
        }
        else
        {
            // use program file version
            StringStream buffer;
            programFile >> buffer.rdbuf();
            source = buffer.str();
        }
    }

    pGpuProgram->setSource(source);

    pGpuProgram->setParameter("entry_point", shaderProgram->getEntryPointFunction()->getName());

    if (language == "hlsl")
    {
        // HLSL program requires specific target profile settings - we have to split the profile string.
        StringVector::const_iterator it = profilesList.begin();
        StringVector::const_iterator itEnd = profilesList.end();
        
        for (; it != itEnd; ++it)
        {
            if (GpuProgramManager::getSingleton().isSyntaxSupported(*it))
            {
                pGpuProgram->setParameter("target", *it);
                break;
            }
        }

        pGpuProgram->setParameter("enable_backwards_compatibility", "true");
        pGpuProgram->setParameter("column_major_matrices", StringConverter::toString(shaderProgram->getUseColumnMajorMatrices()));
    }
    
    pGpuProgram->setParameter("profiles", profiles);
    pGpuProgram->load();

    // Case an error occurred.
    if (pGpuProgram->hasCompileError())
    {
        //! [debug_break]
        pGpuProgram.reset();
        //! [debug_break]
        return GpuProgramPtr(pGpuProgram);
    }

    // Add the created GPU program to local cache.
    if (pGpuProgram->getType() == GPT_VERTEX_PROGRAM)
    {
        mVertexShaderMap[programName] = pGpuProgram;
    }
    else if (pGpuProgram->getType() == GPT_FRAGMENT_PROGRAM)
    {
        mFragmentShaderMap[programName] = pGpuProgram;
    }
    
    return static_pointer_cast<GpuProgram>(pGpuProgram);
}
//-----------------------------------------------------------------------------
void GLSLProgramProcessor::bindSubShaders(Program* program, GpuProgramPtr pGpuProgram)
{
	if (program->getDependencyCount() > 0)
	{
		// Get all attached shaders so we do not attach shaders twice.
		// maybe GLSLProgram should take care of that ( prevent add duplicate shaders )
		String attachedShaders = pGpuProgram->getParameter("attach");
		String subShaderDef = "";

		for (unsigned int i=0; i < program->getDependencyCount(); ++i)
		{
			// Here we append _VS and _FS to the library shaders (so max each lib shader
			// is compiled twice once as vertex and once as fragment shader)
			String subShaderName = program->getDependency(i);
			if (program->getType() == GPT_VERTEX_PROGRAM)
			{
				subShaderName += "_VS";
			}
			else
			{
				subShaderName += "_FS";
			}					

			// Check if the library shader already compiled
			if(!HighLevelGpuProgramManager::getSingleton().resourceExists(subShaderName))
			{
				// Create the library shader
				HighLevelGpuProgramPtr pSubGpuProgram = HighLevelGpuProgramManager::getSingleton().createProgram(subShaderName,
					ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TargetLanguage, program->getType());

				// Set the source name
				String sourceName = program->getDependency(i) + "." + TargetLanguage;
				pSubGpuProgram->setSourceFile(sourceName);
                pSubGpuProgram->load();

                // Prepend the current GLSL version
                String versionLine = "#version " + StringConverter::toString(Root::getSingleton().getRenderSystem()->getNativeShadingLanguageVersion()) + "\n";
                pSubGpuProgram->setSource(versionLine + pSubGpuProgram->getSource());

				// If we have compile errors than stop processing
				if (pSubGpuProgram->hasCompileError())
				{
					OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 
						"Could not compile shader library from the source file: " + sourceName, 
						"GLSLProgramProcessor::bindSubShaders" );	
				}

				mLibraryPrograms.push_back(subShaderName);
			}

			// Check if the lib shader already attached to this shader
			if (attachedShaders.find(subShaderName) == String::npos)
			{
				// Append the shader name to subShaders
				subShaderDef += subShaderName + " ";
			}
		}

		// Check if we have something to attach
		if (subShaderDef.length() > 0)
		{
			pGpuProgram->setParameter("attach", subShaderDef);
		}
	}
	
}
Exemplo n.º 5
0
	//-----------------------------------------------------------------------------------
	Ogre::GpuProgramPtr ShaderManager::getGpuProgram(HlmsDatablock* dataBlock)
	{
		Ogre::uint32 hash = dataBlock->getHash();

		std::map<Ogre::uint32, Ogre::GpuProgramPtr>::iterator it = mShaderCache.find(hash);
		if (it != mShaderCache.end())
		{
			return (*it).second;
		}
		else
		{
			Ogre::String typeStr = FilePatterns[dataBlock->getShaderType()];

			std::stringstream sstream;
			sstream << std::hex << hash;
			std::string hashString = sstream.str();

			Ogre::String name = hashString + typeStr;

			// generate the shader code
			Ogre::String code = dataBlock->getTemplate()->getTemplate();
			code = ShaderGenerator::parse(code, *(dataBlock->getPropertyMap()), mShaderPiecesManager->getPieces(dataBlock->getLanguarge(), dataBlock->getShaderType()));

			HighLevelGpuProgramPtr gpuProgram = Ogre::HighLevelGpuProgramManager::getSingleton().createProgram(name,
				Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, dataBlock->getLanguarge(), dataBlock->getShaderType());

			gpuProgram->setSource(code);
			gpuProgram->setParameter("entry_point", "main");

			if (dataBlock->getLanguarge() == "hlsl")
			{
				// HLSL program requires specific target profile settings - we have to split the profile string.
				const Ogre::StringVector& profilesList = dataBlock->getProfileList();
				Ogre::StringVector::const_iterator it = profilesList.begin();
				Ogre::StringVector::const_iterator itEnd = profilesList.end();

				for (; it != itEnd; ++it)
				{
					if (Ogre::GpuProgramManager::getSingleton().isSyntaxSupported(*it))
					{
						gpuProgram->setParameter("target", *it);
						break;
					}
				}

				//gpuProgram->setParameter("enable_backwards_compatibility", "false");
				//gpuProgram->setParameter("column_major_matrices", Ogre::StringConverter::toString(shaderProgram->getUseColumnMajorMatrices()));
			}

			//gpuProgram->setParameter("profiles", profiles);
			gpuProgram->load();

			// Case an error occurred.
			if (gpuProgram->hasCompileError())
			{
				gpuProgram.setNull();
				return Ogre::GpuProgramPtr(gpuProgram);
			}

			mShaderCache[hash] = gpuProgram;

			return gpuProgram;
		}

	}
Exemplo n.º 6
0
void BatchPage::_updateShaders()
{
	if (!shadersSupported)
		return;

	uint32 i = 0;
	BatchedGeometry::SubBatchIterator it = batch->getSubBatchIterator();
	while (it.hasMoreElements()){
		BatchedGeometry::SubBatch *subBatch = it.getNext();
		MaterialPtr mat = unfadedMaterials[i++];

		//Check if lighting should be enabled
		bool lightingEnabled = false;
		for (unsigned short t = 0; t < mat->getNumTechniques(); ++t){
			Technique *tech = mat->getTechnique(t);
			for (unsigned short p = 0; p < tech->getNumPasses(); ++p){
				Pass *pass = tech->getPass(p);
				if (pass->getLightingEnabled()) {
					lightingEnabled = true;
					break;
				}
			}
			if (lightingEnabled)
				break;
		}

		//Compile the CG shader script based on various material / fade options
		StringUtil::StrStreamType tmpName;
		tmpName << "BatchPage_";
		if (fadeEnabled)
			tmpName << "fade_";
		if (lightingEnabled)
			tmpName << "lit_";
		if (subBatch->vertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL)
			tmpName << "clr_";

		for (unsigned short i = 0; i < subBatch->vertexData->vertexDeclaration->getElementCount(); ++i)
		{
			const VertexElement *el = subBatch->vertexData->vertexDeclaration->getElement(i);
			if (el->getSemantic() == VES_TEXTURE_COORDINATES) {
				String uvType = "";
				switch (el->getType()) {
						case VET_FLOAT1: uvType = "1"; break;
						case VET_FLOAT2: uvType = "2"; break;
						case VET_FLOAT3: uvType = "3"; break;
						case VET_FLOAT4: uvType = "4"; break;
				}
				tmpName << uvType << '_';
			}
		}

		tmpName << "vp";

		const String vertexProgName = tmpName.str();

		String shaderLanguage = ShaderHelper::getShaderLanguage();

		//If the shader hasn't been created yet, create it
		if (HighLevelGpuProgramManager::getSingleton().getByName(vertexProgName).isNull())
		{
			Pass *pass = mat->getTechnique(0)->getPass(0);
			String vertexProgSource;

			if(!shaderLanguage.compare("hlsl") || !shaderLanguage.compare("cg"))
			{

				vertexProgSource =
					"void main( \n"
					"	float4 iPosition : POSITION, \n"
					"	float3 normal    : NORMAL,	\n"
					"	out float4 oPosition : POSITION, \n";

				if (subBatch->vertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL) vertexProgSource +=
					"	float4 iColor    : COLOR, \n";

				unsigned texNum = 0;
				for (unsigned short i = 0; i < subBatch->vertexData->vertexDeclaration->getElementCount(); ++i) {
					const VertexElement *el = subBatch->vertexData->vertexDeclaration->getElement(i);
					if (el->getSemantic() == VES_TEXTURE_COORDINATES) {
						String uvType = "";
						switch (el->getType()) {
							case VET_FLOAT1: uvType = "float"; break;
							case VET_FLOAT2: uvType = "float2"; break;
							case VET_FLOAT3: uvType = "float3"; break;
							case VET_FLOAT4: uvType = "float4"; break;
						}

						vertexProgSource +=
						"	" + uvType + " iUV" + StringConverter::toString(texNum) + "			: TEXCOORD" + StringConverter::toString(texNum) + ",	\n"
						"	out " + uvType + " oUV" + StringConverter::toString(texNum) + "		: TEXCOORD" + StringConverter::toString(texNum) + ",	\n";

						++texNum;
					}
				}

				vertexProgSource +=
					"	out float oFog : FOG,	\n"
				"	out float4 oColor : COLOR, \n"
			    "	uniform float4 iFogParams,	\n";

				if (lightingEnabled) vertexProgSource +=
					"	uniform float4 objSpaceLight,	\n"
					"	uniform float4 lightDiffuse,	\n"
					"	uniform float4 lightAmbient,	\n";

				if (fadeEnabled) vertexProgSource +=
					"	uniform float3 camPos, \n";

				vertexProgSource +=
					"	uniform float4x4 worldViewProj,	\n"
					"	uniform float fadeGap, \n"
					"   uniform float invisibleDist )\n"
					"{	\n";

				if (lightingEnabled) {
					//Perform lighting calculations (no specular)
					vertexProgSource +=
					"	float3 light = normalize(objSpaceLight.xyz - (iPosition.xyz * objSpaceLight.w)); \n"
					"	float diffuseFactor = max(dot(normal, light), 0); \n";
					if (subBatch->vertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL)
						vertexProgSource += "oColor = (lightAmbient + diffuseFactor * lightDiffuse) * iColor; \n";
					else
						vertexProgSource += "oColor = (lightAmbient + diffuseFactor * lightDiffuse); \n";
				} else {
					if (subBatch->vertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL)
						vertexProgSource += "oColor = iColor; \n";
					else
						vertexProgSource += "oColor = float4(1, 1, 1, 1); \n";
				}

				if (fadeEnabled) vertexProgSource +=
					//Fade out in the distance
					"	float dist = distance(camPos.xz, iPosition.xz);	\n"
					"	oColor.a *= (invisibleDist - dist) / fadeGap;   \n";

				texNum = 0;
				for (unsigned short i = 0; i < subBatch->vertexData->vertexDeclaration->getElementCount(); ++i) {
					const VertexElement *el = subBatch->vertexData->vertexDeclaration->getElement(i);
					if (el->getSemantic() == VES_TEXTURE_COORDINATES) {
						vertexProgSource +=
						"	oUV" + StringConverter::toString(texNum) + " = iUV" + StringConverter::toString(texNum) + ";	\n";
						++texNum;
					}
				}
				vertexProgSource +=
					"	oPosition = mul(worldViewProj, iPosition);  \n";
				if (sceneMgr->getFogMode() == Ogre::FOG_EXP2) {
					vertexProgSource +=
						"	oFog = 1 - clamp (pow (2.71828, -oPosition.z * iFogParams.x), 0, 1); \n";
				} else {
					vertexProgSource +=
						"	oFog = oPosition.z; \n";
				}
				vertexProgSource += "}";
			}

			if(!shaderLanguage.compare("glsl"))
			{
				vertexProgSource =
					"uniform float fadeGap;        \n"
					"uniform float invisibleDist;   \n";

				if (lightingEnabled) vertexProgSource +=
					"uniform vec4 objSpaceLight;   \n"
					"uniform vec4 lightDiffuse;	   \n"
					"uniform vec4 lightAmbient;	   \n";

				if (fadeEnabled) vertexProgSource +=
					"uniform vec3 camPos;          \n";

				vertexProgSource +=
					"void main() \n"
					"{ \n";

				if (lightingEnabled)
				{
					//Perform lighting calculations (no specular)
					vertexProgSource +=
					"   vec3 light = normalize(objSpaceLight.xyz - (gl_Vertex.xyz * objSpaceLight.w)); \n"
					"   float diffuseFactor = max(dot(gl_Normal, light), 0.0); \n";
					if (subBatch->vertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL)
					{
						vertexProgSource += "   gl_FrontColor = (lightAmbient + diffuseFactor * lightDiffuse) * gl_Color; \n";
					}
					else
					{
						vertexProgSource += "   gl_FrontColor = (lightAmbient + diffuseFactor * lightDiffuse); \n";
					}
				}
				else
				{
					if (subBatch->vertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL)
					{
						vertexProgSource += "   gl_FrontColor = gl_Color; \n";
					}
					else
					{
						vertexProgSource += "   gl_FrontColor = vec4(1.0, 1.0, 1.0, 1.0); \n";
					}
				}

				if (fadeEnabled)
				{
					vertexProgSource +=
					//Fade out in the distance
					"   float dist = distance(camPos.xz, gl_Vertex.xz);	\n"
					"   gl_FrontColor.a *= (invisibleDist - dist) / fadeGap;   \n";
				}

				unsigned texNum = 0;
				for (unsigned short i = 0; i < subBatch->vertexData->vertexDeclaration->getElementCount(); ++i)
				{
					const VertexElement *el = subBatch->vertexData->vertexDeclaration->getElement(i);
					if (el->getSemantic() == VES_TEXTURE_COORDINATES)
					{
						vertexProgSource +=
						"   gl_TexCoord[" + StringConverter::toString(texNum) + "] = gl_MultiTexCoord" + StringConverter::toString(texNum) + ";	\n";
						++texNum;
					}
				}

				vertexProgSource +=
					"   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;  \n";
				if (sceneMgr->getFogMode() == Ogre::FOG_EXP2) {
					vertexProgSource +=
						"	gl_FogFragCoord = clamp(exp(- gl_Fog.density * gl_Fog.density * gl_Position.z * gl_Position.z), 0.0, 1.0); \n";
				} else {
					vertexProgSource +=
						"	gl_FogFragCoord = gl_Position.z; \n";
				}

				vertexProgSource +=	"}";
			}


			HighLevelGpuProgramPtr vertexShader = HighLevelGpuProgramManager::getSingleton().createProgram(
				vertexProgName,
				ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
				shaderLanguage, GPT_VERTEX_PROGRAM);

			vertexShader->setSource(vertexProgSource);

			if (shaderLanguage == "hlsl")
			{
				vertexShader->setParameter("target", "vs_1_1");
				vertexShader->setParameter("entry_point", "main");
			}
			else if(shaderLanguage == "cg")
			{
				vertexShader->setParameter("profiles", "vs_1_1 arbvp1");
				vertexShader->setParameter("entry_point", "main");
			}
			// GLSL can only have one entry point "main".

			vertexShader->load();
			if (vertexShader->hasCompileError()) {
				OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Error loading the batching vertex shader.", "BatchPage::_updateShaders()");
			}
		}

		std::string fragmentProgramName("BatchFragStandard");
		String fragmentProgSource;
		//We also need a fragment program to go with our vertex program. Especially on ATI cards on Linux where we can't mix shaders and the fixed function pipeline.
		HighLevelGpuProgramPtr fragShader = static_cast<HighLevelGpuProgramPtr>(HighLevelGpuProgramManager::getSingleton().getByName(fragmentProgramName));
		if (fragShader.isNull()){
			Pass *pass = mat->getTechnique(0)->getPass(0);

			if (shaderLanguage == "glsl") {
				fragmentProgSource = "uniform sampler2D diffuseMap;\n"
					"void main()	{"
					"	gl_FragColor = texture2D(diffuseMap, gl_TexCoord[0].st);"
					"	gl_FragColor.rgb = mix(gl_Fog.color, (gl_LightModel.ambient * gl_FragColor + gl_FragColor), gl_FogFragCoord).rgb;"
					"}";

			} else {
				fragmentProgSource = "void main \n"
					"( \n"
					"    float2				iTexcoord		: TEXCOORD0, \n"
					"	 float				iFog 			: FOG, \n"
					"	 out float4         oColour			: COLOR, \n"
					"    uniform sampler2D  diffuseTexture	: TEXUNIT0, \n"
					"    uniform float3		iFogColour \n"
					") \n"
					"{ \n"
					"	oColour = tex2D(diffuseTexture, iTexcoord.xy); \n"
					"   oColour.xyz = lerp(oColour.xyz, iFogColour, iFog);\n"
					"}";
			}

			fragShader = HighLevelGpuProgramManager::getSingleton().createProgram(
				fragmentProgramName,
				ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
				shaderLanguage, GPT_FRAGMENT_PROGRAM);

			fragShader->setSource(fragmentProgSource);

			if (shaderLanguage == "hlsl") {
				fragShader->setParameter("entry_point", "main");
				fragShader->setParameter("target", "ps_2_0");
			} else if (shaderLanguage == "cg") {
				fragShader->setParameter("profiles", "ps_2_0 arbfp1");
				fragShader->setParameter("entry_point", "main");
			}

			fragShader->load();
			if (fragShader->hasCompileError()) {
				OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Error loading the batching fragment shader.", "BatchPage::_updateShaders()");
			}
		}
		//Now that the shader is ready to be applied, apply it
		StringUtil::StrStreamType materialSignature;
		materialSignature << "BatchMat|";
		materialSignature << mat->getName() << "|";
		if (fadeEnabled){
			materialSignature << visibleDist << "|";
			materialSignature << invisibleDist << "|";
		}

		//Search for the desired material
		MaterialPtr generatedMaterial = MaterialManager::getSingleton().getByName(materialSignature.str());
		if (generatedMaterial.isNull()){
			//Clone the material
			generatedMaterial = mat->clone(materialSignature.str());

			//And apply the fade shader
			Ogre::Material::TechniqueIterator I = generatedMaterial->getSupportedTechniqueIterator();
			while (I.hasMoreElements()) {
				Technique *tech = I.getNext();
				for (unsigned short p = 0; p < tech->getNumPasses(); ++p){
					Pass *pass = tech->getPass(p);

					//Setup vertex program
					if (pass->getVertexProgramName() == "")
						pass->setVertexProgram(vertexProgName);

					if (pass->getFragmentProgramName() == "" && fragShader->isSupported())
						pass->setFragmentProgram(fragmentProgramName);

					try{
						GpuProgramParametersSharedPtr params = pass->getVertexProgramParameters();
						params->setIgnoreMissingParams(true);

						if (lightingEnabled) {
							params->setNamedAutoConstant("objSpaceLight", GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE);
							params->setNamedAutoConstant("lightDiffuse", GpuProgramParameters::ACT_DERIVED_LIGHT_DIFFUSE_COLOUR);
							params->setNamedAutoConstant("lightAmbient", GpuProgramParameters::ACT_DERIVED_AMBIENT_LIGHT_COLOUR);
							//params->setNamedAutoConstant("matAmbient", GpuProgramParameters::ACT_SURFACE_AMBIENT_COLOUR);
						}

						if (shaderLanguage.compare("glsl") == 0) {
							//glsl can use the built in gl_ModelViewProjectionMatrix
							params->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
						} else {
							params->setNamedAutoConstant("iFogParams", GpuProgramParameters::ACT_FOG_PARAMS);
						}

						if (fadeEnabled)
						{
							params->setNamedAutoConstant("camPos", GpuProgramParameters::ACT_CAMERA_POSITION_OBJECT_SPACE);

							//Set fade ranges
							params->setNamedAutoConstant("invisibleDist", GpuProgramParameters::ACT_CUSTOM);
							params->setNamedConstant("invisibleDist", invisibleDist);

							params->setNamedAutoConstant("fadeGap", GpuProgramParameters::ACT_CUSTOM);
							params->setNamedConstant("fadeGap", invisibleDist - visibleDist);

							if (pass->getAlphaRejectFunction() == CMPF_ALWAYS_PASS)
								pass->setSceneBlending(SBT_TRANSPARENT_ALPHA);
						}

						if (pass->hasFragmentProgram()) {
							params = pass->getFragmentProgramParameters();
							params->setIgnoreMissingParams(true);
							params->setNamedAutoConstant("iFogColour", GpuProgramParameters::ACT_FOG_COLOUR);
						}
					}
					catch (...) {
						OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Error configuring batched geometry transitions. If you're using materials with custom vertex shaders, they will need to implement fade transitions to be compatible with BatchPage.", "BatchPage::_updateShaders()");
					}
				}
			}

		}

		//Apply the material
		subBatch->setMaterial(generatedMaterial);
	}

}