From a8c23266bb3f9d282c7f4a008b1979eafd67610b Mon Sep 17 00:00:00 2001 From: MaxED Date: Mon, 18 Jul 2016 23:41:02 +0000 Subject: [PATCH] Changed: optimized generated voxel mesh size. Pro: they occupy ~50% less memory. Con: voxel loading takes ~30% more time. Changed, Browse Textures window: several textures with the same name were displayed in "All" texture set when overriding WAD textures by Folder/PK3 textures. --- Source/Core/Config/AllTexturesSet.cs | 22 ++-- Source/Core/Data/VoxelImage.cs | 2 + Source/Core/GZBuilder/md3/ModelReader.cs | 159 +++++++++++++++-------- 3 files changed, 118 insertions(+), 65 deletions(-) diff --git a/Source/Core/Config/AllTexturesSet.cs b/Source/Core/Config/AllTexturesSet.cs index 1bcb2566..0fc50612 100644 --- a/Source/Core/Config/AllTexturesSet.cs +++ b/Source/Core/Config/AllTexturesSet.cs @@ -16,6 +16,7 @@ #region ================== Namespaces +using System; using System.Collections.Generic; using CodeImp.DoomBuilder.Data; @@ -27,22 +28,22 @@ namespace CodeImp.DoomBuilder.Config { #region ================== Constants - public const string NAME = "All"; + private const string NAME = "All"; #endregion #region ================== Variables // Matching textures and flats - private List textures; - private List flats; + private Dictionary textures; + private Dictionary flats; #endregion #region ================== Properties - public ICollection Textures { get { return textures; } } - public ICollection Flats { get { return flats; } } + public ICollection Textures { get { return textures.Values; } } + public ICollection Flats { get { return flats.Values; } } #endregion @@ -52,8 +53,8 @@ namespace CodeImp.DoomBuilder.Config public AllTextureSet() { this.name = NAME; - this.textures = new List(); - this.flats = new List(); + this.textures = new Dictionary(StringComparer.Ordinal); + this.flats = new Dictionary(StringComparer.Ordinal); } #endregion @@ -62,12 +63,15 @@ namespace CodeImp.DoomBuilder.Config internal void AddTexture(ImageData image) { - textures.Add(image); + //mxd. Use short name when adding a texture with "classic" name to override same-named textures + // with textures loaded from directory/pk3 containters + textures[image.DisplayName.Length > 8 ? image.Name : image.ShortName] = image; } internal void AddFlat(ImageData image) { - flats.Add(image); + //mxd. Same with flats + flats[image.DisplayName.Length > 8 ? image.Name : image.ShortName] = image; } #endregion diff --git a/Source/Core/Data/VoxelImage.cs b/Source/Core/Data/VoxelImage.cs index 316e2e3c..af2509f1 100644 --- a/Source/Core/Data/VoxelImage.cs +++ b/Source/Core/Data/VoxelImage.cs @@ -308,6 +308,8 @@ namespace CodeImp.DoomBuilder.Data } } } + + lumpdata.Dispose(); } else { diff --git a/Source/Core/GZBuilder/md3/ModelReader.cs b/Source/Core/GZBuilder/md3/ModelReader.cs index fb2c7714..35375de7 100644 --- a/Source/Core/GZBuilder/md3/ModelReader.cs +++ b/Source/Core/GZBuilder/md3/ModelReader.cs @@ -634,7 +634,10 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 { PixelColor[] palette = new PixelColor[256]; List verts = new List(); + List indices = new List(); + Dictionary verthashes = new Dictionary(); int xsize, ysize, zsize; + int facescount = 0; Vector3D pivot; using(BinaryReader reader = new BinaryReader(stream, Encoding.ASCII)) @@ -724,7 +727,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 if((flags & 16) != 0) { - AddFace(verts, new Vector3D(x, y, ztop), new Vector3D(x + 1, y, ztop), new Vector3D(x, y + 1, ztop), new Vector3D(x + 1, y + 1, ztop), pivot, colorIndices[0]); + AddFace(verts, indices, verthashes, new Vector3D(x, y, ztop), new Vector3D(x + 1, y, ztop), new Vector3D(x, y + 1, ztop), new Vector3D(x + 1, y + 1, ztop), pivot, colorIndices[0]); + facescount += 2; } int z = ztop; @@ -736,19 +740,23 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 if((flags & 1) != 0) { - AddFace(verts, new Vector3D(x, y, z), new Vector3D(x, y + 1, z), new Vector3D(x, y, z + c), new Vector3D(x, y + 1, z + c), pivot, colorIndices[cstart]); + AddFace(verts, indices, verthashes, new Vector3D(x, y, z), new Vector3D(x, y + 1, z), new Vector3D(x, y, z + c), new Vector3D(x, y + 1, z + c), pivot, colorIndices[cstart]); + facescount += 2; } if((flags & 2) != 0) { - AddFace(verts, new Vector3D(x + 1, y + 1, z), new Vector3D(x + 1, y, z), new Vector3D(x + 1, y + 1, z + c), new Vector3D(x + 1, y, z + c), pivot, colorIndices[cstart]); + AddFace(verts, indices, verthashes, new Vector3D(x + 1, y + 1, z), new Vector3D(x + 1, y, z), new Vector3D(x + 1, y + 1, z + c), new Vector3D(x + 1, y, z + c), pivot, colorIndices[cstart]); + facescount += 2; } if((flags & 4) != 0) { - AddFace(verts, new Vector3D(x + 1, y, z), new Vector3D(x, y, z), new Vector3D(x + 1, y, z + c), new Vector3D(x, y, z + c), pivot, colorIndices[cstart]); + AddFace(verts, indices, verthashes, new Vector3D(x + 1, y, z), new Vector3D(x, y, z), new Vector3D(x + 1, y, z + c), new Vector3D(x, y, z + c), pivot, colorIndices[cstart]); + facescount += 2; } if((flags & 8) != 0) { - AddFace(verts, new Vector3D(x, y + 1, z), new Vector3D(x + 1, y + 1, z), new Vector3D(x, y + 1, z + c), new Vector3D(x + 1, y + 1, z + c), pivot, colorIndices[cstart]); + AddFace(verts, indices, verthashes, new Vector3D(x, y + 1, z), new Vector3D(x + 1, y + 1, z), new Vector3D(x, y + 1, z + c), new Vector3D(x + 1, y + 1, z + c), pivot, colorIndices[cstart]); + facescount += 2; } if(c == 0) c++; @@ -759,7 +767,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 if((flags & 32) != 0) { z = ztop + zleng - 1; - AddFace(verts, new Vector3D(x + 1, y, z + 1), new Vector3D(x, y, z + 1), new Vector3D(x + 1, y + 1, z + 1), new Vector3D(x, y + 1, z + 1), pivot, colorIndices[zleng - 1]); + AddFace(verts, indices, verthashes, new Vector3D(x + 1, y, z + 1), new Vector3D(x, y, z + 1), new Vector3D(x + 1, y + 1, z + 1), new Vector3D(x, y + 1, z + 1), pivot, colorIndices[zleng - 1]); + facescount += 2; } } } @@ -775,10 +784,10 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 int minY = (int)((ysize / 2f - pivot.y) * mde.Scale.Y); int maxY = (int)((ysize / 2f + pivot.y) * mde.Scale.Y); - // calculate model radius + // Calculate model radius mde.Model.Radius = Math.Max(Math.Max(Math.Abs(minY), Math.Abs(maxY)), Math.Max(Math.Abs(minX), Math.Abs(maxX))); - //create texture + // Create texture MemoryStream memstream = new MemoryStream((4096 * 4) + 4096); using(Bitmap bmp = CreateVoxelTexture(palette)) bmp.Save(memstream, ImageFormat.Bmp); memstream.Seek(0, SeekOrigin.Begin); @@ -786,78 +795,116 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 Texture texture = Texture.FromStream(device, memstream, (int)memstream.Length, 64, 64, 0, Usage.None, Format.Unknown, Pool.Managed, Filter.Point, Filter.Box, 0); memstream.Dispose(); - //add texture + // Add texture mde.Model.Textures.Add(texture); - //create mesh - int[] indices = new int[verts.Count]; - for(int i = 0; i < verts.Count; i++) - { - indices[i] = i; - } - - Mesh mesh = new Mesh(device, verts.Count / 3, verts.Count, MeshFlags.Use32Bit | MeshFlags.IndexBufferManaged | MeshFlags.VertexBufferManaged, vertexElements); + // Create mesh + MeshFlags meshflags = MeshFlags.Managed; + if(indices.Count > ushort.MaxValue - 1) meshflags |= MeshFlags.Use32Bit; + + Mesh mesh = new Mesh(device, facescount, verts.Count, meshflags, vertexElements); DataStream mstream = mesh.VertexBuffer.Lock(0, 0, LockFlags.None); mstream.WriteRange(verts.ToArray()); mesh.VertexBuffer.Unlock(); mstream = mesh.IndexBuffer.Lock(0, 0, LockFlags.None); - mstream.WriteRange(indices); + + if(indices.Count > ushort.MaxValue - 1) + mstream.WriteRange(indices.ToArray()); + else + foreach(int index in indices) mstream.Write((ushort)index); + mesh.IndexBuffer.Unlock(); mesh.OptimizeInPlace(MeshOptimizeFlags.AttributeSort); - //add mesh + // Add mesh mde.Model.Meshes.Add(mesh); } // Shameless GZDoom rip-off - private static void AddFace(List verts, Vector3D v1, Vector3D v2, Vector3D v3, Vector3D v4, Vector3D pivot, int colorIndex) + private static void AddFace(List verts, List indices, Dictionary hashes, Vector3D v1, Vector3D v2, Vector3D v3, Vector3D v4, Vector3D pivot, int colorIndex) { float pu0 = (colorIndex % 16) / 16f; - float pu1 = pu0 + 0.0001f; + float pu1 = pu0 + 0.001f; float pv0 = (colorIndex / 16) / 16f; - float pv1 = pv0 + 0.0001f; + float pv1 = pv0 + 0.001f; - WorldVertex wv1 = new WorldVertex(); - wv1.x = v1.x - pivot.x; - wv1.y = -v1.y + pivot.y; - wv1.z = -v1.z + pivot.z; - wv1.c = -1; - wv1.u = pu0; - wv1.v = pv0; - verts.Add(wv1); + WorldVertex wv1 = new WorldVertex + { + x = v1.x - pivot.x, + y = -v1.y + pivot.y, + z = -v1.z + pivot.z, + c = -1, + u = pu0, + v = pv0 + }; + int i1 = AddVertex(wv1, verts, indices, hashes); - WorldVertex wv2 = new WorldVertex(); - wv2.x = v2.x - pivot.x; - wv2.y = -v2.y + pivot.y; - wv2.z = -v2.z + pivot.z; - wv2.c = -1; - wv2.u = pu1; - wv2.v = pv1; - verts.Add(wv2); + WorldVertex wv2 = new WorldVertex + { + x = v2.x - pivot.x, + y = -v2.y + pivot.y, + z = -v2.z + pivot.z, + c = -1, + u = pu1, + v = pv1 + }; + AddVertex(wv2, verts, indices, hashes); - WorldVertex wv4 = new WorldVertex(); - wv4.x = v4.x - pivot.x; - wv4.y = -v4.y + pivot.y; - wv4.z = -v4.z + pivot.z; - wv4.c = -1; - wv4.u = pu0; - wv4.v = pv0; - verts.Add(wv4); + WorldVertex wv4 = new WorldVertex + { + x = v4.x - pivot.x, + y = -v4.y + pivot.y, + z = -v4.z + pivot.z, + c = -1, + u = pu0, + v = pv0 + }; + int i4 = AddVertex(wv4, verts, indices, hashes); - WorldVertex wv3 = new WorldVertex(); - wv3.x = v3.x - pivot.x; - wv3.y = -v3.y + pivot.y; - wv3.z = -v3.z + pivot.z; - wv3.c = -1; - wv3.u = pu1; - wv3.v = pv1; - verts.Add(wv3); + WorldVertex wv3 = new WorldVertex + { + x = v3.x - pivot.x, + y = -v3.y + pivot.y, + z = -v3.z + pivot.z, + c = -1, + u = pu1, + v = pv1 + }; + AddVertex(wv3, verts, indices, hashes); - verts.Add(wv1); - verts.Add(wv4); + indices.Add(i1); + indices.Add(i4); + } + + // Returns index of added vert + private static int AddVertex(WorldVertex v, List verts, List indices, Dictionary hashes) + { + long hash; + unchecked // Overflow is fine, just wrap + { + hash = 2166136261; + hash = (hash * 16777619) ^ v.x.GetHashCode(); + hash = (hash * 16777619) ^ v.y.GetHashCode(); + hash = (hash * 16777619) ^ v.z.GetHashCode(); + hash = (hash * 16777619) ^ v.u.GetHashCode(); + hash = (hash * 16777619) ^ v.v.GetHashCode(); + } + + if(hashes.ContainsKey(hash)) + { + indices.Add(hashes[hash]); + return hashes[hash]; + } + else + { + verts.Add(v); + hashes.Add(hash, verts.Count - 1); + indices.Add(verts.Count - 1); + return verts.Count - 1; + } } private unsafe static Bitmap CreateVoxelTexture(PixelColor[] palette)