diff options
Diffstat (limited to 'NW4RTools/Models/OpenGL/GLModel.cs')
-rw-r--r-- | NW4RTools/Models/OpenGL/GLModel.cs | 243 |
1 files changed, 174 insertions, 69 deletions
diff --git a/NW4RTools/Models/OpenGL/GLModel.cs b/NW4RTools/Models/OpenGL/GLModel.cs index 2e5779e..315415e 100644 --- a/NW4RTools/Models/OpenGL/GLModel.cs +++ b/NW4RTools/Models/OpenGL/GLModel.cs @@ -8,34 +8,42 @@ using OpenTK.Graphics.OpenGL; namespace NW4RTools.Models.OpenGL { public class GLModel { - public ResFile SourceFile { - get; private set; - } + public ResFile SourceFile { get; private set; } - public Model SourceModel { - get; private set; - } + public Model SourceModel { get; private set; } public GLModel(ResFile rf, string modelName) { SourceFile = rf; SourceModel = rf.GetGroup<Model>("3DModels(NW4R)")[modelName]; - + // cache some stuff m_textureGroup = rf.GetGroup<Texture>("Textures(NW4R)"); } + private class MyNode { + Node RealNode; + MyNode Parent; + List<MyNode> Children; + } + + private ResDict<Texture> m_textureGroup; private Dictionary<string, GLTexture> m_glTextures; private Dictionary<Material, GLDisplayList> m_glMaterials; private Dictionary<Shape, GLDisplayList> m_glShapes; + private Matrix4[] m_matrices; + private MyNode[] m_nodesByMtxID; + private MyNode[] m_nodes; + + #region Initialisation public void Prepare(IGraphicsContext context) { // convert every texture m_glTextures = new Dictionary<string, GLTexture>(); - + foreach (var material in SourceModel.Materials) { foreach (var texInfo in material.Value.TextureInfos) { if (!m_glTextures.ContainsKey(texInfo.TextureName)) { @@ -45,30 +53,45 @@ namespace NW4RTools.Models.OpenGL { } } } - + // convert every material m_glMaterials = new Dictionary<Material, GLDisplayList>(); - + foreach (var material in SourceModel.Materials.Values) { m_glMaterials.Add(material, MakeMaterialDisplayList(material)); } - + // convert every shape m_glShapes = new Dictionary<Shape, GLDisplayList>(); - + foreach (var shape in SourceModel.Shapes.Values) { m_glShapes.Add(shape, MakeShapeDisplayList(shape)); } + + // allocate stuff for nodes + m_matrices = new Matrix4[SourceModel.MatrixIDtoNodeID.Length]; + + // build the hierarchy + BuildNodeHierarchy(); + } + + private void BuildNodeHierarchy() { + var nodeTree = SourceModel.Bytecode["NodeTree"]; + + foreach (var insn in nodeTree.Instructions) { + if (insn.GetOp() == ByteCode.OpType.AssignNodeToParentMtx) { + MyNode n = new MyNode(); + } + } } + #endregion + private static readonly TextureUnit[] TextureUnits = new TextureUnit[] { TextureUnit.Texture0, TextureUnit.Texture1, TextureUnit.Texture2, TextureUnit.Texture3, TextureUnit.Texture4, TextureUnit.Texture5, TextureUnit.Texture6, TextureUnit.Texture7, TextureUnit.Texture8, TextureUnit.Texture9, + TextureUnit.Texture10, TextureUnit.Texture11, TextureUnit.Texture12, TextureUnit.Texture13, TextureUnit.Texture14, TextureUnit.Texture15 }; - private static readonly TextureUnit[] TextureUnits = new TextureUnit[] { - TextureUnit.Texture0, TextureUnit.Texture1, TextureUnit.Texture2, TextureUnit.Texture3, - TextureUnit.Texture4, TextureUnit.Texture5, TextureUnit.Texture6, TextureUnit.Texture7, - TextureUnit.Texture8, TextureUnit.Texture9, TextureUnit.Texture10, TextureUnit.Texture11, - TextureUnit.Texture12, TextureUnit.Texture13, TextureUnit.Texture14, TextureUnit.Texture15 - }; + // GX_CLAMP, GX_REPEAT, GX_MIRROR + private static readonly TextureWrapMode[] GXtoGLTextureWrapModes = new TextureWrapMode[] { TextureWrapMode.ClampToEdge, TextureWrapMode.Repeat, TextureWrapMode.MirroredRepeat }; private Material m_currentMaterial; @@ -79,29 +102,72 @@ namespace NW4RTools.Models.OpenGL { private void LoadMaterial(Material m) { if (m == m_currentMaterial) return; - + m_currentMaterial = m; m_glMaterials[m].Execute(); } private void DrawShape(ByteCode.DrawShapeInstruction insn) { LoadMaterial(SourceModel.Materials[insn.MaterialID]); - + + // HACKY TEST !! + GL.MatrixMode(MatrixMode.Modelview); + var node = SourceModel.Nodes[insn.NodeID]; + var m = node.NodeMatrix; + /*double cosX = Math.Cos(node.Rotation.x / 180 * Math.PI); + double cosY = Math.Cos(node.Rotation.y / 180 * Math.PI); + double cosZ = Math.Cos(node.Rotation.z / 180 * Math.PI); + double sinX = Math.Sin(node.Rotation.x / 180 * Math.PI); + double sinY = Math.Sin(node.Rotation.y / 180 * Math.PI); + double sinZ = Math.Sin(node.Rotation.z / 180 * Math.PI); + + var nodeMatrix = new Matrix4d(); + nodeMatrix.M11 = node.Scale.x * cosY * cosZ; + nodeMatrix.M12 = node.Scale.y * (sinX * cosZ * sinY - cosX * sinZ); + nodeMatrix.M13 = node.Scale.z * (sinX * sinZ + cosX * cosZ * sinY); + nodeMatrix.M14 = node.Translation.x; + nodeMatrix.M21 = node.Scale.x * sinZ * cosY; + nodeMatrix.M22 = node.Scale.y * (sinX * sinZ * sinY + cosZ * cosX); + nodeMatrix.M23 = node.Scale.z * (cosX * sinZ * sinY - sinX * cosZ); + nodeMatrix.M24 = node.Translation.y; + nodeMatrix.M31 = -node.Scale.x * sinY; + nodeMatrix.M32 = node.Scale.y * sinX * cosY; + nodeMatrix.M33 = node.Scale.z * cosX * cosY; + nodeMatrix.M34 = node.Translation.z; + nodeMatrix.M41 = 0; + nodeMatrix.M42 = 0; + nodeMatrix.M43 = 0; + nodeMatrix.M44 = 1; + + GL.PushMatrix(); + GL.MultTransposeMatrix(ref nodeMatrix); + //*/ + + GL.PushMatrix(); + GL.MultTransposeMatrix(new float[] { m.v00, m.v01, m.v02, m.v03, m.v10, m.v11, m.v12, m.v13, m.v20, m.v21, + m.v22, m.v23, 0, 0, 0, 1 }); + + //GL.Translate(node.Translation.x, node.Translation.y, node.Translation.z); + var shape = SourceModel.Shapes[insn.ShapeID]; m_glShapes[shape].Execute(); + + GL.PopMatrix(); } public void Render(IGraphicsContext context) { // This'll be fun. - + ClearCache(); + //CalculateNodes(); + foreach (var insn in SourceModel.Bytecode["DrawOpa"].Instructions) { if (insn is ByteCode.DrawShapeInstruction) { DrawShape(insn as ByteCode.DrawShapeInstruction); } } - + if (SourceModel.Bytecode.ContainsKey("DrawXlu")) { foreach (var insn in SourceModel.Bytecode["DrawXlu"].Instructions) { if (insn is ByteCode.DrawShapeInstruction) { @@ -112,6 +178,14 @@ namespace NW4RTools.Models.OpenGL { } + private void BindTextureInfo(TextureInfo info) { + m_glTextures[info.TextureName].Bind(TextureTarget.Texture2D); + + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)GXtoGLTextureWrapModes[(int)info.WrapS]); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)GXtoGLTextureWrapModes[(int)info.WrapT]); + } + + #region Display Lists private GLDisplayList MakeMaterialDisplayList(Material m) { @@ -129,12 +203,12 @@ namespace NW4RTools.Models.OpenGL { for (int i = 0; i < 8; i++) { GL.ActiveTexture(TextureUnits[i]); - GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int)TextureEnvMode.Decal); + GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int)TextureEnvMode.Modulate); if (texInfoArray[i] == null) { GL.BindTexture(TextureTarget.Texture2D, 0); } else { - m_glTextures[texInfoArray[i].TextureName].Bind(TextureTarget.Texture2D); + BindTextureInfo(texInfoArray[i]); } } @@ -166,7 +240,6 @@ namespace NW4RTools.Models.OpenGL { vs.SetDesc(vtxDesc1, vtxDesc2); vs.SetAttrFmt(vtxAttr1, vtxAttr2, vtxAttr3); - InputStream dl = new InputStream(shape.DisplayList2); while (true) { @@ -177,58 +250,90 @@ namespace NW4RTools.Models.OpenGL { if (cmd == 0) break; - PrimitiveType prim = (PrimitiveType)((cmd >> 3) & 7); - int vtxCount = dl.ReadUInt16(); - - // first, parse it into a list of vertices - GXIndexedVertex[] vtxs = new GXIndexedVertex[vtxCount]; - for (int i = 0; i < vtxCount; i++) { - vtxs[i].LoadFrom(dl, vs); - } - - switch (prim) { - case PrimitiveType.Quads: - GL.Begin(BeginMode.Quads); - break; - case PrimitiveType.Triangles: - GL.Begin(BeginMode.Triangles); - break; - case PrimitiveType.TriangleStrip: - GL.Begin(BeginMode.TriangleStrip); - break; - case PrimitiveType.TriangleFan: - GL.Begin(BeginMode.TriangleFan); - break; - case PrimitiveType.Lines: - GL.Begin(BeginMode.Lines); - break; - case PrimitiveType.LineStrip: - GL.Begin(BeginMode.LineStrip); - break; - case PrimitiveType.Points: - GL.Begin(BeginMode.Points); - break; - default: - Console.WriteLine("UNIMPLEMENTED PRIMITIVE TYPE {0}", prim); - throw new NotImplementedException(); - } - - for (int i = 0; i < vtxCount; i++) { - for (int j = 0; j < 8; j++) { - if (vs.TexCoordDesc[j] != VertexSettings.DescType.None) - GL.MultiTexCoord2(TextureUnits[j], shape.TexCoordData[j].Data[vtxs[i].TexCoords[j]]); + if ((cmd & (int)GXCommand.DrawPrimitiveMask) != 0) { + PrimitiveType prim = (PrimitiveType)((cmd >> 3) & 7); + int vtxCount = dl.ReadUInt16(); + + if ((cmd & 7) != 0) + Console.WriteLine("WARNING!! Not using vertex attribute table 0"); + + // first, parse it into a list of vertices + GXIndexedVertex[] vtxs = new GXIndexedVertex[vtxCount]; + for (int i = 0; i < vtxCount; i++) { + vtxs[i].LoadFrom(dl, vs); + } + + switch (prim) { + case PrimitiveType.Quads: + GL.Begin(BeginMode.Quads); + break; + case PrimitiveType.Triangles: + GL.Begin(BeginMode.Triangles); + break; + case PrimitiveType.TriangleStrip: + GL.Begin(BeginMode.TriangleStrip); + break; + case PrimitiveType.TriangleFan: + GL.Begin(BeginMode.TriangleFan); + break; + case PrimitiveType.Lines: + GL.Begin(BeginMode.Lines); + break; + case PrimitiveType.LineStrip: + GL.Begin(BeginMode.LineStrip); + break; + case PrimitiveType.Points: + GL.Begin(BeginMode.Points); + break; + default: + Console.WriteLine("UNIMPLEMENTED PRIMITIVE TYPE {0}", prim); + throw new NotImplementedException(); + } + + for (int i = 0; i < vtxCount; i++) { + for (int j = 0; j < 8; j++) { + if (vs.TexCoordDesc[j] != VertexSettings.DescType.None) { + GL.MultiTexCoord2(TextureUnits[j], shape.TexCoordData[j].Data[vtxs[i].TexCoords[j]]); + } + } + + // TODO: normals + + GL.Vertex3(shape.PosData.Data[vtxs[i].Position]); } - GL.Vertex3(shape.PosData.Data[vtxs[i].Position]); + GL.End(); + } else { + // some other command + switch ((GXCommand)cmd) { + case GXCommand.LoadPosMtxFromArray: + int targetID = dl.ReadUInt16(); + int sourceID = (dl.ReadUInt16() & 0xFFF) / 12; + Console.WriteLine("Load PosMtx from array: {0} => {1}", targetID, sourceID); + break; + case GXCommand.LoadNrmMtxFromArray: + dl.Skip(4); + Console.WriteLine("UNIMPLEMENTED: Load NrmMtx from array"); + break; + case GXCommand.LoadTexCoordMtxFromArray: + dl.Skip(4); + Console.WriteLine("UNIMPLEMENTED: Load TexCoordMtx from array"); + break; + case GXCommand.LoadLightFromArray: + dl.Skip(4); + Console.WriteLine("UNIMPLEMENTED: Load Light from array"); + break; + default: + Console.WriteLine("UNKNOWN DL COMMAND"); + break; + } } - - GL.End(); } displayList.End(); return displayList; } - + #endregion } } |