Beispiel #1
0
 public MaterialEntry(EndianBinaryReader er)
 {
     Name           = er.ReadString(Encoding.ASCII, 20).Replace("\0", "");
     BufferColor    = er.ReadColor8();
     ConstColors    = new Color[6];
     ConstColors[0] = er.ReadColor8();
     ConstColors[1] = er.ReadColor8();
     ConstColors[2] = er.ReadColor8();
     ConstColors[3] = er.ReadColor8();
     ConstColors[4] = er.ReadColor8();
     ConstColors[5] = er.ReadColor8();
     Flags          = er.ReadUInt32();
     //Material Flag:
     //  0-1: Nr texMap
     //  2-3: Nr texMatrix
     //  4-5: Nr texCoordGen
     //  6-8: Nr tevStage
     //    9: Has alphaCompare
     //   10: Has blendMode
     //   11: Use Texture Only
     //   12: Separate Blend Mode
     //   14: Has Indirect Parameter
     //15-16: Nr projectionTexGenParameter
     //   17: Has Font Shadow Parameter
     TexMaps = new TexMap[Flags & 3];
     for (int i = 0; i < (Flags & 3); i++)
     {
         TexMaps[i] = new TexMap(er);
     }
     TexMatrices = new TexMatrix[(Flags >> 2) & 3];
     for (int i = 0; i < ((Flags >> 2) & 3); i++)
     {
         TexMatrices[i] = new TexMatrix(er);
     }
     TexCoordGens = new TexCoordGen[(Flags >> 4) & 3];
     for (int i = 0; i < ((Flags >> 4) & 3); i++)
     {
         TexCoordGens[i] = new TexCoordGen(er);
     }
     TevStages = new TevStage[(Flags >> 6) & 7];
     for (int i = 0; i < ((Flags >> 6) & 7); i++)
     {
         TevStages[i] = new TevStage(er);
     }
     if (((Flags >> 9) & 1) == 1)
     {
         AlphaTest = new AlphaCompare(er);
     }
     if (((Flags >> 10) & 1) == 1)
     {
         ColorBlendMode = new BlendMode(er);
     }
     if (((Flags >> 12) & 1) == 1)
     {
         AlphaBlendMode = new BlendMode(er);
     }
     //Some more things
 }
Beispiel #2
0
        private static string GenerateTexGens(StringBuilder stream, Material mat)
        {
            for (int i = 0; i < mat.NumTexGens; i++)
            {
                TexCoordGen gen = mat.TexGens[i];

                stream.AppendLine($"\t// TexGen { i } - Type: { gen.Type }, Source: { gen.Source }, Matrix: { gen.TexMatrixSource }");
                stream.AppendLine($"\tv_Tex{ i } = { GenerateTexGenPost(gen) };\n");
            }

            return(stream.ToString());
        }
Beispiel #3
0
        private static TexCoordGen ReadTexCoordGen(EndianBinaryReader stream)
        {
            var retVal = new TexCoordGen
            {
                Type            = (GXTexGenType)stream.ReadByte(),
                Source          = (GXTexGenSrc)stream.ReadByte(),
                TexMatrixSource = (GXTexMatrix)stream.ReadByte()
            };

            Trace.Assert(stream.ReadByte() == 0xFF); // Padding
            return(retVal);
        }
Beispiel #4
0
        private static string GenerateTexGenPost(TexCoordGen gen)
        {
            StringBuilder stream = new StringBuilder();

            string gen_source = GenerateTexGenSource(gen.Source);

            if (gen.Type == GXTexGenType.SRTG)
            {
                return($"vec3({ gen_source }.xy, 1.0)");
            }
            else if (gen.Type == GXTexGenType.Matrix2x4)
            {
                return($"vec3({ GenerateTexGenMatrixMult(gen, gen_source) }.xy, 1.0)");
            }
            else if (gen.Type == GXTexGenType.Matrix3x4)
            {
                return(GenerateTexGenMatrixMult(gen, gen_source));
            }

            return(stream.ToString());
        }
Beispiel #5
0
 private static string GenerateTexGenMatrixMult(TexCoordGen gen, string src)
 {
     if (false)
     {
     }
     else
     {
         if (gen.TexMatrixSource == GXTexMatrix.Identity)
         {
             return($"{ src }.xyz");
         }
         else if (gen.TexMatrixSource >= GXTexMatrix.TexMtx0)
         {
             int id = (gen.TexMatrixSource - GXTexMatrix.TexMtx0) / 3;
             return($"(mat4x4(TexMatrices[{ id }]) * { src })");
         }
         else
         {
             return(src);
         }
     }
 }
Beispiel #6
0
 public MaterialEntry(EndianBinaryReader er)
 {
     Name = er.ReadString(Encoding.ASCII, 20).Replace("\0", "");
     BufferColor = er.ReadColor8();
     ConstColors = new Color[6];
     ConstColors[0] = er.ReadColor8();
     ConstColors[1] = er.ReadColor8();
     ConstColors[2] = er.ReadColor8();
     ConstColors[3] = er.ReadColor8();
     ConstColors[4] = er.ReadColor8();
     ConstColors[5] = er.ReadColor8();
     Flags = er.ReadUInt32();
     //Material Flag:
     //  0-1: Nr texMap
     //  2-3: Nr texMatrix
     //  4-5: Nr texCoordGen
     //  6-8: Nr tevStage
     //    9: Has alphaCompare
     //   10: Has blendMode
     //   11: Use Texture Only
     //   12: Separate Blend Mode
     //   14: Has Indirect Parameter
     //15-16: Nr projectionTexGenParameter
     //   17: Has Font Shadow Parameter
     TexMaps = new TexMap[Flags & 3];
     for (int i = 0; i < (Flags & 3); i++)
     {
         TexMaps[i] = new TexMap(er);
     }
     TexMatrices = new TexMatrix[(Flags >> 2) & 3];
     for (int i = 0; i < ((Flags >> 2) & 3); i++)
     {
         TexMatrices[i] = new TexMatrix(er);
     }
     TexCoordGens = new TexCoordGen[(Flags >> 4) & 3];
     for (int i = 0; i < ((Flags >> 4) & 3); i++)
     {
         TexCoordGens[i] = new TexCoordGen(er);
     }
     TevStages = new TevStage[(Flags >> 6) & 7];
     for (int i = 0; i < ((Flags >> 6) & 7); i++)
     {
         TevStages[i] = new TevStage(er);
     }
     if (((Flags >> 9) & 1) == 1) AlphaTest = new AlphaCompare(er);
     if (((Flags >> 10) & 1) == 1) ColorBlendMode = new BlendMode(er);
     if (((Flags >> 12) & 1) == 1) AlphaBlendMode = new BlendMode(er);
     //Some more things
 }
        public static bool GenerateVertexShader(Shader shader, Material mat)
        {
            StringBuilder stream = new StringBuilder();

            // Shader Header
            stream.AppendLine("#version 330 core");
            stream.AppendLine();

            // Input Format
            stream.AppendLine("// Input");
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Position))
            {
                stream.AppendLine("in vec3 RawPosition;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Normal))
            {
                stream.AppendLine("in vec3 RawNormal;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Color0))
            {
                stream.AppendLine("in vec4 RawColor0;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Color1))
            {
                stream.AppendLine("in vec4 RawColor1;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Tex0))
            {
                stream.AppendLine("in vec2 RawTex0;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Tex1))
            {
                stream.AppendLine("in vec2 RawTex1;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Tex2))
            {
                stream.AppendLine("in vec2 RawTex2;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Tex3))
            {
                stream.AppendLine("in vec2 RawTex3;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Tex4))
            {
                stream.AppendLine("in vec2 RawTex4;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Tex5))
            {
                stream.AppendLine("in vec2 RawTex5;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Tex6))
            {
                stream.AppendLine("in vec2 RawTex6;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Tex7))
            {
                stream.AppendLine("in vec2 RawTex7;");
            }

            stream.AppendLine();

            // Output Format
            stream.AppendLine("// Output");
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Normal))
            {
                stream.AppendLine("out vec3 Normal;");
            }

            for (int i = 0; i < mat.NumChannelControls; i++)
            {
                stream.AppendLine(string.Format("out vec4 Color{0};", i));
            }

            for (int texGen = 0; texGen < mat.NumTexGens; texGen++)
            {
                if (mat.TexGenInfos[texGen] != null)
                {
                    stream.AppendLine(string.Format("out vec3 Tex{0};", texGen));
                }
            }

            // Uniforms
            stream.AppendLine();
            stream.AppendLine("// Uniforms");
            stream.AppendLine(
                "   uniform mat4 ModelMtx;\n" +
                "   uniform mat4 ViewMtx;\n" +
                "   uniform mat4 ProjMtx;\n" +
                "\n" +

                "   uniform mat4 TexMtx[10];\n" +
                "   uniform mat4 PostMtx[20];\n" +
                "   uniform vec4 COLOR0_Amb;\n" +
                "   uniform vec4 COLOR0_Mat;\n" +
                "   uniform vec4 COLOR1_Amb;\n" +
                "   uniform vec4 COLOR1_Mat;\n" +
                "\n" +
                "struct GXLight\n" +
                "{\n" +
                "   vec4 Position;\n" +
                "   vec4 Direction;\n" +
                "   vec4 Color;\n" +
                "   vec4 DistAtten;\n" +
                "   vec4 AngleAtten;\n" +
                "};\n" +
                "\n" +

                "   GXLight Lights[8];\n" +
                "\n" +
                "uniform int NumLights;\n" +
                "uniform vec4 ambLightColor;\n");

            // Main Shader Code
            stream.AppendLine("// Main");
            stream.AppendLine("void main()");
            stream.AppendLine("{");
            stream.AppendLine("    mat4 MVP = ProjMtx * ViewMtx * ModelMtx;");
            stream.AppendLine("    mat4 MV = ViewMtx * ModelMtx;");

            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Position))
            {
                stream.AppendLine("    gl_Position = MVP * vec4(RawPosition, 1);");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Normal))
            {
                stream.AppendLine("    Normal = normalize(RawNormal.xyz * inverse(transpose(mat3(MV))));");
            }
            //if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Color0))
            //  stream.AppendLine("    Color0 = RawColor0;");
            //if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Color1))
            //stream.AppendLine("    Color1 = RawColor1;");

            stream.AppendLine();
            stream.AppendLine("    // Ambient Colors & Material Colors");
            // Add the Ambient Colors for the Material
            for (int a = 0; a < mat.AmbientColors.Length; a++)
            {
                stream.AppendLine(string.Format("    vec4 ambColor{0} = vec4({1}, {2}, {3}, {4});", a, mat.AmbientColors[a].R, mat.AmbientColors[a].G, mat.AmbientColors[a].B, mat.AmbientColors[a].A));
            }

            // Add in the Material Colors
            for (int m = 0; m < mat.MaterialColors.Length; m++)
            {
                stream.AppendLine(string.Format("    vec4 matColor{0} = vec4({1}, {2}, {3}, {4});", m, mat.MaterialColors[m].R, mat.MaterialColors[m].G, mat.MaterialColors[m].B, mat.MaterialColors[m].A));
            }

            stream.AppendLine();
            stream.AppendLine(string.Format("    // ChanCtrl's - {0} count", mat.NumChannelControls));

            // Channel Controllers
            // A vertex can have up to two color channels (RGBA each) which gives us four possible channels:
            // color0, color1, alpha0, alpha1
            // Each channel has an associated ambient color/alpha and a material color/alpha. These can come
            // from vertex colors or existing amb/mat registers.
            for (int chanSel = 0; chanSel < mat.NumChannelControls; chanSel++)
            {
                ChanCtrl chanInfo = mat.ChannelControls[chanSel];
                string   chanTarget, ambColor, matColor, ambLight, diffLight;
                string   swizzle, chan;
                bool     alpha;

                // Todo: Is this really a fixed order?
                switch (chanSel)
                {
                case /* Color0 */ 0: chan = "0"; swizzle = ".rgb"; alpha = false; break;

                case /* Alpha0 */ 1: chan = "0"; swizzle = ".a"; alpha = true; break;

                case /* Color1 */ 2: chan = "1"; swizzle = ".rgb"; alpha = false; break;

                case /* Alpha1 */ 3: chan = "1"; swizzle = ".a"; alpha = true; break;

                default:
                    WLog.Warning(LogCategory.TEVShaderGenerator, shader, "Unknown vertex output color channel {0}, skipping.", chanSel);
                    continue;
                }

                chanTarget = string.Format("Color{0}{1}", chan, swizzle);
                ambColor   = (chanInfo.AmbientSrc == GXColorSrc.Vertex ? "RawColor" : "ambColor") + chan + swizzle;
                matColor   = (chanInfo.MaterialSrc == GXColorSrc.Vertex ? "RawColor" : "matColor") + chan + swizzle;
                ambLight   = "ambLightColor" + swizzle;
                diffLight  = GetLightCalcString(chanInfo, alpha);

                //Color{0}.rgb = ambient * ambLightColor * light
                stream.AppendLine(string.Format("    Color{0} = vec4(1, 1, 1, 1);", chan));
                if (chanInfo.Enable)
                {
                    stream.AppendLine(string.Format("    {0} = {1} * {2} + {3} * {4};", chanTarget, ambColor, ambLight, matColor, diffLight));
                }
                else
                {
                    stream.AppendLine(string.Format("    {0} = {1};", chanTarget, matColor));
                }

                stream.AppendLine();
                stream.AppendLine();
            }


            // Texture Coordinate Generation
            stream.AppendLine(string.Format("    // TexGen - {0} count", mat.NumTexGens));
            for (int i = 0; i < mat.NumTexGens; i++)
            {
                if (mat.TexGenInfos[i] == null)
                {
                    continue;
                }

                TexCoordGen texGen = mat.TexGenInfos[i];
                string      texGenSrc;

                switch (texGen.Source)
                {
                case GXTexGenSrc.Position: texGenSrc = "RawPosition"; break;

                case GXTexGenSrc.Normal: texGenSrc = "RawNormal"; break;

                case GXTexGenSrc.Color0: texGenSrc = "Color0"; break;

                case GXTexGenSrc.Color1: texGenSrc = "Color1"; break;

                case GXTexGenSrc.Tex0: texGenSrc = "RawTex0"; break;     // Should Tex0 be TEXTURE 0? Or is it TEX0 = Input TEX0, while TEXCOORD0 = Output TEX0?

                case GXTexGenSrc.Tex1: texGenSrc = "RawTex1"; break;

                case GXTexGenSrc.Tex2: texGenSrc = "RawTex2"; break;

                case GXTexGenSrc.Tex3: texGenSrc = "RawTex3"; break;

                case GXTexGenSrc.Tex4: texGenSrc = "RawTex4"; break;

                case GXTexGenSrc.Tex5: texGenSrc = "RawTex5"; break;

                case GXTexGenSrc.Tex6: texGenSrc = "RawTex6"; break;

                case GXTexGenSrc.Tex7: texGenSrc = "RawTex7"; break;

                case GXTexGenSrc.TexCoord0: texGenSrc = "Tex0"; break;

                case GXTexGenSrc.TexCoord1: texGenSrc = "Tex1"; break;

                case GXTexGenSrc.TexCoord2: texGenSrc = "Tex2"; break;

                case GXTexGenSrc.TexCoord3: texGenSrc = "Tex3"; break;

                case GXTexGenSrc.TexCoord4: texGenSrc = "Tex4"; break;

                case GXTexGenSrc.TexCoord5: texGenSrc = "Tex5"; break;

                case GXTexGenSrc.TexCoord6: texGenSrc = "Tex6"; break;

                case GXTexGenSrc.Tangent:
                case GXTexGenSrc.Binormal:
                default:
                    WLog.Warning(LogCategory.TEVShaderGenerator, shader, "Unsupported TexGenSrc: {0}, defaulting to TEXCOORD0.", texGen.Source);
                    texGenSrc = "Tex0";
                    break;
                }

                if (texGen.TexMatrixSource == GXTexMatrix.Identity)
                {
                    switch (texGen.Type)
                    {
                    case GXTexGenType.Matrix2x4:
                        stream.AppendLine(string.Format("    Tex{0} = vec3({1}.xy, 0);", i, texGenSrc));
                        break;

                    case GXTexGenType.Matrix3x4:
                        stream.AppendLine(string.Format("    float3 uvw = {0}.xyz;", texGenSrc));
                        stream.AppendLine(string.Format("    Tex{0} = vec3((uvw / uvw.z).xy,0);", i));
                        break;

                    case GXTexGenType.SRTG:
                        stream.AppendLine(string.Format("    Tex{0} = vec3({1}.rg, 0);", i, texGenSrc));
                        break;

                    case GXTexGenType.Bump0:
                    case GXTexGenType.Bump1:
                    case GXTexGenType.Bump2:
                    case GXTexGenType.Bump3:
                    case GXTexGenType.Bump4:
                    case GXTexGenType.Bump5:
                    case GXTexGenType.Bump6:
                    case GXTexGenType.Bump7:
                    default:
                        WLog.Warning(LogCategory.TEVShaderGenerator, shader, "Unsupported TexMatrixSource: {0}, Defaulting to Matrix2x4", texGen.TexMatrixSource);
                        stream.AppendLine(string.Format("    Tex{0} = vec3({1}.xy, 0);", i, texGenSrc));
                        break;
                    }
                }
                else
                {
                    // Convert to TexMtx0 to TexMtx9
                    int matIndex = ((int)texGen.TexMatrixSource - 30) / 3;
                    switch (texGen.Type)
                    {
                    default:
                        WLog.Warning(LogCategory.TEVShaderGenerator, shader, "Unsupported TexMatrixSource");
                        break;
                    }
                }
            }

            stream.AppendLine("}");
            stream.AppendLine();

            // Compile the Vertex Shader and return whether it compiled sucesfully or not.
            Directory.CreateDirectory("ShaderDump");
            System.IO.File.WriteAllText("ShaderDump/" + mat.Name + "_vert_output", stream.ToString());
            return(shader.CompileSource(stream.ToString(), OpenTK.Graphics.OpenGL.ShaderType.VertexShader));
        }
Beispiel #8
0
        private void GenerateTexGenXFCommands(Material mat)
        {
            XFCommand texGensCommand   = new XFCommand(XFRegister.SETTEXMTXINFO);
            XFCommand dtTexGensCommand = new XFCommand(XFRegister.SETPOSMTXINFO);

            for (int i = 0; i < 8; i++)
            {
                if (mat.TexCoord1Gens[i] == null)
                {
                    continue;
                }
                TexCoordGen texgen = mat.TexCoord1Gens[i].Value;

                XFCommandArgument texGenArg = new XFCommandArgument();
                texGenArg.SetBits(0, 1, 1);
                texGenArg.SetBits(0, 2, 1);
                texGenArg.SetBits(5, 12, 3);
                texGenArg.SetBits(0, 15, 3);

                if (texgen.Type == TexGenType.Matrix3x4)
                {
                    texGenArg.SetFlag(true, 1);
                }
                switch (texgen.Source)
                {
                case TexGenSrc.Position:
                case TexGenSrc.Normal:
                case TexGenSrc.Binormal:
                case TexGenSrc.Tangent:
                    texGenArg.SetFlag(true, 2);
                    break;
                }
                switch (texgen.Type)
                {
                case TexGenType.Bump0:
                case TexGenType.Bump1:
                case TexGenType.Bump2:
                case TexGenType.Bump3:
                case TexGenType.Bump4:
                case TexGenType.Bump5:
                case TexGenType.Bump6:
                case TexGenType.Bump7:
                    texGenArg.SetBits(1, 4, 2);
                    texGenArg.SetBits(texgen.Source - TexGenSrc.Tex0, 12, 3);
                    texGenArg.SetBits(texgen.Type - TexGenType.Bump0, 15, 3);
                    texGenArg.SetBits(5, 7, 3);
                    break;

                case TexGenType.SRTG:
                    texGenArg.SetBits(2, 7, 3);
                    if (texgen.Source == TexGenSrc.Color0)
                    {
                        texGenArg.SetBits(2, 4, 2);
                    }
                    else if (texgen.Source == TexGenSrc.Color1)
                    {
                        texGenArg.SetBits(3, 4, 2);
                    }
                    break;

                default:
                    texGenArg.SetBits(0, 4, 2);
                    if (texgen.Source == TexGenSrc.Position || texgen.Source == TexGenSrc.Normal)
                    {
                        texGenArg.SetBits((int)texgen.Source, 7, 3);
                    }
                    else
                    {
                        texGenArg.SetBits((int)texgen.Source + 1, 7, 3);
                    }
                    break;
                }

                XFCommandArgument dtTexGenArg = new XFCommandArgument();

                dtTexGenArg.SetFlag(false, 8);
                dtTexGenArg.SetBits(61, 0, 6);

                texGensCommand.Args.Add(texGenArg);
                dtTexGensCommand.Args.Add(dtTexGenArg);
            }

            if (texGensCommand.Args.Count > 0)
            {
                XFCommands.Add(texGensCommand);
                XFCommands.Add(dtTexGensCommand);
            }
        }
Beispiel #9
0
                public Material(ref BinaryStream s)
                {
                    name = Encoding.ASCII.GetString(s.ReadBytes(28)).Replace("\0", "");

                    flag    = s.ReadUInt32();
                    unknown = s.ReadUInt32();

                    byte[] black = s.ReadBytes(4), white = s.ReadBytes(4);
                    blackColor = Color.FromArgb(black[3], black[0], black[1], black[2]);
                    whiteColor = Color.FromArgb(white[3], white[0], black[1], black[2]);

                    texMapCount                    = (uint)(flag & 0x03);
                    texSRTCount                    = (uint)((flag >> 2) & 0x03);
                    texCoordGenCount               = (uint)((flag >> 4) & 0x03);
                    tevStageCount                  = (uint)((flag >> 6) & 0x07);
                    hasAlphaCompare                = ((flag >> 9) & 0x01) == 1;
                    hasBlendMode                   = ((flag >> 10) & 0x01) == 1;
                    useTextureOnly                 = ((flag >> 11) & 0x01) == 1;
                    seperateBlendMode              = ((flag >> 12) & 0x01) == 1;
                    hasIndirectParameter           = ((flag >> 14) & 0x01) == 1;
                    projectionTexGenParameterCount = (uint)((flag >> 15) & 0x03);
                    hasFontShadowParameter         = ((flag >> 17) & 0x01) == 1;
                    thresholingAlphaInterpolation  = ((flag >> 18) & 0x01) == 1;

                    texMaps = new TexMap[texMapCount];
                    for (int i = 0; i < texMapCount; i++)
                    {
                        texMaps[i] = new TexMap(ref s);
                    }

                    texSRTs = new TexSRT[texSRTCount];
                    for (int i = 0; i < texSRTCount; i++)
                    {
                        texSRTs[i] = new TexSRT(ref s);
                    }

                    texCoords = new TexCoordGen[texCoordGenCount];
                    for (int i = 0; i < texCoordGenCount; i++)
                    {
                        texCoords[i] = new TexCoordGen(ref s);
                    }

                    tevStages = new TevStage[tevStageCount];
                    for (int i = 0; i < tevStageCount; i++)
                    {
                        tevStages[i] = new TevStage(ref s);
                    }

                    if (hasAlphaCompare)
                    {
                        alphaCompare = new AlphaCompare(ref s);
                    }

                    if (hasBlendMode)
                    {
                        blendMode = new BlendMode(ref s);
                    }

                    if (seperateBlendMode)
                    {
                        blendAlpha = new BlendMode(ref s);
                    }

                    if (hasIndirectParameter)
                    {
                        indirectParameter = new IndirectParameter(ref s);
                    }

                    projectionTexGenParameters = new ProjectionTexGenParameters[projectionTexGenParameterCount];
                    for (int i = 0; i < projectionTexGenParameterCount; i++)
                    {
                        projectionTexGenParameters[i] = new ProjectionTexGenParameters(ref s);
                    }

                    if (hasFontShadowParameter)
                    {
                        fontShadowParameter = new FontShadowParameter(ref s);
                    }

                    //System.Windows.Forms.MessageBox.Show($"[{s.BaseStream.Position}] mat end");
                }
Beispiel #10
0
        public static string GenerateVertexShader(Material mat, MAT3 data)
        {
            StringBuilder stream = new StringBuilder();

            // Shader Header
            stream.AppendLine("// Automatically Generated File. All changes will be lost.");
            stream.AppendLine("#version 330 core");
            stream.AppendLine();

            // Examine the attributes the mesh has so we can ensure the shader knows about the incoming data.
            // I don't think this is technically right, but meh.
            stream.AppendLine("// Per-Vertex Input");
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Position))
            {
                stream.AppendLine("in vec3 RawPosition;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Normal))
            {
                stream.AppendLine("in vec3 RawNormal;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Color0))
            {
                stream.AppendLine("in vec4 RawColor0;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Color1))
            {
                stream.AppendLine("in vec4 RawColor1;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Tex0))
            {
                stream.AppendLine("in vec2 RawTex0;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Tex1))
            {
                stream.AppendLine("in vec2 RawTex1;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Tex2))
            {
                stream.AppendLine("in vec2 RawTex2;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Tex3))
            {
                stream.AppendLine("in vec2 RawTex3;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Tex4))
            {
                stream.AppendLine("in vec2 RawTex4;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Tex5))
            {
                stream.AppendLine("in vec2 RawTex5;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Tex6))
            {
                stream.AppendLine("in vec2 RawTex6;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Tex7))
            {
                stream.AppendLine("in vec2 RawTex7;");
            }
            stream.AppendLine();

            stream.AppendLine("// Output (Interpolated)");
            stream.AppendLine();

            // TEV uses up to 4 channels to accumulate the result of Per-Vertex Lighting/Material/Ambient lighting.
            // Color0, Alpha0, Color1, and Alpha1 are the four possible channel names.
            stream.AppendFormat("// NumChannelControls: {0}\n", mat.NumChannelControls);
            stream.AppendFormat("out vec4 colors_0;\n");
            stream.AppendFormat("out vec4 colors_1;\n");
            stream.AppendLine();

            // TEV can generate up to 16 (?) sets of Texture Coordinates by taking an incoming data value (UV, POS, NRM, BINRM, TNGT) and transforming it by a matrix.
            stream.AppendFormat("// NumTexGens: {0}\n", mat.NumTexGensIndex);
            for (int i = 0; i < mat.NumTexGensIndex; i++)
            {
                stream.AppendFormat("out vec3 TexGen{0};\n", i);
            }
            stream.AppendLine();

            // Declare shader Uniforms coming in from the CPU.
            stream.AppendLine("// Uniforms");
            stream.AppendLine
            (
                "uniform mat4 ModelMtx;\n" +
                "uniform mat4 ViewMtx;\n" +
                "uniform mat4 ProjMtx;\n" +
                "\n" +
                "uniform mat4 TexMtx[10];\n" +
                "uniform mat4 PostMtx[20];\n" +
                "uniform vec4 COLOR0_Amb;\n" +
                "uniform vec4 COLOR0_Mat;\n" +
                "uniform vec4 COLOR1_Mat;\n" +
                "uniform vec4 COLOR1_Amb;\n" +
                "\n" +
                "struct GXLight\n" +
                "{\n" +
                "    vec4 Position;\n" +
                "    vec4 Direction;\n" +
                "    vec4 Color;\n" +
                "    vec4 CosAtten; //AngleAtten\n" + // 1.875000, 0, 0 ?
                "    vec4 DistAtten;\n" +             // 1.875000, 0, 0 ?
                "};\n" +
                "\n" +
                "layout(std140) uniform LightBlock\n" +
                "{\n\tGXLight Lights[8];\n};\n"
            );
            stream.AppendLine();

            // Main Shader Code
            stream.AppendLine("// Main Vertex Shader");
            stream.AppendLine("void main()\n{");
            stream.AppendLine("\tmat4 MVP = ProjMtx * ViewMtx * ModelMtx;");
            stream.AppendLine("\tmat4 MV = ViewMtx * ModelMtx;");
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Position))
            {
                stream.AppendLine("\tgl_Position = MVP * vec4(RawPosition, 1);");
                stream.AppendLine("\tvec4 worldPos = ModelMtx * vec4(RawPosition, 1);");
            }
            stream.AppendLine();

            // Do Color Channel Fixups
            if (mat.NumChannelControls < 2)
            {
                if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Color1))
                {
                    stream.AppendFormat("\tcolors_1 = RawColor1;\n");
                }
                else
                {
                    stream.AppendFormat("\tcolors_1 = vec4(1, 1, 1, 1);\n");
                }
            }

            stream.AppendLine();

            // TEV Channel Colors.
            // A vertex can have two colors each (Color0, Color1) and each color has two channels - RGB and A. This gives us
            // up to 4 channels, color0, color1, alpha0, and alpha1. Channels are associated with an ambient color/alpha which can
            // come from a variety of sources - vertex colors, or special ambient and material registers. The register colors
            // are set in GX via the command: GXSetChanAmbColor(GXChanneLID chan, GXColor amb_color), and GXSetChanMatColor(GXChannelID chan, GXColor mat_color);
            // Now, the source for each channel can be controlled by another command:
            // GXSetChanCtrl(GXCHannelID chan, bool enable, GXColorSrc amb_src, GXColorSrc mat_src, GXLightID light_mask, GXDiffuseFn diff_fn, GXAttnFn attn_fn);
            //
            // If the lighting channel is disabled, then the material color for that channel is passed through unmodified. The mat_src parameter specifies if the
            // material color comes from the Vertex Color, or from the Material Register. If the channel is enabled, then lighting needs to be computed for each light
            // enabled in the light_mask.
            stream.AppendLine("\tvec4 ambColor = vec4(1,1,1,1);\n\tvec4 matColor = vec4(1,1,1,1);\n\tvec4 lightAccum = vec4(0,0,0,0);\n\tvec4 lightFunc;");
            stream.AppendLine("\tvec3 ldir; float dist; float dist2; float attn;"); // Declaring these all anyways in case we use lighting.

            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Normal))
            {
                stream.AppendLine("\tvec3 _norm0 = RawNormal.xyz;");
            }
            else
            {
                stream.AppendLine("\tvec3 _norm0 = vec3(0.0, 0.0, 0.0);");
            }


            stream.AppendFormat("\t// {0} Channel Controller(s).\n", mat.NumChannelControls);
            for (int i = 0; i < mat.NumChannelControls; i++)
            {
                ColorChannelControl channelControl = mat.ColorChannelControls[i];
                stream.AppendFormat("\t// Channel Control: {0} - LightingEnabled: {1} MaterialSrc: {2} LightMask: {3} DiffuseFn: {4} AttenuationFn: {5} AmbientSrc: {6}\n",
                                    i, channelControl.LightingEnabled, channelControl.MaterialSrc, channelControl.LitMask, channelControl.DiffuseFunction, channelControl.AttenuationFunction, channelControl.AmbientSrc);

                string swizzle, channel;
                switch (i)
                {
                case /* Color0 */ 0: channel = "0"; swizzle = ".rgb"; break;

                case /* Alpha0 */ 1: channel = "0"; swizzle = ".a"; break;

                case /* Color1 */ 2: channel = "1"; swizzle = ".rgb"; break;

                case /* Alpha1 */ 3: channel = "1"; swizzle = ".a"; break;     // ToDo: This is wrong. There's a maximum of 2 color channels

                default: Console.WriteLine("Unknown Color Channel Control Index: {0}", i); continue;
                }

                bool   isAlphaChannel = i % 2 != 0;
                string channelTarget  = string.Format("colors_{0}", channel);
                bool   ambSrcVtx      = channelControl.AmbientSrc == GXColorSrc.Vertex;
                bool   matSrcVtx      = channelControl.MaterialSrc == GXColorSrc.Vertex;
                string ambColorSrc    = string.Format("{0}{1}", (ambSrcVtx ? "RawColor" : "COLOR"), channel + (ambSrcVtx ? "" : "_Amb"));
                string matColorSrc    = string.Format("{0}{1}", (matSrcVtx ? "RawColor" : "COLOR"), channel + (matSrcVtx ? "" : "_Mat"));

                stream.AppendFormat("\tambColor = {0};\n", ambColorSrc);
                stream.AppendFormat("\tmatColor = {0};\n", matColorSrc);

                for (int l = 0; l < 8; l++)
                {
                    bool isLit = channelControl.LitMask.HasFlag((GXLightMask)(1 << l));
                    if (isLit)
                    {
                        stream.AppendFormat("\t// ChannelControl: {0} Light: {1}\n", i, l);
                        GenerateLightVertexShader(stream, channelControl, l, swizzle, isAlphaChannel ? 1 : 3);
                    }
                }

                if (channelControl.LightingEnabled)
                {
                    stream.AppendLine("\tvec4 illum = clamp(ambColor + lightAccum, 0, 1);");
                }
                stream.AppendFormat("\tlightFunc = {0};\n", channelControl.LightingEnabled ? "illum" : "vec4(1.0, 1.0, 1.0, 1.0)");
                stream.AppendFormat("\t{0}{1} = (matColor * lightFunc){1};\n", channelTarget, swizzle);

                // Not sure if this is right, but if a single color channel is enabled then the alpha component of color_0 never gets assigned
                // and then something tries to use it and it's empty instead of being the ambSrc/matSrc alpha.
                if (mat.NumChannelControls == 1 || mat.NumChannelControls == 3)
                {
                    // ToDo: https://github.com/dolphin-emu/dolphin/blob/master/Source/Core/VideoCommon/LightingShaderGen.h#L184 looks like a better implementation
                    stream.AppendLine("\t// Doing an unknown fixup. There's only one color channel enabled, so we never write to the alpha of the color_*, and thus it never gets initialized.");
                    stream.AppendFormat("\t{0}.a = matColor.a;\n", channelTarget);
                }
            }



            // TEV "TexGen" Texture Coordinate Generation
            // TEV can generate texture coordinates on the fly from a variety of sources. The various ways all follow the form of:
            // dst_coord = func(src_param, mtx) - that is, the destination coordinate is generated by multiplying an input source by a 2x4 or 3x4 matrix.
            // The input coordinates can come from one of the following locations: TEX0-7, POS, NRM, BINRM, TANGENT.
            // GX has a default set of texture matrices (GXTexMtx enum).
            stream.AppendFormat("\t// {0} Texture Coordinate Generators.\n", mat.NumTexGensIndex);
            stream.Append("\tvec4 coord;\n");
            for (int i = 0; i < mat.NumTexGensIndex; i++)
            {
                TexCoordGen texGen = mat.TexGenInfoIndexes[i];
                stream.AppendFormat("\t// TexGen: {0} Type: {1} Source: {2} TexMatrixIndex: {3}\n", i, texGen.Type, texGen.Source, texGen.TexMatrixSource);
                stream.AppendLine("\t{"); // False scope block so we can re-declare variables

                string texGenSource;
                switch (texGen.Source)
                {
                case GXTexGenSrc.Position: texGenSource = "vec4(RawPosition.xyz, 1.0)"; break;

                case GXTexGenSrc.Normal: texGenSource = "vec4(_norm0.xyz, 1.0)"; break;

                case GXTexGenSrc.Color0: texGenSource = "colors_0"; break;

                case GXTexGenSrc.Color1: texGenSource = "colors_1"; break;

                case GXTexGenSrc.Binormal: texGenSource = "vec4(RawBinormal.xyz, 1.0)"; break;

                case GXTexGenSrc.Tangent: texGenSource = "vec4(RawTangent.xyz, 1.0)"; break;

                case GXTexGenSrc.Tex0:
                case GXTexGenSrc.Tex1:
                case GXTexGenSrc.Tex2:
                case GXTexGenSrc.Tex3:
                case GXTexGenSrc.Tex4:
                case GXTexGenSrc.Tex5:
                case GXTexGenSrc.Tex6:
                case GXTexGenSrc.Tex7:
                    texGenSource = string.Format("vec4(RawTex{0}.xy, 1.0, 1.0)", ((int)texGen.Source - (int)GXTexGenSrc.Tex0)); break;

                // This implies using a texture coordinate set already generated by TEV.
                case GXTexGenSrc.TexCoord0:
                case GXTexGenSrc.TexCoord1:
                case GXTexGenSrc.TexCoord2:
                case GXTexGenSrc.TexCoord3:
                case GXTexGenSrc.TexCoord4:
                case GXTexGenSrc.TexCoord5:
                case GXTexGenSrc.TexCoord6:
                    texGenSource = string.Format("vec4(TexGen{0}.xy, 1.0, 1.0)", ((int)texGen.Source - (int)GXTexGenSrc.TexCoord0)); break;

                default: Console.WriteLine("Unsupported TexGenSrc: {0}, defaulting to TexCoord0.", texGen.Source); texGenSource = "RawTex0"; break;
                }
                stream.AppendFormat("\t\tcoord = {0};\n", texGenSource);

                TexMatrixProjection matrixProj = TexMatrixProjection.TexProj_ST;
                if (texGen.TexMatrixSource != GXTexMatrix.Identity)
                {
                    matrixProj = mat.TexMatrixIndexes[(((int)texGen.TexMatrixSource) - 30) / 3].Projection;
                }

                // TEV Texture Coordinate generation takes the general form:
                // dst_coord = func(src_param, mtx), where func is GXTexGenType, src_param is GXTexGenSrc, and mtx is GXTexMtx.
                string destCoord = string.Format("TexGen{0}", i);
                switch (texGen.Type)
                {
                case GXTexGenType.Matrix3x4:
                case GXTexGenType.Matrix2x4:
                    //if(mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.TexMtxId))
                    //{
                    //    stream.AppendFormat("int temp = {0}.z\n", destCoord);
                    //    if (texMtx.Projection == TexMatrixProjection.TexProj_STQ)
                    //        stream.AppendFormat("{0}.xyz = vec3(dot({1}, TexMtx[temp]), dot({1}, TexMtx[temp+1]), dot({1}, TexMtx[temp+2]));\n", destCoord, texGenSource);
                    //    else
                    //        stream.AppendFormat("{0}.xyz = vec3(dot({1}, TexMtx[temp]), dot({1}, TexMtx[temp+1]), 1);\n", destCoord, texGenSource);
                    //}
                    //else
                {
                    if (texGen.TexMatrixSource != GXTexMatrix.Identity)
                    {
                        if (matrixProj == TexMatrixProjection.TexProj_STQ)
                        {
                            stream.AppendFormat("\t\t{0}.xyz = vec3(dot(coord, TexMtx[{1}][0]), dot(coord, TexMtx[{1}][1]), dot(coord, TexMtx[{1}][2]));\n", destCoord, i);         //3x4
                        }
                        else
                        {
                            stream.AppendFormat("\t\t{0}.xyz = vec3(dot(coord, TexMtx[{1}][0]), dot(coord, TexMtxs[{1}][1]), 1);\n", destCoord, i);         //2x4
                        }
                    }
                    else
                    {
                        stream.AppendFormat("\t\t{0} = coord.xyz;\n", destCoord);
                    }
                }
                break;

                case GXTexGenType.SRTG:
                    stream.AppendFormat("\t{0} = vec3({1}.rg, 1);\n", destCoord, texGenSource); break;

                case GXTexGenType.Bump0:
                case GXTexGenType.Bump1:
                case GXTexGenType.Bump2:
                case GXTexGenType.Bump3:
                case GXTexGenType.Bump4:
                case GXTexGenType.Bump5:
                case GXTexGenType.Bump6:
                case GXTexGenType.Bump7:
                // Transform the light dir into tangent space.
                // ldir = normalize(Lights[{0}.Position.xyz - RawPosition.xyz);\n {0} = "texInfo.embosslightshift";
                // destCoord = TexGen{0} + float3(dot(ldir, _norm0), dot(ldir, RawBinormal), 0.0);\n", {0} = i, {1} = "texInfo.embosssourceshift";
                default:
                    Console.WriteLine("Unsupported TexGenType: {0}", texGen.Type); break;
                }

                // Dual Tex Transforms
                if (mat.PostTexMatrixIndexes.Length > 0)
                {
                    //TexMatrix postTexMtx = mat.PostTexMatrixIndexes
                    // ToDo: Should this just be... i? lol
                    Console.WriteLine("PostMtx transforms are... not really anything supported?");
                    //TexMatrix postTexMtx = mat.PostTexMatrixIndexes[((int)texGen.TexMatrixSource) - 30];
                    //int postIndex = postTexMtx. mat.PostTexMatrixIndexes[i];
                    //stream.AppendFormat("float4 P0 = PostMtx[{0}];\n", postIndex);
                    //stream.AppendFormat("float4 P1 = PostMtx[{0}];\n", postIndex + 1);
                    //stream.AppendFormat("float4 P2 = PostMtx[{0}];\n", postIndex + 2);

                    //stream.AppendFormat("{0}.xyz = vec3(dot(P0.xyz, {0}.xyz) + P0.w, dot(P1.xyz, {0}.xyz) + P1.w, dot(P2.xyz, {0}.xyz) + P2.w);\n", destCoord);
                }

                stream.AppendLine("\t}"); // End of false-scope block.
            }

            // Append the tail end of our shader file.
            stream.AppendLine("}");
            stream.AppendLine();
            return(stream.ToString());
        }