private void GenerateShaders(int matid) { CultureInfo forceusa = new CultureInfo("en-US"); string[] texgensrc = { "normalize(gl_Vertex)", "vec4(gl_Normal,1.0)", "argh", "argh", "gl_MultiTexCoord0", "gl_MultiTexCoord1", "gl_MultiTexCoord2", "gl_MultiTexCoord3", "gl_MultiTexCoord4", "gl_MultiTexCoord5", "gl_MultiTexCoord6", "gl_MultiTexCoord7" }; string[] outputregs = { "rprev", "r0", "r1", "r2" }; string[] c_inputregs = { "truncc3(rprev.rgb)", "truncc3(rprev.aaa)", "truncc3(r0.rgb)", "truncc3(r0.aaa)", "truncc3(r1.rgb)", "truncc3(r1.aaa)", "truncc3(r2.rgb)", "truncc3(r2.aaa)", "texcolor.rgb", "texcolor.aaa", "rascolor.rgb", "rascolor.aaa", "vec3(1.0,1.0,1.0)", "vec3(0.5,0.5,0.5)", "konst.rgb", "vec3(0.0,0.0,0.0)" }; string[] c_inputregsD = { "rprev.rgb", "rprev.aaa", "r0.rgb", "r0.aaa", "r1.rgb", "r1.aaa", "r2.rgb", "r2.aaa", "texcolor.rgb", "texcolor.aaa", "rascolor.rgb", "rascolor.aaa", "vec3(1.0,1.0,1.0)", "vec3(0.5,0.5,0.5)", "konst.rgb", "vec3(0.0,0.0,0.0)" }; string[] c_konstsel = { "vec3(1.0,1.0,1.0)", "vec3(0.875,0.875,0.875)", "vec3(0.75,0.75,0.75)", "vec3(0.625,0.625,0.625)", "vec3(0.5,0.5,0.5)", "vec3(0.375,0.375,0.375)", "vec3(0.25,0.25,0.25)", "vec3(0.125,0.125,0.125)", "", "", "", "", "k0.rgb", "k1.rgb", "k2.rgb", "k3.rgb", "k0.rrr", "k1.rrr", "k2.rrr", "k3.rrr", "k0.ggg", "k1.ggg", "k2.ggg", "k3.ggg", "k0.bbb", "k1.bbb", "k2.bbb", "k3.bbb", "k0.aaa", "k1.aaa", "k2.aaa", "k3.aaa" }; string[] a_inputregs = { "truncc1(rprev.a)", "truncc1(r0.a)", "truncc1(r1.a)", "truncc1(r2.a)", "texcolor.a", "rascolor.a", "konst.a", "0.0" }; string[] a_inputregsD = { "rprev.a", "r0.a", "r1.a", "r2.a", "texcolor.a", "rascolor.a", "konst.a", "0.0" }; string[] a_konstsel = { "1.0", "0.875", "0.75", "0.625", "0.5", "0.375", "0.25", "0.125", "", "", "", "", "", "", "", "", "k0.r", "k1.r", "k2.r", "k3.r", "k0.g", "k1.g", "k2.g", "k3.g", "k0.b", "k1.b", "k2.b", "k3.b", "k0.a", "k1.a", "k2.a", "k3.a" }; string[] tevbias = { "0.0", "0.5", "-0.5" }; string[] tevscale = { "1.0", "2.0", "4.0", "0.5" }; string[] alphacompare = { "{0} != {0}", "{0} < {1}", "{0} == {1}", "{0} <= {1}", "{0} > {1}", "{0} != {1}", "{0} >= {1}", "{0} == {0}" }; // string[] alphacombine = { "all(bvec2({0},{1}))", "any(bvec2({0},{1}))", "any(bvec2(all(bvec2({0},!{1})),all(bvec2(!{0},{1}))))", "any(bvec2(all(bvec2({0},{1})),all(bvec2(!{0},!{1}))))" }; string[] alphacombine = { "({0}) && ({1})", "({0}) || ({1})", "(({0}) && (!({1}))) || ((!({0})) && ({1}))", "(({0}) && ({1})) || ((!({0})) && (!({1})))" }; // yes, oldstyle shaders // I would use version 130 or above but there are certain // of their new designs I don't agree with. Namely, what's // up with removing texture coordinates. That's just plain // retarded. int success = 0; Bmd.Material mat = m_Model.Materials[matid]; StringBuilder vert = new StringBuilder(); vert.AppendLine("#version 120"); vert.AppendLine(""); vert.AppendLine("void main()"); vert.AppendLine("{"); vert.AppendLine(" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;"); vert.AppendLine(" gl_FrontColor = gl_Color;"); vert.AppendLine(" gl_FrontSecondaryColor = gl_SecondaryColor;"); for (int i = 0; i < mat.NumTexgens; i++) { //Ignore unknown texture sources. Modified 1/22/15 if (mat.TexGen[i].Src > texgensrc.Length) { continue; } /*if (mat.TexGen[i].Src == 1) vert.AppendFormat(" gl_TexCoord[{0}].st = gl_Normal.xy;\n", i); * else if (mat.TexGen[i].Src != 4 + i) throw new Exception("!texgen " + mat.TexGen[i].Src.ToString()); * else * vert.AppendFormat(" gl_TexCoord[{0}] = gl_MultiTexCoord{0};\n", i);*/ // TODO matrices vert.AppendFormat(" gl_TexCoord[{0}] = {1};\n", i, texgensrc[mat.TexGen[i].Src]); } vert.AppendLine("}"); int vertid = GL.CreateShader(ShaderType.VertexShader); m_Shaders[matid].VertexShader = vertid; GL.ShaderSource(vertid, vert.ToString()); GL.CompileShader(vertid); GL.GetShader(vertid, ShaderParameter.CompileStatus, out success); if (success == 0) { string log = GL.GetShaderInfoLog(vertid); throw new Exception("!Failed to compile vertex shader: " + log); // TODO: better error reporting/logging? } StringBuilder frag = new StringBuilder(); frag.AppendLine("#version 120"); frag.AppendLine(""); for (int i = 0; i < 8; i++) { if (mat.TexStages[i] == 0xFFFF) { continue; } frag.AppendLine("uniform sampler2D texture" + i.ToString() + ";"); } frag.AppendLine(""); frag.AppendLine("float truncc1(float c)"); frag.AppendLine("{"); frag.AppendLine(" return (c == 0.0) ? 0.0 : ((fract(c) == 0.0) ? 1.0 : fract(c));"); frag.AppendLine("}"); frag.AppendLine(""); frag.AppendLine("vec3 truncc3(vec3 c)"); frag.AppendLine("{"); frag.AppendLine(" return vec3(truncc1(c.r), truncc1(c.g), truncc1(c.b));"); frag.AppendLine("}"); frag.AppendLine(""); frag.AppendLine("void main()"); frag.AppendLine("{"); for (int i = 0; i < 4; i++) { int _i = (i == 0) ? 3 : i - 1; // ??? frag.AppendFormat(forceusa, " vec4 {0} = vec4({1}, {2}, {3}, {4});\n", outputregs[i], (float)mat.ColorS10[_i].R / 255f, (float)mat.ColorS10[_i].G / 255f, (float)mat.ColorS10[_i].B / 255f, (float)mat.ColorS10[_i].A / 255f); } for (int i = 0; i < 4; i++) { frag.AppendFormat(forceusa, " vec4 k{0} = vec4({1}, {2}, {3}, {4});\n", i, (float)mat.ConstColors[i].R / 255f, (float)mat.ConstColors[i].G / 255f, (float)mat.ConstColors[i].B / 255f, (float)mat.ConstColors[i].A / 255f); } frag.AppendLine(" vec4 texcolor, rascolor, konst;"); for (int i = 0; i < mat.NumTevStages; i++) { frag.AppendLine("\n // TEV stage " + i.ToString()); // TEV inputs // for registers prev/0/1/2: use fract() to emulate truncation // if they're selected into a, b or c string rout, a, b, c, d, operation = ""; frag.AppendLine(" konst.rgb = " + c_konstsel[mat.ConstColorSel[i]] + ";"); frag.AppendLine(" konst.a = " + a_konstsel[mat.ConstAlphaSel[i]] + ";"); if (mat.TevOrder[i].TexMap != 0xFF && mat.TevOrder[i].TexcoordId != 0xFF) { frag.AppendFormat(" texcolor = texture2D(texture{0}, gl_TexCoord[{1}].st);\n", mat.TevOrder[i].TexMap, mat.TevOrder[i].TexcoordId); } frag.AppendLine(" rascolor = gl_Color;"); // TODO: take mat.TevOrder[i].ChanId into account // TODO: tex/ras swizzle? (important or not?) //mat.TevSwapMode[0]. //Commented out 1/22/15 //if (mat.TevOrder[i].ChanID != 4) // throw new Exception("!UNSUPPORTED CHANID " + mat.TevOrder[i].ChanID.ToString()); rout = outputregs[mat.TevStage[i].ColorRegID] + ".rgb"; a = c_inputregs[mat.TevStage[i].ColorIn[0]]; b = c_inputregs[mat.TevStage[i].ColorIn[1]]; c = c_inputregs[mat.TevStage[i].ColorIn[2]]; d = c_inputregsD[mat.TevStage[i].ColorIn[3]]; switch (mat.TevStage[i].ColorOp) { case 0: operation = " {0} = ({4} + mix({1},{2},{3}) + vec3({5},{5},{5})) * vec3({6},{6},{6});"; if (mat.TevStage[i].ColorClamp != 0) { operation += "\n {0} = clamp({0}, vec3(0.0,0.0,0.0), vec3(1.0,1.0,1.0));"; } break; case 1: operation = " {0} = ({4} - mix({1},{2},{3}) + vec3({5},{5},{5})) * vec3({6},{6},{6});"; if (mat.TevStage[i].ColorClamp != 0) { operation += "\n {0} = clamp({0}, vec3(0.0,0.0,0.0), vec3(1.0,1.0,1.0));"; } break; case 8: operation = " {0} = {4} + ((({1}).r > ({2}).r) ? {3} : vec(0.0,0.0,0.0));"; break; default: //operation = " {0} = vec3(1.0,0.0,1.0);"; //throw new Exception("!colorop " + mat.TevStage[i].ColorOp.ToString()); continue; // Modified 1/22/15 } operation = string.Format(operation, rout, a, b, c, d, tevbias[mat.TevStage[i].ColorBias], tevscale[mat.TevStage[i].ColorScale]); frag.AppendLine(operation); rout = outputregs[mat.TevStage[i].AlphaRegID] + ".a"; a = a_inputregs[mat.TevStage[i].AlphaIn[0]]; b = a_inputregs[mat.TevStage[i].AlphaIn[1]]; c = a_inputregs[mat.TevStage[i].AlphaIn[2]]; d = a_inputregsD[mat.TevStage[i].AlphaIn[3]]; switch (mat.TevStage[i].AlphaOp) { case 0: operation = " {0} = ({4} + mix({1},{2},{3}) + {5}) * {6};"; if (mat.TevStage[i].AlphaClamp != 0) { operation += "\n {0} = clamp({0}, 0.0, 1.0);"; } break; case 1: operation = " {0} = ({4} - mix({1},{2},{3}) + {5}) * {6};"; if (mat.TevStage[i].AlphaClamp != 0) { operation += "\n {0} = clamp({0}, 0.0, 1.0);"; } break; default: operation = " {0} = 1.0;"; throw new Exception("!alphaop " + mat.TevStage[i].AlphaOp.ToString()); } operation = string.Format(operation, rout, a, b, c, d, tevbias[mat.TevStage[i].AlphaBias], tevscale[mat.TevStage[i].AlphaScale]); frag.AppendLine(operation); } frag.AppendLine(""); frag.AppendLine(" gl_FragColor.rgb = truncc3(rprev.rgb);"); frag.AppendLine(" gl_FragColor.a = truncc1(rprev.a);"); frag.AppendLine(""); frag.AppendLine(" // Alpha test"); if (mat.AlphaComp.MergeFunc == 1 && (mat.AlphaComp.Func0 == 7 || mat.AlphaComp.Func1 == 7)) { // always pass -- do nothing :) } else if (mat.AlphaComp.MergeFunc == 0 && (mat.AlphaComp.Func0 == 0 || mat.AlphaComp.Func1 == 0)) { // never pass // (we did all those color/alpha calculations for uh, nothing ;_; ) frag.AppendLine(" discard;"); } else { string compare0 = string.Format(forceusa, alphacompare[mat.AlphaComp.Func0], "gl_FragColor.a", (float)mat.AlphaComp.Ref0 / 255f); string compare1 = string.Format(forceusa, alphacompare[mat.AlphaComp.Func1], "gl_FragColor.a", (float)mat.AlphaComp.Ref1 / 255f); string fullcompare = ""; if (mat.AlphaComp.MergeFunc == 1) { if (mat.AlphaComp.Func0 == 0) { fullcompare = compare1; } else if (mat.AlphaComp.Func1 == 0) { fullcompare = compare0; } } else if (mat.AlphaComp.MergeFunc == 0) { if (mat.AlphaComp.Func0 == 7) { fullcompare = compare1; } else if (mat.AlphaComp.Func1 == 7) { fullcompare = compare0; } } if (fullcompare == "") { fullcompare = string.Format(alphacombine[mat.AlphaComp.MergeFunc], compare0, compare1); } frag.AppendLine(" if (!(" + fullcompare + ")) discard;"); } frag.AppendLine("}"); int fragid = GL.CreateShader(ShaderType.FragmentShader); m_Shaders[matid].FragmentShader = fragid; GL.ShaderSource(fragid, frag.ToString()); GL.CompileShader(fragid); GL.GetShader(fragid, ShaderParameter.CompileStatus, out success); if (success == 0) { string log = GL.GetShaderInfoLog(fragid); throw new Exception("!Failed to compile fragment shader: " + log); // TODO: better error reporting/logging? } int sid = GL.CreateProgram(); m_Shaders[matid].Program = sid; GL.AttachShader(sid, vertid); GL.AttachShader(sid, fragid); GL.LinkProgram(sid); GL.GetProgram(sid, ProgramParameter.LinkStatus, out success); if (success == 0) { string log = GL.GetProgramInfoLog(sid); throw new Exception("!Failed to link shader program: " + log); // TODO: better error reporting/logging? } //debugshaders += "-----------------------------------------------------------\n" + frag.ToString(); }
public override void Render(RenderInfo info) { BlendingFactorSrc[] blendsrc = { BlendingFactorSrc.Zero, BlendingFactorSrc.One, BlendingFactorSrc.One, BlendingFactorSrc.Zero,// um... BlendingFactorSrc.SrcAlpha, BlendingFactorSrc.OneMinusSrcAlpha, BlendingFactorSrc.DstAlpha, BlendingFactorSrc.OneMinusDstAlpha, BlendingFactorSrc.DstColor, BlendingFactorSrc.OneMinusDstColor }; BlendingFactorDest[] blenddst = { BlendingFactorDest.Zero, BlendingFactorDest.One, BlendingFactorDest.SrcColor, BlendingFactorDest.OneMinusSrcColor, BlendingFactorDest.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha, BlendingFactorDest.DstAlpha, BlendingFactorDest.OneMinusDstAlpha, BlendingFactorDest.DstColor, BlendingFactorDest.OneMinusDstColor }; LogicOp[] logicop = { LogicOp.Clear, LogicOp.And, LogicOp.AndReverse, LogicOp.Copy, LogicOp.AndInverted, LogicOp.Noop, LogicOp.Xor, LogicOp.Or, LogicOp.Nor, LogicOp.Equiv, LogicOp.Invert, LogicOp.OrReverse, LogicOp.CopyInverted, LogicOp.OrInverted, LogicOp.Nand, LogicOp.Set }; Matrix4[] lastmatrixtable = null; foreach (Bmd.SceneGraphNode node in m_Model.SceneGraph) { if (node.NodeType != 0) { continue; } int shape = node.NodeID; if (node.MaterialID != 0xFFFF) { CullFaceMode[] cullmodes = { CullFaceMode.Front, CullFaceMode.Back, CullFaceMode.Front }; DepthFunction[] depthfuncs = { DepthFunction.Never, DepthFunction.Less, DepthFunction.Equal, DepthFunction.Lequal, DepthFunction.Greater, DepthFunction.Notequal, DepthFunction.Gequal, DepthFunction.Always }; Bmd.Material mat = m_Model.Materials[node.MaterialID]; if ((mat.DrawFlag == 4) ^ (info.Mode == RenderMode.Translucent)) { continue; } if (m_HasShaders) { // shader: handles multitexturing, color combination, alpha test GL.UseProgram(m_Shaders[node.MaterialID].Program); // do multitexturing for (int i = 0; i < 8; i++) { GL.ActiveTexture(TextureUnit.Texture0 + i); if (mat.TexStages[i] == 0xFFFF) { GL.Disable(EnableCap.Texture2D); continue; } int loc = GL.GetUniformLocation(m_Shaders[node.MaterialID].Program, "texture" + i.ToString()); GL.Uniform1(loc, i); int texid = m_Textures[mat.TexStages[i]]; GL.Enable(EnableCap.Texture2D); GL.BindTexture(TextureTarget.Texture2D, texid); } } else { AlphaFunction[] alphafunc = { AlphaFunction.Never, AlphaFunction.Less, AlphaFunction.Equal, AlphaFunction.Lequal, AlphaFunction.Greater, AlphaFunction.Notequal, AlphaFunction.Gequal, AlphaFunction.Always }; // texturing -- texture 0 will be used if (mat.TexStages[0] != 0xFFFF) { int texid = m_Textures[mat.TexStages[0]]; GL.Enable(EnableCap.Texture2D); GL.BindTexture(TextureTarget.Texture2D, texid); } else { GL.Disable(EnableCap.Texture2D); } // alpha test -- only one comparison can be done if (mat.AlphaComp.MergeFunc == 1 && (mat.AlphaComp.Func0 == 7 || mat.AlphaComp.Func1 == 7)) { GL.Disable(EnableCap.AlphaTest); } else if (mat.AlphaComp.MergeFunc == 0 && (mat.AlphaComp.Func0 == 0 || mat.AlphaComp.Func1 == 0)) { GL.Enable(EnableCap.AlphaTest); GL.AlphaFunc(AlphaFunction.Never, 0f); } else { GL.Enable(EnableCap.AlphaTest); if ((mat.AlphaComp.MergeFunc == 1 && mat.AlphaComp.Func0 == 0) || (mat.AlphaComp.MergeFunc == 0 && mat.AlphaComp.Func0 == 7)) { GL.AlphaFunc(alphafunc[mat.AlphaComp.Func1], (float)mat.AlphaComp.Ref1 / 255f); } else { GL.AlphaFunc(alphafunc[mat.AlphaComp.Func0], (float)mat.AlphaComp.Ref0 / 255f); } } } switch (mat.BlendMode.BlendMode) { case 0: GL.Disable(EnableCap.Blend); GL.Disable(EnableCap.ColorLogicOp); break; case 1: case 3: GL.Enable(EnableCap.Blend); GL.Disable(EnableCap.ColorLogicOp); if (mat.BlendMode.BlendMode == 3) { GL.BlendEquation(BlendEquationMode.FuncSubtract); } else { GL.BlendEquation(BlendEquationMode.FuncAdd); } GL.BlendFunc(blendsrc[mat.BlendMode.SrcFactor], blenddst[mat.BlendMode.DstFactor]); break; case 2: GL.Disable(EnableCap.Blend); GL.Enable(EnableCap.ColorLogicOp); GL.LogicOp(logicop[mat.BlendMode.BlendOp]); break; } if (mat.CullMode == 0) { GL.Disable(EnableCap.CullFace); } else { GL.Enable(EnableCap.CullFace); GL.CullFace(cullmodes[mat.CullMode - 1]); } if (mat.ZMode.EnableZTest) { GL.Enable(EnableCap.DepthTest); GL.DepthFunc(depthfuncs[mat.ZMode.Func]); } else { GL.Disable(EnableCap.DepthTest); } GL.DepthMask(mat.ZMode.EnableZWrite); } else { //if (info.Mode != RenderMode.Opaque) continue; // if (m_HasShaders) GL.UseProgram(0); throw new Exception("Material-less geometry node " + node.NodeID.ToString()); } Bmd.Batch batch = m_Model.Batches[shape]; /*if (batch.MatrixType == 1) * { * GL.PushMatrix(); * GL.CallList(info.BillboardDL); * } * else if (batch.MatrixType == 2) * { * GL.PushMatrix(); * GL.CallList(info.YBillboardDL); * }*/ foreach (Bmd.Batch.Packet packet in batch.Packets) { Matrix4[] mtxtable = new Matrix4[packet.MatrixTable.Length]; int[] mtx_debug = new int[packet.MatrixTable.Length]; for (int i = 0; i < packet.MatrixTable.Length; i++) { if (packet.MatrixTable[i] == 0xFFFF) { mtxtable[i] = lastmatrixtable[i]; mtx_debug[i] = 2; } else { Bmd.MatrixType mtxtype = m_Model.MatrixTypes[packet.MatrixTable[i]]; if (mtxtype.IsWeighted) { //throw new NotImplementedException("weighted matrix"); // code inspired from bmdview2, except doesn't work right /*Matrix4 mtx = new Matrix4(); * Bmd.MultiMatrix mm = m_Model.MultiMatrices[mtxtype.Index]; * for (int j = 0; j < mm.NumMatrices; j++) * { * Matrix4 wmtx = mm.Matrices[j]; * float weight = mm.MatrixWeights[j]; * * Matrix4.Mult(ref wmtx, ref m_Model.Joints[mm.MatrixIndices[j]].Matrix, out wmtx); * * Vector4.Mult(ref wmtx.Row0, weight, out wmtx.Row0); * Vector4.Mult(ref wmtx.Row1, weight, out wmtx.Row1); * Vector4.Mult(ref wmtx.Row2, weight, out wmtx.Row2); * //Vector4.Mult(ref wmtx.Row3, weight, out wmtx.Row3); * * Vector4.Add(ref mtx.Row0, ref wmtx.Row0, out mtx.Row0); * Vector4.Add(ref mtx.Row1, ref wmtx.Row1, out mtx.Row1); * Vector4.Add(ref mtx.Row2, ref wmtx.Row2, out mtx.Row2); * //Vector4.Add(ref mtx.Row3, ref wmtx.Row3, out mtx.Row3); * } * mtx.M44 = 1f; * mtxtable[i] = mtx;*/ // seems fine in most cases // but hey, certainly not right, that data has to be used in some way mtxtable[i] = Matrix4.Identity; mtx_debug[i] = 1; } else { mtxtable[i] = m_Model.Joints[mtxtype.Index].FinalMatrix; mtx_debug[i] = 0; } } } lastmatrixtable = mtxtable; foreach (Bmd.Batch.Packet.Primitive prim in packet.Primitives) { BeginMode[] primtypes = { BeginMode.Quads, BeginMode.Points, BeginMode.Triangles, BeginMode.TriangleStrip, BeginMode.TriangleFan, BeginMode.Lines, BeginMode.LineStrip, BeginMode.Points }; GL.Begin(primtypes[(prim.PrimitiveType - 0x80) / 8]); //GL.Begin(BeginMode.Points); for (int i = 0; i < prim.NumIndices; i++) { if ((prim.ArrayMask & (1 << 11)) != 0) { GL.Color4(m_Model.ColorArray[0][prim.ColorIndices[0][i]]); } if (m_HasShaders) { if ((prim.ArrayMask & (1 << 12)) != 0) { Vector4 color2 = m_Model.ColorArray[1][prim.ColorIndices[1][i]]; GL.SecondaryColor3(color2.X, color2.Y, color2.Z); throw new Exception("color2 detected"); } if ((prim.ArrayMask & (1 << 13)) != 0) { GL.MultiTexCoord2(TextureUnit.Texture0, ref m_Model.TexcoordArray[0][prim.TexcoordIndices[0][i]]); } if ((prim.ArrayMask & (1 << 14)) != 0) { GL.MultiTexCoord2(TextureUnit.Texture1, ref m_Model.TexcoordArray[1][prim.TexcoordIndices[1][i]]); } if ((prim.ArrayMask & (1 << 15)) != 0) { GL.MultiTexCoord2(TextureUnit.Texture2, ref m_Model.TexcoordArray[2][prim.TexcoordIndices[2][i]]); } if ((prim.ArrayMask & (1 << 16)) != 0) { GL.MultiTexCoord2(TextureUnit.Texture3, ref m_Model.TexcoordArray[3][prim.TexcoordIndices[3][i]]); } if ((prim.ArrayMask & (1 << 17)) != 0) { GL.MultiTexCoord2(TextureUnit.Texture4, ref m_Model.TexcoordArray[4][prim.TexcoordIndices[4][i]]); } if ((prim.ArrayMask & (1 << 18)) != 0) { GL.MultiTexCoord2(TextureUnit.Texture5, ref m_Model.TexcoordArray[5][prim.TexcoordIndices[5][i]]); } if ((prim.ArrayMask & (1 << 19)) != 0) { GL.MultiTexCoord2(TextureUnit.Texture6, ref m_Model.TexcoordArray[6][prim.TexcoordIndices[6][i]]); } if ((prim.ArrayMask & (1 << 20)) != 0) { GL.MultiTexCoord2(TextureUnit.Texture7, ref m_Model.TexcoordArray[7][prim.TexcoordIndices[7][i]]); } } else { if ((prim.ArrayMask & (1 << 13)) != 0) { GL.TexCoord2(m_Model.TexcoordArray[0][prim.TexcoordIndices[0][i]]); } } //if ((prim.ArrayMask & (1 << 0)) != 0) GL.Color4(debug[prim.PosMatrixIndices[i]]); if ((prim.ArrayMask & (1 << 10)) != 0) { GL.Normal3(m_Model.NormalArray[prim.NormalIndices[i]]); } Vector3 pos = m_Model.PositionArray[prim.PositionIndices[i]]; if ((prim.ArrayMask & (1 << 0)) != 0) { Vector3.Transform(ref pos, ref mtxtable[prim.PosMatrixIndices[i]], out pos); } else { Vector3.Transform(ref pos, ref mtxtable[0], out pos); } GL.Vertex3(pos); } GL.End(); } } //if (batch.MatrixType == 1 || batch.MatrixType == 2) // GL.PopMatrix(); } //Clear shaders. Added 1/22/15 foreach (Bmd.SceneGraphNode node in m_Model.SceneGraph) { if (node.NodeType != 0) { continue; } int shape = node.NodeID; if (node.MaterialID != 0xFFFF) { if (m_HasShaders) { // shader: handles multitexturing, color combination, alpha test GL.UseProgram(m_Shaders[node.MaterialID].Program); // do multitexturing for (int i = 0; i < 8; i++) { GL.ActiveTexture(TextureUnit.Texture0 + i); GL.Disable(EnableCap.Texture2D); } } } } GL.UseProgram(0); GL.Color4(1f, 1f, 1f, 1f); }