//-----------------------------------------------------------------------
void GLSLProgramWriter::writeSourceCode(std::ostream& os, Program* program)
{
	GpuProgramType gpuType = program->getType();
	if(gpuType == GPT_GEOMETRY_PROGRAM)
	{
		OGRE_EXCEPT( Exception::ERR_NOT_IMPLEMENTED, 
			"Geometry Program not supported in GLSL writer ", 
			"GLSLProgramWriter::writeSourceCode" );	
	}

	// Clear out old input params
	mFragInputParams.clear();

	const ShaderFunctionList& functionList = program->getFunctions();
	ShaderFunctionConstIterator itFunction;

	const UniformParameterList& parameterList = program->getParameters();
	UniformParameterConstIterator itUniformParam = parameterList.begin();
	
	// Write the current version (this force the driver to more fulfill the glsl standard)
	os << "#version "<< mGLSLVersion << std::endl;

	// Generate source code header.
	writeProgramTitle(os, program);
	os<< std::endl;

	// Write forward declarations
	writeForwardDeclarations(os, program);
	os<< std::endl;
	
	// Generate global variable code.
	writeUniformParametersTitle(os, program);
	os << std::endl;

	// Write the uniforms 
	for (itUniformParam = parameterList.begin();  itUniformParam != parameterList.end(); ++itUniformParam)
	{
		ParameterPtr pUniformParam = *itUniformParam;

		os << "uniform\t"; 
		os << mGpuConstTypeMap[pUniformParam->getType()];
		os << "\t";	
		os << pUniformParam->getName();
		if (pUniformParam->isArray() == true)
		{
			os << "[" << pUniformParam->getSize() << "]";	
		}
		os << ";" << std::endl;		
	}
	os << std::endl;			

	// Write program function(s).
	for (itFunction=functionList.begin(); itFunction != functionList.end(); ++itFunction)
	{
		Function* curFunction = *itFunction;

		writeFunctionTitle(os, curFunction);
		
		// Clear output mapping this map is used when we use
		// glsl built in types like gl_Color for example
		mInputToGLStatesMap.clear();

		// Write inout params and fill mInputToGLStatesMap
		writeInputParameters(os, curFunction, gpuType);
		writeOutParameters(os, curFunction, gpuType);
					
		// The function name must always main.
		os << "void main(void) {" << std::endl;

		// Write local parameters.
		const ShaderParameterList& localParams = curFunction->getLocalParameters();
		ShaderParameterConstIterator itParam = localParams.begin();
		ShaderParameterConstIterator itParamEnd = localParams.end();

		for (; itParam != itParamEnd; ++itParam)
		{
			os << "\t";
			writeLocalParameter(os, *itParam);			
			os << ";" << std::endl;						
		}
		os << std::endl;			

		// Sort function atoms.
		curFunction->sortAtomInstances();
		
		const FunctionAtomInstanceList& atomInstances = curFunction->getAtomInstances();
		FunctionAtomInstanceConstIterator itAtom = atomInstances.begin();
		FunctionAtomInstanceConstIterator itAtomEnd = atomInstances.end();

		for (; itAtom != itAtomEnd; ++itAtom)
		{		
			FunctionInvocation*  pFuncInvoc = (FunctionInvocation*)*itAtom;
			FunctionInvocation::OperandVector::iterator itOperand = pFuncInvoc->getOperandList().begin();
			FunctionInvocation::OperandVector::iterator itOperandEnd = pFuncInvoc->getOperandList().end();

			// Local string stream
			StringStream localOs;

			// Write function name			
			localOs << "\t" << pFuncInvoc->getFunctionName() << "(";

			ushort curIndLevel = 0;

			for (; itOperand != itOperandEnd; )
			{
				Operand op = *itOperand;
				Operand::OpSemantic opSemantic = op.getSemantic();
				String paramName = op.getParameter()->getName();
				Parameter::Content content = op.getParameter()->getContent();

				if (opSemantic == Operand::OPS_OUT || opSemantic == Operand::OPS_INOUT)
				{
					// Is the written parameter a varying 
					bool isVarying = false;

					// Check if we write to an varying because the are only readable in fragment programs 
					if (gpuType == GPT_FRAGMENT_PROGRAM)
					{	
						StringVector::iterator itFound = std::find(mFragInputParams.begin(), mFragInputParams.end(), paramName);	
						if(itFound != mFragInputParams.end())
						{						
							// Declare the copy variable
							String newVar = "local_" + paramName;
							String tempVar = paramName;
							isVarying = true;

							// We stored the original values in the mFragInputParams thats why we have to replace the first var with o
							// because all vertex output vars are prefixed with o in glsl the name has to match in the fragment program.
							tempVar.replace(tempVar.begin(), tempVar.begin() + 1, "o");

							// Declare the copy variable and assign the original
							os << "\t" << mGpuConstTypeMap[op.getParameter()->getType()] << " " << newVar << " = " << tempVar << ";\n" << std::endl;	

							// From now on we replace it automatic 
							mInputToGLStatesMap[paramName] = newVar;

							// Remove the param because now it is replaced automatic with the local variable
							// (which could be written).
							mFragInputParams.erase(itFound++);
						}
					}
					
					// If its not a varying param check if a uniform is written
					if(!isVarying)
					{
						UniformParameterList::const_iterator itFound = std::find_if( parameterList.begin(), parameterList.end(), std::bind2nd( CompareUniformByName(), paramName ) );
						if(itFound != parameterList.end())
						{	
							// Declare the copy variable
							String newVar = "local_" + paramName;

							// now we check if we already declared a uniform redirector var
							if(mInputToGLStatesMap.find(newVar) == mInputToGLStatesMap.end())
							{
								// Declare the copy variable and assign the original
								os << "\t" << mGpuConstTypeMap[itFound->get()->getType()] << " " << newVar << " = " << paramName << ";\n" << std::endl;	

								// From now on we replace it automatic 
								mInputToGLStatesMap[paramName] = newVar;
							}
						}
					}
				}

				if(mInputToGLStatesMap.find(paramName) != mInputToGLStatesMap.end())
				{
					int mask = op.getMask(); // our swizzle mask

					// Here we insert the renamed param name
					localOs << mInputToGLStatesMap[paramName];

					if(mask != Operand::OPM_ALL)
					{
						localOs << "." << Operand::getMaskAsString(mask);
					}	
					// Now that every texcoord is a vec4 (passed as vertex attributes) we
					// have to swizzle them according the desired type.
					else if(gpuType == GPT_VERTEX_PROGRAM &&
							(content == Parameter::SPC_TEXTURE_COORDINATE0 ||
							content == Parameter::SPC_TEXTURE_COORDINATE1 ||
							content == Parameter::SPC_TEXTURE_COORDINATE2 ||
							content == Parameter::SPC_TEXTURE_COORDINATE3 ||
							content == Parameter::SPC_TEXTURE_COORDINATE4 ||
							content == Parameter::SPC_TEXTURE_COORDINATE5 ||
							content == Parameter::SPC_TEXTURE_COORDINATE6 ||
							content == Parameter::SPC_TEXTURE_COORDINATE7) )
					{
						// Now generate the swizzel mask according
						// the type.
						switch(op.getParameter()->getType())
						{
						case GCT_FLOAT1:
							localOs << ".x";
							break;
						case GCT_FLOAT2:
							localOs << ".xy";
							break;
						case GCT_FLOAT3:
							localOs << ".xyz";
							break;
						case GCT_FLOAT4:
							localOs << ".xyzw";
							break;

						default:
							break;
						}
					}						
				}
				else
				{
					localOs << op.toString();
				}
				
				++itOperand;

				// Prepare for the next operand
				ushort opIndLevel = 0;
				if (itOperand != itOperandEnd)
				{
					opIndLevel = itOperand->getIndirectionLevel();
				}

				if (curIndLevel != 0)
				{
					localOs << ")";
				}

				if (curIndLevel < opIndLevel)
				{
					while (curIndLevel < opIndLevel)
					{
						++curIndLevel;
						localOs << "[";
					}
				}
				else //if (curIndLevel >= opIndLevel)
				{
					while (curIndLevel > opIndLevel)
					{
						--curIndLevel;
						localOs << "]";
					}
					if (opIndLevel != 0)
					{
						localOs << "][";
					}
					else if (itOperand != itOperandEnd)
					{
						localOs << ", ";
					}
				}
				if (curIndLevel != 0)
				{
					localOs << "int(";
				}
			}

			// Write function call closer.
			localOs << ");" << std::endl;
			localOs << std::endl;
			os << localOs.str();
		}
		os << "}" << std::endl;
	}
	os << std::endl;
}
//-----------------------------------------------------------------------
void CGProgramWriter::writeSourceCode(std::ostream& os, Program* program)
{
	const ShaderFunctionList& functionList = program->getFunctions();
	ShaderFunctionConstIterator itFunction;

	const UniformParameterList& parameterList = program->getParameters();
	UniformParameterConstIterator itUniformParam = parameterList.begin();

	// Generate source code header.
	writeProgramTitle(os, program);
	os << std::endl;

	// Generate dependencies.
	writeProgramDependencies(os, program);
	os << std::endl;

	// Generate global variable code.
	writeUniformParametersTitle(os, program);
	os << std::endl;

	for (itUniformParam=parameterList.begin();  itUniformParam != parameterList.end(); ++itUniformParam)
	{
		writeUniformParameter(os, *itUniformParam);			
		os << ";" << std::endl;				
	}
	os << std::endl;

	// Write program function(s).
	for (itFunction=functionList.begin(); itFunction != functionList.end(); ++itFunction)
	{
		Function* curFunction = *itFunction;

		writeFunctionTitle(os, curFunction);
		writeFunctionDeclaration(os, curFunction);

		os << "{" << std::endl;

		// Write local parameters.
		const ShaderParameterList& localParams = curFunction->getLocalParameters();
		ShaderParameterConstIterator itParam; 

		for (itParam=localParams.begin();  itParam != localParams.end(); ++itParam)
		{
			os << "\t";
			writeLocalParameter(os, *itParam);			
			os << ";" << std::endl;						
		}

		// Sort and write function atoms.
		curFunction->sortAtomInstances();

		const FunctionAtomInstanceList& atomInstances = curFunction->getAtomInstances();
		FunctionAtomInstanceConstIterator itAtom;

		for (itAtom=atomInstances.begin(); itAtom != atomInstances.end(); ++itAtom)
		{			
			writeAtomInstance(os, *itAtom);
		}


		os << "}" << std::endl;
	}

	os << std::endl;
}
//-----------------------------------------------------------------------
void HLSLProgramWriter::writeSourceCode(std::ostream& os, Program* program)
{
	const ShaderFunctionList& functionList = program->getFunctions();
	ShaderFunctionConstIterator itFunction;

	const UniformParameterList& parameterList = program->getParameters();
	UniformParameterConstIterator itUniformParam = parameterList.begin();

	// Generate source code header.
	writeProgramTitle(os, program);
	os << std::endl;

	// Generate dependencies.
	writeProgramDependencies(os, program);
	os << std::endl;

	// Generate global variable code.
	writeUniformParametersTitle(os, program);
	os << std::endl;

	for (itUniformParam=parameterList.begin();  itUniformParam != parameterList.end(); ++itUniformParam)
	{
		writeUniformParameter(os, *itUniformParam);			
		os << ";" << std::endl;				
	}
	os << std::endl;

	// Write program function(s).
	for (itFunction=functionList.begin(); itFunction != functionList.end(); ++itFunction)
	{
		Function* curFunction = *itFunction;
		bool needToTranslateHlsl4Color = false;
		ParameterPtr colorParameter;

		writeFunctionTitle(os, curFunction);

		writeFunctionDeclaration(os, curFunction, needToTranslateHlsl4Color, colorParameter);

		os << "{" << std::endl;

		// Write local parameters.
		const ShaderParameterList& localParams = curFunction->getLocalParameters();
		ShaderParameterConstIterator itParam = localParams.begin();

		for (;  itParam != localParams.end(); ++itParam)
		{
			os << "\t";
			writeLocalParameter(os, *itParam);			
			os << ";" << std::endl;						
		}

		//  translate hlsl 4 color parameter if needed
		if(needToTranslateHlsl4Color)
		{
			os << "\t";
			writeLocalParameter(os, colorParameter);			
			os << ";" << std::endl;						
			os << std::endl <<"\tFFP_Assign(iHlsl4Color_0, " << colorParameter->getName() << ");" << std::endl;
		}

		// Sort and write function atoms.
		curFunction->sortAtomInstances();

		const FunctionAtomInstanceList& atomInstances = curFunction->getAtomInstances();
		FunctionAtomInstanceConstIterator itAtom;

		for (itAtom=atomInstances.begin(); itAtom != atomInstances.end(); ++itAtom)
		{			
			writeAtomInstance(os, *itAtom);
		}


		os << "}" << std::endl;
	}

	os << std::endl;
}