internal override void WriteSourceCode(System.IO.StreamWriter stream, Program program) { var gpuType = program.Type; if (gpuType == GpuProgramType.Geometry) { throw new Core.AxiomException("Geometry Programs not supported in GLSL ES writer"); } this.fragInputParams.Clear(); var functionList = program.Functions; var parameterList = program.Parameters; // Write the current version (this forces the driver to fulfill the glsl es standard) stream.WriteLine("#version" + this.glslVersion.ToString()); //Default precision declaration is required in fragment and vertex shaders. stream.WriteLine("precision highp float"); stream.WriteLine("precision highp int"); //Generate source code header WriteProgramTitle(stream, program); stream.WriteLine(); //Embed depndencies. WriteProgramDependencies(stream, program); stream.WriteLine(); //Generate global variable code. WriteUniformParametersTitle(stream, program); stream.WriteLine(); //Write the uniforms foreach (var uniformParams in parameterList) { stream.Write("uniform\t"); stream.Write(this.gpuConstTypeMap[uniformParams.Type]); stream.Write("\t"); stream.Write(uniformParams.Name); if (uniformParams.IsArray) { stream.Write("[" + uniformParams.Size.ToString() + "]"); } stream.WriteLine(";"); } stream.WriteLine(); //Write program function(s) foreach (var curFunction in functionList) { WriteFunctionTitle(stream, curFunction); this.inputToGLStatesMap.Clear(); WriteInputParameters(stream, curFunction, gpuType); WriteOutParameters(stream, curFunction, gpuType); stream.WriteLine("void main() {"); if (gpuType == GpuProgramType.Fragment) { stream.WriteLine("\tvec4 outputColor;"); } else if (gpuType == GpuProgramType.Vertex) { stream.WriteLine("\tvec4 outputPosition;"); } //Write local paraemters var localParam = curFunction.LocalParameters; foreach (var itParam in localParam) { stream.Write("\t"); WriteLocalParameter(stream, itParam); stream.WriteLine(";"); } stream.WriteLine(); //sort function atoms curFunction.SortAtomInstances(); var atomInstances = curFunction.AtomInstances; foreach (var itAtom in atomInstances) { var funcInvoc = (FunctionInvocation)itAtom; int itOperand = 0; int itOperandEnd = funcInvoc.OperandList.Count; var localOs = new StringBuilder(); localOs.Append("\t" + funcInvoc.FunctionName + "("); int curIndLevel = 0; while (itOperand != itOperandEnd) { Operand op = funcInvoc.OperandList[itOperand]; Operand.OpSemantic opSemantic = op.Semantic; string paramName = op.Parameter.Name; Parameter.ContentType content = op.Parameter.Content; // Check if we write to a varying because the are only readable in fragment programs if (opSemantic == Operand.OpSemantic.Out || opSemantic == Operand.OpSemantic.InOut) { bool isVarying = false; if (gpuType == GpuProgramType.Fragment) { if (this.fragInputParams.Contains(paramName)) { //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.Remove(0); tempVar.Insert(0, "o"); //Declare the copy variable and assign the original stream.WriteLine("\t" + this.gpuConstTypeMap[op.Parameter.Type] + " " + newVar + " = " + tempVar + ";\n"); //Fromnow on we replace it automatic this.inputToGLStatesMap.Add(paramName, newVar); this.fragInputParams.Remove(paramName); } } if (!isVarying) { foreach (var param in parameterList) { if (CompareUniformByName(param, paramName)) { string newVar = "local_" + paramName; if (this.inputToGLStatesMap.ContainsKey(newVar) == false) { //Declare the copy variable and assign the original stream.WriteLine("\t" + this.gpuConstTypeMap[param.Type] + " " + newVar + " = " + paramName + ";\n"); //From now on we replace it automatic this.inputToGLStatesMap.Add(paramName, newVar); } } } } string newParam; if (this.inputToGLStatesMap.ContainsKey(paramName)) { int mask = op.Mask; //our swizzle mask //Here we insert the renamed param name newParam = this.inputToGLStatesMap[paramName]; if (mask != (int)Operand.OpMask.All) { newParam += "." + 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 == GpuProgramType.Vertex && content == Parameter.ContentType.TextureCoordinate0 || content == Parameter.ContentType.TextureCoordinate1 || content == Parameter.ContentType.TextureCoordinate2 || content == Parameter.ContentType.TextureCoordinate3 || content == Parameter.ContentType.TextureCoordinate4 || content == Parameter.ContentType.TextureCoordinate5 || content == Parameter.ContentType.TextureCoordinate6 || content == Parameter.ContentType.TextureCoordinate7) { //Now generate the swizzle mask according // the type. switch (op.Parameter.Type) { case GpuProgramParameters.GpuConstantType.Float1: newParam += ".x"; break; case GpuProgramParameters.GpuConstantType.Float2: newParam += ".xy"; break; case GpuProgramParameters.GpuConstantType.Float3: newParam += ".xyz"; break; case GpuProgramParameters.GpuConstantType.Float4: newParam += ".xyzw"; break; default: break; } } } else { newParam = op.ToString(); } itOperand++; //Prepare for the next operand localOs.Append(newParam); int opIndLevel = 0; if (itOperand != itOperandEnd) { opIndLevel = funcInvoc.OperandList[itOperand].IndirectionLevel; } if (curIndLevel != 0) { localOs.Append(")"); } if (curIndLevel < opIndLevel) { while (curIndLevel < opIndLevel) { curIndLevel++; localOs.Append("["); } } else { while (curIndLevel > opIndLevel) { curIndLevel--; localOs.Append("]"); } if (opIndLevel != 0) { localOs.Append("]["); } else if (itOperand != itOperandEnd) { localOs.Append(", "); } } if (curIndLevel != 0) { localOs.Append("int("); } } //Write function call closer localOs.AppendLine(");"); localOs.AppendLine(); stream.Write(localOs.ToString()); } } if (gpuType == GpuProgramType.Fragment) { stream.WriteLine("\tgl_FragColor = outputColor;"); } else if (gpuType == GpuProgramType.Vertex) { stream.WriteLine("\tgl_Position = outputPosition;"); } stream.WriteLine("}"); } stream.WriteLine(); }
internal override void WriteSourceCode(System.IO.StreamWriter stream, Program program) { var gpuType = program.Type; if (gpuType == GpuProgramType.Geometry) { throw new Core.AxiomException("Geometry Program not supported iin GLSL writer"); } this.fragInputParams.Clear(); var functionList = program.Functions; var parameterList = program.Parameters; // Write the current version (this force the driver to more fulfill the glsl standard) stream.WriteLine("#version " + this.glslVersion.ToString()); //Generate source code header WriteProgramTitle(stream, program); stream.WriteLine(); //Write forward declarations WriteForwardDeclarations(stream, program); stream.WriteLine(); //Generate global variable code WriteUniformParametersTitle(stream, program); stream.WriteLine(); //Write the uniforms foreach (var uniformParam in parameterList) { stream.Write("uniform\t"); stream.Write(this.gpuConstTypeMap[uniformParam.Type]); stream.Write("\t"); stream.Write(uniformParam.Name); if (uniformParam.IsArray) { stream.Write("[" + uniformParam.Size.ToString() + "]"); } stream.Write(";"); stream.WriteLine(); } stream.WriteLine(); //Write program function(s) foreach (var curFunction in functionList) { WriteFunctionTitle(stream, curFunction); //Clear output mapping this map is used when we use //glsl built in types like gl_Color for example this.inputToGLStatesMap.Clear(); //Write inout params and fill inputToGLStatesMap WriteInputParameters(stream, curFunction, gpuType); WriteOutParameters(stream, curFunction, gpuType); stream.Write("void main() {"); stream.WriteLine(); //Write local parameters var localParams = curFunction.LocalParameters; foreach (var itParam in localParams) { stream.Write("\t"); WriteLocalParameter(stream, itParam); stream.Write(";"); stream.WriteLine(); } stream.WriteLine(); //Sort function atoms curFunction.SortAtomInstances(); var atomInstances = curFunction.AtomInstances; foreach (var itAtom in atomInstances) { var funcInvoc = itAtom as FunctionInvocation; var localOs = new StringBuilder(); //Write function name localOs.Append("\t" + funcInvoc.FunctionAtomType + "("); int curIndLevel = 0; int itOperand = 0; int itOperandEnd = funcInvoc.OperandList.Count; while (itOperand != itOperandEnd) { Operand op = funcInvoc.OperandList[itOperand]; Operand.OpSemantic opSemantic = op.Semantic; string paramName = op.Parameter.Name; Parameter.ContentType content = op.Parameter.Content; if (opSemantic == Operand.OpSemantic.Out || opSemantic == Operand.OpSemantic.InOut) { bool isVarying = false; // Check if we write to an varying because the are only readable in fragment programs if (gpuType == GpuProgramType.Fragment) { if (this.fragInputParams.Contains(paramName)) { //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 = tempVar.Remove(0); tempVar = tempVar.Insert(0, "o"); //Declare the copy variable and assign the original stream.WriteLine("\t" + this.gpuConstTypeMap[op.Parameter.Type] + " " + newVar + " = " + tempVar); //From now on we replace it automatic this.inputToGLStatesMap[paramName] = newVar; //Remove the param because now it is replaced automatic with the local variable //(which could be written). this.fragInputParams.Remove(paramName); } } //If its not varying param check if a uniform is written if (!isVarying) { foreach (var param in parameterList) { if (GLSLProgramWriter.CompareUniformByName(param, paramName)) { //Declare the copy variable string newVar = "local_" + paramName; //now we check if we already declared a uniform redirector var if (this.inputToGLStatesMap.ContainsKey(newVar) == false) { //Declare the copy variable and assign the original stream.WriteLine("\t" + this.gpuConstTypeMap[param.Type] + " " + newVar + paramName + ";\n"); //From now on we replace it automatic this.inputToGLStatesMap.Add(paramName, newVar); } } } } } if (this.inputToGLStatesMap.ContainsKey(paramName)) { int mask = op.Mask; // our swizzle mask //Here we insert the renamed param name localOs.Append("." + Operand.GetMaskAsString(mask)); if (mask != (int)Operand.OpMask.All) { localOs.Append("." + Operand.GetMaskAsString(mask)); } //Now that every texcoord is a vec4 (passed as vertex attributes) //we have to swizzle them aoccording the desired type. else if (gpuType == GpuProgramType.Vertex && content == Parameter.ContentType.TextureCoordinate0 || content == Parameter.ContentType.TextureCoordinate1 || content == Parameter.ContentType.TextureCoordinate2 || content == Parameter.ContentType.TextureCoordinate3 || content == Parameter.ContentType.TextureCoordinate4 || content == Parameter.ContentType.TextureCoordinate5 || content == Parameter.ContentType.TextureCoordinate6 || content == Parameter.ContentType.TextureCoordinate7) { //Now generate the swizzel mask according //the type. switch (op.Parameter.Type) { case GpuProgramParameters.GpuConstantType.Float1: localOs.Append(".x"); break; case GpuProgramParameters.GpuConstantType.Float2: localOs.Append(".xy"); break; case GpuProgramParameters.GpuConstantType.Float3: localOs.Append(".xyz"); break; case GpuProgramParameters.GpuConstantType.Float4: localOs.Append(".xyzw"); break; default: break; } } } else { localOs.Append(op.ToString()); } itOperand++; //Prepare for the next operand int opIndLevel = 0; if (itOperand != itOperandEnd) { opIndLevel = funcInvoc.OperandList[itOperand].IndirectionLevel; } if (curIndLevel < opIndLevel) { while (curIndLevel < opIndLevel) { curIndLevel++; localOs.Append("["); } } else { while (curIndLevel > opIndLevel) { curIndLevel--; localOs.Append("]"); } if (opIndLevel != 0) { localOs.Append("]["); } else if (itOperand != itOperandEnd) { localOs.Append(", "); } } if (curIndLevel != 0) { localOs.Append("int("); } } //Write function call closer localOs.AppendLine(");"); localOs.AppendLine(); stream.Write(localOs.ToString()); } stream.WriteLine("}"); } stream.WriteLine(); }