Ejemplo n.º 1
0
        public BmdFixedFunctionMaterial(
            IMaterialManager materialManager,
            int materialEntryIndex,
            BMD bmd,
            IList <BmdTexture> tex1Textures)
        {
            // TODO: materialEntry.Flag determines draw order

            var materialEntry = bmd.MAT3.MaterialEntries[materialEntryIndex];
            var materialName  = bmd.MAT3.MaterialNameTable[materialEntryIndex];

            var populatedMaterial = bmd.MAT3.PopulatedMaterials[materialEntryIndex];

            var textures =
                populatedMaterial.TextureIndices
                .Select(i => i != -1 ? tex1Textures[i] : null)
                .ToArray();

            var material = materialManager.AddFixedFunctionMaterial();

            material.Name        = materialName;
            material.CullingMode =
                bmd.MAT3.CullModes[materialEntry.CullModeIndex] switch {
                BMD.CullMode.None => CullingMode.SHOW_BOTH,
                BMD.CullMode.Front => CullingMode.SHOW_BACK_ONLY,
                BMD.CullMode.Back => CullingMode.SHOW_FRONT_ONLY,
                BMD.CullMode.All => CullingMode.SHOW_NEITHER,
                _ => throw new ArgumentOutOfRangeException(),
            };

            material.SetBlending(
                ConvertBmdBlendModeToFin(populatedMaterial.BlendMode.BlendMode),
                ConvertBmdBlendFactorToFin(populatedMaterial.BlendMode.SrcFactor),
                ConvertBmdBlendFactorToFin(populatedMaterial.BlendMode.DstFactor),
                ConvertBmdLogicOpToFin(populatedMaterial.BlendMode.LogicOp));

            material.SetAlphaCompare(
                ConvertBmdAlphaOpToFin(populatedMaterial.AlphaCompare.MergeFunc),
                ConvertBmdAlphaCompareTypeToFin(populatedMaterial.AlphaCompare.Func0),
                populatedMaterial.AlphaCompare.Reference0 / 255f,
                ConvertBmdAlphaCompareTypeToFin(populatedMaterial.AlphaCompare.Func1),
                populatedMaterial.AlphaCompare.Reference1 / 255f);

            this.Material = material;

            var colorConstants = new List <Color>();

            // TODO: Need to use material entry indices

            var equations = material.Equations;

            var colorZero = equations.CreateColorConstant(0);

            var scZero      = equations.CreateScalarConstant(0);
            var scOne       = equations.CreateScalarConstant(1);
            var scTwo       = equations.CreateScalarConstant(2);
            var scFour      = equations.CreateScalarConstant(4);
            var scHalf      = equations.CreateScalarConstant(.5);
            var scMinusHalf = equations.CreateScalarConstant(-.5);

            var colorFixedFunctionOps  = new ColorFixedFunctionOps(equations);
            var scalarFixedFunctionOps = new ScalarFixedFunctionOps(equations);

            var valueManager = new ValueManager(equations);

            // TODO: Where are color constants set inside the materials?
            // TODO: Need to support registers
            // TODO: Need to support multiple vertex colors
            // TODO: Colors should just be RGB in the fixed function library
            // TODO: Seems like only texture 1 is used, is this accurate?

            // TODO: This might need to be TevKonstColorIndexes
            valueManager.SetColorRegisters(
                materialEntry.TevColorIndexes.Take(4)
                .Select(
                    tevColorIndex => bmd.MAT3.ColorS10[tevColorIndex])
                .ToArray());

            var konstColors =
                materialEntry.TevKonstColorIndexes
                .Take(4)
                .Select(konstIndex => bmd.MAT3.Color3[konstIndex])
                .ToArray();

            valueManager.SetKonstColors(konstColors);

            for (var i = 0; i < materialEntry.TevStageInfoIndexes.Length; ++i)
            {
                var tevStageIndex = materialEntry.TevStageInfoIndexes[i];
                if (tevStageIndex == -1)
                {
                    continue;
                }

                var tevStage = bmd.MAT3.TevStages[tevStageIndex];

                var tevOrderIndex = materialEntry.TevOrderInfoIndexes[i];
                var tevOrder      = bmd.MAT3.TevOrders[tevOrderIndex];

                // Updates which texture is referred to by TEXC
                var textureIndex = tevOrder.TexMap;
                if (textureIndex == -1)
                {
                    valueManager.UpdateTextureColor(null);
                }
                else
                {
                    var bmdTexture = textures[textureIndex];

                    // TODO: Share texture definitions between materials?
                    var texture = materialManager.CreateTexture(bmdTexture.Image);

                    texture.Name      = bmdTexture.Name;
                    texture.WrapModeU = bmdTexture.WrapModeS;
                    texture.WrapModeV = bmdTexture.WrapModeT;
                    texture.ColorType = bmdTexture.ColorType;

                    var texCoordGen =
                        bmd.MAT3.TexCoordGens[
                            materialEntry.TexGenInfo[tevOrder.TexCoordId]];

                    var texGenSrc = texCoordGen.TexGenSrc;
                    switch (texGenSrc)
                    {
                    case >= GxTexGenSrc.Tex0 and <= GxTexGenSrc.Tex7: {
                        var texCoordIndex = texGenSrc - GxTexGenSrc.Tex0;
                        texture.UvIndex = texCoordIndex;
                        break;
                    }

                    case GxTexGenSrc.Normal: {
                        texture.UvType = UvType.LINEAR;
                        break;
                    }

                    default: {
                        //Asserts.Fail($"Unsupported texGenSrc type: {texGenSrc}");
                        texture.UvIndex = 0;
                        break;
                    }
                    }

                    valueManager.UpdateTextureColor(textureIndex);
                    material.SetTextureSource(textureIndex, texture);
                }

                // Updates which color is referred to by RASC
                var colorChannel = tevOrder.ColorChannelId;
                valueManager.UpdateRascColor(colorChannel);

                // Updates which values are referred to by konst
                valueManager.UpdateKonst(materialEntry.KonstColorSel[tevOrderIndex],
                                         materialEntry.KonstAlphaSel[tevOrderIndex]);

                // Set up color logic
                {
                    var colorA = valueManager.GetColor(tevStage.color_a);
                    var colorB = valueManager.GetColor(tevStage.color_b);
                    var colorC = valueManager.GetColor(tevStage.color_c);
                    var colorD = valueManager.GetColor(tevStage.color_d);

                    IColorValue?colorValue = null;

                    // TODO: Switch this to an enum
                    var colorOp = tevStage.color_op;
                    switch (colorOp)
                    {
                    // ADD: out = a*(1 - c) + b*c + d
                    case TevOp.GX_TEV_ADD:
                    case TevOp.GX_TEV_SUB: {
                        var bias = tevStage.color_bias switch {
                            TevBias.GX_TB_ZERO => null,
                            TevBias.GX_TB_ADDHALF => scHalf,
                            TevBias.GX_TB_SUBHALF => scMinusHalf,
                            _ => throw new ArgumentOutOfRangeException(
                                      "Unsupported color bias!")
                        };

                        var scale = tevStage.color_scale switch {
                            TevScale.GX_CS_SCALE_1 => scOne,
                            TevScale.GX_CS_SCALE_2 => scTwo,
                            TevScale.GX_CS_SCALE_4 => scFour,
                            TevScale.GX_CS_DIVIDE_2 => scHalf,
                            _ => throw new ArgumentOutOfRangeException(
                                      "Unsupported color scale!")
                        };

                        colorValue =
                            colorFixedFunctionOps.AddOrSubtractOp(
                                colorOp == TevOp.GX_TEV_ADD,
                                colorA,
                                colorB,
                                colorC,
                                colorD,
                                bias,
                                scale
                                );

                        colorValue ??= colorZero;
                        colorValue.Clamp = tevStage.color_clamp;

                        break;
                    }

                    default: {
                        if (BmdFixedFunctionMaterial.STRICT)
                        {
                            throw new NotImplementedException();
                        }
                        else
                        {
                            colorValue = colorC;
                        }
                        break;
                    }
                    }

                    valueManager.UpdateColorRegister(tevStage.color_regid, colorValue);

                    var colorAText =
                        new FixedFunctionEquationsPrettyPrinter <FixedFunctionSource>()
                        .Print(colorA);
                    var colorBText =
                        new FixedFunctionEquationsPrettyPrinter <FixedFunctionSource>()
                        .Print(colorB);
                    var colorCText =
                        new FixedFunctionEquationsPrettyPrinter <FixedFunctionSource>()
                        .Print(colorC);
                    var colorDText =
                        new FixedFunctionEquationsPrettyPrinter <FixedFunctionSource>()
                        .Print(colorD);

                    var colorValueText =
                        new FixedFunctionEquationsPrettyPrinter <FixedFunctionSource>()
                        .Print(colorValue);

                    ;
                }

                // Set up alpha logic
                {
                    var alphaA = valueManager.GetAlpha(tevStage.alpha_a);
                    var alphaB = valueManager.GetAlpha(tevStage.alpha_b);
                    var alphaC = valueManager.GetAlpha(tevStage.alpha_c);
                    var alphaD = valueManager.GetAlpha(tevStage.alpha_d);

                    IScalarValue?alphaValue = null;

                    // TODO: Switch this to an enum
                    var alphaOp = tevStage.alpha_op;
                    switch (alphaOp)
                    {
                    // ADD: out = a*(1 - c) + b*c + d
                    case TevOp.GX_TEV_ADD:
                    case TevOp.GX_TEV_SUB: {
                        var bias = tevStage.alpha_bias switch {
                            TevBias.GX_TB_ZERO => null,
                            TevBias.GX_TB_ADDHALF => scHalf,
                            TevBias.GX_TB_SUBHALF => scMinusHalf,
                            _ => throw new ArgumentOutOfRangeException(
                                      "Unsupported alpha bias!")
                        };

                        var scale = tevStage.alpha_scale switch {
                            TevScale.GX_CS_SCALE_1 => scOne,
                            TevScale.GX_CS_SCALE_2 => scTwo,
                            TevScale.GX_CS_SCALE_4 => scFour,
                            TevScale.GX_CS_DIVIDE_2 => scHalf,
                            _ => throw new ArgumentOutOfRangeException(
                                      "Unsupported alpha scale!")
                        };

                        alphaValue =
                            scalarFixedFunctionOps.AddOrSubtractOp(
                                alphaOp == TevOp.GX_TEV_ADD,
                                alphaA,
                                alphaB,
                                alphaC,
                                alphaD,
                                bias,
                                scale
                                );

                        alphaValue ??= scZero;
                        //alphaValue.Clamp = tevStage.alpha_clamp;

                        break;
                    }

                    default: {
                        if (BmdFixedFunctionMaterial.STRICT)
                        {
                            throw new NotImplementedException();
                        }
                        else
                        {
                            alphaValue = scZero;
                        }
                        break;
                    }
                    }

                    valueManager.UpdateAlphaRegister(tevStage.alpha_regid, alphaValue);

                    var alphaAText =
                        new FixedFunctionEquationsPrettyPrinter <FixedFunctionSource>()
                        .Print(alphaA);
                    var alphaBText =
                        new FixedFunctionEquationsPrettyPrinter <FixedFunctionSource>()
                        .Print(alphaB);
                    var alphaCText =
                        new FixedFunctionEquationsPrettyPrinter <FixedFunctionSource>()
                        .Print(alphaC);
                    var alphaDText =
                        new FixedFunctionEquationsPrettyPrinter <FixedFunctionSource>()
                        .Print(alphaD);

                    var alphaValueText =
                        new FixedFunctionEquationsPrettyPrinter <FixedFunctionSource>()
                        .Print(alphaValue);

                    ;
                }
            }

            equations.CreateColorOutput(
                FixedFunctionSource.OUTPUT_COLOR,
                valueManager.GetColor(GxCc.GX_CC_CPREV));

            equations.CreateScalarOutput(
                FixedFunctionSource.OUTPUT_ALPHA,
                valueManager.GetAlpha(GxCa.GX_CA_APREV));

            // TODO: Set up compiled texture
            // TODO: If only a const color, create a texture for that


            var sb = new StringBuilder();

            {
                using var os = new StringWriter(sb);

                // TODO: Print textures, colors

                new FixedFunctionEquationsPrettyPrinter <FixedFunctionSource>()
                .Print(os, equations);
            }

            var output = sb.ToString();

            var colorTextureCount =
                material.Textures.Count(
                    texture => texture.ColorType == ColorType.COLOR);

            // TODO: This is a bad assumption!
            if (colorTextureCount == 0 && colorConstants.Count > 0)
            {
                var colorConstant = colorConstants.Last();

                var intensityTexture = material.Textures
                                       .FirstOrDefault(
                    texture => texture.ColorType ==
                    ColorType.INTENSITY);
                if (intensityTexture != null)
                {
                    return;
                }

                var colorImage   = FinImage.Create1x1WithColor(colorConstant);
                var colorTexture = materialManager.CreateTexture(colorImage);
                material.CompiledTexture = colorTexture;
            }
        }
Ejemplo n.º 2
0
        public GlFixedFunctionMaterialShader(
            IFixedFunctionMaterial fixedFunctionMaterial)
        {
            this.Material = fixedFunctionMaterial;

            // TODO: Sometimes vertex colors are passed in from model, and sometimes they
            // represent lighting. How to tell the difference??

            var vertexShaderSrc = @"
# version 120

in vec2 in_uv0;

varying vec3 vertexNormal;
varying vec2 normalUv;
varying vec4 vertexColor0_;
varying vec4 vertexColor1_;
varying vec2 uv0;
varying vec2 uv1;
varying vec2 uv2;
varying vec2 uv3;

void main() {
    gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;
    vertexNormal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0)).xyz;
    normalUv = normalize(gl_ProjectionMatrix * gl_ModelViewMatrix * vec4(gl_Normal, 0)).xy;
    vertexColor0_ = vec4(0.5, 0.5, 0.5, 1);
    vertexColor1_ = vec4(0, 0, 0, 1);
    uv0 = gl_MultiTexCoord0.st;
    uv1 = gl_MultiTexCoord1.st;
    uv2 = gl_MultiTexCoord2.st;
    uv3 = gl_MultiTexCoord3.st;
}";

            var pretty =
                new FixedFunctionEquationsPrettyPrinter <FixedFunctionSource>()
                .Print(fixedFunctionMaterial.Equations);

            var fragmentShaderSrc =
                new FixedFunctionEquationsGlslPrinter(
                    fixedFunctionMaterial.TextureSources)
                .Print(fixedFunctionMaterial);

            this.impl_ =
                GlShaderProgram.FromShaders(vertexShaderSrc, fragmentShaderSrc);

            var finTextures = fixedFunctionMaterial.TextureSources;

            var nSupportedTextures = 8;

            this.textures_ = new List <GlTexture>();
            for (var i = 0; i < nSupportedTextures; ++i)
            {
                var finTexture = i < (finTextures?.Count ?? 0)
                             ? finTextures[i]
                             : null;

                this.textures_.Add(finTexture != null
                               ? new GlTexture(finTexture)
                               : GlMaterialConstants.NULL_WHITE_TEXTURE);
            }
        }