From 6f308e56f426a68f3d7c10830ea29b0074b4b2bb Mon Sep 17 00:00:00 2001 From: Robert Jordan Date: Thu, 20 Jul 2023 21:19:56 -0400 Subject: [PATCH] Untextured semi-transparency and Textured render flag Untextured semi-transparency and Textured render flag Shader changes: * Add uniform int textureMode. When 1, the surface is untextured, and stp is always set, allowing these surfaces to be semi-transparent (implements #106). * Switched bool stp back to int, because bool is supposedly less supported. Renderer changes: * Textured/untextured surfaces are now separated into different models. * Textures are no longer bound unless the mesh has the Textured render flag. Exporter changes: * Textures are no longer exported if the model doesn't have the Textured render flag. Parser changes: * All model readers now use groupedTriangles with RenderInfo. Previously some were just a triangle list, and others just a texture page lookup. * PMDParser now applies render flags and texture page. Refactor changes: * Moved SupportedFlags out of RenderFlags and into RenderInfo, this way "SupportedFlags" won't show up in the property grid instead of listing each individual flag. * PMDParser now automatically adds `_offset` in ReadSharedVertices, so `_offset` no longer needs to be passed to functions. * Cleaned up TriangleFromPrimitive function for PMDParser and BFFModelReader. * Changed PSXParser triangle flag variable to quad. Mainly to follow consistency, but also because triangle is ambiguous with Triangle variables, that are seen everywhere. (tri would have also worked...) * Added TotalTriangles properties to RootEntity and ModelEntity, the one in root entity is visible to the property grid (implements #105). --- Classes/BFFModelReader.cs | 141 ++++--------- Classes/CrocModelReader.cs | 62 ++++-- Classes/Mesh.cs | 6 +- Classes/MeshBatch.cs | 24 ++- Classes/ModelEntity.cs | 32 ++- Classes/ObjExporter.cs | 2 +- Classes/PMDParser.cs | 411 ++++++++++++++----------------------- Classes/PSXParser.cs | 82 ++++---- Classes/PlyExporter.cs | 11 +- Classes/RenderInfo.cs | 16 +- Classes/RootEntity.cs | 17 ++ Classes/Scene.cs | 4 + Classes/TMDHelper.cs | 2 + Classes/TMDParser.cs | 19 +- Forms/PreviewForm.cs | 10 +- Shaders/Shader.frag | 42 ++-- Shaders/Shader.vert | 1 + 17 files changed, 415 insertions(+), 467 deletions(-) diff --git a/Classes/BFFModelReader.cs b/Classes/BFFModelReader.cs index 5c90c11..34a2aff 100644 --- a/Classes/BFFModelReader.cs +++ b/Classes/BFFModelReader.cs @@ -33,19 +33,16 @@ protected override void Parse(BinaryReader reader, string fileTitle, out List>(); + var groupedTriangles = new Dictionary>(); - void AddTriangle(Triangle triangle, uint tPage) + void AddTriangle(Triangle triangle, uint tPage, RenderFlags renderFlags) { - List triangles; - if (groupedTriangles.ContainsKey(tPage)) - { - triangles = groupedTriangles[tPage]; - } - else + renderFlags |= RenderFlags.DoubleSided; //todo + var renderInfo = new RenderInfo(tPage, renderFlags); + if (!groupedTriangles.TryGetValue(renderInfo, out var triangles)) { triangles = new List(); - groupedTriangles.Add(tPage, triangles); + groupedTriangles.Add(renderInfo, triangles); } triangles.Add(triangle); } @@ -192,14 +189,6 @@ void AddTriangle(Triangle triangle, uint tPage) uvs[i] = new Vector2(tu, tv); } - using (var writer = File.CreateText("C:\\USERS\\RICKO\\DESKTOP\\TEST"+ nameCrc+".OBJ")) - { - foreach (var vertex in vertices) - { - writer.WriteLine("v " + vertex.X + " " + vertex.Y + " " + vertex.Z); - } - } - reader.BaseStream.Seek(position, SeekOrigin.Begin); var numGT3s = ReadInt(reader); @@ -247,7 +236,7 @@ void AddTriangle(Triangle triangle, uint tPage) u1, v1, u2, v2); - AddTriangle(triangle, tPage); + AddTriangle(triangle, tPage, RenderFlags.Textured); } } else @@ -259,8 +248,8 @@ void AddTriangle(Triangle triangle, uint tPage) var triangle1 = ReadPolyGT3(reader, vertices, vert0, vert1, vert2, out var tPage1); //var triangle2 = ReadPolyGT3(reader, vertices, vert1, vert3, vert2, out var tPage2); - AddTriangle(triangle1, tPage1); - //AddTriangle(triangle2, 0); + AddTriangle(triangle1, tPage1, RenderFlags.Textured); + //AddTriangle(triangle2, tPage2, RenderFlags.Textured); } reader.BaseStream.Seek(position, SeekOrigin.Begin); @@ -328,8 +317,8 @@ void AddTriangle(Triangle triangle, uint tPage) u3, v3, u2, v2); - AddTriangle(triangle1, tPage); - AddTriangle(triangle2, tPage); + AddTriangle(triangle1, tPage, RenderFlags.Textured); + AddTriangle(triangle2, tPage, RenderFlags.Textured); } } else @@ -343,8 +332,9 @@ void AddTriangle(Triangle triangle, uint tPage) //two POLY_GT3 var triangle1 = ReadPolyGT3(reader, vertices, vert0, vert1, vert2, out var tPage1); var triangle2 = ReadPolyGT3(reader, vertices, vert1, vert3, vert2, out var tPage2); - AddTriangle(triangle1, tPage1); - AddTriangle(triangle2, tPage2); + + AddTriangle(triangle1, tPage1, RenderFlags.Textured); + AddTriangle(triangle2, tPage2, RenderFlags.Textured); } reader.BaseStream.Seek(position, SeekOrigin.Begin); @@ -386,7 +376,7 @@ void AddTriangle(Triangle triangle, uint tPage) 0, 0, 0, 0); - AddTriangle(triangle, 0); + AddTriangle(triangle, 0, RenderFlags.None); } reader.BaseStream.Seek(position, SeekOrigin.Begin); @@ -440,24 +430,24 @@ void AddTriangle(Triangle triangle, uint tPage) 0, 0); - AddTriangle(triangle1, 0); - AddTriangle(triangle2, 0); + AddTriangle(triangle1, 0, RenderFlags.None); + AddTriangle(triangle2, 0, RenderFlags.None); } reader.BaseStream.Seek(position, SeekOrigin.Begin); foreach (var kvp in groupedTriangles) { + var renderInfo = kvp.Key; var triangles = kvp.Value; - if (triangles.Count > 0) + var model = new ModelEntity { - var model = new ModelEntity - { - Triangles = triangles.ToArray(), - TexturePage = kvp.Key, - TMDID = 0 - }; - models.Add(model); - } + Triangles = triangles.ToArray(), + TexturePage = renderInfo.TexturePage, + RenderFlags = renderInfo.RenderFlags, + MixtureRate = renderInfo.MixtureRate, + TMDID = 0 + }; + models.Add(model); } if (models.Count > 0) @@ -562,7 +552,7 @@ private Triangle ReadPolyGT3(BinaryReader reader, Vector3[] vertices, uint vert0 //#endif private Triangle TriangleFromPrimitive(Vector3[] vertices, - uint vertex0, uint vertex1, uint vertex2, + uint vertexIndex0, uint vertexIndex1, uint vertexIndex2, byte r0, byte g0, byte b0, byte r1, byte g1, byte b1, byte r2, byte g2, byte b2, @@ -571,74 +561,29 @@ private Triangle TriangleFromPrimitive(Vector3[] vertices, byte u2, byte v2 ) { - Vector3 ver1, ver2, ver3; - if (vertex0 >= vertices.Length || vertex1 >= vertices.Length || vertex2 >= vertices.Length) + if (vertexIndex0 >= vertices.Length || vertexIndex1 >= vertices.Length || vertexIndex2 >= vertices.Length) { - - throw new Exception("Out of indices"); } - else - { - ver1 = vertices[vertex0]; - ver2 = vertices[vertex1]; - ver3 = vertices[vertex2]; - } + var vertex0 = vertices[vertexIndex0]; + var vertex1 = vertices[vertexIndex1]; + var vertex2 = vertices[vertexIndex2]; + + var color0 = new Color(r0/255f, g0/255f, b0/255f); + var color1 = new Color(r1/255f, g1/255f, b1/255f); + var color2 = new Color(r2/255f, g2/255f, b2/255f); + + var uv0 = new Vector2(u0/255f, v0/255f); + var uv1 = new Vector2(u1/255f, v1/255f); + var uv2 = new Vector2(u2/255f, v2/255f); var triangle = new Triangle { - Colors = new[] - { - new Color - ( - r0/255f, - g0/255f, - b0/255f - ), - new Color - ( - r1/255f, - g1/255f, - b1/255f - ), - new Color - ( - r2/255f, - g2/255f, - b2/255f - ) - }, - Normals = new[] - { - Vector3.Zero, - Vector3.Zero, - Vector3.Zero, - }, - Vertices = new[] - { - ver1, - ver2, - ver3 - }, - Uv = new[] - { - new Vector2 - { - X = u0/255f, - Y = v0/255f - }, - new Vector2 - { - X = u1/255f, - Y = v1/255f - }, - new Vector2 - { - X = u2/255f, - Y = v2/255f - } - }, + Vertices = new[] { vertex0, vertex1, vertex2 }, + Normals = new[] { Vector3.Zero, Vector3.Zero, Vector3.Zero }, + Colors = new[] { color0, color1, color2 }, + Uv = new[] { uv0, uv1, uv2 }, AttachableIndices = new[] { uint.MaxValue, uint.MaxValue, uint.MaxValue } }; diff --git a/Classes/CrocModelReader.cs b/Classes/CrocModelReader.cs index d2e4656..6981d02 100644 --- a/Classes/CrocModelReader.cs +++ b/Classes/CrocModelReader.cs @@ -48,6 +48,20 @@ private static Vector3 ReadVector(BinaryReader reader, bool normal = false, bool private static RootEntity ReadModels(BinaryReader reader) { + var groupedTriangles = new Dictionary>(); + + void AddTriangle(Triangle triangle, uint tPage, RenderFlags renderFlags) + { + renderFlags |= RenderFlags.DoubleSided; //todo + var renderInfo = new RenderInfo(tPage, renderFlags); + if (!groupedTriangles.TryGetValue(renderInfo, out var triangles)) + { + triangles = new List(); + groupedTriangles.Add(renderInfo, triangles); + } + triangles.Add(triangle); + } + // Some data is properly handled thanks to vs49688's work on CrocUtils. // Notably: Fixed point size, flags, bounding box indices, color, UVs, and the collision section. // @@ -111,7 +125,6 @@ private static RootEntity ReadModels(BinaryReader reader) { return null; } - var triangles = new List((int)countFaces); // Groups are observed as consecutive faces that share some similar properties. // They are defined by the fourth uint16 in a face. When non-zero, a new group is started. @@ -178,11 +191,15 @@ private static RootEntity ReadModels(BinaryReader reader) normal0 = normal1 = normal2 = GeomUtils.CalculateNormal(vertex0, vertex1, vertex2); } + var renderFlags = RenderFlags.None; + uint tPage; + // We can't actually use UVs yet, since they're likely scaled for the material, and not the whole VRAM page. Vector2 uv0, uv1, uv2, uv3; - float r, g, b; + Color color; if (texture) { + renderFlags |= RenderFlags.Textured; if (!quad) { // Is uvFlip flag ignored for tri? (flag has been observed both set and unset) @@ -210,26 +227,30 @@ private static RootEntity ReadModels(BinaryReader reader) } var materialId = faceInfo & 0xffff; - r = g = b = Color.DefaultColorTone; + color = Color.Grey; + + tPage = 0; //todo } else { uv0 = uv1 = uv2 = uv3 = Vector2.Zero; - r = ((faceInfo >> 0) & 0xff) / 255f; - g = ((faceInfo >> 8) & 0xff) / 255f; - b = ((faceInfo >> 16) & 0xff) / 255f; + var r = ((faceInfo >> 0) & 0xff) / 255f; + var g = ((faceInfo >> 8) & 0xff) / 255f; + var b = ((faceInfo >> 16) & 0xff) / 255f; + color = new Color(r, g, b); + + tPage = 0; //todo } - var color = new Color(r, g, b); - triangles.Add(new Triangle + AddTriangle(new Triangle { Vertices = new[] { vertex0, vertex1, vertex2 }, Normals = new[] { normal0, normal1, normal2 }, Colors = new[] { color, color, color }, - Uv = new[] { Vector2.Zero, Vector2.Zero, Vector2.Zero }, + Uv = new[] { Vector2.Zero, Vector2.Zero, Vector2.Zero }, // Can't use UVs yet AttachableIndices = new [] {uint.MaxValue, uint.MaxValue, uint.MaxValue} - }); + }, tPage, renderFlags); if (quad) { var vertex3 = vertices[index3]; @@ -245,14 +266,14 @@ private static RootEntity ReadModels(BinaryReader reader) normal1 = normal3 = normal2 = GeomUtils.CalculateNormal(vertex1, vertex3, vertex2); } - triangles.Add(new Triangle + AddTriangle(new Triangle { Vertices = new[] { vertex1, vertex3, vertex2 }, Normals = new[] { normal1, normal3, normal2 }, Colors = new[] { color, color, color }, - Uv = new[] { Vector2.Zero, Vector2.Zero, Vector2.Zero }, + Uv = new[] { Vector2.Zero, Vector2.Zero, Vector2.Zero }, // Can't use UVs yet AttachableIndices = new[] { uint.MaxValue, uint.MaxValue, uint.MaxValue } - }); + }, tPage, renderFlags); } } @@ -264,16 +285,21 @@ private static RootEntity ReadModels(BinaryReader reader) reader.BaseStream.Seek((size1 + size2) * 44, SeekOrigin.Current); } - // Don't add empty models. - if (triangles.Count > 0) + foreach (var kvp in groupedTriangles) { - var modelEntity = new ModelEntity + var renderInfo = kvp.Key; + var triangles = kvp.Value; + var model = new ModelEntity { Triangles = triangles.ToArray(), - TMDID = i, + TexturePage = renderInfo.TexturePage, + RenderFlags = renderInfo.RenderFlags, + MixtureRate = renderInfo.MixtureRate, + TMDID = i + 1, //todo }; - models.Add(modelEntity); + models.Add(model); } + groupedTriangles.Clear(); } if (models.Count > 0) { diff --git a/Classes/Mesh.cs b/Classes/Mesh.cs index 5dec697..aca79f7 100644 --- a/Classes/Mesh.cs +++ b/Classes/Mesh.cs @@ -10,7 +10,7 @@ public class Mesh public Matrix4 WorldMatrix { get; set; } public uint Texture { get; set; } - public RenderFlags RenderFlags { get; set; } + public RenderFlags RenderFlags { get; set; } = RenderFlags.DoubleSided; // Default flags public MixtureRate MixtureRate { get; set; } private readonly uint _meshId; @@ -71,7 +71,7 @@ public void Draw(TextureBinder textureBinder = null, bool wireframe = false, boo GL.EnableVertexAttribArray((uint)Scene.AttributeIndexTiledArea); GL.VertexAttribPointer((uint)Scene.AttributeIndexTiledArea, 4, VertexAttribPointerType.Float, false, 0, IntPtr.Zero); - if (textureBinder != null && Texture != 0) + if (textureBinder != null && Texture != 0 && RenderFlags.HasFlag(RenderFlags.Textured)) { textureBinder.BindTexture(Texture); } @@ -80,7 +80,7 @@ public void Draw(TextureBinder textureBinder = null, bool wireframe = false, boo GL.DrawArrays(verticesOnly ? OpenTK.Graphics.OpenGL.PrimitiveType.Points : OpenTK.Graphics.OpenGL.PrimitiveType.Triangles, 0, _numElements); GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); - if (textureBinder != null && Texture != 0) + if (textureBinder != null && Texture != 0 && RenderFlags.HasFlag(RenderFlags.Textured)) { textureBinder.Unbind(); } diff --git a/Classes/MeshBatch.cs b/Classes/MeshBatch.cs index 7839759..137f68e 100644 --- a/Classes/MeshBatch.cs +++ b/Classes/MeshBatch.cs @@ -342,9 +342,13 @@ private void BindMesh(ModelEntity modelEntity, Matrix4? matrix = null, TextureBi } mesh.SetData(numElements, positionList, normalList, colorList, uvList, tiledAreaList); } - if (textureBinder != null) + if (textureBinder != null && modelEntity.Texture != null && modelEntity.RenderFlags.HasFlag(RenderFlags.Textured)) + { + mesh.Texture = textureBinder.GetTexture((int)modelEntity.TexturePage); + } + else { - mesh.Texture = modelEntity.Texture != null ? textureBinder.GetTexture((int)modelEntity.TexturePage) : 0; + mesh.Texture = 0; } } @@ -395,14 +399,22 @@ private void DrawMesh(Mesh mesh, Matrix4 viewMatrix, Matrix4 projectionMatrix, T { GL.Uniform1(Scene.UniformRenderMode, 0); // Enable lighting } + if (mesh.RenderFlags.HasFlag(RenderFlags.Textured)) + { + GL.Uniform1(Scene.UniformTextureMode, 0); // Enable texture + } + else + { + GL.Uniform1(Scene.UniformTextureMode, 1); // Disable texture + } } if (_scene.ForceDoubleSided || mesh.RenderFlags.HasFlag(RenderFlags.DoubleSided)) { - GL.Disable(EnableCap.CullFace); + GL.Disable(EnableCap.CullFace); // Double-sided } else { - GL.Enable(EnableCap.CullFace); + GL.Enable(EnableCap.CullFace); // Single-sided GL.CullFace(CullFaceMode.Front); } var modelMatrix = mesh.WorldMatrix; @@ -442,6 +454,10 @@ public void Draw(Matrix4 viewMatrix, Matrix4 projectionMatrix, TextureBinder tex { continue; // Not a semi-transparent mesh } + if (!mesh.RenderFlags.HasFlag(RenderFlags.Textured)) + { + continue; // Untextured surfaces always have stp bit SET. + } DrawMesh(mesh, viewMatrix, projectionMatrix, textureBinder, wireframe, standard, verticesOnly); } diff --git a/Classes/ModelEntity.cs b/Classes/ModelEntity.cs index 11dfd2b..9ebc99c 100644 --- a/Classes/ModelEntity.cs +++ b/Classes/ModelEntity.cs @@ -7,24 +7,38 @@ namespace PSXPrev.Classes { public class ModelEntity : EntityBase { - // Default flags for when a reader doesn't assign any. - public const RenderFlags DefaultRenderFlags = RenderFlags.DoubleSided; - - private Triangle[] _triangles; [DisplayName("VRAM Page")] public uint TexturePage { get; set; } - + + // Use default flags for when a reader doesn't assign any. [DisplayName("Render Flags")] - public RenderFlags RenderFlags { get; set; } = DefaultRenderFlags; - + public RenderFlags RenderFlags { get; set; } = RenderFlags.DoubleSided | RenderFlags.Textured; + [DisplayName("Mixture Rate")] public MixtureRate MixtureRate { get; set; } - [ReadOnly(true), DisplayName("Total Triangles")] + [DisplayName("Triangles"), ReadOnly(true)] public int TrianglesCount => Triangles.Length; + [Browsable(false)] + public int TotalTriangles + { + get + { + var count = TrianglesCount; + if (ChildEntities != null) + { + foreach (ModelEntity subModel in ChildEntities) + { + count += subModel.TotalTriangles; + } + } + return count; + } + } + [Browsable(false)] public Triangle[] Triangles { @@ -48,7 +62,7 @@ public Triangle[] Triangles [DisplayName("TMD ID")] public uint TMDID { get; set; } - [ReadOnly(true), DisplayName("Has Tiled Texture")] + [DisplayName("Has Tiled Texture"), ReadOnly(true)] public bool HasTiled { get diff --git a/Classes/ObjExporter.cs b/Classes/ObjExporter.cs index 1246fe2..e7188bf 100644 --- a/Classes/ObjExporter.cs +++ b/Classes/ObjExporter.cs @@ -68,7 +68,7 @@ public void Export(RootEntity[] entities, string selectedPath, bool experimental private void WriteModel(ModelEntity model) { - if (model.Texture != null) + if (model.Texture != null && model.RenderFlags.HasFlag(RenderFlags.Textured)) { if (_mtlExporter.AddMaterial((int) model.TexturePage)) { diff --git a/Classes/PMDParser.cs b/Classes/PMDParser.cs index a23e602..1465f76 100644 --- a/Classes/PMDParser.cs +++ b/Classes/PMDParser.cs @@ -33,6 +33,27 @@ protected override void Parse(BinaryReader reader, string fileTitle, out List>(); + + void AddTriangle(Triangle triangle, uint tPage, RenderFlags renderFlags) + { + var renderInfo = new RenderInfo(tPage, renderFlags); + if (!groupedTriangles.TryGetValue(renderInfo, out var triangles)) + { + triangles = new List(); + groupedTriangles.Add(renderInfo, triangles); + } + triangles.Add(triangle); + } + + void AddTriangles(Triangle[] triangles, uint tPage, RenderFlags renderFlags) + { + foreach (var triangle in triangles) + { + AddTriangle(triangle, tPage, renderFlags); + } + } + var primPoint = reader.ReadUInt32(); var vertPoint = reader.ReadUInt32(); var nObj = reader.ReadUInt32(); @@ -41,10 +62,8 @@ private RootEntity ParsePMD(BinaryReader reader) return null; } var models = new List(); - for (var o = 0; o < nObj; o++) + for (uint o = 0; o < nObj; o++) { - var model = new ModelEntity(); - var triangles = new List(); var nPointers = reader.ReadUInt32(); if (nPointers < 1 || nPointers > 4000) { @@ -62,10 +81,15 @@ private RootEntity ParsePMD(BinaryReader reader) } var primType = reader.ReadUInt16(); + var quad = ((primType >> 0) & 0x1) == 1; // Polygon: 0-Triangle, 1-Quad + var iipBit = ((primType >> 1) & 0x1) == 1; // Shading: 0-Flat, 1-Gouraud (separate colors when !lgtBit) + var tmeBit = ((primType >> 2) & 0x1) == 0; // Texture: 1-On, 0-Off + var shared = ((primType >> 3) & 0x1) == 1; // Vertex: 0-Independent, 1-Shared var lgtBit = ((primType >> 4) & 0x1) == 1; // Light: 0-Unlit, 1-Lit var botBit = ((primType >> 5) & 0x1) == 1; // Both sides: 0-Single sided, 1-Double sided var renderFlags = RenderFlags.None; + if (tmeBit) renderFlags |= RenderFlags.Textured; if (!lgtBit) renderFlags |= RenderFlags.Unlit; if (botBit) renderFlags |= RenderFlags.DoubleSided; @@ -77,55 +101,56 @@ private RootEntity ParsePMD(BinaryReader reader) for (var pk = 0; pk < nPacket; pk++) { + uint tPage; switch (primTypeSwitch) { case 0x00: - triangles.Add(ReadPolyFT3(reader)); + AddTriangle(ReadPolyFT3(reader, out tPage), tPage, renderFlags); break; case 0x01: - triangles.AddRange(ReadPolyFT4(reader)); + AddTriangles(ReadPolyFT4(reader, out tPage), tPage, renderFlags); break; case 0x02: - triangles.Add(ReadPolyGT3(reader)); + AddTriangle(ReadPolyGT3(reader, out tPage), tPage, renderFlags); break; case 0x03: - triangles.AddRange(ReadPolyGT4(reader)); + AddTriangles(ReadPolyGT4(reader, out tPage), tPage, renderFlags); break; case 0x04: - triangles.Add(ReadPolyF3(reader)); + AddTriangle(ReadPolyF3(reader), 0, renderFlags); break; case 0x05: - triangles.AddRange(ReadPolyF4(reader)); + AddTriangles(ReadPolyF4(reader), 0, renderFlags); break; case 0x06: - triangles.Add(ReadPolyG3(reader)); + AddTriangle(ReadPolyG3(reader), 0, renderFlags); break; case 0x07: - triangles.AddRange(ReadPolyG4(reader)); + AddTriangles(ReadPolyG4(reader), 0, renderFlags); break; case 0x08: - triangles.Add(ReadPolyFT3(reader, true, _offset + vertPoint)); + AddTriangle(ReadPolyFT3(reader, out tPage, true, vertPoint), tPage, renderFlags); break; case 0x09: - triangles.AddRange(ReadPolyFT4(reader, true, _offset + vertPoint)); + AddTriangles(ReadPolyFT4(reader, out tPage, true, vertPoint), tPage, renderFlags); break; case 0x0a: - triangles.Add(ReadPolyGT3(reader, true, _offset + vertPoint)); + AddTriangle(ReadPolyGT3(reader, out tPage, true, vertPoint), tPage, renderFlags); break; case 0x0b: - triangles.AddRange(ReadPolyGT4(reader, true, _offset + vertPoint)); + AddTriangles(ReadPolyGT4(reader, out tPage, true, vertPoint), tPage, renderFlags); break; case 0x0c: - triangles.Add(ReadPolyF3(reader, true, _offset + vertPoint)); + AddTriangle(ReadPolyF3(reader, true, vertPoint), 0, renderFlags); break; case 0x0d: - triangles.AddRange(ReadPolyF4(reader, true, _offset + vertPoint)); + AddTriangles(ReadPolyF4(reader, true, vertPoint), 0, renderFlags); break; case 0x0e: - triangles.Add(ReadPolyG3(reader, true, _offset + vertPoint)); + AddTriangle(ReadPolyG3(reader, true, vertPoint), 0, renderFlags); break; case 0x0f: - triangles.AddRange(ReadPolyG4(reader, true, _offset + vertPoint)); + AddTriangles(ReadPolyG4(reader, true, vertPoint), 0, renderFlags); break; default: if (Program.Debug) @@ -138,8 +163,21 @@ private RootEntity ParsePMD(BinaryReader reader) reader.BaseStream.Seek(position + 4, SeekOrigin.Begin); } EndObject: - model.Triangles = triangles.ToArray(); - models.Add(model); + foreach (var kvp in groupedTriangles) + { + var renderInfo = kvp.Key; + var triangles = kvp.Value; + var model = new ModelEntity + { + Triangles = triangles.ToArray(), + TexturePage = renderInfo.TexturePage, + RenderFlags = renderInfo.RenderFlags, + MixtureRate = renderInfo.MixtureRate, + TMDID = o + 1, //todo + }; + models.Add(model); + } + groupedTriangles.Clear(); } EndModel: @@ -157,7 +195,7 @@ private RootEntity ParsePMD(BinaryReader reader) return null; } - private Triangle[] ReadPolyGT4(BinaryReader reader, bool sharedVertices = false, long verticesOffset = 0) + private Triangle[] ReadPolyGT4(BinaryReader reader, out uint tPage, bool sharedVertices = false, uint vertPoint = 0) { int tag; byte r0 = 0, g0 = 0, b0 = 0; @@ -173,7 +211,7 @@ private Triangle[] ReadPolyGT4(BinaryReader reader, bool sharedVertices = false, byte u2 = 0, v2 = 0; byte u3 = 0, v3 = 0; ushort clut; - ushort tPage; + tPage = 0; byte code; for (var i = 0; i < 2; i++) { @@ -215,10 +253,10 @@ private Triangle[] ReadPolyGT4(BinaryReader reader, bool sharedVertices = false, v3 = reader.ReadByte(); reader.ReadUInt16(); } - Int16 v0x, v0y, v0z; - Int16 v1x, v1y, v1z; - Int16 v2x, v2y, v2z; - Int16 v3x, v3y, v3z; + short v0x, v0y, v0z; + short v1x, v1y, v1z; + short v2x, v2y, v2z; + short v3x, v3y, v3z; if (!sharedVertices) { ReadSVector(reader, out v0x, out v0y, out v0z); @@ -228,10 +266,10 @@ private Triangle[] ReadPolyGT4(BinaryReader reader, bool sharedVertices = false, } else { - long vo0 = verticesOffset + reader.ReadUInt32(); - long vo1 = verticesOffset + reader.ReadUInt32(); - long vo2 = verticesOffset + reader.ReadUInt32(); - long vo3 = verticesOffset + reader.ReadUInt32(); + var vo0 = vertPoint + reader.ReadUInt32(); + var vo1 = vertPoint + reader.ReadUInt32(); + var vo2 = vertPoint + reader.ReadUInt32(); + var vo3 = vertPoint + reader.ReadUInt32(); var position = reader.BaseStream.Position; ReadSharedVertices(reader, vo0, out v0x, out v0y, out v0z); ReadSharedVertices(reader, vo1, out v1x, out v1y, out v1z); @@ -246,7 +284,7 @@ private Triangle[] ReadPolyGT4(BinaryReader reader, bool sharedVertices = false, return new[] { triangle1, triangle2 }; } - private Triangle[] ReadPolyG4(BinaryReader reader, bool sharedVertices = false, long verticesOffset = 0) + private Triangle[] ReadPolyG4(BinaryReader reader, bool sharedVertices = false, uint vertPoint = 0) { long tag; byte r0 = 0, g0 = 0, b0 = 0; @@ -286,10 +324,10 @@ private Triangle[] ReadPolyG4(BinaryReader reader, bool sharedVertices = false, x3 = reader.ReadInt16(); y3 = reader.ReadInt16(); } - Int16 v0x, v0y, v0z; - Int16 v1x, v1y, v1z; - Int16 v2x, v2y, v2z; - Int16 v3x, v3y, v3z; + short v0x, v0y, v0z; + short v1x, v1y, v1z; + short v2x, v2y, v2z; + short v3x, v3y, v3z; if (!sharedVertices) { ReadSVector(reader, out v0x, out v0y, out v0z); @@ -299,10 +337,10 @@ private Triangle[] ReadPolyG4(BinaryReader reader, bool sharedVertices = false, } else { - long vo0 = verticesOffset + reader.ReadUInt32(); - long vo1 = verticesOffset + reader.ReadUInt32(); - long vo2 = verticesOffset + reader.ReadUInt32(); - long vo3 = verticesOffset + reader.ReadUInt32(); + var vo0 = vertPoint + reader.ReadUInt32(); + var vo1 = vertPoint + reader.ReadUInt32(); + var vo2 = vertPoint + reader.ReadUInt32(); + var vo3 = vertPoint + reader.ReadUInt32(); var position = reader.BaseStream.Position; ReadSharedVertices(reader, vo0, out v0x, out v0y, out v0z); ReadSharedVertices(reader, vo1, out v1x, out v1y, out v1z); @@ -318,7 +356,7 @@ private Triangle[] ReadPolyG4(BinaryReader reader, bool sharedVertices = false, return new[] { triangle1, triangle2 }; } - private Triangle[] ReadPolyFT4(BinaryReader reader, bool sharedVertices = false, long verticesOffset = 0) + private Triangle[] ReadPolyFT4(BinaryReader reader, out uint tPage, bool sharedVertices = false, uint vertPoint = 0) { long tag; byte r = 0, g = 0, b = 0; @@ -332,7 +370,7 @@ private Triangle[] ReadPolyFT4(BinaryReader reader, bool sharedVertices = false, byte u2 = 0, v2 = 0; byte u3 = 0, v3 = 0; ushort clutId; - ushort tPage; + tPage = 0; for (var i = 0; i < 2; i++) { tag = reader.ReadUInt32(); @@ -361,10 +399,10 @@ private Triangle[] ReadPolyFT4(BinaryReader reader, bool sharedVertices = false, v3 = reader.ReadByte(); reader.ReadUInt16(); } - Int16 v0x, v0y, v0z; - Int16 v1x, v1y, v1z; - Int16 v2x, v2y, v2z; - Int16 v3x, v3y, v3z; + short v0x, v0y, v0z; + short v1x, v1y, v1z; + short v2x, v2y, v2z; + short v3x, v3y, v3z; if (!sharedVertices) { ReadSVector(reader, out v0x, out v0y, out v0z); @@ -374,10 +412,10 @@ private Triangle[] ReadPolyFT4(BinaryReader reader, bool sharedVertices = false, } else { - long vo0 = verticesOffset + reader.ReadUInt32(); - long vo1 = verticesOffset + reader.ReadUInt32(); - long vo2 = verticesOffset + reader.ReadUInt32(); - long vo3 = verticesOffset + reader.ReadUInt32(); + var vo0 = vertPoint + reader.ReadUInt32(); + var vo1 = vertPoint + reader.ReadUInt32(); + var vo2 = vertPoint + reader.ReadUInt32(); + var vo3 = vertPoint + reader.ReadUInt32(); var position = reader.BaseStream.Position; ReadSharedVertices(reader, vo0, out v0x, out v0y, out v0z); ReadSharedVertices(reader, vo1, out v1x, out v1y, out v1z); @@ -392,7 +430,7 @@ private Triangle[] ReadPolyFT4(BinaryReader reader, bool sharedVertices = false, return new[] { triangle1, triangle2 }; } - private Triangle[] ReadPolyF4(BinaryReader reader, bool sharedVertices = false, long verticesOffset = 0) + private Triangle[] ReadPolyF4(BinaryReader reader, bool sharedVertices = false, uint vertPoint = 0) { int tag; byte r0 = 0, g0 = 0, b0 = 0; @@ -417,10 +455,10 @@ private Triangle[] ReadPolyF4(BinaryReader reader, bool sharedVertices = false, x3 = reader.ReadInt16(); y3 = reader.ReadInt16(); } - Int16 v0x, v0y, v0z; - Int16 v1x, v1y, v1z; - Int16 v2x, v2y, v2z; - Int16 v3x, v3y, v3z; + short v0x, v0y, v0z; + short v1x, v1y, v1z; + short v2x, v2y, v2z; + short v3x, v3y, v3z; if (!sharedVertices) { ReadSVector(reader, out v0x, out v0y, out v0z); @@ -430,10 +468,10 @@ private Triangle[] ReadPolyF4(BinaryReader reader, bool sharedVertices = false, } else { - long vo0 = verticesOffset + reader.ReadUInt32(); - long vo1 = verticesOffset + reader.ReadUInt32(); - long vo2 = verticesOffset + reader.ReadUInt32(); - long vo3 = verticesOffset + reader.ReadUInt32(); + var vo0 = vertPoint + reader.ReadUInt32(); + var vo1 = vertPoint + reader.ReadUInt32(); + var vo2 = vertPoint + reader.ReadUInt32(); + var vo3 = vertPoint + reader.ReadUInt32(); var position = reader.BaseStream.Position; ReadSharedVertices(reader, vo0, out v0x, out v0y, out v0z); ReadSharedVertices(reader, vo1, out v1x, out v1y, out v1z); @@ -449,7 +487,7 @@ private Triangle[] ReadPolyF4(BinaryReader reader, bool sharedVertices = false, return new[] { triangle1, triangle2 }; } - private Triangle ReadPolyGT3(BinaryReader reader, bool sharedVertices = false, long verticesOffset = 0) + private Triangle ReadPolyGT3(BinaryReader reader, out uint tPage, bool sharedVertices = false, uint vertPoint = 0) { int tag; byte r0 = 0, g0 = 0, b0 = 0; @@ -462,7 +500,7 @@ private Triangle ReadPolyGT3(BinaryReader reader, bool sharedVertices = false, l byte u1 = 0, v1 = 0; byte u2 = 0, v2 = 0; ushort clut; - ushort tPage; + tPage = 0; byte code; for (var i = 0; i < 2; i++) { @@ -495,9 +533,9 @@ private Triangle ReadPolyGT3(BinaryReader reader, bool sharedVertices = false, l v2 = reader.ReadByte(); reader.ReadUInt16(); } - Int16 v0x, v0y, v0z; - Int16 v1x, v1y, v1z; - Int16 v2x, v2y, v2z; + short v0x, v0y, v0z; + short v1x, v1y, v1z; + short v2x, v2y, v2z; if (!sharedVertices) { ReadSVector(reader, out v0x, out v0y, out v0z); @@ -506,9 +544,9 @@ private Triangle ReadPolyGT3(BinaryReader reader, bool sharedVertices = false, l } else { - long vo0 = verticesOffset + reader.ReadUInt32(); - long vo1 = verticesOffset + reader.ReadUInt32(); - long vo2 = verticesOffset + reader.ReadUInt32(); + var vo0 = vertPoint + reader.ReadUInt32(); + var vo1 = vertPoint + reader.ReadUInt32(); + var vo2 = vertPoint + reader.ReadUInt32(); var position = reader.BaseStream.Position; ReadSharedVertices(reader, vo0, out v0x, out v0y, out v0z); ReadSharedVertices(reader, vo1, out v1x, out v1y, out v1z); @@ -521,7 +559,7 @@ private Triangle ReadPolyGT3(BinaryReader reader, bool sharedVertices = false, l return triangle; } - private Triangle ReadPolyF3(BinaryReader reader, bool sharedVertices = false, long verticesOffset = 0) + private Triangle ReadPolyF3(BinaryReader reader, bool sharedVertices = false, uint vertPoint = 0) { int tag; byte r0 = 0, g0 = 0, b0 = 0; @@ -543,9 +581,9 @@ private Triangle ReadPolyF3(BinaryReader reader, bool sharedVertices = false, lo x2 = reader.ReadInt16(); y2 = reader.ReadInt16(); } - Int16 v0x, v0y, v0z; - Int16 v1x, v1y, v1z; - Int16 v2x, v2y, v2z; + short v0x, v0y, v0z; + short v1x, v1y, v1z; + short v2x, v2y, v2z; if (!sharedVertices) { ReadSVector(reader, out v0x, out v0y, out v0z); @@ -554,9 +592,9 @@ private Triangle ReadPolyF3(BinaryReader reader, bool sharedVertices = false, lo } else { - long vo0 = verticesOffset + reader.ReadUInt32(); - long vo1 = verticesOffset + reader.ReadUInt32(); - long vo2 = verticesOffset + reader.ReadUInt32(); + var vo0 = vertPoint + reader.ReadUInt32(); + var vo1 = vertPoint + reader.ReadUInt32(); + var vo2 = vertPoint + reader.ReadUInt32(); var position = reader.BaseStream.Position; ReadSharedVertices(reader, vo0, out v0x, out v0y, out v0z); ReadSharedVertices(reader, vo1, out v1x, out v1y, out v1z); @@ -568,7 +606,7 @@ private Triangle ReadPolyF3(BinaryReader reader, bool sharedVertices = false, lo return triangle; } - private Triangle ReadPolyG3(BinaryReader reader, bool sharedVertices = false, long verticesOffset = 0) + private Triangle ReadPolyG3(BinaryReader reader, bool sharedVertices = false, uint vertPoint = 0) { long tag; byte r0 = 0, g0 = 0, b0 = 0; @@ -600,9 +638,9 @@ private Triangle ReadPolyG3(BinaryReader reader, bool sharedVertices = false, lo x2 = reader.ReadInt16(); y2 = reader.ReadInt16(); } - Int16 v0x, v0y, v0z; - Int16 v1x, v1y, v1z; - Int16 v2x, v2y, v2z; + short v0x, v0y, v0z; + short v1x, v1y, v1z; + short v2x, v2y, v2z; if (!sharedVertices) { ReadSVector(reader, out v0x, out v0y, out v0z); @@ -611,9 +649,9 @@ private Triangle ReadPolyG3(BinaryReader reader, bool sharedVertices = false, lo } else { - long vo0 = verticesOffset + reader.ReadUInt32(); - long vo1 = verticesOffset + reader.ReadUInt32(); - long vo2 = verticesOffset + reader.ReadUInt32(); + var vo0 = vertPoint + reader.ReadUInt32(); + var vo1 = vertPoint + reader.ReadUInt32(); + var vo2 = vertPoint + reader.ReadUInt32(); var position = reader.BaseStream.Position; ReadSharedVertices(reader, vo0, out v0x, out v0y, out v0z); ReadSharedVertices(reader, vo1, out v1x, out v1y, out v1z); @@ -626,7 +664,7 @@ private Triangle ReadPolyG3(BinaryReader reader, bool sharedVertices = false, lo return triangle; } - private Triangle ReadPolyFT3(BinaryReader reader, bool sharedVertices = false, long verticesOffset = 0) + private Triangle ReadPolyFT3(BinaryReader reader, out uint tPage, bool sharedVertices = false, uint vertPoint = 0) { long tag; byte r = 0, g = 0, b = 0; @@ -638,7 +676,7 @@ private Triangle ReadPolyFT3(BinaryReader reader, bool sharedVertices = false, l byte u1 = 0, v1 = 0; byte u2 = 0, v2 = 0; ushort clutId; - ushort tPage; + tPage = 0; for (var i = 0; i < 2; i++) { tag = reader.ReadUInt32(); @@ -663,9 +701,9 @@ private Triangle ReadPolyFT3(BinaryReader reader, bool sharedVertices = false, l reader.ReadUInt16(); } - Int16 v0x, v0y, v0z; - Int16 v1x, v1y, v1z; - Int16 v2x, v2y, v2z; + short v0x, v0y, v0z; + short v1x, v1y, v1z; + short v2x, v2y, v2z; if (!sharedVertices) { ReadSVector(reader, out v0x, out v0y, out v0z); @@ -674,9 +712,9 @@ private Triangle ReadPolyFT3(BinaryReader reader, bool sharedVertices = false, l } else { - long vo0 = verticesOffset + reader.ReadUInt32(); - long vo1 = verticesOffset + reader.ReadUInt32(); - long vo2 = verticesOffset + reader.ReadUInt32(); + var vo0 = vertPoint + reader.ReadUInt32(); + var vo1 = vertPoint + reader.ReadUInt32(); + var vo2 = vertPoint + reader.ReadUInt32(); var position = reader.BaseStream.Position; ReadSharedVertices(reader, vo0, out v0x, out v0y, out v0z); ReadSharedVertices(reader, vo1, out v1x, out v1y, out v1z); @@ -688,46 +726,30 @@ private Triangle ReadPolyFT3(BinaryReader reader, bool sharedVertices = false, l return triangle; } - private void ReadSVector(BinaryReader stream, out Int16 X, out Int16 Y, out Int16 Z) + private void ReadSVector(BinaryReader stream, out short x, out short y, out short z) { - X = stream.ReadInt16(); - Y = stream.ReadInt16(); - Z = stream.ReadInt16(); + x = stream.ReadInt16(); + y = stream.ReadInt16(); + z = stream.ReadInt16(); stream.ReadInt16(); } - private void ReadSharedVertices(BinaryReader reader, long offset, out short v0X, out short v0Y, out short v0Z) + private void ReadSharedVertices(BinaryReader reader, uint vertOffset, out short v0X, out short v0Y, out short v0Z) { - reader.BaseStream.Position = offset; + reader.BaseStream.Seek(_offset + vertOffset, SeekOrigin.Begin); ReadSVector(reader, out v0X, out v0Y, out v0Z); } - private void AddTriangle(Dictionary> groupedTriangles, Triangle triangle, uint p) - { - List triangles; - if (groupedTriangles.ContainsKey(p)) - { - triangles = groupedTriangles[p]; - } - else - { - triangles = new List(); - groupedTriangles.Add(p, triangles); - } - triangles.Add(triangle); - } - - private Triangle TriangleFromPrimitive(Triangle.PrimitiveTypeEnum primitiveType, bool sharedVertices, bool sharedNormals, Vector3[] vertices, Vector3[] normals, ushort vertex0, ushort vertex1, - ushort vertex2, ushort normal0, ushort normal1, ushort normal2, byte r0, byte g0, byte b0, byte r1, byte g1, - byte b1, byte r2, byte g2, byte b2, byte u0, byte v0, byte u1, byte v1, byte u2, byte v2, short p1x = 0, short p1y = 0, short p1z = 0, short p2x = 0, short p2y = 0, short p2z = 0, short p3x = 0, short p3y = 0, short p3z = 0 - - , short n1x = 0, short n1y = 0, short n1z = 0, short n2x = 0, short n2y = 0, short n2z = 0, short n3x = 0, short n3y = 0, short n3z = 0 - + private Triangle TriangleFromPrimitive(Triangle.PrimitiveTypeEnum primitiveType, bool sharedVertices, bool sharedNormals, Vector3[] vertices, Vector3[] normals, + ushort vertexIndex0, ushort vertexIndex1, ushort vertexIndex2, ushort normalIndex0, ushort normalIndex1, ushort normalIndex2, + byte r0, byte g0, byte b0, byte r1, byte g1, byte b1, byte r2, byte g2, byte b2, byte u0, byte v0, byte u1, byte v1, byte u2, byte v2, + short p0x = 0, short p0y = 0, short p0z = 0, short p1x = 0, short p1y = 0, short p1z = 0, short p2x = 0, short p2y = 0, short p2z = 0, + short n0x = 0, short n0y = 0, short n0z = 0, short n1x = 0, short n1y = 0, short n1z = 0, short n2x = 0, short n2y = 0, short n2z = 0 ) { if (sharedVertices) { - if (vertex0 >= vertices.Length) + if (vertexIndex0 >= vertices.Length)// || vertexIndex1 >= vertices.Length || vertexIndex2 >= vertices.Length) { return null; } @@ -735,156 +757,35 @@ private Triangle TriangleFromPrimitive(Triangle.PrimitiveTypeEnum primitiveType, if (sharedNormals) { - if (normal0 >= normals.Length || normal1 >= normals.Length || normal2 >= normals.Length) + if (normalIndex0 >= normals.Length || normalIndex1 >= normals.Length || normalIndex2 >= normals.Length) { return null; } } - Vector3 ver1, ver2, ver3; - if (sharedVertices) - { - ver1 = new Vector3 - { - X = vertices[vertex0].X, - Y = vertices[vertex0].Y, - Z = vertices[vertex0].Z, - }; + var vertex0 = sharedVertices ? vertices[vertexIndex0] : new Vector3(p0x, p0y, p0z); + var vertex1 = sharedVertices ? vertices[vertexIndex1] : new Vector3(p1x, p1y, p1z); + var vertex2 = sharedVertices ? vertices[vertexIndex2] : new Vector3(p2x, p2y, p2z); - ver2 = new Vector3 - { - X = vertices[vertex1].X, - Y = vertices[vertex1].Y, - Z = vertices[vertex1].Z, - }; + var normal0 = sharedNormals ? normals[normalIndex0] : new Vector3(n0x, n0y, n0z); + var normal1 = sharedNormals ? normals[normalIndex1] : new Vector3(n1x, n1y, n1z); + var normal2 = sharedNormals ? normals[normalIndex2] : new Vector3(n2x, n2y, n2z); - ver3 = new Vector3 - { - X = vertices[vertex2].X, - Y = vertices[vertex2].Y, - Z = vertices[vertex2].Z, - }; - } - else - { - ver1 = new Vector3 - { - X = p1x, - Y = p1y, - Z = p1z - }; - ver2 = new Vector3 - { - X = p2x, - Y = p2y, - Z = p2z - }; - ver3 = new Vector3 - { - X = p3x, - Y = p3y, - Z = p3z - }; - } + var color0 = new Color(r0/255f, g0/255f, b0/255f); + var color1 = new Color(r1/255f, g1/255f, b1/255f); + var color2 = new Color(r2/255f, g2/255f, b2/255f); - Vector3 nor1, nor2, nor3; - if (sharedNormals) - { - nor1 = new Vector3 - { - X = normals[normal0].X, - Y = normals[normal0].Y, - Z = normals[normal0].Z - }; - nor2 = new Vector3 - { - X = normals[normal1].X, - Y = normals[normal1].Y, - Z = normals[normal1].Z - }; - nor3 = new Vector3 - { - X = normals[normal2].X, - Y = normals[normal2].Y, - Z = normals[normal2].Z - }; - } - else - { - nor1 = new Vector3 - { - X = n1x, - Y = n1y, - Z = n1z - }; - nor2 = new Vector3 - { - X = n2x, - Y = n2y, - Z = n2z - }; - nor3 = new Vector3 - { - X = n3x, - Y = n3y, - Z = n3z - }; - } + var uv0 = new Vector2(u0/255f, v0/255f); + var uv1 = new Vector2(u1/255f, v1/255f); + var uv2 = new Vector2(u2/255f, v2/255f); var triangle = new Triangle { //PrimitiveType = primitiveType, - Colors = new[] - { - new Color - ( - r0/255f, - g0/255f, - b0/255f - ), - new Color - ( - r1/255f, - g1/255f, - b1/255f - ), - new Color - ( - r2/255f, - g2/255f, - b2/255f - ) - }, - Normals = new[] - { - nor1, - nor2, - nor3 - }, - Vertices = new[] - { - ver1, - ver2, - ver3 - }, - Uv = new[] - { - new Vector2 - { - X = u0/255f, - Y = v0/255f - }, - new Vector2 - { - X = u1/255f, - Y = v1/255f - }, - new Vector2 - { - X = u2/255f, - Y = v2/255f - } - }, + Vertices = new[] { vertex0, vertex1, vertex2 }, + Normals = new[] { normal0, normal1, normal2 }, + Colors = new[] { color0, color1, color2 }, + Uv = new[] { uv0, uv1, uv2 }, AttachableIndices = new[] { uint.MaxValue, uint.MaxValue, uint.MaxValue } }; diff --git a/Classes/PSXParser.cs b/Classes/PSXParser.cs index 6c1b49a..50566b5 100644 --- a/Classes/PSXParser.cs +++ b/Classes/PSXParser.cs @@ -35,21 +35,22 @@ protected override void Parse(BinaryReader reader, string fileTitle, out List, List> groupedTriangles, Triangle triangle, uint modelIndex, uint tPage) + // (modelIndex, RenderInfo) + var groupedTriangles = new Dictionary, List>(); + + void AddTriangle(Triangle triangle, uint modelIndex, uint tPage, RenderFlags renderFlags) { - var tuple = new Tuple(modelIndex, tPage); - List triangles; - if (groupedTriangles.ContainsKey(tuple)) - { - triangles = groupedTriangles[tuple]; - } - else + renderFlags |= RenderFlags.DoubleSided; //todo + var renderInfo = new RenderInfo(tPage, renderFlags); + var tuple = new Tuple(modelIndex, renderInfo); + if (!groupedTriangles.TryGetValue(tuple, out var triangles)) { triangles = new List(); groupedTriangles.Add(tuple, triangles); } triangles.Add(triangle); } + var version = reader.ReadByte(); var magic2 = reader.ReadByte(); var magic3 = reader.ReadByte(); @@ -68,7 +69,6 @@ void AddTriangle(Dictionary, List> groupedTriangles, { return null; } - var childEntities = new ModelEntity(); var objectModels = new PSXModel[objectCount]; for (var i = 0; i < objectCount; i++) { @@ -90,7 +90,6 @@ void AddTriangle(Dictionary, List> groupedTriangles, { return null; } - var triangleGroups = new Dictionary, List>(); var modelEntities = new List(); var attachmentIndex = 0; for (uint i = 0; i < modelCount; i++) @@ -171,7 +170,7 @@ void AddTriangle(Dictionary, List> groupedTriangles, var faceBegin = reader.BaseStream.Position; var faceFlags = reader.ReadUInt16(); var faceLength = reader.ReadUInt16(); - var triangle = (faceFlags & 0x0010) != 0; + var quad = (faceFlags & 0x0010) == 0; var gouraud = (faceFlags & 0x0800) != 0; var textured = (faceFlags & 0x0003) != 0; var invisible = (faceFlags & 0x0080) != 0; @@ -219,8 +218,10 @@ void AddTriangle(Dictionary, List> groupedTriangles, var uv2 = Vector2.Zero; var uv3 = Vector2.Zero; uint tPage = 0; + var renderFlags = RenderFlags.None; if (textured) { + renderFlags |= RenderFlags.Textured; tPage = reader.ReadUInt32(); //todo var u0 = reader.ReadByte() / 255f; var v0 = reader.ReadByte() / 255f; @@ -237,7 +238,7 @@ void AddTriangle(Dictionary, List> groupedTriangles, } if (!invisible) { - AddTriangle(triangleGroups, new Triangle + AddTriangle(new Triangle { Vertices = new[] { vertex2, vertex1, vertex0 }, Normals = new[] { normal2, normal1, normal0 }, @@ -246,10 +247,10 @@ void AddTriangle(Dictionary, List> groupedTriangles, OriginalVertexIndices = new uint[] { i2, i1, i0 }, AttachedIndices = new[] { attachedIndex2, attachedIndex1, attachedIndex0 }, AttachableIndices = new[] { attachableIndex2, attachableIndex1, attachableIndex0 } - }, i, tPage); - if (!triangle) + }, i, tPage, renderFlags); + if (quad) { - AddTriangle(triangleGroups, new Triangle + AddTriangle(new Triangle { Vertices = new[] { vertex1, vertex2, vertex3 }, Normals = new[] { normal1, normal2, normal3 }, @@ -258,7 +259,7 @@ void AddTriangle(Dictionary, List> groupedTriangles, OriginalVertexIndices = new uint[] { i1, i2, i3 }, AttachedIndices = new[] { attachedIndex1, attachedIndex2, attachedIndex3 }, AttachableIndices = new[] { attachableIndex1, attachableIndex2, attachableIndex3 } - }, i, tPage); + }, i, tPage, renderFlags); } } reader.BaseStream.Seek(faceBegin + faceLength, SeekOrigin.Begin); @@ -268,7 +269,7 @@ void AddTriangle(Dictionary, List> groupedTriangles, var faceBegin = reader.BaseStream.Position; var faceFlags = reader.ReadUInt16(); var faceLength = reader.ReadUInt16(); - var triangle = (faceFlags & 0x0010) != 0; + var quad = (faceFlags & 0x0010) == 0; var gouraud = (faceFlags & 0x0800) != 0; var textured = (faceFlags & 0x0003) != 0; var invisible = (faceFlags & 0x0080) != 0; @@ -316,8 +317,10 @@ void AddTriangle(Dictionary, List> groupedTriangles, var uv2 = Vector2.Zero; var uv3 = Vector2.Zero; uint tPage = 0; + var renderFlags = RenderFlags.None; if (textured) { + renderFlags |= RenderFlags.Textured; tPage = reader.ReadUInt32(); //todo var u0 = reader.ReadByte() / 255f; var v0 = reader.ReadByte() / 255f; @@ -334,7 +337,7 @@ void AddTriangle(Dictionary, List> groupedTriangles, } if (!invisible) { - AddTriangle(triangleGroups, new Triangle + AddTriangle(new Triangle { Vertices = new[] { vertex2, vertex1, vertex0 }, Normals = new[] { normal2, normal1, normal0 }, @@ -343,10 +346,10 @@ void AddTriangle(Dictionary, List> groupedTriangles, OriginalVertexIndices = new uint[] { i2, i1, i0 }, AttachedIndices = new[] { attachedIndex2, attachedIndex1, attachedIndex0 }, AttachableIndices = new[] { attachableIndex2, attachableIndex1, attachableIndex0 } - }, i, tPage); - if (!triangle) + }, i, tPage, renderFlags); + if (quad) { - AddTriangle(triangleGroups, new Triangle + AddTriangle(new Triangle { Vertices = new[] { vertex1, vertex2, vertex3 }, Normals = new[] { normal1, normal2, normal3 }, @@ -355,7 +358,7 @@ void AddTriangle(Dictionary, List> groupedTriangles, OriginalVertexIndices = new uint[] { i1, i2, i3 }, AttachedIndices = new[] { attachedIndex1, attachedIndex2, attachedIndex3 }, AttachableIndices = new[] { attachableIndex1, attachableIndex2, attachableIndex3 } - }, i, tPage); + }, i, tPage, renderFlags); } } reader.BaseStream.Seek(faceBegin + faceLength, SeekOrigin.Begin); @@ -381,16 +384,19 @@ void AddTriangle(Dictionary, List> groupedTriangles, foreach (var psxModel in objectModels) { - foreach (var kvp in triangleGroups) + foreach (var kvp in groupedTriangles) { if (kvp.Key.Item1 == psxModel.ModelIndex) { var triangles = kvp.Value; + var renderInfo = kvp.Key.Item2; var model = new ModelEntity { Triangles = triangles.ToArray(), - TexturePage = kvp.Key.Item2, - TMDID = 1, //todo + TexturePage = renderInfo.TexturePage, + RenderFlags = renderInfo.RenderFlags, + MixtureRate = renderInfo.MixtureRate, + TMDID = psxModel.ModelIndex, //todo OriginalLocalMatrix = Matrix4.CreateTranslation(psxModel.X, psxModel.Y, psxModel.Z) }; modelEntities.Add(model); @@ -414,21 +420,21 @@ void AddTriangle(Dictionary, List> groupedTriangles, } return rootEntity; } - } - internal class PSXModel - { - public float X { get; } - public float Y { get; } - public float Z { get; } - public ushort ModelIndex { get; } - - public PSXModel(float x, float y, float z, ushort modelIndex) + private class PSXModel { - X = x; - Y = y; - Z = z; - ModelIndex = modelIndex; + public float X { get; } + public float Y { get; } + public float Z { get; } + public ushort ModelIndex { get; } + + public PSXModel(float x, float y, float z, ushort modelIndex) + { + X = x; + Y = y; + Z = z; + ModelIndex = modelIndex; + } } } } diff --git a/Classes/PlyExporter.cs b/Classes/PlyExporter.cs index 8db2aac..95a8a5e 100644 --- a/Classes/PlyExporter.cs +++ b/Classes/PlyExporter.cs @@ -28,11 +28,14 @@ public void Export(RootEntity[] entities, string selectedPath) { var model = (ModelEntity)entityBase; faceCount += model.Triangles.Count(); - var texturePage = model.TexturePage; - if (!materialsDic.ContainsKey((int) texturePage)) + if (model.RenderFlags.HasFlag(RenderFlags.Textured)) { - materialsDic.Add((int) texturePage, numMaterials++); - pngExporter.Export(model.Texture, (int) texturePage, selectedPath); + var texturePage = model.TexturePage; + if (!materialsDic.ContainsKey((int)texturePage)) + { + materialsDic.Add((int)texturePage, numMaterials++); + pngExporter.Export(model.Texture, (int)texturePage, selectedPath); + } } } var vertexCount = faceCount * 3; diff --git a/Classes/RenderInfo.cs b/Classes/RenderInfo.cs index f5a3fa5..5a111e0 100644 --- a/Classes/RenderInfo.cs +++ b/Classes/RenderInfo.cs @@ -11,12 +11,10 @@ public enum RenderFlags Unlit = (1 << 1), SemiTransparent = (1 << 3), Fog = (1 << 4), - // Are these even render-related? - Subdivision = (1 << 5), - AutomaticDivision = (1 << 6), - - // Use this mask when separating meshes by render info. - SupportedFlags = DoubleSided | Unlit | SemiTransparent, + Textured = (1 << 5), + // todo: Are these even render-related? + Subdivision = (1 << 6), + AutomaticDivision = (1 << 7), // Bits 30 and 31 are reserved for MixtureRate. } @@ -34,6 +32,10 @@ public enum MixtureRate // A named Tuple for render information used to separate models/meshes. public struct RenderInfo : IEquatable { + // Use this mask when separating meshes by render info. + public const RenderFlags SupportedFlags = RenderFlags.DoubleSided | RenderFlags.Unlit | + RenderFlags.SemiTransparent | RenderFlags.Textured; + public uint TexturePage { get; } public RenderFlags RenderFlags { get; } public MixtureRate MixtureRate { get; } @@ -52,7 +54,7 @@ private ulong RawValue public RenderInfo(uint texturePage, RenderFlags renderFlags, MixtureRate mixtureRate = MixtureRate.None) { TexturePage = texturePage; - RenderFlags = renderFlags & RenderFlags.SupportedFlags; // Ignore flags that we can't use for now + RenderFlags = renderFlags & SupportedFlags; // Ignore flags that we can't use for now MixtureRate = mixtureRate; } diff --git a/Classes/RootEntity.cs b/Classes/RootEntity.cs index 1f5435d..e72140c 100644 --- a/Classes/RootEntity.cs +++ b/Classes/RootEntity.cs @@ -11,6 +11,23 @@ public class RootEntity : EntityBase [Browsable(false)] public CoordUnit[] Coords { get; set; } + [DisplayName("Total Triangles"), ReadOnly(false)] + public int TotalTriangles + { + get + { + var count = 0; + if (ChildEntities != null) + { + foreach (ModelEntity subModel in ChildEntities) + { + count += subModel.TrianglesCount; + } + } + return count; + } + } + public override void ComputeBounds() { base.ComputeBounds(); diff --git a/Classes/Scene.cs b/Classes/Scene.cs index 79f458f..4efc939 100644 --- a/Classes/Scene.cs +++ b/Classes/Scene.cs @@ -36,6 +36,7 @@ public class Scene public static int UniformMaskColor; public static int UniformAmbientColor; public static int UniformRenderMode; + public static int UniformTextureMode; public static int UniformSemiTransparentMode; public static int UniformLightIntensity; @@ -51,6 +52,7 @@ public class Scene public const string UniformMaskColorName = "maskColor"; public const string UniformAmbientColorName = "ambientColor"; public const string UniformRenderModeName = "renderMode"; + public const string UniformTextureModeName = "textureMode"; public const string UniformSemiTransparentModeName = "semiTransparentMode"; public const string UniformLightIntensityName = "lightIntensity"; @@ -251,6 +253,7 @@ private void SetupShaders() UniformMaskColor = GL.GetUniformLocation(_shaderProgram, UniformMaskColorName); UniformAmbientColor = GL.GetUniformLocation(_shaderProgram, UniformAmbientColorName); UniformRenderMode = GL.GetUniformLocation(_shaderProgram, UniformRenderModeName); + UniformTextureMode = GL.GetUniformLocation(_shaderProgram, UniformTextureModeName); UniformSemiTransparentMode = GL.GetUniformLocation(_shaderProgram, UniformSemiTransparentModeName); UniformLightIntensity = GL.GetUniformLocation(_shaderProgram, UniformLightIntensityName); } @@ -315,6 +318,7 @@ public void Draw() GL.Uniform3(UniformAmbientColor, AmbientColor.R / 255f, AmbientColor.G / 255f, AmbientColor.B / 255f); GL.Uniform1(UniformLightIntensity, LightIntensity); GL.Uniform1(UniformRenderMode, LightEnabled ? 0 : 1); + GL.Uniform1(UniformTextureMode, 0); GL.Uniform1(UniformSemiTransparentMode, 0); MeshBatch.Draw(_viewMatrix, _projectionMatrix, TextureBinder, Wireframe, true, VerticesOnly); GL.Uniform1(UniformRenderMode, 2); diff --git a/Classes/TMDHelper.cs b/Classes/TMDHelper.cs index 8ffd233..c445dd4 100644 --- a/Classes/TMDHelper.cs +++ b/Classes/TMDHelper.cs @@ -26,6 +26,7 @@ public static PrimitiveData CreateTMDPacketStructure(byte flag, byte mode, Binar if (!lgtBit) renderFlags |= RenderFlags.Unlit; if (fceBit) renderFlags |= RenderFlags.DoubleSided; if (abeBit) renderFlags |= RenderFlags.SemiTransparent; + if (tmeBit) renderFlags |= RenderFlags.Textured; if (Program.Debug) { @@ -101,6 +102,7 @@ public static PrimitiveData CreateHMDPacketStructure(uint driver, uint flag, Bin if (advBit) renderFlags |= RenderFlags.AutomaticDivision; if (botBit) renderFlags |= RenderFlags.DoubleSided; if (stpBit) renderFlags |= RenderFlags.SemiTransparent; + if (tmeBit) renderFlags |= RenderFlags.Textured; var primitiveType = PrimitiveType.None; // invalid var supported = false; diff --git a/Classes/TMDParser.cs b/Classes/TMDParser.cs index f629d3f..4ff85ba 100644 --- a/Classes/TMDParser.cs +++ b/Classes/TMDParser.cs @@ -227,18 +227,15 @@ private RootEntity ParseTmd(BinaryReader reader, string fileTitle) { var renderInfo = kvp.Key; var triangles = kvp.Value; - if (triangles.Count > 0) + var model = new ModelEntity { - var model = new ModelEntity - { - Triangles = triangles.ToArray(), - TexturePage = renderInfo.TexturePage, - RenderFlags = renderInfo.RenderFlags, - MixtureRate = renderInfo.MixtureRate, - TMDID = o - }; - models.Add(model); - } + Triangles = triangles.ToArray(), + TexturePage = renderInfo.TexturePage, + RenderFlags = renderInfo.RenderFlags, + MixtureRate = renderInfo.MixtureRate, + TMDID = o + }; + models.Add(model); } } diff --git a/Forms/PreviewForm.cs b/Forms/PreviewForm.cs index 90a1047..d6b9ea1 100644 --- a/Forms/PreviewForm.cs +++ b/Forms/PreviewForm.cs @@ -102,7 +102,10 @@ private void EntityAdded(RootEntity entity) { var model = (ModelEntity)entityBase; model.TexturePage = VRAMPages.ClampTexturePage(model.TexturePage); - model.Texture = _vram[model.TexturePage]; + if (model.RenderFlags.HasFlag(RenderFlags.Textured)) + { + model.Texture = _vram[model.TexturePage]; + } } entitiesTreeView.BeginUpdate(); var entityNode = entitiesTreeView.Nodes.Add(entity.EntityName); @@ -838,7 +841,10 @@ private void modelPropertyGrid_PropertyValueChanged(object s, PropertyValueChang if (_selectedModelEntity != null) { _selectedModelEntity.TexturePage = VRAMPages.ClampTexturePage(_selectedModelEntity.TexturePage); - _selectedModelEntity.Texture = _vram[_selectedModelEntity.TexturePage]; + if (_selectedModelEntity.RenderFlags.HasFlag(RenderFlags.Textured)) + { + _selectedModelEntity.Texture = _vram[_selectedModelEntity.TexturePage]; + } } var selectedEntityBase = (EntityBase)_selectedRootEntity ?? _selectedModelEntity; if (selectedEntityBase != null) diff --git a/Shaders/Shader.frag b/Shaders/Shader.frag index ce8f241..09c4b89 100644 --- a/Shaders/Shader.frag +++ b/Shaders/Shader.frag @@ -15,6 +15,7 @@ uniform vec3 lightDirection; uniform vec3 maskColor; uniform vec3 ambientColor; uniform int renderMode; +uniform int textureMode; uniform int semiTransparentMode; uniform float lightIntensity; uniform sampler2D mainTex; @@ -25,34 +26,41 @@ void main(void) { } vec4 finalColor; if (renderMode == 0 || renderMode == 1) { - vec2 uv = pass_Uv; - // X,Y is tiled U,V offset and Z,W is tiled U,V wrap size. - if (pass_TiledArea.z != 0.0) { - uv.x = pass_TiledArea.x + mod(pass_Uv.x, pass_TiledArea.z); - } - if (pass_TiledArea.w != 0.0) { - uv.y = pass_TiledArea.y + mod(pass_Uv.y, pass_TiledArea.w); - } - //if (pass_TiledArea.z != 0.0 && pass_TiledArea.w != 0.0) { - // uv = pass_TiledArea.xy + mod(pass_Uv, pass_TiledArea.zw); - //} + // Process texture UVs and stp bit + vec4 tex2D; + int stp; + if (textureMode == 0) { + vec2 uv = pass_Uv; + // X,Y is tiled U,V offset and Z,W is tiled U,V wrap size. + if (pass_TiledArea.z != 0.0) { + uv.x = pass_TiledArea.x + mod(pass_Uv.x, pass_TiledArea.z); + } + if (pass_TiledArea.w != 0.0) { + uv.y = pass_TiledArea.y + mod(pass_Uv.y, pass_TiledArea.w); + } - vec4 tex2D = texture(mainTex, vec2(uv.x * 0.5, uv.y)); - vec4 stp2D = texture(mainTex, vec2(uv.x * 0.5 + 0.5, uv.y)); - bool stp = (stp2D.x != 0.0); + tex2D = texture(mainTex, vec2(uv.x * 0.5, uv.y)); + vec4 stp2D = texture(mainTex, vec2(uv.x * 0.5 + 0.5, uv.y)); + stp = (stp2D.x == 0.0 ? 0 : 1); + } else { + tex2D = vec4(1.0, 1.0, 1.0, 1.0); + stp = 1; // Untextured always treats stp bit as set. + } - if (!stp && tex2D.xyz == maskColor) { + // Process semi-transparency discarding + if (stp == 0 && tex2D.xyz == maskColor) { discard; // Black surfaces are transparent when stp bit is unset. } else if (semiTransparentMode == 1) { - if (stp) { + if (stp != 0) { discard; // Semi-transparent surface during no-stp bit pass. } } else if (semiTransparentMode == 2) { - if (!stp) { + if (stp == 0) { discard; // Opaque surface during stp bit pass. } } + // Process final color if (renderMode == 0) { finalColor = (pass_Ambient + pass_NormalDotLight) * tex2D * pass_Color; } else { diff --git a/Shaders/Shader.vert b/Shaders/Shader.vert index 7041a79..fde1539 100644 --- a/Shaders/Shader.vert +++ b/Shaders/Shader.vert @@ -18,6 +18,7 @@ uniform vec3 lightDirection; uniform vec3 maskColor; uniform vec3 ambientColor; uniform int renderMode; +uniform int textureMode; uniform int semiTransparentMode; uniform float lightIntensity; uniform sampler2D mainTex;