mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2025-02-12 07:01:21 +00:00
optimized visual mode even further: visible geometry is grouped by texture and sorted by sector (to optimize out any redundant vertex source stream switches)
This commit is contained in:
parent
43a0e69de7
commit
a2407ebc3b
4 changed files with 291 additions and 23 deletions
|
@ -650,6 +650,7 @@
|
||||||
<None Include="Resources\Close.png" />
|
<None Include="Resources\Close.png" />
|
||||||
<Compile Include="Editing\EditingManager.cs" />
|
<Compile Include="Editing\EditingManager.cs" />
|
||||||
<Content Include="Resources\DB2.ico" />
|
<Content Include="Resources\DB2.ico" />
|
||||||
|
<Compile Include="General\BinaryHeap.cs" />
|
||||||
<Compile Include="Geometry\ProjectedFrustum2D.cs" />
|
<Compile Include="Geometry\ProjectedFrustum2D.cs" />
|
||||||
<Compile Include="VisualModes\Clipper.cs" />
|
<Compile Include="VisualModes\Clipper.cs" />
|
||||||
<Compile Include="VisualModes\VisualBlockEntry.cs" />
|
<Compile Include="VisualModes\VisualBlockEntry.cs" />
|
||||||
|
|
260
Source/General/BinaryHeap.cs
Normal file
260
Source/General/BinaryHeap.cs
Normal file
|
@ -0,0 +1,260 @@
|
||||||
|
|
||||||
|
#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.Runtime.InteropServices;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
namespace CodeImp.DoomBuilder
|
||||||
|
{
|
||||||
|
internal class BinaryHeap<T> : IEnumerable<T>, ICollection<T> where T : IComparable<T>
|
||||||
|
{
|
||||||
|
#region ================== Variables
|
||||||
|
|
||||||
|
// This will keep all items
|
||||||
|
private List<T> heap;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ================== Properties
|
||||||
|
|
||||||
|
public int Count { get { return heap.Count; } }
|
||||||
|
public virtual bool IsReadOnly { get { return false; } }
|
||||||
|
public T Root { get { if(heap.Count > 0) return heap[0]; else return default(T); } }
|
||||||
|
public T this[int index] { get { return ItemAt(index); } }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ================== Constructor / Destructor
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
public BinaryHeap()
|
||||||
|
{
|
||||||
|
// Initialize with default capacity
|
||||||
|
heap = new List<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
public BinaryHeap(int capacity)
|
||||||
|
{
|
||||||
|
// Initialize with specified capacity
|
||||||
|
heap = new List<T>(capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
~BinaryHeap()
|
||||||
|
{
|
||||||
|
// Clean up
|
||||||
|
heap = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ================== Methods
|
||||||
|
|
||||||
|
// Methods to find our way through the heap
|
||||||
|
private int ParentOf(int index) { return (index - 1) >> 1; }
|
||||||
|
private int LeftOf(int index) { return (index << 1) + 1; }
|
||||||
|
private int RightOf(int index) { return (index << 1) + 2; }
|
||||||
|
|
||||||
|
// This swaps two items in place
|
||||||
|
protected virtual void SwapItems(int index1, int index2)
|
||||||
|
{
|
||||||
|
// Swap items
|
||||||
|
T tempitem = heap[index1];
|
||||||
|
heap[index1] = heap[index2];
|
||||||
|
heap[index2] = tempitem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This adds an item to the list
|
||||||
|
// This is an O(log n) operation, where n is Count
|
||||||
|
public virtual void Add(T item)
|
||||||
|
{
|
||||||
|
int index = heap.Count;
|
||||||
|
|
||||||
|
// Add to the end of the heap
|
||||||
|
heap.Add(item);
|
||||||
|
|
||||||
|
// Continue until the item is at the top
|
||||||
|
// or compares higher to the parent item
|
||||||
|
while((index > 0) && (heap[index].CompareTo(heap[ParentOf(index)]) > 0))
|
||||||
|
{
|
||||||
|
// Swap with parent item
|
||||||
|
SwapItems(index, ParentOf(index));
|
||||||
|
index = ParentOf(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finds and returns the index of an item
|
||||||
|
// This is an O(n) operation, where n is Count
|
||||||
|
public virtual int IndexOf(T item)
|
||||||
|
{
|
||||||
|
return heap.IndexOf(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This returns the item at the given index
|
||||||
|
// This is an O(1) operation
|
||||||
|
public virtual T ItemAt(int index)
|
||||||
|
{
|
||||||
|
return heap[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
// This removes an item from the list
|
||||||
|
// This is an O(log n) operation, where n is Count
|
||||||
|
public virtual void RemoveAt(int index)
|
||||||
|
{
|
||||||
|
int newindex = index;
|
||||||
|
|
||||||
|
// Replace with last item
|
||||||
|
heap[index] = heap[heap.Count - 1];
|
||||||
|
heap.RemoveAt(heap.Count - 1);
|
||||||
|
|
||||||
|
// Continue while item has at least a left child
|
||||||
|
while(LeftOf(index) < heap.Count)
|
||||||
|
{
|
||||||
|
// Right childs also available?
|
||||||
|
if(RightOf(index) < heap.Count)
|
||||||
|
{
|
||||||
|
// Compare with both childs
|
||||||
|
// NOTE: Using newindex as indexer in the second line to ensure the lowest of both is chosen
|
||||||
|
if(heap[index].CompareTo(heap[LeftOf(index)]) < 0) newindex = LeftOf(index);
|
||||||
|
if(heap[newindex].CompareTo(heap[RightOf(index)]) < 0) newindex = RightOf(index);
|
||||||
|
}
|
||||||
|
// Only left child available
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Compare with left child
|
||||||
|
if(heap[index].CompareTo(heap[LeftOf(index)]) < 0) newindex = LeftOf(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Item should move down?
|
||||||
|
if(newindex != index)
|
||||||
|
{
|
||||||
|
// Swap the items
|
||||||
|
SwapItems(index, newindex);
|
||||||
|
index = newindex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Item is fine where it is, we're done
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This removes the root item from the list
|
||||||
|
// This is an O(log n) operation, where n is Count
|
||||||
|
public virtual void RemoveRoot()
|
||||||
|
{
|
||||||
|
// Remove the root item
|
||||||
|
RemoveAt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This removes a specific item from the list
|
||||||
|
// This is an O(n) operation, where n is Count
|
||||||
|
public virtual bool Remove(T item)
|
||||||
|
{
|
||||||
|
// Find the item in the heap
|
||||||
|
int index = IndexOf(item);
|
||||||
|
if(index > -1)
|
||||||
|
{
|
||||||
|
// Remove the item from the heap
|
||||||
|
RemoveAt(index);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No such item
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This clears the heap
|
||||||
|
public virtual void Clear()
|
||||||
|
{
|
||||||
|
// Clear the heap
|
||||||
|
heap.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This checks if the heap contains a specific item
|
||||||
|
// This is an O(n) operation, where n is Count
|
||||||
|
public virtual bool Contains(T item)
|
||||||
|
{
|
||||||
|
return (IndexOf(item) > -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This copies all items to an array
|
||||||
|
public virtual void CopyTo(T[] array)
|
||||||
|
{
|
||||||
|
// Copy items
|
||||||
|
heap.CopyTo(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This copies all items to an array
|
||||||
|
public virtual void CopyTo(T[] array, int arrayindex)
|
||||||
|
{
|
||||||
|
// Copy items
|
||||||
|
heap.CopyTo(array, arrayindex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This copies all items to an array
|
||||||
|
public virtual void CopyTo(int index, T[] array, int arrayindex, int count)
|
||||||
|
{
|
||||||
|
// Copy items
|
||||||
|
heap.CopyTo(index, array, arrayindex, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implemented to display the list
|
||||||
|
// This is an O(n) operation, where n is Count
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
StringBuilder str = new StringBuilder(heap.Count * 5);
|
||||||
|
|
||||||
|
// Go for all items
|
||||||
|
for(int i = 0; i < heap.Count; i++)
|
||||||
|
{
|
||||||
|
// Append item to string
|
||||||
|
if(i > 0) str.Append(", ");
|
||||||
|
str.Append(heap[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the string
|
||||||
|
return str.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This returns an enumerator
|
||||||
|
public IEnumerator<T> GetEnumerator()
|
||||||
|
{
|
||||||
|
return heap.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This returns an enumerator
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return heap.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,6 +31,7 @@ using CodeImp.DoomBuilder.Geometry;
|
||||||
using SlimDX.Direct3D9;
|
using SlimDX.Direct3D9;
|
||||||
using CodeImp.DoomBuilder.Data;
|
using CodeImp.DoomBuilder.Data;
|
||||||
using CodeImp.DoomBuilder.VisualModes;
|
using CodeImp.DoomBuilder.VisualModes;
|
||||||
|
using CodeImp.DoomBuilder.Map;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -56,7 +57,7 @@ namespace CodeImp.DoomBuilder.Rendering
|
||||||
private ProjectedFrustum2D frustum;
|
private ProjectedFrustum2D frustum;
|
||||||
|
|
||||||
// Geometry, grouped by texture
|
// Geometry, grouped by texture
|
||||||
private Dictionary<ImageData, List<VisualGeometry>> geometry;
|
private Dictionary<ImageData, BinaryHeap<VisualGeometry>> geometry;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -219,14 +220,14 @@ namespace CodeImp.DoomBuilder.Rendering
|
||||||
graphics.Shaders.World3D.BeginPass(0);
|
graphics.Shaders.World3D.BeginPass(0);
|
||||||
|
|
||||||
// Make collection
|
// Make collection
|
||||||
geometry = new Dictionary<ImageData, List<VisualGeometry>>();
|
geometry = new Dictionary<ImageData, BinaryHeap<VisualGeometry>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This ends rendering world geometry
|
// This ends rendering world geometry
|
||||||
public void FinishGeometry()
|
public void FinishGeometry()
|
||||||
{
|
{
|
||||||
// We now render the actual geometry collected
|
// We now render the actual geometry collected
|
||||||
foreach(KeyValuePair<ImageData, List<VisualGeometry>> group in geometry)
|
foreach(KeyValuePair<ImageData, BinaryHeap<VisualGeometry>> group in geometry)
|
||||||
{
|
{
|
||||||
ImageData curtexture;
|
ImageData curtexture;
|
||||||
|
|
||||||
|
@ -246,18 +247,32 @@ namespace CodeImp.DoomBuilder.Rendering
|
||||||
graphics.Shaders.World3D.ApplySettings();
|
graphics.Shaders.World3D.ApplySettings();
|
||||||
|
|
||||||
// Go for all geometry that uses this texture
|
// Go for all geometry that uses this texture
|
||||||
|
VisualSector sector = null;
|
||||||
foreach(VisualGeometry g in group.Value)
|
foreach(VisualGeometry g in group.Value)
|
||||||
{
|
{
|
||||||
// Update the sector if needed
|
// Changing sector?
|
||||||
if(g.Sector.NeedsUpdateGeo) g.Sector.Update();
|
if(!object.ReferenceEquals(g.Sector, sector))
|
||||||
|
|
||||||
// Only render when a vertexbuffer exists
|
|
||||||
if(g.Sector.GeometryBuffer != null)
|
|
||||||
{
|
{
|
||||||
// Render!
|
// Update the sector if needed
|
||||||
graphics.Device.SetStreamSource(0, g.Sector.GeometryBuffer, 0, WorldVertex.Stride);
|
if(g.Sector.NeedsUpdateGeo) g.Sector.Update();
|
||||||
graphics.Device.DrawPrimitives(PrimitiveType.TriangleList, g.VertexOffset, g.Triangles);
|
|
||||||
|
// Only do this sector when a vertexbuffer is created
|
||||||
|
if(g.Sector.GeometryBuffer != null)
|
||||||
|
{
|
||||||
|
// Change current sector
|
||||||
|
sector = g.Sector;
|
||||||
|
|
||||||
|
// Set stream source
|
||||||
|
graphics.Device.SetStreamSource(0, sector.GeometryBuffer, 0, WorldVertex.Stride);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sector = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Render!
|
||||||
|
if(sector != null) graphics.Device.DrawPrimitives(PrimitiveType.TriangleList, g.VertexOffset, g.Triangles);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,7 +307,7 @@ namespace CodeImp.DoomBuilder.Rendering
|
||||||
if(!geometry.ContainsKey(g.Texture))
|
if(!geometry.ContainsKey(g.Texture))
|
||||||
{
|
{
|
||||||
// Create texture group
|
// Create texture group
|
||||||
geometry.Add(g.Texture, new List<VisualGeometry>());
|
geometry.Add(g.Texture, new BinaryHeap<VisualGeometry>());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add geometry to texture group
|
// Add geometry to texture group
|
||||||
|
|
|
@ -110,16 +110,8 @@ namespace CodeImp.DoomBuilder.VisualModes
|
||||||
// This compares for sorting
|
// This compares for sorting
|
||||||
public int CompareTo(VisualGeometry other)
|
public int CompareTo(VisualGeometry other)
|
||||||
{
|
{
|
||||||
long thislongname, otherlongname;
|
// Compare sectors
|
||||||
|
return this.sector.Sector.Index - other.sector.Sector.Index;
|
||||||
// Get long names
|
|
||||||
if(this.texture != null) thislongname = this.texture.LongName; else thislongname = 0;
|
|
||||||
if(other.texture != null) otherlongname = other.texture.LongName; else otherlongname = 0;
|
|
||||||
|
|
||||||
// Compare names
|
|
||||||
if(thislongname > otherlongname) return 1;
|
|
||||||
else if(thislongname < otherlongname) return -1;
|
|
||||||
else return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
Loading…
Reference in a new issue