//----------------------------------------------------------------------------- void ProgramProcessor::buildParameterReferenceMap(FunctionAtomInstanceList& funcAtomList, ParameterOperandMap& paramsRefMap) { FunctionAtomInstanceIterator it = funcAtomList.begin(); FunctionAtomInstanceIterator itEnd = funcAtomList.end(); for (; it != itEnd; ++it) { FunctionAtom* curAtom = *it; // Deal only with function invocations. if (curAtom->getFunctionAtomType() == FunctionInvocation::Type) { FunctionInvocation* curFuncInvocation = static_cast<FunctionInvocation*>(curAtom); FunctionInvocation::OperandVector& funcOperands = curFuncInvocation->getOperandList(); for (unsigned int op=0; op < funcOperands.size(); ++op) { Operand& curOperand = funcOperands[op]; paramsRefMap[curOperand.getParameter().get()].push_back(&curOperand); } } } }
//----------------------------------------------------------------------- void GLSLProgramWriter::writeForwardDeclarations(std::ostream& os, Program* program) { os << "//-----------------------------------------------------------------------------" << std::endl; os << "// FORWARD DECLARATIONS" << std::endl; os << "//-----------------------------------------------------------------------------" << std::endl; StringVector forwardDecl; // holds all generated function declarations const ShaderFunctionList& functionList = program->getFunctions(); ShaderFunctionConstIterator itFunction; // Iterate over all functions in the current program (in our case this is always the main() function) for ( itFunction = functionList.begin(); itFunction != functionList.end(); ++itFunction) { Function* curFunction = *itFunction; const FunctionAtomInstanceList& atomInstances = curFunction->getAtomInstances(); FunctionAtomInstanceConstIterator itAtom = atomInstances.begin(); FunctionAtomInstanceConstIterator itAtomEnd = atomInstances.end(); // Now iterate over all function atoms for ( ; itAtom != itAtomEnd; ++itAtom) { // Skip non function invocation atoms. if ((*itAtom)->getFunctionAtomType() != FunctionInvocation::Type) continue; FunctionInvocation* pFuncInvoc = static_cast<FunctionInvocation*>(*itAtom); FunctionInvocation::OperandVector::iterator itOperator = pFuncInvoc->getOperandList().begin(); FunctionInvocation::OperandVector::iterator itOperatorEnd = pFuncInvoc->getOperandList().end(); // Start with function declaration String funcDecl = pFuncInvoc->getReturnType() + " " + pFuncInvoc->getFunctionName() + "("; // Now iterate overall operands for (; itOperator != itOperatorEnd; ) { ParameterPtr pParam = (*itOperator).getParameter(); Operand::OpSemantic opSemantic = (*itOperator).getSemantic(); int opMask = (*itOperator).getMask(); GpuConstantType gpuType = GCT_UNKNOWN; // Write the semantic in, out, inout switch(opSemantic) { case Operand::OPS_IN: funcDecl += "in "; break; case Operand::OPS_OUT: funcDecl += "out "; break; case Operand::OPS_INOUT: funcDecl += "inout "; break; default: break; } // Swizzle masks are only defined for types like vec2, vec3, vec4. if (opMask == Operand::OPM_ALL) { gpuType = pParam->getType(); } else { // Now we have to convert the mask to operator gpuType = Operand::getGpuConstantType(opMask); } // We need a valid type otherwise glsl compilation will not work if (gpuType == GCT_UNKNOWN) { OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Can not convert Operand::OpMask to GpuConstantType", "GLSLProgramWriter::writeForwardDeclarations" ); } // Write the operand type. funcDecl += mGpuConstTypeMap[gpuType]; ++itOperator; //move over all operators with indirection while ((itOperator != itOperatorEnd) && (itOperator->getIndirectionLevel() != 0)) { ++itOperator; } // Prepare for the next operand if (itOperator != itOperatorEnd) { funcDecl += ", "; } } // Write function call closer. funcDecl += ");\n"; // Push the generated declaration into the vector // duplicate declarations will be removed later. forwardDecl.push_back(funcDecl); } } // Now remove duplicate declaration, first we have to sort the vector. std::sort(forwardDecl.begin(), forwardDecl.end()); StringVector::iterator endIt = std::unique(forwardDecl.begin(), forwardDecl.end()); // Finally write all function declarations to the shader file for (StringVector::iterator it = forwardDecl.begin(); it != endIt; it++) { os << *it; } }
//----------------------------------------------------------------------- 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; }