public GeometryBucket(MaterialBucket parent, string formatString, VertexData vData, IndexData iData) { // Clone the structure from the example this.parent = parent; this.formatString = formatString; vertexData = vData.Clone(false); indexData = iData.Clone(false); vertexData.vertexCount = 0; vertexData.vertexStart = 0; indexData.indexCount = 0; indexData.indexStart = 0; indexType = indexData.indexBuffer.Type; queuedGeometry = new List<QueuedGeometry>(); // Derive the max vertices if (indexType == IndexType.Size32) maxVertexIndex = int.MaxValue; else maxVertexIndex = ushort.MaxValue; // Check to see if we have blend indices / blend weights // remove them if so, they can try to blend non-existent bones! VertexElement blendIndices = vertexData.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.BlendIndices); VertexElement blendWeights = vertexData.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.BlendWeights); if (blendIndices != null && blendWeights != null) { Debug.Assert(blendIndices.Source == blendWeights.Source, "Blend indices and weights should be in the same buffer"); // Get the source ushort source = blendIndices.Source; Debug.Assert(blendIndices.Size + blendWeights.Size == vertexData.vertexBufferBinding.GetBuffer(source).VertexSize, "Blend indices and blend buffers should have buffer to themselves!"); // Unset the buffer vertexData.vertexBufferBinding.UnsetBinding(source); // Remove the elements vertexData.vertexDeclaration.RemoveElement(VertexElementSemantic.BlendIndices); vertexData.vertexDeclaration.RemoveElement(VertexElementSemantic.BlendWeights); } }
/// <summary> /// Internal method to clone vertex data definitions but to remove blend buffers. /// </summary> /// <param name="source">Vertex data to clone.</param> /// <returns>A cloned instance of 'source' without blending information.</returns> protected internal VertexData CloneVertexDataRemoveBlendInfo( VertexData source ) { // Clone without copying data var ret = source.Clone( false ); var blendIndexElem = source.vertexDeclaration.FindElementBySemantic( VertexElementSemantic.BlendIndices ); var blendWeightElem = source.vertexDeclaration.FindElementBySemantic( VertexElementSemantic.BlendWeights ); // Remove blend index if ( blendIndexElem != null ) { // Remove buffer reference ret.vertexBufferBinding.UnsetBinding( blendIndexElem.Source ); } if ( blendWeightElem != null && blendWeightElem.Source != blendIndexElem.Source ) { // Remove buffer reference ret.vertexBufferBinding.UnsetBinding( blendWeightElem.Source ); } // remove elements from declaration ret.vertexDeclaration.RemoveElement( VertexElementSemantic.BlendIndices ); ret.vertexDeclaration.RemoveElement( VertexElementSemantic.BlendWeights ); // copy reference to w-coord buffer if ( source.hardwareShadowVolWBuffer != null ) { ret.hardwareShadowVolWBuffer = source.hardwareShadowVolWBuffer; } return ret; }
/// <summary> /// Split some shared geometry into dedicated geometry. /// </summary> /// <param name="vd"> </param> /// <param name="id"> </param> /// <param name="targetGeomLink"> </param> public 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; var indexRemap = new Dictionary<int, int>(); if ( use32bitIndexes ) { var p32 = id.indexBuffer.Lock( id.indexStart, id.indexCount*id.indexBuffer.IndexSize, BufferLocking.ReadOnly ); BuildIndexRemap( p32, id.indexCount, ref indexRemap ); id.indexBuffer.Unlock(); } else { var p16 = 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.VertexDeclaration, 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) var pSrcBase = oldBuf.Lock( BufferLocking.ReadOnly ); var pDstBase = newBuf.Lock( BufferLocking.Discard ); int vertexSize = oldBuf.VertexSize; // Buffers should be the same size Debug.Assert( vertexSize == newBuf.VertexSize ); foreach ( var r in indexRemap ) { Debug.Assert( r.Key < oldBuf.VertexCount ); Debug.Assert( r.Value < newBuf.VertexCount ); var pSrc = pSrcBase + r.Key*vertexSize; var pDst = pDstBase + r.Value*vertexSize; var pSrcPtr = pSrc; var pDstPtr = 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 var optGeom = new OptimisedSubMeshGeometry(); optGeom.indexData = targetGeomLink.indexData; optGeom.vertexData = targetGeomLink.vertexData; mOptimisedSubMeshGeometryList.Add( optGeom ); }
public GeometryBucket( MaterialBucket parent, String formatString, VertexData vData, IndexData iData ) : base() { mParent = parent; mFormatString = formatString; mVertexData = null; mIndexData = null; mBatch = mParent.Parent.Parent.Parent; if ( mBatch.BaseSkeleton != null ) { SetCustomParameter( 0, new Vector4( mBatch.BaseSkeleton.BoneCount, 0, 0, 0 ) ); } mVertexData = vData.Clone( false ); renderOperation.useIndices = true; renderOperation.indexData = new IndexData(); renderOperation.indexData.indexCount = 0; renderOperation.indexData.indexStart = 0; renderOperation.vertexData = new VertexData(); renderOperation.vertexData.vertexCount = 0; renderOperation.vertexData.vertexDeclaration = (VertexDeclaration)vData.vertexDeclaration.Clone(); mIndexType = iData.indexBuffer.Type; // Derive the max vertices if ( mIndexType == IndexType.Size32 ) { mMaxVertexIndex = 0xFFFFFFFF; } else { mMaxVertexIndex = 0xFFFF; } int offset = 0, tcOffset = 0; short texCoordOffset = 0; short texCoordSource = 0; for ( int i = 0; i < renderOperation.vertexData.vertexDeclaration.ElementCount; i++ ) { if ( renderOperation.vertexData.vertexDeclaration.GetElement( i ).Semantic == VertexElementSemantic.TexCoords ) { texCoordOffset++; texCoordSource = renderOperation.vertexData.vertexDeclaration.GetElement( i ).Source; tcOffset = renderOperation.vertexData.vertexDeclaration.GetElement( i ).Offset + VertexElement.GetTypeSize( renderOperation.vertexData.vertexDeclaration.GetElement( i ).Type ); } offset += VertexElement.GetTypeSize( renderOperation.vertexData.vertexDeclaration.GetElement( i ).Type ); } renderOperation.vertexData.vertexDeclaration.AddElement( texCoordSource, tcOffset, VertexElementType.Float1, VertexElementSemantic.TexCoords, texCoordOffset ); mTexCoordIndex = texCoordOffset; }
protected void SplitGeometry( VertexData vd, IndexData id, SubMeshLodGeometryLink targetGeomLink ) { #if !AXIOM_SAFE_ONLY unsafe #endif { if ( this.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 var use32bitIndexes = id.indexBuffer.Type == IndexType.Size32; var indexRemap = new Dictionary<int, int>(); var src = id.indexBuffer.Lock( BufferLocking.ReadOnly ); indexRemap.Clear(); if ( use32bitIndexes ) { var p32 = src.ToIntPointer(); for ( var i = 0; i < id.indexCount; ++i ) { indexRemap[ p32[ i ] ] = indexRemap.Count; } } else { var p16 = src.ToShortPointer(); for ( var i = 0; i < id.indexCount; ++i ) { indexRemap[ p16[ i ] ] = 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 var newvd = targetGeomLink.vertexData; //IndexData newid = targetGeomLink.IndexData; // Update the vertex count newvd.vertexCount = indexRemap.Count; var numvbufs = vd.vertexBufferBinding.BindingCount; // Copy buffers from old to new for ( short b = 0; b < numvbufs; ++b ) { // Lock old buffer var oldBuf = vd.vertexBufferBinding.GetBuffer( b ); // Create new buffer var 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) var vdSrc = oldBuf.Lock( BufferLocking.ReadOnly ); var pSrcBase = vdSrc; var vdDest = newBuf.Lock( BufferLocking.Discard ); var pDstBase = vdDest; var vertexSize = oldBuf.VertexSize; // Buffers should be the same size Debug.Assert( vertexSize == newBuf.VertexSize ); foreach ( var pair in indexRemap ) { Debug.Assert( pair.Key < oldBuf.VertexCount ); Debug.Assert( pair.Value < newBuf.VertexCount ); var pSrc = ( pSrcBase + pair.Key*vertexSize ).ToBytePointer(); var pDst = ( pDstBase + pair.Value*vertexSize ).ToBytePointer(); for ( var i = 0; i < vertexSize; i++ ) { pDst[ i ] = pSrc[ i ]; } } // unlock oldBuf.Unlock(); newBuf.Unlock(); } // Now create a new index buffer var ibuf = HardwareBufferManager.Instance.CreateIndexBuffer( id.indexBuffer.Type, id.indexCount, BufferUsage.Static ); var idSrc = id.indexBuffer.Lock( BufferLocking.ReadOnly ); var idDest = ibuf.Lock( BufferLocking.Discard ); if ( use32bitIndexes ) { var pSrc32 = idSrc.ToIntPointer(); var pDst32 = idDest.ToIntPointer(); for ( var i = 0; i < id.indexCount; ++i ) { pDst32[ i ] = indexRemap[ pSrc32[ i ] ]; } } else { var pSrc16 = idSrc.ToUShortPointer(); var pDst16 = idDest.ToUShortPointer(); for ( var i = 0; i < id.indexCount; ++i ) { pDst16[ i ] = (ushort)indexRemap[ pSrc16[ i ] ]; } } 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 var optGeom = new OptimisedSubMeshGeometry(); optGeom.indexData = targetGeomLink.indexData; optGeom.vertexData = targetGeomLink.vertexData; this.optimisedSubMeshGeometryList.Add( optGeom ); } }
protected unsafe void SplitGeometry(VertexData vd, IndexData id, SubMeshLodGeometryLink targetGeomLink) { log.Info("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 (ushort b = 0; b < numvbufs; ++b) { // Lock old buffer HardwareVertexBuffer oldBuf = vd.vertexBufferBinding.GetBuffer(b); // Create new buffer HardwareVertexBuffer newBuf = HardwareBufferManager.Instance.CreateVertexBuffer(oldBuf.VertexSize, 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); }