diff --git a/Builder.sln b/Builder.sln index 012faef1..58a838a1 100644 --- a/Builder.sln +++ b/Builder.sln @@ -51,6 +51,7 @@ Global {FBC0A503-9152-4BE2-9B5C-128FFD0B0D3F}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 {FBC0A503-9152-4BE2-9B5C-128FFD0B0D3F}.Debug|Mixed Platforms.Build.0 = Debug|x86 {FBC0A503-9152-4BE2-9B5C-128FFD0B0D3F}.Debug|x86.ActiveCfg = Debug|x86 + {FBC0A503-9152-4BE2-9B5C-128FFD0B0D3F}.Debug|x86.Build.0 = Debug|x86 {FBC0A503-9152-4BE2-9B5C-128FFD0B0D3F}.Release|Any CPU.ActiveCfg = Release|x86 {FBC0A503-9152-4BE2-9B5C-128FFD0B0D3F}.Release|Mixed Platforms.ActiveCfg = Release|x86 {FBC0A503-9152-4BE2-9B5C-128FFD0B0D3F}.Release|Mixed Platforms.Build.0 = Release|x86 @@ -59,6 +60,7 @@ Global {A5F93B70-18D9-4F3C-9B72-BC8B5B13998E}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 {A5F93B70-18D9-4F3C-9B72-BC8B5B13998E}.Debug|Mixed Platforms.Build.0 = Debug|x86 {A5F93B70-18D9-4F3C-9B72-BC8B5B13998E}.Debug|x86.ActiveCfg = Debug|x86 + {A5F93B70-18D9-4F3C-9B72-BC8B5B13998E}.Debug|x86.Build.0 = Debug|x86 {A5F93B70-18D9-4F3C-9B72-BC8B5B13998E}.Release|Any CPU.ActiveCfg = Release|x86 {A5F93B70-18D9-4F3C-9B72-BC8B5B13998E}.Release|Mixed Platforms.ActiveCfg = Release|x86 {A5F93B70-18D9-4F3C-9B72-BC8B5B13998E}.Release|Mixed Platforms.Build.0 = Release|x86 @@ -67,6 +69,7 @@ Global {CBD14608-D467-458A-97B3-CA767CA85203}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 {CBD14608-D467-458A-97B3-CA767CA85203}.Debug|Mixed Platforms.Build.0 = Debug|x86 {CBD14608-D467-458A-97B3-CA767CA85203}.Debug|x86.ActiveCfg = Debug|x86 + {CBD14608-D467-458A-97B3-CA767CA85203}.Debug|x86.Build.0 = Debug|x86 {CBD14608-D467-458A-97B3-CA767CA85203}.Release|Any CPU.ActiveCfg = Release|x86 {CBD14608-D467-458A-97B3-CA767CA85203}.Release|Mixed Platforms.ActiveCfg = Release|x86 {CBD14608-D467-458A-97B3-CA767CA85203}.Release|Mixed Platforms.Build.0 = Release|x86 diff --git a/Source/Core/Builder.csproj b/Source/Core/Builder.csproj index 7e1c0f99..b288c7d6 100644 --- a/Source/Core/Builder.csproj +++ b/Source/Core/Builder.csproj @@ -703,7 +703,9 @@ + + diff --git a/Source/Core/Map/Sector.cs b/Source/Core/Map/Sector.cs index 25c37049..b9c23c6f 100644 --- a/Source/Core/Map/Sector.cs +++ b/Source/Core/Map/Sector.cs @@ -73,7 +73,7 @@ namespace CodeImp.DoomBuilder.Map private Triangulation triangles; private FlatVertex[] flatvertices; private ReadOnlyCollection labels; - private SurfaceEntry surfaceentry; + private SurfaceEntryCollection surfaceentries; #endregion @@ -121,7 +121,7 @@ namespace CodeImp.DoomBuilder.Map this.longceiltexname = MapSet.EmptyLongName; this.updateneeded = true; this.triangulationneeded = true; - this.surfaceentry = new SurfaceEntry(-1, -1, -1); + this.surfaceentries = new SurfaceEntryCollection(); if(map == General.Map.Map) General.Map.UndoRedo.RecAddSector(this); @@ -156,7 +156,7 @@ namespace CodeImp.DoomBuilder.Map map.AddSectorIndexHole(fixedindex); // Free surface entry - General.Map.CRenderer2D.Surfaces.FreeSurfaces(surfaceentry); + General.Map.CRenderer2D.Surfaces.FreeSurfaces(surfaceentries); // Clean up sidedefs = null; @@ -273,8 +273,8 @@ namespace CodeImp.DoomBuilder.Map labels = Array.AsReadOnly(Tools.FindLabelPositions(this).ToArray()); // Number of vertices changed? - if((surfaceentry != null) && (triangles.Vertices.Count != surfaceentry.numvertices)) - General.Map.CRenderer2D.Surfaces.FreeSurfaces(surfaceentry); + if(triangles.Vertices.Count != surfaceentries.totalvertices) + General.Map.CRenderer2D.Surfaces.FreeSurfaces(surfaceentries); } } } @@ -302,25 +302,17 @@ namespace CodeImp.DoomBuilder.Map // Create bounding box bbox = CreateBBox(); - // Make a dummy entry if we don't have one yet - if(surfaceentry == null) surfaceentry = new SurfaceEntry(-1, -1, -1); - - // Create floor vertices - FlatVertex[] floorvertices = new FlatVertex[flatvertices.Length]; - flatvertices.CopyTo(floorvertices, 0); - General.Plugins.OnSectorFloorSurfaceUpdate(this, ref floorvertices); - surfaceentry.floorvertices = floorvertices; - surfaceentry.floortexture = longfloortexname; - - // Create ceiling vertices - FlatVertex[] ceilvertices = new FlatVertex[flatvertices.Length]; - flatvertices.CopyTo(ceilvertices, 0); - General.Plugins.OnSectorCeilingSurfaceUpdate(this, ref ceilvertices); - surfaceentry.ceilvertices = ceilvertices; - surfaceentry.ceiltexture = longceiltexname; + // Make update info (this lets the plugin fill in texture coordinates and such) + SurfaceUpdate updateinfo = new SurfaceUpdate(flatvertices.Length, true, true); + flatvertices.CopyTo(updateinfo.floorvertices, 0); + General.Plugins.OnSectorFloorSurfaceUpdate(this, ref updateinfo.floorvertices); + flatvertices.CopyTo(updateinfo.ceilvertices, 0); + General.Plugins.OnSectorCeilingSurfaceUpdate(this, ref updateinfo.ceilvertices); + updateinfo.floortexture = longfloortexname; + updateinfo.ceiltexture = longceiltexname; - // Update entry - surfaceentry = General.Map.CRenderer2D.Surfaces.UpdateSurfaces(surfaceentry); + // Update surfaces + General.Map.CRenderer2D.Surfaces.UpdateSurfaces(surfaceentries, updateinfo); // Updated updateneeded = false; @@ -333,16 +325,13 @@ namespace CodeImp.DoomBuilder.Map if(flatvertices == null) return; // Create floor vertices - FlatVertex[] floorvertices = new FlatVertex[flatvertices.Length]; - flatvertices.CopyTo(floorvertices, 0); - General.Plugins.OnSectorFloorSurfaceUpdate(this, ref floorvertices); - surfaceentry.floorvertices = floorvertices; - surfaceentry.floortexture = longfloortexname; - if(surfaceentry.ceilvertices == null) - surfaceentry.ceilvertices = floorvertices; + SurfaceUpdate updateinfo = new SurfaceUpdate(flatvertices.Length, true, false); + flatvertices.CopyTo(updateinfo.floorvertices, 0); + General.Plugins.OnSectorFloorSurfaceUpdate(this, ref updateinfo.floorvertices); + updateinfo.floortexture = longfloortexname; // Update entry - surfaceentry = General.Map.CRenderer2D.Surfaces.UpdateSurfaces(surfaceentry); + General.Map.CRenderer2D.Surfaces.UpdateSurfaces(surfaceentries, updateinfo); General.Map.CRenderer2D.Surfaces.UnlockBuffers(); } @@ -352,16 +341,13 @@ namespace CodeImp.DoomBuilder.Map if(flatvertices == null) return; // Create ceiling vertices - FlatVertex[] ceilvertices = new FlatVertex[flatvertices.Length]; - flatvertices.CopyTo(ceilvertices, 0); - General.Plugins.OnSectorCeilingSurfaceUpdate(this, ref ceilvertices); - surfaceentry.ceilvertices = ceilvertices; - surfaceentry.ceiltexture = longceiltexname; - if(surfaceentry.floorvertices == null) - surfaceentry.floorvertices = ceilvertices; + SurfaceUpdate updateinfo = new SurfaceUpdate(flatvertices.Length, false, true); + flatvertices.CopyTo(updateinfo.ceilvertices, 0); + General.Plugins.OnSectorCeilingSurfaceUpdate(this, ref updateinfo.ceilvertices); + updateinfo.ceiltexture = longceiltexname; // Update entry - surfaceentry = General.Map.CRenderer2D.Surfaces.UpdateSurfaces(surfaceentry); + General.Map.CRenderer2D.Surfaces.UpdateSurfaces(surfaceentries, updateinfo); General.Map.CRenderer2D.Surfaces.UnlockBuffers(); } diff --git a/Source/Core/Rendering/SurfaceEntryCollection.cs b/Source/Core/Rendering/SurfaceEntryCollection.cs new file mode 100644 index 00000000..8eafd581 --- /dev/null +++ b/Source/Core/Rendering/SurfaceEntryCollection.cs @@ -0,0 +1,49 @@ + +#region ================== Copyright (c) 2007 Pascal vd Heiden + +/* + * Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com + * This program is released under GNU General Public License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#endregion + +#region ================== Namespaces + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using System.Windows.Forms; +using System.IO; +using System.Reflection; +using System.Drawing; +using System.ComponentModel; +using CodeImp.DoomBuilder.Map; +using SlimDX.Direct3D9; +using SlimDX; +using CodeImp.DoomBuilder.Geometry; +using System.Drawing.Imaging; +using CodeImp.DoomBuilder.Data; +using CodeImp.DoomBuilder.Editing; + +using Configuration = CodeImp.DoomBuilder.IO.Configuration; + +#endregion + +namespace CodeImp.DoomBuilder.Rendering +{ + // This contains information to update surface entries with. This may exceed the maximum number + // of sector vertices, the surface manager will take care of splitting it up in several SurfaceEntries. + internal class SurfaceEntryCollection : List + { + public int totalvertices = 0; + } +} diff --git a/Source/Core/Rendering/SurfaceManager.cs b/Source/Core/Rendering/SurfaceManager.cs index ce927ca4..13f9c64c 100644 --- a/Source/Core/Rendering/SurfaceManager.cs +++ b/Source/Core/Rendering/SurfaceManager.cs @@ -48,6 +48,10 @@ namespace CodeImp.DoomBuilder.Rendering // is a scary big number for a vertexbuffer. private const int MAX_VERTICES_PER_BUFFER = 30000; + // When a sector exceeds this number of vertices, it should split up it's triangles + // This number must be a multiple of 3. + public const int MAX_VERTICES_PER_SECTOR = 6000; + #endregion #region ================== Variables @@ -220,10 +224,19 @@ namespace CodeImp.DoomBuilder.Rendering { if(s.Triangles != null) { - // We count the number of sectors that have specific number of vertices - if(!sectorverts.ContainsKey(s.Triangles.Vertices.Count)) - sectorverts.Add(s.Triangles.Vertices.Count, 0); - sectorverts[s.Triangles.Vertices.Count]++; + int numvertices = s.Triangles.Vertices.Count; + while(numvertices > 0) + { + // Determine for how many vertices in this entry + int vertsinentry = (numvertices > MAX_VERTICES_PER_SECTOR) ? MAX_VERTICES_PER_SECTOR : numvertices; + + // We count the number of sectors that have specific number of vertices + if(!sectorverts.ContainsKey(vertsinentry)) + sectorverts.Add(vertsinentry, 0); + sectorverts[vertsinentry]++; + + numvertices -= vertsinentry; + } } } @@ -385,53 +398,95 @@ namespace CodeImp.DoomBuilder.Rendering } // This adds or updates sector geometry into a buffer. - // Always specify the entry when a previous entry was already given for that sector! - // Sector must set the floorvertices and ceilvertices members on the entry. - // Returns the new surface entry for the stored geometry, floorvertices and ceilvertices will be preserved. - public SurfaceEntry UpdateSurfaces(SurfaceEntry entry) + // Modiies the list of SurfaceEntries with the new surface entry for the stored geometry. + public void UpdateSurfaces(SurfaceEntryCollection entries, SurfaceUpdate update) { - if(entry.floorvertices.Length != entry.ceilvertices.Length) - General.Fail("Floor vertices has different length from ceiling vertices!"); - - int numvertices = entry.floorvertices.Length; - - // Free entry when number of vertices have changed - if((entry.numvertices != numvertices) && (entry.numvertices != -1)) - FreeSurfaces(entry); - - // Check if we can render this at all - if(numvertices > 0) + // Free entries when number of vertices has changed + if((entries.Count > 0) && (entries.totalvertices != update.numvertices)) { - SurfaceBufferSet set = GetSet(numvertices); + FreeSurfaces(entries); + entries.Clear(); + } + + if((entries.Count == 0) && (update.numvertices > 0)) + { + #if DEBUG + if((update.floorvertices == null) || (update.ceilvertices == null)) + General.Fail("We need both floor and ceiling vertices when the number of vertices changes!"); + #endif + + // If we have no entries yet, we have to make them now + int vertsremaining = update.numvertices; + while(vertsremaining > 0) + { + // Determine for how many vertices in this entry + int vertsinentry = (vertsremaining > MAX_VERTICES_PER_SECTOR) ? MAX_VERTICES_PER_SECTOR : vertsremaining; + + // Lookup the set that holds entries for this number of vertices + SurfaceBufferSet set = GetSet(vertsinentry); + + // Make sure we can get a new entry in this set + EnsureFreeBufferSpace(set, 1); + + // Get a new entry in this set + SurfaceEntry e = set.holes[set.holes.Count - 1]; + set.holes.RemoveAt(set.holes.Count - 1); + set.entries.Add(e); + + // Fill the entry data + e.floorvertices = new FlatVertex[vertsinentry]; + e.ceilvertices = new FlatVertex[vertsinentry]; + Array.Copy(update.floorvertices, update.numvertices - vertsremaining, e.floorvertices, 0, vertsinentry); + Array.Copy(update.ceilvertices, update.numvertices - vertsremaining, e.ceilvertices, 0, vertsinentry); + e.floortexture = update.floortexture; + e.ceiltexture = update.ceiltexture; + + entries.Add(e); + vertsremaining -= vertsinentry; + } + } + else + { + // We re-use the same entries, just copy over the updated data + int vertsremaining = update.numvertices; + foreach(SurfaceEntry e in entries) + { + if(update.floorvertices != null) + { + Array.Copy(update.floorvertices, update.numvertices - vertsremaining, e.floorvertices, 0, e.numvertices); + e.floortexture = update.floortexture; + } + + if(update.ceilvertices != null) + { + Array.Copy(update.ceilvertices, update.numvertices - vertsremaining, e.ceilvertices, 0, e.numvertices); + e.ceiltexture = update.ceiltexture; + } + + vertsremaining -= e.numvertices; + } + } + + entries.totalvertices = update.numvertices; + + // Time to update or create the buffers + foreach(SurfaceEntry e in entries) + { + SurfaceBufferSet set = GetSet(e.numvertices); // Update bounding box - entry.UpdateBBox(); + e.UpdateBBox(); - // Check if we need a new entry - if(entry.numvertices == -1) - { - EnsureFreeBufferSpace(set, 1); - SurfaceEntry nentry = set.holes[set.holes.Count - 1]; - set.holes.RemoveAt(set.holes.Count - 1); - nentry.ceilvertices = entry.ceilvertices; - nentry.floorvertices = entry.floorvertices; - nentry.floortexture = entry.floortexture; - nentry.ceiltexture = entry.ceiltexture; - nentry.bbox = entry.bbox; - set.entries.Add(nentry); - entry = nentry; - } - if(!resourcesunloaded) { // Lock the buffer DataStream bstream; - VertexBuffer vb = set.buffers[entry.bufferindex]; + VertexBuffer vb = set.buffers[e.bufferindex]; if(vb.Tag == null) { // Note: DirectX warns me that I am not using LockFlags.Discard or LockFlags.NoOverwrite here, - // but we don't care (we don't have much of a choice since we want to update our data) - bstream = vb.Lock(0, set.buffersizes[entry.bufferindex] * FlatVertex.Stride, LockFlags.None); + // but we don't have much of a choice since we want to update our data and not destroy other data + bstream = vb.Lock(0, set.buffersizes[e.bufferindex] * FlatVertex.Stride, LockFlags.None); vb.Tag = bstream; lockedbuffers.Add(vb); } @@ -441,27 +496,28 @@ namespace CodeImp.DoomBuilder.Rendering } // Write the vertices to buffer - bstream.Seek(entry.vertexoffset * FlatVertex.Stride, SeekOrigin.Begin); - bstream.WriteRange(entry.floorvertices); - bstream.WriteRange(entry.ceilvertices); + bstream.Seek(e.vertexoffset * FlatVertex.Stride, SeekOrigin.Begin); + bstream.WriteRange(e.floorvertices); + bstream.WriteRange(e.ceilvertices); } } - - return entry; } // This frees the given surface entry - public void FreeSurfaces(SurfaceEntry entry) + public void FreeSurfaces(SurfaceEntryCollection entries) { - if((entry.numvertices > 0) && (entry.bufferindex > -1)) + foreach(SurfaceEntry e in entries) { - SurfaceBufferSet set = sets[entry.numvertices]; - set.entries.Remove(entry); - SurfaceEntry newentry = new SurfaceEntry(entry); - set.holes.Add(newentry); + if((e.numvertices > 0) && (e.bufferindex > -1)) + { + SurfaceBufferSet set = sets[e.numvertices]; + set.entries.Remove(e); + SurfaceEntry newentry = new SurfaceEntry(e); + set.holes.Add(newentry); + } + e.numvertices = -1; + e.bufferindex = -1; } - entry.numvertices = -1; - entry.bufferindex = -1; } // This unlocks the locked buffers diff --git a/Source/Core/Rendering/SurfaceUpdate.cs b/Source/Core/Rendering/SurfaceUpdate.cs new file mode 100644 index 00000000..96f8bf58 --- /dev/null +++ b/Source/Core/Rendering/SurfaceUpdate.cs @@ -0,0 +1,77 @@ + +#region ================== Copyright (c) 2007 Pascal vd Heiden + +/* + * Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com + * This program is released under GNU General Public License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#endregion + +#region ================== Namespaces + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using System.Windows.Forms; +using System.IO; +using System.Reflection; +using System.Drawing; +using System.ComponentModel; +using CodeImp.DoomBuilder.Map; +using SlimDX.Direct3D9; +using SlimDX; +using CodeImp.DoomBuilder.Geometry; +using System.Drawing.Imaging; +using CodeImp.DoomBuilder.Data; +using CodeImp.DoomBuilder.Editing; + +using Configuration = CodeImp.DoomBuilder.IO.Configuration; + +#endregion + +namespace CodeImp.DoomBuilder.Rendering +{ + // This contains information to update surface entries with. This may exceed the maximum number + // of sector vertices, the surface manager will take care of splitting it up in several SurfaceEntries. + internal class SurfaceUpdate + { + public int numvertices; + + // Sector geometry (local copy used to quickly refill buffers) + // The sector must set these! + public FlatVertex[] floorvertices; + public FlatVertex[] ceilvertices; + + // Sector images + // The sector must set these! + public long floortexture; + public long ceiltexture; + + // Constructor + internal SurfaceUpdate(int numvertices, bool updatefloor, bool updateceiling) + { + this.numvertices = numvertices; + this.floortexture = 0; + this.ceiltexture = 0; + + if(updatefloor) + this.floorvertices = new FlatVertex[numvertices]; + else + this.floorvertices = null; + + if(updateceiling) + this.ceilvertices = new FlatVertex[numvertices]; + else + this.ceilvertices = null; + } + } +}