protected unsafe void SplitGeometry( VertexData vd, IndexData id, SubMeshLodGeometryLink targetGeomLink )
{
if ( logLevel <= 1 )
LogManager.Instance.Write( "StaticGeometry.SplitGeometry called" );
// 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;
Dictionary<int, int> indexRemap = new Dictionary<int, int>();
IntPtr src = id.indexBuffer.Lock( BufferLocking.ReadOnly );
indexRemap.Clear();
if ( use32bitIndexes )
{
int* p32 = (int*)src.ToPointer();
for ( int i = 0; i < id.indexCount; ++i )
indexRemap[ *p32++ ] = indexRemap.Count;
}
else
{
short* p16 = (short*)src.ToPointer();
for ( int i = 0; i < id.indexCount; ++i )
indexRemap[ *p16++ ] = indexRemap.Count;
}
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 ( short b = 0; b < numvbufs; ++b )
{
// Lock old buffer
HardwareVertexBuffer oldBuf = vd.vertexBufferBinding.GetBuffer( b );
// Create new buffer
HardwareVertexBuffer newBuf =
HardwareBufferManager.Instance.CreateVertexBuffer( oldBuf.VertexDeclaration, indexRemap.Count, BufferUsage.Static );
// rebind
newvd.vertexBufferBinding.SetBinding( 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)
IntPtr vdSrc = oldBuf.Lock( BufferLocking.ReadOnly );
byte* pSrcBase = (byte*)vdSrc.ToPointer();
IntPtr vdDest = newBuf.Lock( BufferLocking.Discard );
byte* pDstBase = (byte*)vdDest.ToPointer();
int vertexSize = oldBuf.VertexSize;
// Buffers should be the same size
Debug.Assert( vertexSize == newBuf.VertexSize );
foreach ( KeyValuePair<int, int> pair in indexRemap )
{
Debug.Assert( pair.Key < oldBuf.VertexCount );
Debug.Assert( pair.Value < newBuf.VertexCount );
byte* pSrc = pSrcBase + pair.Key * vertexSize;
byte* pDst = pDstBase + pair.Value * vertexSize;
for ( int i = 0; i < vertexSize; i++ )
*pDst++ = *pSrc++;
}
// unlock
oldBuf.Unlock();
newBuf.Unlock();
}
// Now create a new index buffer
HardwareIndexBuffer ibuf =
HardwareBufferManager.Instance.CreateIndexBuffer( id.indexBuffer.Type, id.indexCount, BufferUsage.Static );
IntPtr idSrc = id.indexBuffer.Lock( BufferLocking.ReadOnly );
IntPtr idDest = ibuf.Lock( BufferLocking.Discard );
if ( use32bitIndexes )
{
int* pSrc32 = (int*)idSrc.ToPointer();
int* pDst32 = (int*)idDest.ToPointer();
for ( int i = 0; i < id.indexCount; ++i )
*pDst32++ = (int)indexRemap[ *pSrc32++ ];
}
else
{
ushort* pSrc16 = (ushort*)idSrc.ToPointer();
ushort* pDst16 = (ushort*)idDest.ToPointer();
for ( int i = 0; i < id.indexCount; ++i )
*pDst16++ = (ushort)indexRemap[ *pSrc16++ ];
}
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;
optimisedSubMeshGeometryList.Add( optGeom );
}