Merge pull request #127 from mrpimpunicorn/master
Refactored and expanded Mesh class
This commit is contained in:
commit
65b1626e26
@ -5,19 +5,43 @@ using Microsoft.Xna.Framework;
|
||||
|
||||
namespace TrueCraft.Client.Rendering
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class ChunkMesh : Mesh
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public ReadOnlyChunk Chunk { get; set; }
|
||||
|
||||
public ChunkMesh(ReadOnlyChunk chunk, GraphicsDevice device, VertexPositionNormalTexture[] verticies, int[] indicies)
|
||||
: base(device, verticies, indicies, false)
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="chunk"></param>
|
||||
/// <param name="device"></param>
|
||||
/// <param name="vertices"></param>
|
||||
/// <param name="indices"></param>
|
||||
public ChunkMesh(ReadOnlyChunk chunk, GraphicsDevice device, VertexPositionNormalTexture[] vertices, int[] indices)
|
||||
: base(device, 1, true)
|
||||
{
|
||||
Chunk = chunk;
|
||||
BoundingBox = new BoundingBox(
|
||||
new Vector3(chunk.X * TrueCraft.Core.World.Chunk.Width, 0, chunk.Z * TrueCraft.Core.World.Chunk.Depth),
|
||||
new Vector3(chunk.X * TrueCraft.Core.World.Chunk.Width
|
||||
Vertices = vertices;
|
||||
SetSubmesh(0, indices);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="vertices"></param>
|
||||
/// <returns></returns>
|
||||
protected override BoundingBox RecalculateBounds(VertexPositionNormalTexture[] vertices)
|
||||
{
|
||||
return new BoundingBox(
|
||||
new Vector3(Chunk.X * TrueCraft.Core.World.Chunk.Width, 0, Chunk.Z * TrueCraft.Core.World.Chunk.Depth),
|
||||
new Vector3(Chunk.X * TrueCraft.Core.World.Chunk.Width
|
||||
+ TrueCraft.Core.World.Chunk.Width, TrueCraft.Core.World.Chunk.Height,
|
||||
chunk.Z * TrueCraft.Core.World.Chunk.Depth + TrueCraft.Core.World.Chunk.Depth));
|
||||
Chunk.Z * TrueCraft.Core.World.Chunk.Depth + TrueCraft.Core.World.Chunk.Depth));
|
||||
}
|
||||
}
|
||||
}
|
@ -5,75 +5,242 @@ using System.Linq;
|
||||
|
||||
namespace TrueCraft.Client.Rendering
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an indexed collection of data that can be rendered.
|
||||
/// </summary>
|
||||
public class Mesh : IDisposable
|
||||
{
|
||||
public bool Empty { get; set; }
|
||||
public VertexBuffer Verticies { get; set; }
|
||||
public IndexBuffer Indicies { get; set; }
|
||||
public BoundingBox BoundingBox { get; set; }
|
||||
/// <summary>
|
||||
/// The maximum number of submeshes stored in a single mesh.
|
||||
/// </summary>
|
||||
public const int SubmeshLimit = 16;
|
||||
|
||||
private static object GraphicsDeviceLock = new object();
|
||||
// Used for synchronous access to the graphics device.
|
||||
private static readonly object _syncLock =
|
||||
new object();
|
||||
|
||||
public Mesh(GraphicsDevice device, VertexPositionNormalTexture[] verticies, int[] indicies, bool calculateBounds = true)
|
||||
private GraphicsDevice _graphicsDevice;
|
||||
protected VertexBuffer _vertices; // ChunkMesh uses these but external classes shouldn't, so I've made them protected.
|
||||
protected IndexBuffer[] _indices;
|
||||
|
||||
private bool _recalculateBounds; // Whether this mesh should recalculate its bounding box when changed.
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the vertices in this mesh.
|
||||
/// </summary>
|
||||
public VertexPositionNormalTexture[] Vertices
|
||||
{
|
||||
Empty = verticies.Length == 0 && indicies.Length == 0;
|
||||
if (!Empty)
|
||||
set
|
||||
{
|
||||
lock (GraphicsDeviceLock)
|
||||
if (_vertices != null)
|
||||
_vertices.Dispose();
|
||||
|
||||
lock (_syncLock)
|
||||
{
|
||||
Verticies = new VertexBuffer(device, VertexPositionNormalTexture.VertexDeclaration,
|
||||
verticies.Length, BufferUsage.WriteOnly);
|
||||
Verticies.SetData(verticies);
|
||||
Indicies = new IndexBuffer(device, typeof(int), indicies.Length, BufferUsage.WriteOnly);
|
||||
Indicies.SetData(indicies);
|
||||
}
|
||||
if (calculateBounds)
|
||||
{
|
||||
BoundingBox = new BoundingBox(
|
||||
verticies.Select(v => v.Position).OrderBy(v => v.Length()).First(),
|
||||
verticies.Select(v => v.Position).OrderByDescending(v => v.Length()).First());
|
||||
_vertices = new VertexBuffer(_graphicsDevice, VertexPositionNormalTexture.VertexDeclaration,
|
||||
value.Length, BufferUsage.WriteOnly);
|
||||
_vertices.SetData(value);
|
||||
}
|
||||
|
||||
if (_recalculateBounds)
|
||||
BoundingBox = RecalculateBounds(value);
|
||||
}
|
||||
}
|
||||
|
||||
~Mesh()
|
||||
/// <summary>
|
||||
/// Gets the bounding box for this mesh.
|
||||
/// </summary>
|
||||
public BoundingBox BoundingBox { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether this mesh is disposed of.
|
||||
/// </summary>
|
||||
public bool IsDisposed { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new mesh.
|
||||
/// </summary>
|
||||
/// <param name="graphicsDevice">The graphics device to store the mesh on.</param>
|
||||
/// <param name="submeshes">The number of submeshes in the mesh.</param>
|
||||
/// <param name="recalculateBounds">Whether the mesh should recalculate its bounding box when changed.</param>
|
||||
public Mesh(GraphicsDevice graphicsDevice, int submeshes = 1, bool recalculateBounds = true)
|
||||
{
|
||||
Dispose(false);
|
||||
if (graphicsDevice == null)
|
||||
throw new ArgumentException();
|
||||
|
||||
if ((submeshes < 0) || (submeshes >= Mesh.SubmeshLimit))
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
_graphicsDevice = graphicsDevice;
|
||||
_indices = new IndexBuffer[submeshes];
|
||||
_recalculateBounds = recalculateBounds;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
/// <summary>
|
||||
/// Creates a new mesh.
|
||||
/// </summary>
|
||||
/// <param name="graphicsDevice">The graphics device to store the mesh on.</param>
|
||||
/// <param name="vertices">The vertices in the mesh.</param>
|
||||
/// <param name="submeshes">The number of submeshes in the mesh.</param>
|
||||
/// <param name="recalculateBounds">Whether the mesh should recalculate its bounding box when changed.</param>
|
||||
public Mesh(GraphicsDevice graphicsDevice, VertexPositionNormalTexture[] vertices, int submeshes = 1, bool recalculateBounds = true)
|
||||
: this(graphicsDevice, submeshes, recalculateBounds)
|
||||
{
|
||||
Dispose(true);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
Vertices = vertices;
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
/// <summary>
|
||||
/// Creates a new mesh.
|
||||
/// </summary>
|
||||
/// <param name="graphicsDevice">The graphics device to store the mesh on.</param>
|
||||
/// <param name="vertices">The vertices in the mesh.</param>
|
||||
/// <param name="indices">The first (and only) submesh in the mesh.</param>
|
||||
/// <param name="recalculateBounds">Whether the mesh should recalculate its bounding box when changed.</param>
|
||||
public Mesh(GraphicsDevice graphicsDevice, VertexPositionNormalTexture[] vertices, int[] indices, bool recalculateBounds = true)
|
||||
: this(graphicsDevice, 1, recalculateBounds)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (Verticies != null)
|
||||
Verticies.Dispose();
|
||||
if (Indicies != null)
|
||||
Indicies.Dispose();
|
||||
Vertices = vertices;
|
||||
SetSubmesh(0, indices);
|
||||
}
|
||||
|
||||
Verticies = null;
|
||||
Indicies = null;
|
||||
/// <summary>
|
||||
/// Sets a submesh in this mesh.
|
||||
/// </summary>
|
||||
/// <param name="index">The submesh index.</param>
|
||||
/// <param name="data">The indices for the submesh.</param>
|
||||
public void SetSubmesh(int index, int[] indices)
|
||||
{
|
||||
if ((index < 0) || (index > _indices.Length))
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
lock (_syncLock)
|
||||
{
|
||||
if (_indices[index] != null)
|
||||
_indices[index].Dispose();
|
||||
|
||||
_indices[index] = new IndexBuffer(_graphicsDevice, typeof(int),
|
||||
indices.Length, BufferUsage.WriteOnly);
|
||||
_indices[index].SetData(indices);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws this mesh using the specified effect.
|
||||
/// </summary>
|
||||
/// <param name="effect">The effect to use.</param>
|
||||
public void Draw(Effect effect)
|
||||
{
|
||||
if (Empty)
|
||||
return;
|
||||
effect.GraphicsDevice.SetVertexBuffer(Verticies);
|
||||
effect.GraphicsDevice.Indices = Indicies;
|
||||
if (effect == null)
|
||||
throw new ArgumentException();
|
||||
|
||||
for (int i = 0; i < _indices.Length; i++)
|
||||
Draw(effect, i);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a submesh in this mesh using the specified effect.
|
||||
/// </summary>
|
||||
/// <param name="effect">The effect to use.</param>
|
||||
/// <param name="index">The submesh index.</param>
|
||||
public void Draw(Effect effect, int index)
|
||||
{
|
||||
if (effect == null)
|
||||
throw new ArgumentException();
|
||||
|
||||
if ((index < 0) || (index > _indices.Length))
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
if (_vertices == null || _vertices.IsDisposed || _indices[index] == null || _indices[index].IsDisposed)
|
||||
return; // Invalid state for rendering, just return.
|
||||
|
||||
effect.GraphicsDevice.SetVertexBuffer(_vertices);
|
||||
effect.GraphicsDevice.Indices = _indices[index];
|
||||
foreach (var pass in effect.CurrentTechnique.Passes)
|
||||
{
|
||||
pass.Apply();
|
||||
effect.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList,
|
||||
0, 0, Indicies.IndexCount, 0, Indicies.IndexCount / 3);
|
||||
0, 0, _indices[index].IndexCount, 0, _indices[index].IndexCount / 3);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the total vertices in this mesh.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public int GetTotalVertices()
|
||||
{
|
||||
if (_vertices == null)
|
||||
return 0;
|
||||
|
||||
lock (_syncLock)
|
||||
return _vertices.VertexCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the total indices for all the submeshes in this mesh.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public int GetTotalIndices()
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
int sum = 0;
|
||||
foreach (var element in _indices)
|
||||
sum += (element != null) ? element.IndexCount : 0;
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recalculates the bounding box for this mesh.
|
||||
/// </summary>
|
||||
/// <param name="vertices">The vertices in this mesh.</param>
|
||||
/// <returns></returns>
|
||||
protected virtual BoundingBox RecalculateBounds(VertexPositionNormalTexture[] vertices)
|
||||
{
|
||||
return new BoundingBox(
|
||||
vertices.Select(v => v.Position).OrderBy(v => v.Length()).First(),
|
||||
vertices.Select(v => v.Position).OrderByDescending(v => v.Length()).First());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes of this mesh.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (IsDisposed)
|
||||
return;
|
||||
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes of this mesh.
|
||||
/// </summary>
|
||||
/// <param name="disposing">Whether Dispose() called the method.</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_graphicsDevice = null; // Lose the reference to our graphics device.
|
||||
|
||||
if (_vertices != null)
|
||||
_vertices.Dispose();
|
||||
foreach (var element in _indices)
|
||||
{
|
||||
if (element != null)
|
||||
element.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes this mesh.
|
||||
/// </summary>
|
||||
~Mesh()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
}
|
||||
}
|
@ -350,9 +350,9 @@ namespace TrueCraft.Client
|
||||
GraphicsDevice.DepthStencilState = new DepthStencilState { DepthBufferEnable = true };
|
||||
for (int i = 0; i < ChunkMeshes.Count; i++)
|
||||
{
|
||||
if (CameraView.Intersects(ChunkMeshes[i].BoundingBox) && !ChunkMeshes[i].Empty)
|
||||
if (CameraView.Intersects(ChunkMeshes[i].BoundingBox))
|
||||
{
|
||||
verticies += ChunkMeshes[i].Verticies.VertexCount;
|
||||
verticies += ChunkMeshes[i].GetTotalVertices();
|
||||
chunks++;
|
||||
ChunkMeshes[i].Draw(OpaqueEffect);
|
||||
}
|
||||
@ -360,10 +360,10 @@ namespace TrueCraft.Client
|
||||
GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
|
||||
for (int i = 0; i < TransparentChunkMeshes.Count; i++)
|
||||
{
|
||||
if (CameraView.Intersects(TransparentChunkMeshes[i].BoundingBox) && !TransparentChunkMeshes[i].Empty)
|
||||
if (CameraView.Intersects(TransparentChunkMeshes[i].BoundingBox))
|
||||
{
|
||||
if (TransparentChunkMeshes[i].Verticies != null)
|
||||
verticies += TransparentChunkMeshes[i].Verticies.VertexCount;
|
||||
if (!TransparentChunkMeshes[i].IsDisposed)
|
||||
verticies += TransparentChunkMeshes[i].GetTotalVertices();
|
||||
TransparentChunkMeshes[i].Draw(TransparentEffect);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user