public unsafe void SplitGeometry( VertexData vd, IndexData id, ref SubMeshLodGeometryLink targetGeomLink )
{
// Firstly we need to scan to see how many vertices are being used
// and while we're at it, build the remap we can use later
bool use32bitIndexes = id.indexBuffer.Type == IndexType.Size32;
ushort* p16;
uint* p32;
Dictionary<int, int> indexRemap = new Dictionary<int, int>();
if ( use32bitIndexes )
{
p32 = (uint*)id.indexBuffer.Lock(
id.indexStart,
id.indexCount * id.indexBuffer.IndexSize,
BufferLocking.ReadOnly );
BuildIndexRemap( p32, id.indexCount, ref indexRemap );
id.indexBuffer.Unlock();
}
else
{
p16 = (ushort*)id.indexBuffer.Lock(
id.indexStart,
id.indexCount * id.indexBuffer.IndexSize,
BufferLocking.ReadOnly );
BuildIndexRemap( p16, id.indexCount, ref indexRemap );
id.indexBuffer.Unlock();
}
if ( indexRemap.Count == vd.vertexCount )
{
// ha, complete usage after all
targetGeomLink.vertexData = vd;
targetGeomLink.indexData = id;
return;
}
// Create the new vertex data records
targetGeomLink.vertexData = vd.Clone( false );
// Convenience
VertexData newvd = targetGeomLink.vertexData;
//IndexData* newid = targetGeomLink->indexData;
// Update the vertex count
newvd.vertexCount = indexRemap.Count;
int numvbufs = vd.vertexBufferBinding.BindingCount;
// Copy buffers from old to new
for ( int b = 0; b < numvbufs; ++b )
{
// Lock old buffer
HardwareVertexBuffer oldBuf = vd.vertexBufferBinding.GetBuffer( (short)b );
// Create new buffer
HardwareVertexBuffer newBuf =
HardwareBufferManager.Instance.CreateVertexBuffer(
oldBuf.VertexSize,
indexRemap.Count,
BufferUsage.Static );
// rebind
newvd.vertexBufferBinding.SetBinding( (short)b, newBuf );
// Copy all the elements of the buffer across, by iterating over
// the IndexRemap which describes how to move the old vertices
// to the new ones. By nature of the map the remap is in order of
// indexes in the old buffer, but note that we're not guaranteed to
// address every vertex (which is kinda why we're here)
byte* pSrcBase = (byte*)oldBuf.Lock( BufferLocking.ReadOnly );
byte* pDstBase = (byte*)newBuf.Lock( BufferLocking.Discard );
int vertexSize = oldBuf.VertexSize;
// Buffers should be the same size
Debug.Assert( vertexSize == newBuf.VertexSize );
foreach ( KeyValuePair<int, int> r in indexRemap )
{
Debug.Assert( r.Key < oldBuf.VertexCount );
Debug.Assert( r.Value < newBuf.VertexCount );
void* pSrc = pSrcBase + r.Key * vertexSize;
void* pDst = pDstBase + r.Value * vertexSize;
IntPtr pSrcPtr = new IntPtr( pSrc );
IntPtr pDstPtr = new IntPtr( pDst );
Memory.Copy( pDstPtr, pSrcPtr, vertexSize );
}
// unlock
oldBuf.Unlock();
newBuf.Unlock();
}
// Now create a new index buffer
HardwareIndexBuffer ibuf = HardwareBufferManager.Instance.CreateIndexBuffer(
id.indexBuffer.Type, id.indexCount, BufferUsage.Static );
if ( use32bitIndexes )
{
uint* pSrc32, pDst32;
pSrc32 = (uint*)id.indexBuffer.Lock(
id.indexStart, id.indexCount * id.indexBuffer.IndexSize, BufferLocking.ReadOnly );
pDst32 = (uint*)ibuf.Lock( BufferLocking.Discard );
RemapIndexes( pSrc32, pDst32, ref indexRemap, id.indexCount );
id.indexBuffer.Unlock();
ibuf.Unlock();
}
else
{
ushort* pSrc16, pDst16;
pSrc16 = (ushort*)id.indexBuffer.Lock(
id.indexStart, id.indexCount * id.indexBuffer.IndexSize, BufferLocking.ReadOnly );
pDst16 = (ushort*)ibuf.Lock( BufferLocking.Discard );
RemapIndexes( pSrc16, pDst16, ref indexRemap, id.indexCount );
id.indexBuffer.Unlock();
ibuf.Unlock();
}
targetGeomLink.indexData = new IndexData();
targetGeomLink.indexData.indexStart = 0;
targetGeomLink.indexData.indexCount = id.indexCount;
targetGeomLink.indexData.indexBuffer = ibuf;
// Store optimised geometry for deallocation later
OptimisedSubMeshGeometry optGeom = new OptimisedSubMeshGeometry();
optGeom.indexData = targetGeomLink.indexData;
optGeom.vertexData = targetGeomLink.vertexData;
mOptimisedSubMeshGeometryList.Add( optGeom );
}