From b0760b28807b31cc1403584265c07feb87ac4887 Mon Sep 17 00:00:00 2001 From: Treeki Date: Fri, 18 Feb 2011 03:28:31 +0100 Subject: some collada work, and an unfinished OGL renderer using OpenTK. huge commit --- NW4RTools/Models/OpenGL/GLDisplayList.cs | 31 ++++ NW4RTools/Models/OpenGL/GLModel.cs | 235 +++++++++++++++++++++++++++++++ NW4RTools/Models/OpenGL/GLTexture.cs | 46 ++++++ 3 files changed, 312 insertions(+) create mode 100644 NW4RTools/Models/OpenGL/GLDisplayList.cs create mode 100644 NW4RTools/Models/OpenGL/GLModel.cs create mode 100644 NW4RTools/Models/OpenGL/GLTexture.cs (limited to 'NW4RTools/Models/OpenGL') diff --git a/NW4RTools/Models/OpenGL/GLDisplayList.cs b/NW4RTools/Models/OpenGL/GLDisplayList.cs new file mode 100644 index 0000000..180e89e --- /dev/null +++ b/NW4RTools/Models/OpenGL/GLDisplayList.cs @@ -0,0 +1,31 @@ +using System; +using OpenTK; +using OpenTK.Graphics; +using OpenTK.Graphics.OpenGL; + +namespace NW4RTools.Models.OpenGL { + public class GLDisplayList : IDisposable { + public readonly int ListID; + + public GLDisplayList() { + ListID = GL.GenLists(1); + } + + void IDisposable.Dispose() { + GL.DeleteLists(ListID, 1); + } + + public void Begin() { + GL.NewList(ListID, ListMode.Compile); + } + + public void End() { + GL.EndList(); + } + + public void Execute() { + GL.CallList(ListID); + } + } +} + diff --git a/NW4RTools/Models/OpenGL/GLModel.cs b/NW4RTools/Models/OpenGL/GLModel.cs new file mode 100644 index 0000000..2e5779e --- /dev/null +++ b/NW4RTools/Models/OpenGL/GLModel.cs @@ -0,0 +1,235 @@ +using System; +using System.Collections.Generic; +using NW4RTools; +using NW4RTools.Models; +using OpenTK; +using OpenTK.Graphics; +using OpenTK.Graphics.OpenGL; + +namespace NW4RTools.Models.OpenGL { + public class GLModel { + public ResFile SourceFile { + get; private set; + } + + public Model SourceModel { + get; private set; + } + + public GLModel(ResFile rf, string modelName) { + SourceFile = rf; + SourceModel = rf.GetGroup("3DModels(NW4R)")[modelName]; + + // cache some stuff + m_textureGroup = rf.GetGroup("Textures(NW4R)"); + } + + + + + private ResDict m_textureGroup; + private Dictionary m_glTextures; + private Dictionary m_glMaterials; + private Dictionary m_glShapes; + + public void Prepare(IGraphicsContext context) { + // convert every texture + m_glTextures = new Dictionary(); + + foreach (var material in SourceModel.Materials) { + foreach (var texInfo in material.Value.TextureInfos) { + if (!m_glTextures.ContainsKey(texInfo.TextureName)) { + var newTex = new GLTexture(); + newTex.Load(m_textureGroup[texInfo.TextureName]); + m_glTextures.Add(texInfo.TextureName, newTex); + } + } + } + + // convert every material + m_glMaterials = new Dictionary(); + + foreach (var material in SourceModel.Materials.Values) { + m_glMaterials.Add(material, MakeMaterialDisplayList(material)); + } + + // convert every shape + m_glShapes = new Dictionary(); + + foreach (var shape in SourceModel.Shapes.Values) { + m_glShapes.Add(shape, MakeShapeDisplayList(shape)); + } + } + + + + 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 Material m_currentMaterial; + + private void ClearCache() { + m_currentMaterial = null; + } + + 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]); + + var shape = SourceModel.Shapes[insn.ShapeID]; + m_glShapes[shape].Execute(); + } + + public void Render(IGraphicsContext context) { + // This'll be fun. + + ClearCache(); + + 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) { + DrawShape(insn as ByteCode.DrawShapeInstruction); + } + } + } + } + + + + #region Display Lists + private GLDisplayList MakeMaterialDisplayList(Material m) { + var displayList = new GLDisplayList(); + displayList.Begin(); + + if (m.TextureInfos.Count > 0) { + GL.Enable(EnableCap.Texture2D); + + TextureInfo[] texInfoArray = new TextureInfo[8]; + + foreach (var texInfo in m.TextureInfos) { + texInfoArray[texInfo.TexMapID] = texInfo; + } + + for (int i = 0; i < 8; i++) { + GL.ActiveTexture(TextureUnits[i]); + GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int)TextureEnvMode.Decal); + + if (texInfoArray[i] == null) { + GL.BindTexture(TextureTarget.Texture2D, 0); + } else { + m_glTextures[texInfoArray[i].TextureName].Bind(TextureTarget.Texture2D); + } + } + + } else { + GL.Disable(EnableCap.Texture2D); + } + + displayList.End(); + return displayList; + } + + private GLDisplayList MakeShapeDisplayList(Shape shape) { + var displayList = new GLDisplayList(); + displayList.Begin(); + + var firstDL = new InputStream(shape.DisplayList1); + firstDL.Seek(0x0C); + UInt32 vtxDesc1 = firstDL.ReadUInt32(); + firstDL.Seek(0x12); + UInt32 vtxDesc2 = firstDL.ReadUInt32(); + firstDL.Seek(0x22); + UInt32 vtxAttr1 = firstDL.ReadUInt32(); + firstDL.Seek(0x28); + UInt32 vtxAttr2 = firstDL.ReadUInt32(); + firstDL.Seek(0x2E); + UInt32 vtxAttr3 = firstDL.ReadUInt32(); + + var vs = new VertexSettings(); + vs.SetDesc(vtxDesc1, vtxDesc2); + vs.SetAttrFmt(vtxAttr1, vtxAttr2, vtxAttr3); + + + InputStream dl = new InputStream(shape.DisplayList2); + + while (true) { + if (dl.AtEnd) + break; + + byte cmd = dl.ReadByte(); + 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]]); + } + + GL.Vertex3(shape.PosData.Data[vtxs[i].Position]); + } + + GL.End(); + } + + displayList.End(); + return displayList; + } + + #endregion + } +} + diff --git a/NW4RTools/Models/OpenGL/GLTexture.cs b/NW4RTools/Models/OpenGL/GLTexture.cs new file mode 100644 index 0000000..c4cdee6 --- /dev/null +++ b/NW4RTools/Models/OpenGL/GLTexture.cs @@ -0,0 +1,46 @@ +using System; +using NW4RTools; +using NW4RTools.Models; +using OpenTK; +using OpenTK.Graphics; +using OpenTK.Graphics.OpenGL; + +namespace NW4RTools.Models.OpenGL { + public class GLTexture : IDisposable { + public readonly int TextureID; + + public GLTexture() { + TextureID = GL.GenTexture(); + } + + void IDisposable.Dispose() { + GL.DeleteTexture(TextureID); + } + + public void Load(Texture tex) { + Bind(TextureTarget.Texture2D); + + // todo: check if this is configurable + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMagFilter.Linear); + + //byte[] pixelData = new byte[tex.BaseImage.Width * tex.BaseImage.Height * 4]; + + var lb = tex.BaseImage.LockBits( + new System.Drawing.Rectangle(0, 0, tex.BaseImage.Width, tex.BaseImage.Height), + System.Drawing.Imaging.ImageLockMode.ReadOnly, + System.Drawing.Imaging.PixelFormat.Format32bppArgb); + + GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Four, + tex.BaseImage.Width, tex.BaseImage.Height, 0, + PixelFormat.Bgra, PixelType.UnsignedByte, lb.Scan0); + + tex.BaseImage.UnlockBits(lb); + } + + public void Bind(TextureTarget target) { + GL.BindTexture(target, TextureID); + } + } +} + -- cgit v1.2.3