mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2025-04-25 03:51:01 +00:00
@ major change in the way sector surfaces are allocated and rendered for optimization
@ white texture has been moved to the DataManager and is now also available to plugins
This commit is contained in:
parent
6144b9b7ad
commit
45ad5f5943
9 changed files with 864 additions and 246 deletions
|
@ -676,6 +676,9 @@
|
|||
<Compile Include="General\ErrorLogger.cs" />
|
||||
<Compile Include="IO\DoomColormapReader.cs" />
|
||||
<Compile Include="Map\SelectionType.cs" />
|
||||
<Compile Include="Rendering\SurfaceBufferSet.cs" />
|
||||
<Compile Include="Rendering\SurfaceEntry.cs" />
|
||||
<Compile Include="Rendering\SurfaceManager.cs" />
|
||||
<Compile Include="Windows\ErrorsForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
|
|
|
@ -81,6 +81,7 @@ namespace CodeImp.DoomBuilder.Data
|
|||
private ImageData crosshairbusy;
|
||||
private Dictionary<string, ImageData> internalsprites;
|
||||
private ImageData thingbox;
|
||||
private ImageData whitetexture;
|
||||
|
||||
// Used images
|
||||
private Dictionary<long, long> usedimages;
|
||||
|
@ -113,6 +114,7 @@ namespace CodeImp.DoomBuilder.Data
|
|||
public ImageData Crosshair3D { get { return crosshair; } }
|
||||
public ImageData CrosshairBusy3D { get { return crosshairbusy; } }
|
||||
public ImageData ThingBox { get { return thingbox; } }
|
||||
public ImageData WhiteTexture { get { return whitetexture; } }
|
||||
public List<ThingCategory> ThingCategories { get { return thingcategories; } }
|
||||
public ICollection<ThingTypeInfo> ThingTypes { get { return thingtypes.Values; } }
|
||||
internal ICollection<MatchingTextureSet> TextureSets { get { return texturesets; } }
|
||||
|
@ -157,8 +159,12 @@ namespace CodeImp.DoomBuilder.Data
|
|||
crosshairbusy.LoadImage();
|
||||
thingbox = new ResourceImage("ThingBox.png");
|
||||
thingbox.LoadImage();
|
||||
whitetexture = new ResourceImage("White.png");
|
||||
whitetexture.UseColorCorrection = false;
|
||||
whitetexture.LoadImage();
|
||||
whitetexture.CreateTexture();
|
||||
}
|
||||
|
||||
|
||||
// Disposer
|
||||
internal void Dispose()
|
||||
{
|
||||
|
@ -179,6 +185,8 @@ namespace CodeImp.DoomBuilder.Data
|
|||
crosshairbusy = null;
|
||||
thingbox.Dispose();
|
||||
thingbox = null;
|
||||
whitetexture.Dispose();
|
||||
whitetexture = null;
|
||||
|
||||
// Done
|
||||
isdisposed = true;
|
||||
|
|
|
@ -1392,6 +1392,9 @@ namespace CodeImp.DoomBuilder
|
|||
// Can't have a selection in an old map set
|
||||
map.ClearAllSelected();
|
||||
|
||||
// Reset surfaces
|
||||
renderer2d.Surfaces.Reset();
|
||||
|
||||
// Apply
|
||||
map.Dispose();
|
||||
map = newmap;
|
||||
|
|
|
@ -891,9 +891,18 @@ namespace CodeImp.DoomBuilder.Map
|
|||
{
|
||||
// Update all linedefs
|
||||
if(dolines) foreach(Linedef l in linedefs) l.UpdateCache();
|
||||
|
||||
|
||||
// Update all sectors
|
||||
if(dosectors) foreach(Sector s in sectors) s.UpdateCache();
|
||||
if(dosectors)
|
||||
{
|
||||
foreach(Sector s in sectors) s.Triangulate();
|
||||
|
||||
General.Map.CRenderer2D.Surfaces.AllocateBuffers();
|
||||
|
||||
foreach(Sector s in sectors) s.CreateSurfaces();
|
||||
|
||||
General.Map.CRenderer2D.Surfaces.UnlockBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -33,7 +33,7 @@ using SlimDX;
|
|||
|
||||
namespace CodeImp.DoomBuilder.Map
|
||||
{
|
||||
public sealed class Sector : SelectableElement, ID3DResource
|
||||
public sealed class Sector : SelectableElement
|
||||
{
|
||||
#region ================== Constants
|
||||
|
||||
|
@ -74,8 +74,7 @@ namespace CodeImp.DoomBuilder.Map
|
|||
private Triangulation triangles;
|
||||
private FlatVertex[] flatvertices;
|
||||
private ReadOnlyCollection<LabelPositionInfo> labels;
|
||||
private VertexBuffer flatceilingbuffer;
|
||||
private VertexBuffer flatfloorbuffer;
|
||||
private SurfaceEntry surfaceentry;
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -103,8 +102,6 @@ namespace CodeImp.DoomBuilder.Map
|
|||
internal int SerializedIndex { get { return serializedindex; } set { serializedindex = value; } }
|
||||
public Triangulation Triangles { get { return triangles; } }
|
||||
public FlatVertex[] FlatVertices { get { return flatvertices; } }
|
||||
internal VertexBuffer FlatCeilingBuffer { get { return flatceilingbuffer; } }
|
||||
internal VertexBuffer FlatFloorBuffer { get { return flatfloorbuffer; } }
|
||||
public ReadOnlyCollection<LabelPositionInfo> Labels { get { return labels; } }
|
||||
|
||||
#endregion
|
||||
|
@ -125,8 +122,6 @@ namespace CodeImp.DoomBuilder.Map
|
|||
this.longceiltexname = MapSet.EmptyLongName;
|
||||
this.triangulationneeded = true;
|
||||
|
||||
General.Map.Graphics.RegisterResource(this);
|
||||
|
||||
// We have no destructor
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
@ -141,8 +136,6 @@ namespace CodeImp.DoomBuilder.Map
|
|||
this.triangulationneeded = true;
|
||||
|
||||
ReadWrite(stream);
|
||||
|
||||
General.Map.Graphics.RegisterResource(this);
|
||||
|
||||
// We have no destructor
|
||||
GC.SuppressFinalize(this);
|
||||
|
@ -167,13 +160,10 @@ namespace CodeImp.DoomBuilder.Map
|
|||
// because a sidedef cannot exist without reference to its sector.
|
||||
foreach(Sidedef sd in sidedefs) sd.Dispose();
|
||||
|
||||
General.Map.Graphics.UnregisterResource(this);
|
||||
|
||||
// Free surface entry
|
||||
General.Map.CRenderer2D.Surfaces.FreeSurfaces(surfaceentry);
|
||||
|
||||
// Clean up
|
||||
if(flatceilingbuffer != null) flatceilingbuffer.Dispose();
|
||||
if(flatfloorbuffer != null) flatfloorbuffer.Dispose();
|
||||
flatceilingbuffer = null;
|
||||
flatfloorbuffer = null;
|
||||
mainlistitem = null;
|
||||
sidedefs = null;
|
||||
map = null;
|
||||
|
@ -296,10 +286,9 @@ namespace CodeImp.DoomBuilder.Map
|
|||
}
|
||||
}
|
||||
|
||||
// This updates the sector when changes have been made
|
||||
public void UpdateCache()
|
||||
// This triangulates the sector geometry
|
||||
internal void Triangulate()
|
||||
{
|
||||
// Update if needed
|
||||
if(updateneeded)
|
||||
{
|
||||
// Triangulate again?
|
||||
|
@ -308,11 +297,23 @@ namespace CodeImp.DoomBuilder.Map
|
|||
// Triangulate sector
|
||||
triangles = Triangulation.Create(this);
|
||||
triangulationneeded = false;
|
||||
updateneeded = true;
|
||||
|
||||
// Make label positions
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// This makes new vertices as well as floor and ceiling surfaces
|
||||
internal void CreateSurfaces()
|
||||
{
|
||||
if(updateneeded)
|
||||
{
|
||||
// Brightness color (alpha is opaque)
|
||||
byte clampedbright = 0;
|
||||
if((brightness >= 0) && (brightness <= 255)) clampedbright = (byte)brightness;
|
||||
|
@ -335,120 +336,71 @@ 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;
|
||||
|
||||
// Update entry
|
||||
surfaceentry = General.Map.CRenderer2D.Surfaces.UpdateSurfaces(surfaceentry);
|
||||
|
||||
// Updated
|
||||
updateneeded = false;
|
||||
|
||||
// Update buffers
|
||||
UpdateFloorSurface();
|
||||
UpdateCeilingSurface();
|
||||
}
|
||||
}
|
||||
|
||||
// This updates the buffer with flat vertices
|
||||
// This updates the floor surface
|
||||
public void UpdateFloorSurface()
|
||||
{
|
||||
// Trash buffer, if any
|
||||
if(flatfloorbuffer != null)
|
||||
{
|
||||
flatfloorbuffer.Dispose();
|
||||
flatfloorbuffer = null;
|
||||
}
|
||||
|
||||
// Not updated?
|
||||
if(updateneeded)
|
||||
{
|
||||
// Make sure the sector is up-to-date
|
||||
// This will automatically call this function again
|
||||
UpdateCache();
|
||||
}
|
||||
// Any vertices?
|
||||
else if(flatvertices.Length > 0)
|
||||
{
|
||||
if(General.Map.Graphics.CheckAvailability())
|
||||
{
|
||||
FlatVertex[] buffervertices = new FlatVertex[triangles.Vertices.Count];
|
||||
flatvertices.CopyTo(buffervertices, 0);
|
||||
|
||||
// Raise event to allow plugins to modify this data
|
||||
General.Plugins.OnSectorFloorSurfaceUpdate(this, ref buffervertices);
|
||||
|
||||
// Make the buffer
|
||||
flatfloorbuffer = new VertexBuffer(General.Map.Graphics.Device, FlatVertex.Stride * buffervertices.Length,
|
||||
Usage.WriteOnly | Usage.Dynamic, VertexFormat.None, Pool.Default);
|
||||
|
||||
// Fill it
|
||||
DataStream bufferstream = flatfloorbuffer.Lock(0, FlatVertex.Stride * buffervertices.Length, LockFlags.Discard);
|
||||
bufferstream.WriteRange<FlatVertex>(buffervertices);
|
||||
flatfloorbuffer.Unlock();
|
||||
bufferstream.Dispose();
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
|
||||
// Update entry
|
||||
surfaceentry = General.Map.CRenderer2D.Surfaces.UpdateSurfaces(surfaceentry);
|
||||
General.Map.CRenderer2D.Surfaces.UnlockBuffers();
|
||||
}
|
||||
|
||||
// This updates the buffer with flat vertices
|
||||
// This updates the ceiling surface
|
||||
public void UpdateCeilingSurface()
|
||||
{
|
||||
// Trash buffer, if any
|
||||
if(flatceilingbuffer != null)
|
||||
{
|
||||
flatceilingbuffer.Dispose();
|
||||
flatceilingbuffer = null;
|
||||
}
|
||||
// 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;
|
||||
|
||||
// Not updated?
|
||||
// Update entry
|
||||
surfaceentry = General.Map.CRenderer2D.Surfaces.UpdateSurfaces(surfaceentry);
|
||||
General.Map.CRenderer2D.Surfaces.UnlockBuffers();
|
||||
}
|
||||
|
||||
// This updates the sector when changes have been made
|
||||
public void UpdateCache()
|
||||
{
|
||||
// Update if needed
|
||||
if(updateneeded)
|
||||
{
|
||||
// Make sure the sector is up-to-date
|
||||
// This will automatically call this function again
|
||||
UpdateCache();
|
||||
Triangulate();
|
||||
|
||||
CreateSurfaces();
|
||||
}
|
||||
// Any vertices?
|
||||
else if(flatvertices.Length > 0)
|
||||
{
|
||||
if(General.Map.Graphics.CheckAvailability())
|
||||
{
|
||||
FlatVertex[] buffervertices = new FlatVertex[triangles.Vertices.Count];
|
||||
flatvertices.CopyTo(buffervertices, 0);
|
||||
|
||||
// Raise event to allow plugins to modify this data
|
||||
General.Plugins.OnSectorCeilingSurfaceUpdate(this, ref buffervertices);
|
||||
|
||||
// Make the buffer
|
||||
flatceilingbuffer = new VertexBuffer(General.Map.Graphics.Device, FlatVertex.Stride * buffervertices.Length,
|
||||
Usage.WriteOnly | Usage.Dynamic, VertexFormat.None, Pool.Default);
|
||||
|
||||
// Fill it
|
||||
DataStream bufferstream = flatceilingbuffer.Lock(0, FlatVertex.Stride * buffervertices.Length, LockFlags.Discard);
|
||||
bufferstream.WriteRange<FlatVertex>(buffervertices);
|
||||
flatceilingbuffer.Unlock();
|
||||
bufferstream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unload unstable resources
|
||||
public void UnloadResource()
|
||||
{
|
||||
// Trash buffer, if any
|
||||
if(flatfloorbuffer != null)
|
||||
{
|
||||
flatfloorbuffer.Dispose();
|
||||
flatfloorbuffer = null;
|
||||
}
|
||||
|
||||
// Trash buffer, if any
|
||||
if(flatceilingbuffer != null)
|
||||
{
|
||||
flatceilingbuffer.Dispose();
|
||||
flatceilingbuffer = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Reload unstable resources
|
||||
public void ReloadResource()
|
||||
{
|
||||
UpdateFloorSurface();
|
||||
UpdateCeilingSurface();
|
||||
}
|
||||
|
||||
// Selected
|
||||
|
|
|
@ -106,9 +106,11 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
private bool thingsfront;
|
||||
private int vertexsize;
|
||||
private RenderLayers renderlayer = RenderLayers.None;
|
||||
|
||||
|
||||
// Surfaces
|
||||
private SurfaceManager surfaces;
|
||||
|
||||
// Images
|
||||
private ResourceImage whitetexture;
|
||||
private ResourceImage[] thingtexture;
|
||||
|
||||
// View settings (world coordinates)
|
||||
|
@ -139,6 +141,7 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
public float Scale { get { return scale; } }
|
||||
public int VertexSize { get { return vertexsize; } }
|
||||
public ViewMode ViewMode { get { return viewmode; } }
|
||||
public SurfaceManager Surfaces { get { return surfaces; } }
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -157,11 +160,8 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
thingtexture[i].CreateTexture();
|
||||
}
|
||||
|
||||
// Load white texture
|
||||
whitetexture = new ResourceImage("White.png");
|
||||
whitetexture.UseColorCorrection = false;
|
||||
whitetexture.LoadImage();
|
||||
whitetexture.CreateTexture();
|
||||
// Create surface manager
|
||||
surfaces = new SurfaceManager();
|
||||
|
||||
// Create rendertargets
|
||||
CreateRendertargets();
|
||||
|
@ -179,7 +179,9 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
// Destroy rendertargets
|
||||
DestroyRendertargets();
|
||||
foreach(ResourceImage i in thingtexture) i.Dispose();
|
||||
whitetexture.Dispose();
|
||||
|
||||
// Dispose surface manager
|
||||
surfaces.Dispose();
|
||||
|
||||
// Done
|
||||
base.Dispose();
|
||||
|
@ -1138,12 +1140,33 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
// Set transformations
|
||||
UpdateTransformations();
|
||||
|
||||
// Render what must be rendered
|
||||
// Set states
|
||||
graphics.Device.SetRenderState(RenderState.CullMode, Cull.None);
|
||||
graphics.Device.SetRenderState(RenderState.ZEnable, false);
|
||||
graphics.Device.SetRenderState(RenderState.AlphaBlendEnable, false);
|
||||
graphics.Device.SetRenderState(RenderState.AlphaTestEnable, false);
|
||||
graphics.Device.SetRenderState(RenderState.TextureFactor, -1);
|
||||
graphics.Device.SetRenderState(RenderState.FogEnable, false);
|
||||
SetWorldTransformation(true);
|
||||
graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, General.Settings.ClassicBilinear);
|
||||
|
||||
// Prepare for rendering
|
||||
switch(viewmode)
|
||||
{
|
||||
case ViewMode.Brightness: RenderSectorBrightness(General.Map.Map.Sectors); break;
|
||||
case ViewMode.FloorTextures: RenderSectorFloors(General.Map.Map.Sectors); break;
|
||||
case ViewMode.CeilingTextures: RenderSectorCeilings(General.Map.Map.Sectors); break;
|
||||
case ViewMode.Brightness:
|
||||
surfaces.RenderSectorBrightness();
|
||||
surfaces.RenderSectorSurfaces(graphics);
|
||||
break;
|
||||
|
||||
case ViewMode.FloorTextures:
|
||||
surfaces.RenderSectorFloors();
|
||||
surfaces.RenderSectorSurfaces(graphics);
|
||||
break;
|
||||
|
||||
case ViewMode.CeilingTextures:
|
||||
surfaces.RenderSectorCeilings();
|
||||
surfaces.RenderSectorSurfaces(graphics);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1152,112 +1175,6 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
Finish();
|
||||
}
|
||||
|
||||
// This renders all sector floors
|
||||
private void RenderSectorFloors(ICollection<Sector> sectors)
|
||||
{
|
||||
// Set states
|
||||
graphics.Device.SetRenderState(RenderState.CullMode, Cull.None);
|
||||
graphics.Device.SetRenderState(RenderState.ZEnable, false);
|
||||
graphics.Device.SetRenderState(RenderState.AlphaBlendEnable, false);
|
||||
graphics.Device.SetRenderState(RenderState.AlphaTestEnable, false);
|
||||
graphics.Device.SetRenderState(RenderState.TextureFactor, -1);
|
||||
graphics.Device.SetRenderState(RenderState.FogEnable, false);
|
||||
SetWorldTransformation(true);
|
||||
graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, General.Settings.ClassicBilinear);
|
||||
|
||||
// Render all sectors
|
||||
foreach(Sector s in sectors)
|
||||
RenderSectorSurface(s, s.FlatFloorBuffer, s.LongFloorTexture);
|
||||
}
|
||||
|
||||
// This renders all sector ceilings
|
||||
private void RenderSectorCeilings(ICollection<Sector> sectors)
|
||||
{
|
||||
// Set states
|
||||
graphics.Device.SetRenderState(RenderState.CullMode, Cull.None);
|
||||
graphics.Device.SetRenderState(RenderState.ZEnable, false);
|
||||
graphics.Device.SetRenderState(RenderState.AlphaBlendEnable, false);
|
||||
graphics.Device.SetRenderState(RenderState.AlphaTestEnable, false);
|
||||
graphics.Device.SetRenderState(RenderState.TextureFactor, -1);
|
||||
graphics.Device.SetRenderState(RenderState.FogEnable, false);
|
||||
SetWorldTransformation(true);
|
||||
graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, General.Settings.ClassicBilinear);
|
||||
|
||||
// Render all sectors
|
||||
foreach(Sector s in sectors)
|
||||
RenderSectorSurface(s, s.FlatCeilingBuffer, s.LongCeilTexture);
|
||||
}
|
||||
|
||||
// This renders all sector brightness levels
|
||||
private void RenderSectorBrightness(ICollection<Sector> sectors)
|
||||
{
|
||||
// Set states
|
||||
graphics.Device.SetRenderState(RenderState.CullMode, Cull.None);
|
||||
graphics.Device.SetRenderState(RenderState.ZEnable, false);
|
||||
graphics.Device.SetRenderState(RenderState.AlphaBlendEnable, false);
|
||||
graphics.Device.SetRenderState(RenderState.AlphaTestEnable, false);
|
||||
graphics.Device.SetRenderState(RenderState.TextureFactor, -1);
|
||||
graphics.Device.SetRenderState(RenderState.FogEnable, false);
|
||||
SetWorldTransformation(true);
|
||||
graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, General.Settings.ClassicBilinear);
|
||||
|
||||
// Render all sectors
|
||||
foreach(Sector s in sectors)
|
||||
RenderSectorSurface(s, s.FlatFloorBuffer, 0);
|
||||
}
|
||||
|
||||
// This renders the geometry and tecture of the sector
|
||||
private void RenderSectorSurface(Sector s, VertexBuffer buffer, long longimagename)
|
||||
{
|
||||
Texture t = null;
|
||||
|
||||
if((buffer != null) && (s.FlatVertices != null) && (s.FlatVertices.Length > 0))
|
||||
{
|
||||
if(longimagename == 0)
|
||||
{
|
||||
t = whitetexture.Texture;
|
||||
}
|
||||
else
|
||||
{
|
||||
ImageData img = General.Map.Data.GetFlatImage(longimagename);
|
||||
if(img != null)
|
||||
{
|
||||
// Texture unknown?
|
||||
if(img is UnknownImage)
|
||||
{
|
||||
t = General.Map.Data.UnknownTexture3D.Texture;
|
||||
}
|
||||
// Is the texture loaded?
|
||||
else if(img.IsImageLoaded && !img.LoadFailed)
|
||||
{
|
||||
if(img.Texture == null) img.CreateTexture();
|
||||
t = img.Texture;
|
||||
}
|
||||
else
|
||||
{
|
||||
t = whitetexture.Texture;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
t = whitetexture.Texture;
|
||||
}
|
||||
}
|
||||
|
||||
// Set renderstates for rendering
|
||||
graphics.Shaders.Display2D.Texture1 = t;
|
||||
graphics.Device.SetTexture(0, t);
|
||||
graphics.Device.SetStreamSource(0, buffer, 0, FlatVertex.Stride);
|
||||
|
||||
// Draw
|
||||
graphics.Shaders.Display2D.Begin();
|
||||
graphics.Shaders.Display2D.BeginPass(1);
|
||||
graphics.Device.DrawPrimitives(PrimitiveType.TriangleList, 0, s.FlatVertices.Length / 3);
|
||||
graphics.Shaders.Display2D.EndPass();
|
||||
graphics.Shaders.Display2D.End();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Overlay
|
||||
|
@ -1279,7 +1196,7 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
}
|
||||
else
|
||||
{
|
||||
t = whitetexture.Texture;
|
||||
t = General.Map.Data.WhiteTexture.Texture;
|
||||
}
|
||||
|
||||
// Set renderstates for rendering
|
||||
|
@ -1385,8 +1302,8 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
graphics.Device.SetRenderState(RenderState.TextureFactor, -1);
|
||||
graphics.Device.SetRenderState(RenderState.FogEnable, false);
|
||||
SetWorldTransformation(false);
|
||||
graphics.Device.SetTexture(0, whitetexture.Texture);
|
||||
graphics.Shaders.Display2D.Texture1 = whitetexture.Texture;
|
||||
graphics.Device.SetTexture(0, General.Map.Data.WhiteTexture.Texture);
|
||||
graphics.Shaders.Display2D.Texture1 = General.Map.Data.WhiteTexture.Texture;
|
||||
graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, General.Settings.ClassicBilinear);
|
||||
|
||||
// Draw
|
||||
|
@ -1424,8 +1341,8 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
graphics.Device.SetRenderState(RenderState.TextureFactor, -1);
|
||||
graphics.Device.SetRenderState(RenderState.FogEnable, false);
|
||||
SetWorldTransformation(false);
|
||||
graphics.Device.SetTexture(0, whitetexture.Texture);
|
||||
graphics.Shaders.Display2D.Texture1 = whitetexture.Texture;
|
||||
graphics.Device.SetTexture(0, General.Map.Data.WhiteTexture.Texture);
|
||||
graphics.Shaders.Display2D.Texture1 = General.Map.Data.WhiteTexture.Texture;
|
||||
graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, General.Settings.ClassicBilinear);
|
||||
|
||||
// Draw
|
||||
|
@ -1478,8 +1395,8 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
graphics.Device.SetRenderState(RenderState.TextureFactor, -1);
|
||||
graphics.Device.SetRenderState(RenderState.FogEnable, false);
|
||||
SetWorldTransformation(false);
|
||||
graphics.Device.SetTexture(0, whitetexture.Texture);
|
||||
graphics.Shaders.Display2D.Texture1 = whitetexture.Texture;
|
||||
graphics.Device.SetTexture(0, General.Map.Data.WhiteTexture.Texture);
|
||||
graphics.Shaders.Display2D.Texture1 = General.Map.Data.WhiteTexture.Texture;
|
||||
graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, General.Settings.ClassicBilinear);
|
||||
|
||||
// Draw
|
||||
|
|
59
Source/Core/Rendering/SurfaceBufferSet.cs
Normal file
59
Source/Core/Rendering/SurfaceBufferSet.cs
Normal file
|
@ -0,0 +1,59 @@
|
|||
|
||||
#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
|
||||
{
|
||||
internal struct SurfaceBufferSet
|
||||
{
|
||||
// The number of vertices per sector that this set is for
|
||||
public int numvertices;
|
||||
|
||||
// These are the vertex buffers. They are hashed by an integer key which
|
||||
// is the number of vertices per sector geometry the buffer if meant for.
|
||||
public List<VertexBuffer> buffers;
|
||||
public List<int> buffersizes;
|
||||
|
||||
// These are the entries that contain information for the contents of the buffers.
|
||||
public List<SurfaceEntry> entries;
|
||||
|
||||
// These are the empty entries in buferrs that are available.
|
||||
public List<SurfaceEntry> holes;
|
||||
}
|
||||
}
|
83
Source/Core/Rendering/SurfaceEntry.cs
Normal file
83
Source/Core/Rendering/SurfaceEntry.cs
Normal file
|
@ -0,0 +1,83 @@
|
|||
|
||||
#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 is an entry is the surface manager and contains the information
|
||||
// needed for a sector to place it's ceiling and floor surface geometry
|
||||
// in a vertexbuffer. Sectors keep a reference to this entry to tell the
|
||||
// surface manager to remove them if needed.
|
||||
internal class SurfaceEntry
|
||||
{
|
||||
// Number of vertices in the geometry and index of the buffer
|
||||
// This tells the surface manager which vertexbuffer this is in.
|
||||
public int numvertices;
|
||||
public int bufferindex;
|
||||
|
||||
// Offset in the buffer (in number of vertices)
|
||||
public int vertexoffset;
|
||||
|
||||
// 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 SurfaceEntry(int numvertices, int bufferindex, int vertexoffset)
|
||||
{
|
||||
this.numvertices = numvertices;
|
||||
this.bufferindex = bufferindex;
|
||||
this.vertexoffset = vertexoffset;
|
||||
}
|
||||
|
||||
// Constructor that copies the entry, but does not copy the vertices
|
||||
internal SurfaceEntry(SurfaceEntry oldentry)
|
||||
{
|
||||
this.numvertices = oldentry.numvertices;
|
||||
this.bufferindex = oldentry.bufferindex;
|
||||
this.vertexoffset = oldentry.vertexoffset;
|
||||
}
|
||||
}
|
||||
}
|
584
Source/Core/Rendering/SurfaceManager.cs
Normal file
584
Source/Core/Rendering/SurfaceManager.cs
Normal file
|
@ -0,0 +1,584 @@
|
|||
|
||||
#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
|
||||
{
|
||||
internal class SurfaceManager : ID3DResource
|
||||
{
|
||||
#region ================== Constants
|
||||
|
||||
// The true maximum lies at 65535 if I remember correctly, but that
|
||||
// is a scary big number for a vertexbuffer.
|
||||
private const int MAX_VERTICES_PER_BUFFER = 30000;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Variables
|
||||
|
||||
// Set of buffers for a specific number of vertices per sector
|
||||
private Dictionary<int, SurfaceBufferSet> sets;
|
||||
|
||||
// List of buffers that are locked
|
||||
// This is null when not in the process of updating
|
||||
private List<VertexBuffer> lockedbuffers;
|
||||
|
||||
// Surface to be rendered.
|
||||
// Each BinaryHeap in the Dictionary contains all geometry that needs
|
||||
// to be rendered with the associated ImageData.
|
||||
// The BinaryHeap sorts the geometry by sector to minimize stream switchs.
|
||||
// This is null when not in the process of rendering
|
||||
private Dictionary<ImageData, List<SurfaceEntry>> surfaces;
|
||||
|
||||
// This is 1 to add the number of vertices to the offset
|
||||
// (effectively rendering the ceiling vertices instead of floor vertices)
|
||||
private int surfacevertexoffsetmul;
|
||||
|
||||
// This is set to true when the resources have been unloaded
|
||||
private bool resourcesunloaded;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Properties
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Constructor / Disposer
|
||||
|
||||
// Constructor
|
||||
public SurfaceManager()
|
||||
{
|
||||
sets = new Dictionary<int, SurfaceBufferSet>();
|
||||
lockedbuffers = new List<VertexBuffer>();
|
||||
|
||||
General.Map.Graphics.RegisterResource(this);
|
||||
}
|
||||
|
||||
// Disposer
|
||||
public void Dispose()
|
||||
{
|
||||
if(sets != null)
|
||||
{
|
||||
General.Map.Graphics.UnregisterResource(this);
|
||||
|
||||
// Dispose all sets
|
||||
foreach(KeyValuePair<int, SurfaceBufferSet> set in sets)
|
||||
{
|
||||
// Dispose vertex buffers
|
||||
foreach(VertexBuffer vb in set.Value.buffers)
|
||||
vb.Dispose();
|
||||
}
|
||||
|
||||
sets = null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Management
|
||||
|
||||
// Called when all resource must be unloaded
|
||||
public void UnloadResource()
|
||||
{
|
||||
resourcesunloaded = true;
|
||||
foreach(KeyValuePair<int, SurfaceBufferSet> set in sets)
|
||||
{
|
||||
foreach(VertexBuffer vb in set.Value.buffers)
|
||||
vb.Dispose();
|
||||
|
||||
set.Value.buffers.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Called when all resource must be reloaded
|
||||
public void ReloadResource()
|
||||
{
|
||||
foreach(KeyValuePair<int, SurfaceBufferSet> set in sets)
|
||||
{
|
||||
// Rebuild vertex buffers
|
||||
for(int i = 0; i < set.Value.buffersizes.Count; i++)
|
||||
{
|
||||
// Make the new buffer!
|
||||
VertexBuffer b = new VertexBuffer(General.Map.Graphics.Device, FlatVertex.Stride * set.Value.buffersizes[i],
|
||||
Usage.None, VertexFormat.None, Pool.Default);
|
||||
|
||||
// Start refilling the buffer with sector geometry
|
||||
int vertexoffset = 0;
|
||||
DataStream bstream = b.Lock(0, FlatVertex.Stride * set.Value.buffersizes[i], LockFlags.Discard);
|
||||
foreach(SurfaceEntry e in set.Value.entries)
|
||||
{
|
||||
if(e.bufferindex == i)
|
||||
{
|
||||
// Fill buffer
|
||||
bstream.Seek(e.vertexoffset * FlatVertex.Stride, SeekOrigin.Begin);
|
||||
bstream.WriteRange(e.floorvertices);
|
||||
bstream.WriteRange(e.ceilvertices);
|
||||
}
|
||||
}
|
||||
|
||||
// Unlock buffer
|
||||
b.Unlock();
|
||||
bstream.Dispose();
|
||||
|
||||
// Add to list
|
||||
set.Value.buffers.Add(b);
|
||||
}
|
||||
}
|
||||
|
||||
resourcesunloaded = false;
|
||||
}
|
||||
|
||||
// This resets all buffers and requires all sectors to get new entries
|
||||
public void Reset()
|
||||
{
|
||||
// Clear all items
|
||||
foreach(KeyValuePair<int, SurfaceBufferSet> set in sets)
|
||||
{
|
||||
foreach(SurfaceEntry entry in set.Value.entries)
|
||||
{
|
||||
entry.numvertices = -1;
|
||||
entry.bufferindex = -1;
|
||||
}
|
||||
|
||||
foreach(SurfaceEntry entry in set.Value.holes)
|
||||
{
|
||||
entry.numvertices = -1;
|
||||
entry.bufferindex = -1;
|
||||
}
|
||||
|
||||
foreach(VertexBuffer vb in set.Value.buffers)
|
||||
vb.Dispose();
|
||||
}
|
||||
|
||||
// New dictionary
|
||||
sets = new Dictionary<int, SurfaceBufferSet>();
|
||||
}
|
||||
|
||||
// Updating sector surface geometry should go in this order;
|
||||
// - Triangulate sectors
|
||||
// - Call FreeSurfaces to remove entries that have changed number of vertices
|
||||
// - Call AllocateBuffers
|
||||
// - Call UpdateSurfaces to add/update entries
|
||||
// - Call UnlockBuffers
|
||||
|
||||
// This (re)allocates the buffers based on an analysis of the map
|
||||
// The map must be updated (triangulated) before calling this
|
||||
public void AllocateBuffers()
|
||||
{
|
||||
// Make analysis of sector geometry
|
||||
Dictionary<int, int> sectorverts = new Dictionary<int, int>();
|
||||
foreach(Sector s in General.Map.Map.Sectors)
|
||||
{
|
||||
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]++;
|
||||
}
|
||||
}
|
||||
|
||||
// Now (re)allocate the needed buffers
|
||||
foreach(KeyValuePair<int, int> sv in sectorverts)
|
||||
{
|
||||
// Zero vertices can't be drawn
|
||||
if(sv.Key > 0)
|
||||
{
|
||||
SurfaceBufferSet set = GetSet(sv.Key);
|
||||
|
||||
// Calculte how many free entries we need
|
||||
int neededentries = sv.Value;
|
||||
int freeentriesneeded = neededentries - set.entries.Count;
|
||||
|
||||
// Allocate the space needed
|
||||
EnsureFreeBufferSpace(set, freeentriesneeded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This ensures there is enough space for a given number of free entries (also adds new bufers if needed)
|
||||
private void EnsureFreeBufferSpace(SurfaceBufferSet set, int freeentries)
|
||||
{
|
||||
DataStream bstream;
|
||||
|
||||
// Check if we have to add entries
|
||||
int addentries = freeentries - set.holes.Count;
|
||||
|
||||
// Begin resizing buffers starting with the last in this set
|
||||
int bufferindex = set.buffers.Count - 1;
|
||||
|
||||
// Calculate the maximum number of entries we can put in a new buffer
|
||||
// Note that verticesperentry is the number of vertices multiplied by 2, because
|
||||
// we have to store both the floor and ceiling
|
||||
int verticesperentry = set.numvertices * 2;
|
||||
int maxentriesperbuffer = MAX_VERTICES_PER_BUFFER / verticesperentry;
|
||||
|
||||
while(addentries > 0)
|
||||
{
|
||||
// Create a new buffer?
|
||||
if((bufferindex == -1) || (bufferindex > (set.buffers.Count - 1)))
|
||||
{
|
||||
// Determine the number of entries we will be making this buffer for
|
||||
int bufferentries = (addentries > maxentriesperbuffer) ? maxentriesperbuffer : addentries;
|
||||
|
||||
// Calculate the number of vertices that will be
|
||||
int buffernumvertices = bufferentries * verticesperentry;
|
||||
|
||||
// Make the new buffer!
|
||||
VertexBuffer b = new VertexBuffer(General.Map.Graphics.Device, FlatVertex.Stride * buffernumvertices,
|
||||
Usage.None, VertexFormat.None, Pool.Default);
|
||||
|
||||
// Add it. Also add available entries as holes, because they are not used yet.
|
||||
set.buffers.Add(b);
|
||||
set.buffersizes.Add(buffernumvertices);
|
||||
for(int i = 0; i < bufferentries; i++)
|
||||
set.holes.Add(new SurfaceEntry(set.numvertices, set.buffers.Count - 1, i * verticesperentry));
|
||||
|
||||
// Done
|
||||
addentries -= bufferentries;
|
||||
}
|
||||
// Reallocate a buffer
|
||||
else
|
||||
{
|
||||
// Trash the old buffer
|
||||
if(set.buffers[bufferindex].Tag != null)
|
||||
{
|
||||
bstream = (DataStream)set.buffers[bufferindex].Tag;
|
||||
set.buffers[bufferindex].Unlock();
|
||||
bstream.Dispose();
|
||||
set.buffers[bufferindex].Tag = null;
|
||||
}
|
||||
set.buffers[bufferindex].Dispose();
|
||||
|
||||
// Get the entries that are in this buffer only
|
||||
List<SurfaceEntry> theseentries = new List<SurfaceEntry>();
|
||||
foreach(SurfaceEntry e in set.entries)
|
||||
{
|
||||
if(e.bufferindex == bufferindex)
|
||||
theseentries.Add(e);
|
||||
}
|
||||
|
||||
// Determine the number of entries we will be making this buffer for
|
||||
int bufferentries = ((theseentries.Count + addentries) > maxentriesperbuffer) ? maxentriesperbuffer : (theseentries.Count + addentries);
|
||||
|
||||
// Calculate the number of vertices that will be
|
||||
int buffernumvertices = bufferentries * verticesperentry;
|
||||
|
||||
// Make the new buffer!
|
||||
VertexBuffer b = new VertexBuffer(General.Map.Graphics.Device, FlatVertex.Stride * buffernumvertices,
|
||||
Usage.None, VertexFormat.None, Pool.Default);
|
||||
|
||||
// Start refilling the buffer with sector geometry
|
||||
int vertexoffset = 0;
|
||||
bstream = b.Lock(0, FlatVertex.Stride * theseentries.Count * verticesperentry, LockFlags.Discard);
|
||||
foreach(SurfaceEntry e in theseentries)
|
||||
{
|
||||
// Fill buffer
|
||||
bstream.WriteRange(e.floorvertices);
|
||||
bstream.WriteRange(e.ceilvertices);
|
||||
|
||||
// Set the new location in the buffer
|
||||
e.vertexoffset = vertexoffset;
|
||||
|
||||
// Move on
|
||||
vertexoffset += verticesperentry;
|
||||
}
|
||||
|
||||
// Unlock buffer
|
||||
b.Unlock();
|
||||
bstream.Dispose();
|
||||
|
||||
// Set the new buffer and add available entries as holes, because they are not used yet.
|
||||
set.buffers[bufferindex] = b;
|
||||
set.buffersizes[bufferindex] = buffernumvertices;
|
||||
set.holes.Clear();
|
||||
for(int i = 0; i < bufferentries - theseentries.Count; i++)
|
||||
set.holes.Add(new SurfaceEntry(set.numvertices, bufferindex, i * verticesperentry + vertexoffset));
|
||||
|
||||
// Done
|
||||
addentries -= bufferentries;
|
||||
}
|
||||
|
||||
// Always continue in next (new) buffer
|
||||
bufferindex = set.buffers.Count;
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
SurfaceBufferSet set = GetSet(numvertices);
|
||||
|
||||
// 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;
|
||||
set.entries.Add(nentry);
|
||||
entry = nentry;
|
||||
}
|
||||
|
||||
// Lock the buffer
|
||||
DataStream bstream;
|
||||
VertexBuffer vb = set.buffers[entry.bufferindex];
|
||||
if(vb.Tag == null)
|
||||
{
|
||||
bstream = vb.Lock(0, set.buffersizes[entry.bufferindex] * FlatVertex.Stride, LockFlags.None);
|
||||
vb.Tag = bstream;
|
||||
lockedbuffers.Add(vb);
|
||||
}
|
||||
else
|
||||
{
|
||||
bstream = (DataStream)vb.Tag;
|
||||
}
|
||||
|
||||
// Write the vertices to buffer
|
||||
bstream.Seek(entry.vertexoffset * FlatVertex.Stride, SeekOrigin.Begin);
|
||||
bstream.WriteRange(entry.floorvertices);
|
||||
bstream.WriteRange(entry.ceilvertices);
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
// This frees the given surface entry
|
||||
public void FreeSurfaces(SurfaceEntry entry)
|
||||
{
|
||||
if((entry.numvertices > 0) && (entry.bufferindex > -1))
|
||||
{
|
||||
SurfaceBufferSet set = sets[entry.numvertices];
|
||||
set.entries.Remove(entry);
|
||||
SurfaceEntry newentry = new SurfaceEntry(entry);
|
||||
set.holes.Add(newentry);
|
||||
}
|
||||
entry.numvertices = -1;
|
||||
entry.bufferindex = -1;
|
||||
}
|
||||
|
||||
// This unlocks the locked buffers
|
||||
public void UnlockBuffers()
|
||||
{
|
||||
foreach(VertexBuffer vb in lockedbuffers)
|
||||
{
|
||||
if(vb.Tag != null)
|
||||
{
|
||||
DataStream bstream = (DataStream)vb.Tag;
|
||||
vb.Unlock();
|
||||
bstream.Dispose();
|
||||
vb.Tag = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Clear list
|
||||
lockedbuffers = new List<VertexBuffer>();
|
||||
}
|
||||
|
||||
// This gets or creates a set for a specific number of vertices
|
||||
private SurfaceBufferSet GetSet(int numvertices)
|
||||
{
|
||||
SurfaceBufferSet set;
|
||||
|
||||
// Get or create the set
|
||||
if(!sets.ContainsKey(numvertices))
|
||||
{
|
||||
set = new SurfaceBufferSet();
|
||||
set.numvertices = numvertices;
|
||||
set.buffers = new List<VertexBuffer>();
|
||||
set.buffersizes = new List<int>();
|
||||
set.entries = new List<SurfaceEntry>();
|
||||
set.holes = new List<SurfaceEntry>();
|
||||
sets.Add(numvertices, set);
|
||||
}
|
||||
else
|
||||
{
|
||||
set = sets[numvertices];
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Rendering
|
||||
|
||||
// This renders all sector floors
|
||||
internal void RenderSectorFloors()
|
||||
{
|
||||
surfaces = new Dictionary<ImageData, List<SurfaceEntry>>();
|
||||
surfacevertexoffsetmul = 0;
|
||||
|
||||
// Go for all surfaces as they are sorted in the buffers, so that
|
||||
// they are automatically already sorted by vertexbuffer
|
||||
foreach(KeyValuePair<int, SurfaceBufferSet> set in sets)
|
||||
{
|
||||
foreach(SurfaceEntry entry in set.Value.entries)
|
||||
AddSurfaceEntryForRendering(entry, entry.floortexture);
|
||||
}
|
||||
}
|
||||
|
||||
// This renders all sector ceilings
|
||||
internal void RenderSectorCeilings()
|
||||
{
|
||||
surfaces = new Dictionary<ImageData, List<SurfaceEntry>>();
|
||||
surfacevertexoffsetmul = 1;
|
||||
|
||||
// Go for all surfaces as they are sorted in the buffers, so that
|
||||
// they are automatically already sorted by vertexbuffer
|
||||
foreach(KeyValuePair<int, SurfaceBufferSet> set in sets)
|
||||
{
|
||||
foreach(SurfaceEntry entry in set.Value.entries)
|
||||
AddSurfaceEntryForRendering(entry, entry.ceiltexture);
|
||||
}
|
||||
}
|
||||
|
||||
// This renders all sector brightness levels
|
||||
internal void RenderSectorBrightness()
|
||||
{
|
||||
surfaces = new Dictionary<ImageData, List<SurfaceEntry>>();
|
||||
surfacevertexoffsetmul = 0;
|
||||
|
||||
// Go for all surfaces as they are sorted in the buffers, so that
|
||||
// they are automatically already sorted by vertexbuffer
|
||||
foreach(KeyValuePair<int, SurfaceBufferSet> set in sets)
|
||||
{
|
||||
foreach(SurfaceEntry entry in set.Value.entries)
|
||||
AddSurfaceEntryForRendering(entry, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// This adds a surface entry to the list of surfaces
|
||||
private void AddSurfaceEntryForRendering(SurfaceEntry entry, long longimagename)
|
||||
{
|
||||
// Determine texture to use
|
||||
ImageData img;
|
||||
if(longimagename == 0)
|
||||
{
|
||||
img = General.Map.Data.WhiteTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
img = General.Map.Data.GetFlatImage(longimagename);
|
||||
if(img != null)
|
||||
{
|
||||
// Texture unknown?
|
||||
if(img is UnknownImage)
|
||||
{
|
||||
img = General.Map.Data.UnknownTexture3D;
|
||||
}
|
||||
// Is the texture loaded?
|
||||
else if(img.IsImageLoaded && !img.LoadFailed)
|
||||
{
|
||||
if(img.Texture == null) img.CreateTexture();
|
||||
}
|
||||
else
|
||||
{
|
||||
img = General.Map.Data.WhiteTexture;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
img = General.Map.Data.WhiteTexture;
|
||||
}
|
||||
}
|
||||
|
||||
// Store by texture
|
||||
if(!surfaces.ContainsKey(img))
|
||||
surfaces.Add(img, new List<SurfaceEntry>());
|
||||
surfaces[img].Add(entry);
|
||||
}
|
||||
|
||||
// This renders the sorted sector surfaces
|
||||
internal void RenderSectorSurfaces(D3DDevice graphics)
|
||||
{
|
||||
if(!resourcesunloaded)
|
||||
{
|
||||
graphics.Shaders.Display2D.Begin();
|
||||
foreach(KeyValuePair<ImageData, List<SurfaceEntry>> imgsurfaces in surfaces)
|
||||
{
|
||||
// Set texture
|
||||
graphics.Shaders.Display2D.Texture1 = imgsurfaces.Key.Texture;
|
||||
if(!graphics.Shaders.Enabled) graphics.Device.SetTexture(0, imgsurfaces.Key.Texture);
|
||||
|
||||
graphics.Shaders.Display2D.BeginPass(1);
|
||||
|
||||
// Go for all surfaces
|
||||
VertexBuffer lastbuffer = null;
|
||||
foreach(SurfaceEntry entry in imgsurfaces.Value)
|
||||
{
|
||||
// Set the vertex buffer
|
||||
SurfaceBufferSet set = sets[entry.numvertices];
|
||||
if(set.buffers[entry.bufferindex] != lastbuffer)
|
||||
{
|
||||
lastbuffer = set.buffers[entry.bufferindex];
|
||||
graphics.Device.SetStreamSource(0, lastbuffer, 0, FlatVertex.Stride);
|
||||
}
|
||||
|
||||
// Draw
|
||||
graphics.Device.DrawPrimitives(PrimitiveType.TriangleList, entry.vertexoffset + (entry.numvertices * surfacevertexoffsetmul), entry.numvertices / 3);
|
||||
}
|
||||
|
||||
graphics.Shaders.Display2D.EndPass();
|
||||
}
|
||||
graphics.Shaders.Display2D.End();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue