private static bool GenerateFragmentShader(Shader shader, Material mat) { StringBuilder stream = new StringBuilder(); // Shader Header stream.AppendLine("#version 330 core"); stream.AppendLine(); // Configure inputs to match our outputs from VS if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Position)) { stream.AppendLine("in vec3 Position;"); } if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Normal)) { stream.AppendLine("in vec3 Normal;"); } for (int i = 0; i < mat.NumChannelControls; i++) { stream.AppendLine(string.Format("in vec4 Color{0};", i)); } for (int texGen = 0; texGen < mat.NumTexGens; texGen++) { stream.AppendLine(string.Format("in vec3 Tex{0};", texGen)); } stream.AppendLine(); // Final Output stream.AppendLine("// Final Output"); stream.AppendLine("out vec4 PixelColor;"); // Texture Inputs for (int i = 0; i < 8; i++) { if (mat.Textures[i] == null) { continue; } stream.AppendLine(string.Format("uniform sampler2D Texture{0};", i)); } // Main Function stream.AppendLine("void main()"); stream.AppendLine("{"); // Default initial values of the TEV registers. // ToDo: Does this need swizzling? themikelester has it marked as mat.registerColor[i==0?3:i-1]] stream.AppendLine(" // Initial TEV Register Values"); for (int i = 0; i < 4; i++) { stream.AppendLine(string.Format(" vec4 {0} = vec4({1}, {2}, {3}, {4});", m_tevOutputRegs[i], mat.TevColor[i].R, mat.TevColor[i].G, mat.TevColor[i].B, mat.TevColor[i].A)); } stream.AppendLine(); // Constant Color Registers stream.AppendLine(" // Konst TEV Colors"); for (int i = 0; i < 4; i++) { stream.AppendLine(string.Format(" vec4 konst{0} = vec4({1}, {2}, {3}, {4});", i, mat.TevKonstColors[i].R, mat.TevKonstColors[i].G, mat.TevKonstColors[i].B, mat.TevKonstColors[i].A)); } stream.AppendLine(); // Texture Samples bool[] oldCombos = new bool[256]; for (int i = 0; i < mat.NumTevStages; i++) { TevOrder order = mat.TevOrderInfos[i]; int tex = order.TexMap; GXTexCoordSlot coord = order.TexCoordId; // This TEV probably doesn't use textures. if (tex == 0xFF || coord == GXTexCoordSlot.Null) { continue; } if (IsNewTexCombo(tex, (int)coord, oldCombos)) { string swizzle = ""; // Uhh I don't know if we need to swizzle since everyone's been converted into ARGB stream.AppendLine(string.Format(" vec4 texCol{0} = texture(Texture{0}, Tex{1}.xy){2};", tex, (int)coord, swizzle)); } } stream.AppendLine(); // ToDo: Implement indirect texturing. stream.AppendLine(" // TEV Stages"); stream.AppendLine(); stream.AppendLine(); for (int i = 0; i < mat.NumTevStages; i++) { stream.AppendLine(string.Format(" // TEV Stage {0}", i)); TevOrder order = mat.TevOrderInfos[i]; TevStage stage = mat.TevStageInfos[i]; TevSwapMode swap = mat.TevSwapModes[i]; TevSwapModeTable rasTable = mat.TevSwapModeTables[swap.RasSel]; TevSwapModeTable texTable = mat.TevSwapModeTables[swap.TexSel]; // There's swapping involved in the ras table. stream.AppendLine(string.Format(" // Rasterization Swap Table: {0}", rasTable)); if (!(rasTable.R == 0 && rasTable.G == 1 && rasTable.B == 2 && rasTable.A == 3)) { stream.AppendLine(string.Format(" {0} = {1}{2};", GetVertColorString(order), GetVertColorString(order), GetSwapModeSwizzleString(rasTable))); } stream.AppendLine(); // There's swapping involved in the texture table. stream.AppendLine(string.Format(" // Texture Swap Table: {0}", texTable)); if (!(texTable.R == 0 && texTable.G == 1 && texTable.B == 2 && texTable.A == 3)) { stream.AppendLine(string.Format(" {0} = {1}{2};", GetTexTapString(order), GetTexTapString(order), GetSwapModeSwizzleString(rasTable))); } stream.AppendLine(); string[] colorInputs = new string[4]; colorInputs[0] = GetColorInString(stage.ColorIn[0], mat.KonstColorSels[i], order); colorInputs[1] = GetColorInString(stage.ColorIn[1], mat.KonstColorSels[i], order); colorInputs[2] = GetColorInString(stage.ColorIn[2], mat.KonstColorSels[i], order); colorInputs[3] = GetColorInString(stage.ColorIn[3], mat.KonstColorSels[i], order); stream.AppendLine(" // Color and Alpha Operations"); stream.AppendLine(string.Format(" {0}", GetColorOpString(stage.ColorOp, stage.ColorBias, stage.ColorScale, stage.ColorClamp, stage.ColorRegId, colorInputs))); string[] alphaInputs = new string[4]; alphaInputs[0] = GetAlphaInString(stage.AlphaIn[0], mat.KonstAlphaSels[i], order); alphaInputs[1] = GetAlphaInString(stage.AlphaIn[1], mat.KonstAlphaSels[i], order); alphaInputs[2] = GetAlphaInString(stage.AlphaIn[2], mat.KonstAlphaSels[i], order); alphaInputs[3] = GetAlphaInString(stage.AlphaIn[3], mat.KonstAlphaSels[i], order); stream.AppendLine(string.Format(" {0}", GetAlphaOpString(stage.AlphaOp, stage.AlphaBias, stage.AlphaScale, stage.AlphaClamp, stage.AlphaRegId, alphaInputs))); stream.AppendLine(); } stream.AppendLine(); // Alpha Compare stream.AppendLine(" // Alpha Compare Test"); AlphaCompare alphaCompare = mat.AlphaCompare; string alphaOp; switch (alphaCompare.Operation) { case GXAlphaOp.And: alphaOp = "&&"; break; case GXAlphaOp.Or: alphaOp = "||"; break; case GXAlphaOp.XOR: alphaOp = "^"; break; // Not really tested, unsupported in some examples but I don't see why. case GXAlphaOp.XNOR: alphaOp = "=="; break; // Not really tested. ^ default: WLog.Warning(LogCategory.TEVShaderGenerator, null, "Unsupported alpha compare operation: {0}", alphaCompare.Operation); alphaOp = "||"; break; } // clip(result.a < 0.5 && result a > 0.2 ? -1 : 1) string ifContents = string.Format("(!({0} {1} {2}))", GetCompareString(alphaCompare.Comp0, m_tevOutputRegs[0] + ".a", alphaCompare.Reference0), alphaOp, GetCompareString(alphaCompare.Comp1, m_tevOutputRegs[0] + ".a", alphaCompare.Reference1)); // clip equivelent stream.AppendLine(" // Alpha Compare (Clip)"); stream.AppendLine(string.Format(" if{0}\n\t\tdiscard;", ifContents)); //string output = "PixelColor = texCol0" + (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Color0) ? " * Color0;" : ";"); //stream.AppendLine(output); stream.AppendLine(string.Format(" PixelColor = {0};", m_tevOutputRegs[0])); stream.AppendLine("}"); stream.AppendLine(); // Compile the Fragment Shader and return whether it compiled sucesfully or not. Directory.CreateDirectory("ShaderDump"); System.IO.File.WriteAllText("ShaderDump/" + mat.Name + "_frag_output", stream.ToString()); return(shader.CompileSource(stream.ToString(), OpenTK.Graphics.OpenGL.ShaderType.FragmentShader)); }
public TevOrder(GXTexCoordSlot slot, byte texMap, GXColorChannelId chanID) { TexCoordId = slot; TexMap = texMap; ChannelId = chanID; }