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; } }
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); } }