summaryrefslogtreecommitdiff
path: root/NW4RTools/Models/OpenGL
diff options
context:
space:
mode:
authorTreeki <treeki@gmail.com>2011-02-18 03:28:31 +0100
committerTreeki <treeki@gmail.com>2011-02-18 03:28:31 +0100
commitb0760b28807b31cc1403584265c07feb87ac4887 (patch)
treedc97346a0c0d0cdcdc066d77df3905a614a858e8 /NW4RTools/Models/OpenGL
parent7d7491feb41bc9724bf63bef545b996226406889 (diff)
downloadnw4rtools-b0760b28807b31cc1403584265c07feb87ac4887.tar.gz
nw4rtools-b0760b28807b31cc1403584265c07feb87ac4887.zip
some collada work, and an unfinished OGL renderer using OpenTK. huge commit
Diffstat (limited to '')
-rw-r--r--NW4RTools/Models/OpenGL/GLDisplayList.cs31
-rw-r--r--NW4RTools/Models/OpenGL/GLModel.cs235
-rw-r--r--NW4RTools/Models/OpenGL/GLTexture.cs46
3 files changed, 312 insertions, 0 deletions
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<Model>("3DModels(NW4R)")[modelName];
+
+ // cache some stuff
+ m_textureGroup = rf.GetGroup<Texture>("Textures(NW4R)");
+ }
+
+
+
+
+ private ResDict<Texture> m_textureGroup;
+ private Dictionary<string, GLTexture> m_glTextures;
+ private Dictionary<Material, GLDisplayList> m_glMaterials;
+ private Dictionary<Shape, GLDisplayList> m_glShapes;
+
+ 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)) {
+ var newTex = new GLTexture();
+ newTex.Load(m_textureGroup[texInfo.TextureName]);
+ m_glTextures.Add(texInfo.TextureName, newTex);
+ }
+ }
+ }
+
+ // 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));
+ }
+ }
+
+
+
+ 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);
+ }
+ }
+}
+