diff --git a/Assets/Scripts/Data/QModel.cs b/Assets/Scripts/Data/QModel.cs index 37a05ef..cd9feb8 100644 --- a/Assets/Scripts/Data/QModel.cs +++ b/Assets/Scripts/Data/QModel.cs @@ -238,7 +238,7 @@ public struct QSubModel public QNode GetHeadNode(QModel model) { - IntPtr nodePtr = IntPtr.Add(model.nodes, headNode[0]); + IntPtr nodePtr = IntPtr.Add(model.nodes, headNode[0] * Marshal.SizeOf()); return Marshal.PtrToStructure(nodePtr); } } @@ -249,12 +249,16 @@ public struct QSubModel [StructLayout(LayoutKind.Sequential, Pack = 0)] public struct QNode { + // Common with leaf public int contents; // 0 for nodes, negative for leafs public int visFrame; public QVec3 mins, maxs; public IntPtr parent; // Pointer to mnode_t + + // Node specific public IntPtr plane; // Pointer to mplane_t [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public IntPtr[] children; // Array of pointers to mnode_t + public uint firstSurface; public uint numSurfaces; diff --git a/Assets/Scripts/Modules/BrushModel.cs b/Assets/Scripts/Modules/BrushModel.cs index 39a1ecf..91e6c39 100644 --- a/Assets/Scripts/Modules/BrushModel.cs +++ b/Assets/Scripts/Modules/BrushModel.cs @@ -7,6 +7,12 @@ public class BrushModel private readonly string name; private readonly List meshes = new List(); + // Reusable temporary data containers + private readonly List tempVertices = new List(); + private readonly List tempTextureUVs = new List(); + private readonly List tempLightmapUVs = new List(); + private readonly List tempIndices = new List(); + public BrushModel(string name) { this.name = name; @@ -17,48 +23,12 @@ public class BrushModel var subModels = model.SubModels; var surfaces = model.Surfaces; - List vertices = new List(); - List textureUVs = new List(); - List lightmapUVs = new List(); - List indices = new List(); - - for (int surfIdx = 0; surfIdx < surfaces.Length; ++surfIdx) + for (int modelIdx = 0; modelIdx < subModels.Length; ++modelIdx) { - foreach (var polyVerts in surfaces[surfIdx].GetPolygons()) - { - vertices.Clear(); - textureUVs.Clear(); - lightmapUVs.Clear(); - indices.Clear(); - - for (int vertIdx = 0; vertIdx < polyVerts.Length; ++vertIdx) - { - vertices.Add(polyVerts[vertIdx].position.ToVector3().ToUnity()); - textureUVs.Add(polyVerts[vertIdx].textureUV.ToVector2()); - lightmapUVs.Add(polyVerts[vertIdx].lightmapUV.ToVector2()); - } - - // Reconstruct triangle fan - for (ushort index = 2; index < polyVerts.Length; ++index) - { - indices.Add(0); - indices.Add((ushort)(index - 1)); - indices.Add(index); - } - - Mesh mesh = new Mesh(); - mesh.SetVertices(vertices); - mesh.SetUVs(0, textureUVs); - mesh.SetUVs(1, lightmapUVs); - mesh.SetIndices(indices, MeshTopology.Triangles, 0); - mesh.RecalculateNormals(); - mesh.UploadMeshData(true); - meshes.Add(mesh); - } - - var texNum = surfaces[surfIdx].TextureInfo.Texture.TextureNum; + var headNode = subModels[modelIdx].GetHeadNode(model); + CreateNodeMeshes(headNode, surfaces); } - + // DEBUG var go = new GameObject(name); var mat = new Material(Shader.Find("Universal Render Pipeline/Simple Lit")); @@ -83,4 +53,59 @@ public class BrushModel go.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity); } + + private void CreateNodeMeshes(QNode node, QSurface[] surfaces) + { + if (node.contents < 0) // Leaf node + return; + + CreateSurfaceMeshes(node, surfaces); + + foreach (var childNode in node.Children) + { + CreateNodeMeshes(childNode, surfaces); + } + } + + private void CreateSurfaceMeshes(QNode node, QSurface[] surfaces) + { + for (int surfIdx = 0; surfIdx < node.numSurfaces; ++surfIdx) + { + var surface = surfaces[node.firstSurface + surfIdx]; + + foreach (var polyVerts in surface.GetPolygons()) + { + tempVertices.Clear(); + tempTextureUVs.Clear(); + tempLightmapUVs.Clear(); + tempIndices.Clear(); + + for (int vertIdx = 0; vertIdx < polyVerts.Length; ++vertIdx) + { + tempVertices.Add(polyVerts[vertIdx].position.ToVector3().ToUnity()); + tempTextureUVs.Add(polyVerts[vertIdx].textureUV.ToVector2()); + tempLightmapUVs.Add(polyVerts[vertIdx].lightmapUV.ToVector2()); + } + + // Reconstruct triangle fan + for (ushort index = 2; index < polyVerts.Length; ++index) + { + tempIndices.Add(0); + tempIndices.Add((ushort) (index - 1)); + tempIndices.Add(index); + } + + Mesh mesh = new Mesh(); + mesh.SetVertices(tempVertices); + mesh.SetUVs(0, tempTextureUVs); + mesh.SetUVs(1, tempLightmapUVs); + mesh.SetIndices(tempIndices, MeshTopology.Triangles, 0); + mesh.RecalculateNormals(); + mesh.UploadMeshData(true); + meshes.Add(mesh); + } + + var texNum = surface.TextureInfo.Texture.TextureNum; + } + } }