Fixed crash when sectors with lots of sidedefs are created or loaded

This commit is contained in:
codeimp 2010-08-26 21:47:25 +00:00
parent d84312ea92
commit 89bf322a74
6 changed files with 264 additions and 91 deletions

View file

@ -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

View file

@ -703,7 +703,9 @@
<Compile Include="Map\MapElementCollection.cs" />
<Compile Include="Rendering\SurfaceBufferSet.cs" />
<Compile Include="Rendering\SurfaceEntry.cs" />
<Compile Include="Rendering\SurfaceEntryCollection.cs" />
<Compile Include="Rendering\SurfaceManager.cs" />
<Compile Include="Rendering\SurfaceUpdate.cs" />
<Compile Include="Types\ThingClassHandler.cs" />
<Compile Include="Types\ThingTypeHandler.cs" />
<Compile Include="Windows\ErrorsForm.cs">

View file

@ -73,7 +73,7 @@ namespace CodeImp.DoomBuilder.Map
private Triangulation triangles;
private FlatVertex[] flatvertices;
private ReadOnlyCollection<LabelPositionInfo> 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<LabelPositionInfo>(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);
// 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;
// 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;
// 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();
}

View file

@ -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<SurfaceEntry>
{
public int totalvertices = 0;
}
}

View file

@ -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();
// 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;
}
e.UpdateBBox();
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

View file

@ -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;
}
}
}