port from perforce
This commit is contained in:
554
aiwaz/Aiwaz.Resources/GeometryBuffer.cs
Normal file
554
aiwaz/Aiwaz.Resources/GeometryBuffer.cs
Normal file
@@ -0,0 +1,554 @@
|
||||
using System.Collections.Generic;
|
||||
using Aiwaz.Core;
|
||||
using Aiwaz.Contracts;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using SlimDX.Direct3D10;
|
||||
using SlimDX;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Aiwaz.Resources
|
||||
{
|
||||
[AiwazResource("Geometry Buffer", "Renderable buffer with vertex or index data.")]
|
||||
public class GeometryBuffer : CommandUser, IDisposable, IGeometryBuffer
|
||||
{
|
||||
#region Constructor
|
||||
|
||||
public GeometryBuffer()
|
||||
: base()
|
||||
{
|
||||
Console.WriteLine("Creating GeometryBuffer..");
|
||||
|
||||
PrimitiveTopology = PrimitiveTopology.TriangleList;
|
||||
Commands.Add(new Command(this, CommandFlags.None, SetIndexBufferCommandType, 1));
|
||||
Commands.Add(new Command(this, CommandFlags.None, SetVertexBufferCommandType, 0));
|
||||
Commands.Add(new Command(this, CommandFlags.EndChain | CommandFlags.Unique, DrawGeometryCommandType, 6));
|
||||
}
|
||||
|
||||
public GeometryBuffer(IEnumerable<uint> argIndexData, bool argNeedsDynamicAccess)
|
||||
: this()
|
||||
{
|
||||
this.SetIndexData(argIndexData, argNeedsDynamicAccess);
|
||||
}
|
||||
|
||||
public GeometryBuffer(int argIndexCount, SlimDX.DataStream argIndexData, int argVertexCount, SlimDX.DataStream argVertexData, VertexElement[] argVertexElements, bool argNeedsDynamicAccess)
|
||||
: this()
|
||||
{
|
||||
this.SetIndexData(argIndexCount, argIndexData, argNeedsDynamicAccess);
|
||||
this.SetVertexData(argVertexCount, argVertexData, argVertexElements, argNeedsDynamicAccess);
|
||||
}
|
||||
|
||||
public static GeometryBuffer Create<TVertex>(IEnumerable<TVertex> argVertexData, VertexElement[] argVertexElements, bool argNeedsDynamicAccess) where TVertex : struct
|
||||
{
|
||||
var geoBuffer = new GeometryBuffer();
|
||||
geoBuffer.SetVertexData(argVertexData, argVertexElements, argNeedsDynamicAccess);
|
||||
|
||||
return geoBuffer;
|
||||
}
|
||||
|
||||
public static GeometryBuffer Create<TVertex>(IEnumerable<uint> argIndexData, IEnumerable<TVertex> argVertexData, VertexElement[] argVertexElements, bool argNeedsDynamicAccess) where TVertex : struct
|
||||
{
|
||||
var geoBuffer = new GeometryBuffer();
|
||||
geoBuffer.SetIndexData(argIndexData, argNeedsDynamicAccess);
|
||||
geoBuffer.SetVertexData(argVertexData, argVertexElements, argNeedsDynamicAccess);
|
||||
|
||||
return geoBuffer;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public void SetVertexData(int argVertexCount, DataStream argVertexData, VertexElement[] argVertexElements, bool argNeedsDynamicAccess)
|
||||
{
|
||||
Console.WriteLine(string.Format("Vertex data: {0} bytes ({1} elements).", argVertexData.Length, argVertexCount));
|
||||
|
||||
var usePickHull = this.IsPickable;
|
||||
DeleteVertexData();
|
||||
|
||||
BufferDescription desc = new BufferDescription((int)argVertexData.Length,
|
||||
argNeedsDynamicAccess ? ResourceUsage.Dynamic : ResourceUsage.Default,
|
||||
SlimDX.Direct3D10.BindFlags.VertexBuffer,
|
||||
argNeedsDynamicAccess ? CpuAccessFlags.Write : 0, ResourceOptionFlags.None);
|
||||
|
||||
vertexBuffer = new SlimDX.Direct3D10.Buffer(Engine.Device, argVertexData, desc);
|
||||
if (vertexBuffer == null)
|
||||
{
|
||||
throw new ActionFailedException("GeometryBuffer: Couldn't create vertex buffer!");
|
||||
}
|
||||
|
||||
VertexBufferLength = argVertexCount;
|
||||
vertexElementSize = (int)argVertexData.Length / argVertexCount;
|
||||
vertexElements = argVertexElements;
|
||||
|
||||
rawVertexData = argVertexData;
|
||||
|
||||
if (inputElementDesc == null)
|
||||
{
|
||||
if (vertexElements.Length > 0)
|
||||
{
|
||||
inputElementDesc = new InputElement[vertexElements.Length];
|
||||
|
||||
int i = 0;
|
||||
foreach (var element in vertexElements)
|
||||
{
|
||||
inputElementDesc[i++] = new InputElement(element.SemanticName, element.NameIndex, element.ElementFormat, -1, 0, InputClassification.PerVertexData, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.IsPickable = usePickHull;
|
||||
}
|
||||
|
||||
public void DeleteVertexData()
|
||||
{
|
||||
if (vertexBuffer != null)
|
||||
Engine.Device.ClearState();
|
||||
|
||||
vertexElements = new VertexElement[0];
|
||||
|
||||
if (vertexBuffer != null)
|
||||
vertexBuffer.Dispose();
|
||||
|
||||
if (rawVertexData != null)
|
||||
rawVertexData.Dispose();
|
||||
|
||||
vertexBuffer = null;
|
||||
VertexBufferLength = 0;
|
||||
vertexElementSize = 0;
|
||||
rawMappedVertexData = null;
|
||||
typeMappedVertexData = null;
|
||||
rawVertexData = null;
|
||||
inputElementDesc = null;
|
||||
PickHull = null;
|
||||
}
|
||||
|
||||
public void SetIndexData(int argIndexCount, DataStream argIndexData, bool argNeedsDynamicAccess)
|
||||
{
|
||||
Console.WriteLine(string.Format("Index data: {0} bytes ({1} elements).", argIndexData.Length, argIndexCount));
|
||||
|
||||
bool usePickHull = this.IsPickable;
|
||||
DeleteIndexData();
|
||||
|
||||
BufferDescription desc = new BufferDescription(
|
||||
sizeof(uint) * argIndexCount,
|
||||
ResourceUsage.Default,
|
||||
SlimDX.Direct3D10.BindFlags.IndexBuffer,
|
||||
argNeedsDynamicAccess ? CpuAccessFlags.Write : 0, ResourceOptionFlags.None);
|
||||
|
||||
indexBuffer = new SlimDX.Direct3D10.Buffer(Engine.Device, argIndexData, desc);
|
||||
if (indexBuffer == null)
|
||||
{
|
||||
throw new ActionFailedException("GeometryBuffer: Couldn't create index buffer!");
|
||||
}
|
||||
|
||||
IndexBufferLength = argIndexCount;
|
||||
IndexBufferUsableLength = argIndexCount;
|
||||
IndexBufferOffset = 0;
|
||||
rawIndexData = argIndexData;
|
||||
|
||||
this.IsPickable = usePickHull;
|
||||
}
|
||||
|
||||
public void DeleteIndexData()
|
||||
{
|
||||
if (indexBuffer != null)
|
||||
Engine.Device.ClearState();
|
||||
|
||||
if (indexBuffer != null)
|
||||
indexBuffer.Dispose();
|
||||
|
||||
if (rawIndexData != null)
|
||||
rawIndexData.Dispose();
|
||||
|
||||
indexBuffer = null;
|
||||
rawIndexData = null;
|
||||
IndexBufferLength = 0;
|
||||
|
||||
foreach (var inputLayouts in vertexLayoutsPerShaderAndPass.Values)
|
||||
foreach (var inputLayout in inputLayouts)
|
||||
inputLayout.Dispose();
|
||||
vertexLayoutsPerShaderAndPass.Clear();
|
||||
PickHull = null;
|
||||
}
|
||||
|
||||
public DataStream MapVertexBufferRaw(MapMode argAccessMode)
|
||||
{
|
||||
if (vertexBuffer == null)
|
||||
throw new NullReferenceException("GeometryBuffer: Access forbidden until resource has been initialized.");
|
||||
|
||||
if (rawMappedVertexData != null)
|
||||
throw new InvalidOperationException("GeometryBuffer: Only one access to the vertex buffer at one time possible.");
|
||||
|
||||
try
|
||||
{
|
||||
rawMappedVertexData = vertexBuffer.Map(argAccessMode, MapFlags.None);
|
||||
return rawMappedVertexData;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ActionFailedException("GeometryBuffer: Access to the vertex buffer was not successful. " + ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public void UnmapVertexBuffer()
|
||||
{
|
||||
if (vertexBuffer == null)
|
||||
throw new NullReferenceException("GeometryBuffer: Access forbidden until resource has been initialized.");
|
||||
|
||||
if (rawMappedVertexData == null)
|
||||
throw new InvalidOperationException("GeometryBuffer: No access was done, ending the access to the vertex buffer is not possible.");
|
||||
|
||||
if (typeMappedVertexData != null)
|
||||
{
|
||||
rawMappedVertexData.Position = 0;
|
||||
var tmp = (byte[])typeMappedVertexData;
|
||||
rawMappedVertexData.WriteRange(tmp);
|
||||
}
|
||||
vertexBuffer.Unmap();
|
||||
rawMappedVertexData = null;
|
||||
typeMappedVertexData = null;
|
||||
}
|
||||
|
||||
public DataStream MapIndexBufferRaw(MapMode argAccessMode)
|
||||
{
|
||||
if (indexBuffer == null)
|
||||
throw new NullReferenceException("GeometryBuffer: Access forbidden until resource has been initialized.");
|
||||
|
||||
if (rawMappedIndexData != null)
|
||||
throw new InvalidOperationException("GeometryBuffer: Only one access to the index buffer at one time possible.");
|
||||
|
||||
try
|
||||
{
|
||||
rawMappedIndexData = indexBuffer.Map(argAccessMode, MapFlags.None);
|
||||
return rawMappedIndexData;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ActionFailedException("GeometryBuffer: Access to the index buffer was not successful. " + ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public void UnmapIndexBuffer()
|
||||
{
|
||||
if (indexBuffer == null)
|
||||
throw new NullReferenceException("GeometryBuffer: Access forbidden until resource has been initialized.");
|
||||
|
||||
if (rawMappedIndexData == null)
|
||||
throw new InvalidOperationException("GeometryBuffer: No access was done ending, the access to the index buffer is not possible.");
|
||||
|
||||
if (typeMappedIndexData != null)
|
||||
{
|
||||
rawMappedIndexData.Position = 0;
|
||||
rawMappedIndexData.WriteRange(typeMappedIndexData);
|
||||
}
|
||||
|
||||
indexBuffer.Unmap();
|
||||
rawMappedIndexData = null;
|
||||
typeMappedIndexData = null;
|
||||
}
|
||||
|
||||
public void ConvertToAdjacency()
|
||||
{
|
||||
Console.WriteLine(string.Format("Convert to adjacency."));
|
||||
|
||||
switch (PrimitiveTopology)
|
||||
{
|
||||
case PrimitiveTopology.LineList:
|
||||
case PrimitiveTopology.LineStrip:
|
||||
case PrimitiveTopology.TriangleList:
|
||||
case PrimitiveTopology.TriangleStrip:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
InputElement[] inputLayout = new InputElement[2];
|
||||
inputLayout[0] = new InputElement("POSITION", 0, SlimDX.DXGI.Format.R32G32B32_Float, 0, 0, InputClassification.PerVertexData, 0);
|
||||
inputLayout[1] = new InputElement("END", 0, SlimDX.DXGI.Format.R8_UInt, vertexElementSize - 1, 0, InputClassification.PerVertexData, 0);
|
||||
|
||||
// create the mesh
|
||||
int numVertices = VertexBufferLength;
|
||||
int numIndices = IndexBufferLength;
|
||||
|
||||
Mesh mesh = null;
|
||||
try
|
||||
{
|
||||
mesh = new Mesh(Engine.Device, inputLayout, inputLayout[0].SemanticName, numVertices, numIndices / 3, MeshFlags.Has32BitIndices);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
throw new ActionFailedException("GeometryBuffer: Unable to create temp. mesh for adjacency data generation. " + ex.ToString());
|
||||
}
|
||||
|
||||
//set the VB
|
||||
mesh.SetVertexData(0, rawVertexData);
|
||||
|
||||
//set the IB
|
||||
mesh.SetIndexData(rawIndexData, numIndices);
|
||||
|
||||
//generate adjacency
|
||||
const float epsilon = 0.0f;
|
||||
mesh.GenerateAdjacencyAndPointRepresentation(epsilon);
|
||||
|
||||
//generate adjacency indices
|
||||
mesh.GenerateGeometryShaderAdjacency();
|
||||
|
||||
//get the adjacency data out of the mesh
|
||||
MeshBuffer indexBufferMesh = null;
|
||||
DataStream adjIndices = null;
|
||||
|
||||
try
|
||||
{
|
||||
indexBufferMesh = mesh.GetIndexBuffer();
|
||||
adjIndices = indexBufferMesh.Map();
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
throw new ActionFailedException("GeometryBuffer: Unable to retrive indexdata for adjacency data generation. " + ex.ToString());
|
||||
}
|
||||
|
||||
SetIndexData((int)(adjIndices.Length / sizeof(uint)), adjIndices, false);
|
||||
|
||||
//cleanup
|
||||
indexBufferMesh.Unmap();
|
||||
indexBufferMesh.Dispose();
|
||||
mesh.Dispose();
|
||||
|
||||
switch (this.PrimitiveTopology)
|
||||
{
|
||||
case PrimitiveTopology.LineList:
|
||||
PrimitiveTopology = PrimitiveTopology.LineListWithAdjacency;
|
||||
break;
|
||||
case PrimitiveTopology.LineStrip:
|
||||
PrimitiveTopology = PrimitiveTopology.LineStripWithAdjacency;
|
||||
break;
|
||||
case PrimitiveTopology.TriangleList:
|
||||
PrimitiveTopology = PrimitiveTopology.TriangleListWithAdjacency;
|
||||
break;
|
||||
case PrimitiveTopology.TriangleStrip:
|
||||
PrimitiveTopology = PrimitiveTopology.TriangleStripWithAdjacency;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void Render(IShader argShader)
|
||||
{
|
||||
if (vertexElements.Length == 0)
|
||||
return;
|
||||
|
||||
if (argShader.Technique == null)
|
||||
return;
|
||||
|
||||
int currentPass = argShader.CurrentPass;
|
||||
EffectPass currentEffectPass = argShader.Technique.GetPassByIndex(currentPass);
|
||||
|
||||
InputLayout vertexLayout = null;
|
||||
List<InputLayout> ilList;
|
||||
if (vertexLayoutsPerShaderAndPass.TryGetValue(argShader, out ilList) && ilList.Count > currentPass)
|
||||
{
|
||||
vertexLayout = ilList[currentPass];
|
||||
}
|
||||
else
|
||||
{
|
||||
vertexLayout = new InputLayout(Engine.Device, inputElementDesc, currentEffectPass.Description.Signature);
|
||||
if (vertexLayout != null)
|
||||
{
|
||||
if (ilList == null)
|
||||
{
|
||||
ilList = new List<InputLayout>();
|
||||
ilList.Add(vertexLayout);
|
||||
vertexLayoutsPerShaderAndPass[argShader] = ilList;
|
||||
}
|
||||
else
|
||||
{
|
||||
ilList.Add(vertexLayout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vertexLayout != null)
|
||||
{
|
||||
currentEffectPass.Apply();
|
||||
Engine.Device.InputAssembler.SetInputLayout(vertexLayout);
|
||||
if (indexBuffer == null)
|
||||
Engine.Device.Draw(VertexBufferLength, 0);
|
||||
else
|
||||
Engine.Device.DrawIndexed(IndexBufferUsableLength, IndexBufferOffset, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public int IndexBufferOffset { get; set; }
|
||||
public int IndexBufferUsableLength { get; set; }
|
||||
public int IndexBufferLength { get; private set; }
|
||||
public int VertexBufferLength { get; private set; }
|
||||
public PrimitiveTopology PrimitiveTopology { get; set; }
|
||||
|
||||
public bool IsPickable
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.PickHull != null;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (this.IsPickable == value)
|
||||
return;
|
||||
|
||||
this.PickHull = new PickHull(rawVertexData, VertexBufferLength, vertexElements, rawIndexData, IndexBufferLength);
|
||||
}
|
||||
}
|
||||
|
||||
public IPickHull PickHull { get; protected set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constants
|
||||
public static byte SetIndexBufferCommandType = 0;
|
||||
public static byte SetVertexBufferCommandType = 1;
|
||||
public static byte DrawGeometryCommandType = 2;
|
||||
#endregion
|
||||
|
||||
#region Private members
|
||||
|
||||
SlimDX.Direct3D10.Buffer indexBuffer;
|
||||
DataStream rawIndexData;
|
||||
uint[] typeMappedIndexData;
|
||||
DataStream rawMappedIndexData;
|
||||
|
||||
int vertexElementSize;
|
||||
SlimDX.Direct3D10.Buffer vertexBuffer;
|
||||
DataStream rawVertexData;
|
||||
object typeMappedVertexData;
|
||||
Type typeMappedVertexDataType;
|
||||
DataStream rawMappedVertexData;
|
||||
|
||||
VertexElement[] vertexElements;
|
||||
InputElement[] inputElementDesc;
|
||||
|
||||
Dictionary<IShader, List<InputLayout>> vertexLayoutsPerShaderAndPass = new Dictionary<IShader, List<InputLayout>>();
|
||||
|
||||
#endregion
|
||||
|
||||
#region CommandUser Members
|
||||
|
||||
public override CommandExecuteResult ExecuteCommand(byte argCommandType, CommandBuffer argCurrentBuffer, int argCurrentPositon)
|
||||
{
|
||||
if (argCommandType == GeometryBuffer.SetIndexBufferCommandType)
|
||||
{
|
||||
if (Engine.EngineStates.LastIndexBufferProvider != this)
|
||||
{
|
||||
Engine.Device.InputAssembler.SetIndexBuffer(indexBuffer, SlimDX.DXGI.Format.R32_UInt, IndexBufferOffset);
|
||||
Engine.EngineStates.LastIndexBufferProvider = this;
|
||||
}
|
||||
}
|
||||
else if (argCommandType == GeometryBuffer.SetVertexBufferCommandType)
|
||||
{
|
||||
if (Engine.EngineStates.LastVertexBufferProvider != this)
|
||||
{
|
||||
Engine.Device.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(vertexBuffer, vertexElementSize, 0));
|
||||
Engine.Device.InputAssembler.SetPrimitiveTopology(PrimitiveTopology);
|
||||
Engine.EngineStates.LastVertexBufferProvider = this;
|
||||
}
|
||||
}
|
||||
else if (argCommandType == GeometryBuffer.DrawGeometryCommandType)
|
||||
{
|
||||
if (Engine.EngineStates.LastShader == null)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine("GeometryBuffer could not render without a valid shader.");
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
}
|
||||
else if (Engine.EngineStates.LastVertexBufferProvider == null)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine("GeometryBuffer could not render without a valid vertex buffer.");
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
}
|
||||
else
|
||||
{
|
||||
Render(Engine.EngineStates.LastShader);
|
||||
}
|
||||
}
|
||||
|
||||
return CommandExecuteResult.None;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
if (Engine.EngineStates.LastIndexBufferProvider == this)
|
||||
Engine.EngineStates.LastIndexBufferProvider = null;
|
||||
if (Engine.EngineStates.LastVertexBufferProvider == this)
|
||||
Engine.EngineStates.LastVertexBufferProvider = null;
|
||||
|
||||
DeleteVertexData();
|
||||
DeleteIndexData();
|
||||
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public override ICreationParams CreationParams
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public override ObservableCollection<IResource> Children
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
#region IGeometryBuffer Members
|
||||
|
||||
|
||||
public void SetIndexData(IEnumerable<uint> argIndexData, bool argNeedsDynamicAccess)
|
||||
{
|
||||
this.SetIndexData(argIndexData.Count(), new DataStream(argIndexData.ToArray(), true, true), argNeedsDynamicAccess);
|
||||
}
|
||||
|
||||
public uint[] MapIndexBuffer(MapMode argAccessMode)
|
||||
{
|
||||
var rawData = this.MapIndexBufferRaw(argAccessMode);
|
||||
this.typeMappedIndexData = new uint[this.IndexBufferLength];
|
||||
rawData.Position = 0;
|
||||
rawData.ReadRange(this.typeMappedIndexData, 0, this.IndexBufferLength);
|
||||
rawData.Position = 0;
|
||||
|
||||
return this.typeMappedIndexData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IGeometryBuffer<TVertex> Members
|
||||
|
||||
public void SetVertexData<TVertex>(IEnumerable<TVertex> argVertexData, VertexElement[] argVertexElements, bool argNeedsDynamicAccess) where TVertex : struct
|
||||
{
|
||||
this.SetVertexData(argVertexData.Count(), new DataStream(argVertexData.ToArray(), true, true), argVertexElements, argNeedsDynamicAccess);
|
||||
}
|
||||
|
||||
public TVertex[] MapVertexBuffer<TVertex>(MapMode argAccessMode) where TVertex : struct
|
||||
{
|
||||
var rawData = this.MapVertexBufferRaw(argAccessMode);
|
||||
typeMappedVertexDataType = typeof(TVertex);
|
||||
var tmp = new TVertex[this.VertexBufferLength];
|
||||
typeMappedVertexData = tmp;
|
||||
rawData.Position = 0;
|
||||
rawData.ReadRange<TVertex>(tmp, 0, this.VertexBufferLength);
|
||||
rawData.Position = 0;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
#endregion
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user