/// <summary> /// /// </summary> /// <param name="disposeManagedResources"></param> protected override void dispose(bool disposeManagedResources) { if (!IsDisposed) { if (disposeManagedResources) { if (this.vertexData != null) { if (!this.vertexData.IsDisposed) { this.vertexData.Dispose(); } this.vertexData = null; } if (this.indexData != null) { if (!this.indexData.IsDisposed) { this.indexData.Dispose(); } this.indexData = null; } } } base.dispose(disposeManagedResources); }
/// <summary> /// Clones this vertex data, potentially including replicating any index buffers. /// </summary> /// <param name="copyData"> /// If true, makes a copy the index buffer in addition to the definition. /// If false, the clone will refer to the same index buffer this object refers to. /// </param> /// <returns>A copy of this IndexData object.</returns> public IndexData Clone(bool copyData) { var clone = new IndexData(); if (this.indexBuffer != null) { if (copyData) { clone.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer(this.indexBuffer.Type, this.indexBuffer.IndexCount, this.indexBuffer.Usage, this.indexBuffer.HasShadowBuffer); // copy all the existing buffer data clone.indexBuffer.CopyTo(this.indexBuffer, 0, 0, this.indexBuffer.Size, true); } else { clone.indexBuffer = this.indexBuffer; } } clone.indexStart = this.indexStart; clone.indexCount = this.indexCount; return(clone); }
public static void GetSubmeshIndexData(out int[,] indices, IndexData indexData) { HardwareIndexBuffer idxBuffer = indexData.indexBuffer; IndexType indexType = IndexType.Size16; if ((idxBuffer.Size / indexData.indexCount) != 2) { Debug.Assert(false, "Unexpected index buffer size"); indexType = IndexType.Size32; } Debug.Assert(indexData.indexCount % 3 == 0); indices = new int[indexData.indexCount / 3, 3]; ReadBuffer(idxBuffer, indexData.indexCount, indexType, ref indices); }
/// <summary> /// Class level dispose method /// </summary> /// <remarks> /// When implementing this method in an inherited class the following template should be used; /// protected override void dispose( bool disposeManagedResources ) /// { /// if ( !isDisposed ) /// { /// if ( disposeManagedResources ) /// { /// // Dispose managed resources. /// } /// /// // There are no unmanaged resources to release, but /// // if we add them, they need to be released here. /// } /// /// // If it is available, make the call to the /// // base class's Dispose(Boolean) method /// base.dispose( disposeManagedResources ); /// } /// </remarks> /// <param name="disposeManagedResources">True if Unmanaged resources should be released.</param> protected override void dispose(bool disposeManagedResources) { if (!IsDisposed) { if (disposeManagedResources) { // Dispose managed resources. if (this.renderOperation != null) { if (!this.renderOperation.IsDisposed) { this.renderOperation.Dispose(); } this.renderOperation = null; } if (this.indexData != null) { if (!this.indexData.IsDisposed) { this.indexData.Dispose(); } this.indexData = null; } if (this.vertexData != null) { if (!this.vertexData.IsDisposed) { this.vertexData.Dispose(); } this.vertexData = null; } } // There are no unmanaged resources to release, but // if we add them, they need to be released here. } base.dispose(disposeManagedResources); }
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); } }
public List <TriangleVertices> Build() { List <TriangleVertices> triangles = new List <TriangleVertices>(); try { for (int ind = 0, indexSet = 0; ind < indexDataList.Count; ind++, indexSet++) { int vertexSet = (int)indexDataVertexDataSetList[ind]; IndexData indexData = (IndexData)indexDataList[indexSet]; OperationType opType = operationTypes[indexSet]; int iterations = 0; switch (opType) { case OperationType.TriangleList: iterations = indexData.indexCount / 3; break; case OperationType.TriangleFan: case OperationType.TriangleStrip: iterations = indexData.indexCount - 2; break; } // locate position element & the buffer to go with it VertexData vertexData = (VertexData)vertexDataList[vertexSet]; VertexElement posElem = vertexData.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Position); HardwareVertexBuffer posBuffer = vertexData.vertexBufferBinding.GetBuffer(posElem.Source); try { IntPtr posPtr = posBuffer.Lock(BufferLocking.ReadOnly); IntPtr idxPtr = indexData.indexBuffer.Lock(BufferLocking.ReadOnly); unsafe { byte *pBaseVertex = (byte *)posPtr.ToPointer(); ushort *p16Idx = null; uint * p32Idx = null; // counters used for pointer indexing int count16 = 0; int count32 = 0; if (indexData.indexBuffer.Type == IndexType.Size16) { p16Idx = (ushort *)idxPtr.ToPointer(); } else { p32Idx = (uint *)idxPtr.ToPointer(); } float *pReal = null; int triStart = triangles.Count; // iterate over all the groups of 3 indices triangles.Capacity = triStart + iterations; uint[] index = new uint[3]; for (int t = 0; t < iterations; t++) { Vector3[] v = new Vector3[3]; TriangleVertices tri = new TriangleVertices(v); bool broken = false; for (int i = 0; i < 3; i++) { // Standard 3-index read for tri list or first tri in strip / fan if (opType == OperationType.TriangleList || t == 0) { if (indexData.indexBuffer.Type == IndexType.Size32) { index[i] = p32Idx[count32++]; } else { index[i] = p16Idx[count16++]; } } else { // Strips and fans are formed from last 2 indexes plus the // current one for triangles after the first if (indexData.indexBuffer.Type == IndexType.Size32) { index[i] = p32Idx[i - 2]; } else { index[i] = p16Idx[i - 2]; } // Perform single-index increment at the last tri index if (i == 2) { if (indexData.indexBuffer.Type == IndexType.Size32) { count32++; } else { count16++; } } } // Retrieve the vertex position if (index[i] >= posBuffer.VertexCount) { log.InfoFormat("TriangleListBuilder.Build: Error: index[i] {0} is not less than posBuffer.VertexCount {1}, iteration t {2}", index[i], posBuffer.VertexCount, t); broken = true; break; } Debug.Assert(index[i] < posBuffer.VertexCount); byte *pVertex = pBaseVertex + (index[i] * posBuffer.VertexSize); pReal = (float *)(pVertex + posElem.Offset); v[i].x = *pReal++; v[i].y = *pReal++; v[i].z = *pReal++; } if (!broken) { // Put the points in in counter-clockwise order if (((v[0].x - v[2].x) * (v[1].y - v[2].y) - (v[1].x - v[2].x) * (v[0].y - v[2].y)) < 0) { // Clockwise, so reverse points 1 and 2 Vector3 tmp = v[1]; v[1] = v[2]; v[2] = tmp; } // Debug.Assert(((v[0].x - v[2].x) * (v[1].y - v[2].y) - (v[1].x - v[2].x) * (v[0].y - v[2].y)) >= 0); // Add to the list of triangles triangles.Add(new TriangleVertices(v)); } } // for iterations } // unsafe } finally { // unlock those buffers! indexData.indexBuffer.Unlock(); posBuffer.Unlock(); } } return(triangles); } catch (Exception e) { log.ErrorFormat("TriangleListBuilder.Build: Exception raised during triangle building: {0}", e.Message); triangles.Clear(); return(triangles); } }
/// <summary> /// /// </summary> /// <param name="disposeManagedResources"></param> protected override void dispose(bool disposeManagedResources) { if (!this.IsDisposed) { if (disposeManagedResources) { if (this.vertexData != null) { if (!this.vertexData.IsDisposed) this.vertexData.Dispose(); this.vertexData = null; } if (this.indexData != null) { if (!this.indexData.IsDisposed) this.indexData.Dispose(); this.indexData = null; } } } base.dispose(disposeManagedResources); }
public static void CopyIndexData(IndexData dst, IndexData src, Dictionary<uint, uint> vertexIdMap) { dst.indexStart = src.indexStart; dst.indexCount = src.indexCount; IndexType iType = IndexType.Size16; if (vertexIdMap.Count > ushort.MaxValue) iType = IndexType.Size32; HardwareIndexBuffer srcBuf = src.indexBuffer; HardwareIndexBuffer dstBuf = HardwareBufferManager.Instance.CreateIndexBuffer(iType, dst.indexCount, srcBuf.Usage); // TODO: copy the data IntPtr srcData = srcBuf.Lock(BufferLocking.ReadOnly); IntPtr dstData = dstBuf.Lock(BufferLocking.Discard); unsafe { if (srcBuf.IndexSize == 2 && dstBuf.IndexSize == 2) { ushort* srcPtr = (ushort *)srcData.ToPointer(); ushort* dstPtr = (ushort *)dstData.ToPointer(); for (int i = 0; i < srcBuf.IndexCount; ++i) dstPtr[i] = (ushort)vertexIdMap[srcPtr[i]]; } else if (srcBuf.IndexSize == 4 && dstBuf.IndexSize == 2) { uint* srcPtr = (uint *)srcData.ToPointer(); ushort* dstPtr = (ushort *)dstData.ToPointer(); for (int i = 0; i < srcBuf.IndexCount; ++i) dstPtr[i] = (ushort)vertexIdMap[srcPtr[i]]; } else if (srcBuf.IndexSize == 4 && dstBuf.IndexSize == 4) { uint* srcPtr = (uint *)srcData.ToPointer(); uint* dstPtr = (uint *)dstData.ToPointer(); for (int i = 0; i < srcBuf.IndexCount; ++i) dstPtr[i] = vertexIdMap[srcPtr[i]]; } else { throw new NotImplementedException(); } } dstBuf.Unlock(); srcBuf.Unlock(); dst.indexBuffer = dstBuf; }
/// <summary> /// /// </summary> /// <param name="dstData"></param> /// <param name="orgdata"></param> /// <param name="indexData"></param> /// <param name="normals"></param> private unsafe void UpdateVertexDataNoiseAndNormals(VertexData dstData, VertexData orgData, IndexData indexData, float* normals) { // destination vertex buffer VertexElement dstPosElement = dstData.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Position); HardwareVertexBuffer dstPosBuffer = dstData.vertexBufferBinding.GetBuffer(dstPosElement.Source); // source vertex buffer VertexElement orgPosElement = orgData.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Position); HardwareVertexBuffer orgPosBuffer = orgData.vertexBufferBinding.GetBuffer(orgPosElement.Source); // lock the buffers IntPtr dstPosData = dstPosBuffer.Lock(BufferLocking.Discard); IntPtr orgPosData = orgPosBuffer.Lock(BufferLocking.ReadOnly); // get some raw pointer action goin on float* dstPosPtr = (float*)dstPosData.ToPointer(); float* orgPosPtr = (float*)orgPosData.ToPointer(); // make noise int numVerts = orgPosBuffer.VertexCount; for(int i = 0; i < 3 * numVerts; i += 3) { float n = 1 + displacement * Noise3(orgPosPtr[i] / density + tm, orgPosPtr[i + 1] / density + tm, orgPosPtr[i + 2] / density + tm); dstPosPtr[i] = orgPosPtr[i] * n; dstPosPtr[i + 1] = orgPosPtr[i + 1] * n; dstPosPtr[i + 2] = orgPosPtr[i + 2] * n; } // for // unlock the original position buffer orgPosBuffer.Unlock(); // calculate normals HardwareIndexBuffer indexBuffer = indexData.indexBuffer; short* vertexIndices = (short*)indexBuffer.Lock(BufferLocking.ReadOnly); int numFaces = indexData.indexCount / 3; for(int i = 0, index = 0; i < numFaces; i++, index += 3) { int p0 = vertexIndices[index]; int p1 = vertexIndices[index + 1]; int p2 = vertexIndices[index + 2]; Vector3 v0 = new Vector3(dstPosPtr[3 * p0], dstPosPtr[3 * p0 + 1], dstPosPtr[3 * p0 + 2]); Vector3 v1 = new Vector3(dstPosPtr[3 * p1], dstPosPtr[3 * p1 + 1], dstPosPtr[3 * p1 + 2]); Vector3 v2 = new Vector3(dstPosPtr[3 * p2], dstPosPtr[3 * p2 + 1], dstPosPtr[3 * p2 + 2]); Vector3 diff1 = v1 - v2; Vector3 diff2 = v1 - v0; Vector3 fn = diff1.Cross(diff2); // update the normal of each vertex in the current face normals[3 * p0] += fn.x; normals[3 * p0 + 1] += fn.y; normals[3 * p0 + 2] += fn.z; normals[3 * p1] += fn.x; normals[3 * p1 + 1] += fn.y; normals[3 * p1 + 2] += fn.z; normals[3 * p2] += fn.x; normals[3 * p2 + 1] += fn.y; normals[3 * p2 + 2] += fn.z; } // unlock index buffer indexBuffer.Unlock(); // unlock destination vertex buffer dstPosBuffer.Unlock(); }
/// <summary> /// Class level dispose method /// </summary> /// <remarks> /// When implementing this method in an inherited class the following template should be used; /// protected override void dispose( bool disposeManagedResources ) /// { /// if ( !isDisposed ) /// { /// if ( disposeManagedResources ) /// { /// // Dispose managed resources. /// } /// /// // There are no unmanaged resources to release, but /// // if we add them, they need to be released here. /// } /// /// // If it is available, make the call to the /// // base class's Dispose(Boolean) method /// base.dispose( disposeManagedResources ); /// } /// </remarks> /// <param name="disposeManagedResources">True if Unmanaged resources should be released.</param> protected override void dispose( bool disposeManagedResources ) { if ( !IsDisposed ) { if ( disposeManagedResources ) { // Dispose managed resources. if ( renderOperation != null ) { if (!this.renderOperation.IsDisposed) this.renderOperation.Dispose(); renderOperation = null; } if (indexData != null) { if (!indexData.IsDisposed) indexData.Dispose(); indexData = null; } if (vertexData != null) { if (!vertexData.IsDisposed) vertexData.Dispose(); vertexData = null; } } // There are no unmanaged resources to release, but // if we add them, they need to be released here. } base.dispose(disposeManagedResources); }
public unsafe void DebugLog(Log log) { log.Write("EdgeListBuilder Log"); log.Write("-------------------"); log.Write("Number of vertex sets: {0}", vertexDataList.Count); log.Write("Number of index sets: {0}", indexDataList.Count); int i, j; // Log original vertex data for (i = 0; i < vertexDataList.Count; i++) { VertexData vData = (VertexData)vertexDataList[i]; log.Write("."); log.Write("Original vertex set {0} - vertex count {1}", i, vData.vertexCount); VertexElement posElem = vData.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Position); HardwareVertexBuffer vbuf = vData.vertexBufferBinding.GetBuffer(posElem.Source); // lock the buffer for reading IntPtr basePtr = vbuf.Lock(BufferLocking.ReadOnly); byte *pBaseVertex = (byte *)basePtr.ToPointer(); float *pReal; for (j = 0; j < vData.vertexCount; j++) { pReal = (float *)(pBaseVertex + posElem.Offset); log.Write("Vertex {0}: ({1}, {2}, {3})", j, pReal[0], pReal[1], pReal[2]); pBaseVertex += vbuf.VertexSize; } vbuf.Unlock(); } // Log original index data for (i = 0; i < indexDataList.Count; i += 3) { IndexData iData = (IndexData)indexDataList[i]; log.Write("."); log.Write("Original triangle set {0} - index count {1} - vertex set {2})", i, iData.indexCount, indexDataVertexDataSetList[i]); // Get the indexes ready for reading short *p16Idx = null; int * p32Idx = null; IntPtr idxPtr = iData.indexBuffer.Lock(BufferLocking.ReadOnly); if (iData.indexBuffer.Type == IndexType.Size32) { p32Idx = (int *)idxPtr.ToPointer(); } else { p16Idx = (short *)idxPtr.ToPointer(); } for (j = 0; j < iData.indexCount / 3; j++) { if (iData.indexBuffer.Type == IndexType.Size32) { log.Write("Triangle {0}: ({1}, {2}, {3})", j, *p32Idx++, *p32Idx++, *p32Idx++); } else { log.Write("Triangle {0}: ({1}, {2}, {3})", j, *p16Idx++, *p16Idx++, *p16Idx++); } } iData.indexBuffer.Unlock(); // Log common vertex list log.Write("."); log.Write("Common vertex list - vertex count {0}", vertices.Count); for (i = 0; i < vertices.Count; i++) { CommonVertex c = (CommonVertex)vertices[i]; log.Write("Common vertex {0}: (vertexSet={1}, originalIndex={2}, position={3}", i, c.vertexSet, c.index, c.position); } } }
/// <summary> /// Add a set of index geometry data to the edge builder. /// </summary> /// <remarks> /// You must add at least one set of index data to the builder before invoking the /// <see name="Build"/> method. /// </remarks> /// <param name="indexData">The index information which describes the triangles.</param> public void AddIndexData( IndexData indexData ) { AddIndexData( indexData, 0, OperationType.TriangleList ); }
public void AddIndexData(IndexData indexData, int vertexSet) { AddIndexData(indexData, vertexSet, OperationType.TriangleList); }
/// <summary> /// Add a set of index geometry data to the edge builder. /// </summary> /// <remarks> /// You must add at least one set of index data to the builder before invoking the /// <see name="Build"/> method. /// </remarks> /// <param name="indexData">The index information which describes the triangles.</param> public void AddIndexData(IndexData indexData) { AddIndexData(indexData, 0, OperationType.TriangleList); }
public unsafe IndexData GenerateTriListIndexes( uint stitchFlags ) { int numIndexes = 0; int step = 1 << mRenderLevel; IndexData indexData; int north = ( stitchFlags & STITCH_NORTH ) != 0 ? step : 0; int south = ( stitchFlags & STITCH_SOUTH ) != 0 ? step : 0; int east = ( stitchFlags & STITCH_EAST ) != 0 ? step : 0; int west = ( stitchFlags & STITCH_WEST ) != 0 ? step : 0; int new_length = ( mOptions.tileSize / step ) * ( mOptions.tileSize / step ) * 2 * 2 * 2; //this is the maximum for a level. It wastes a little, but shouldn't be a problem. indexData = new IndexData(); indexData.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer( IndexType.Size16, new_length, BufferUsage.StaticWriteOnly );//, false); mTerrainZone.IndexCache.mCache.Add( indexData ); ushort* pIdx = (ushort*)indexData.indexBuffer.Lock( 0, indexData.indexBuffer.Size, BufferLocking.Discard ); // Do the core vertices, minus stitches for ( int j = north; j < mOptions.tileSize - 1 - south; j += step ) { for ( int i = west; i < mOptions.tileSize - 1 - east; i += step ) { //triangles *pIdx++ = Index( i, j + step ); numIndexes++; // original order: 2 *pIdx++ = Index( i + step, j ); numIndexes++; // original order: 3 *pIdx++ = Index( i, j ); numIndexes++; // original order: 1 *pIdx++ = Index( i + step, j + step ); numIndexes++; // original order: 2 *pIdx++ = Index( i + step, j ); numIndexes++; // original order: 3 *pIdx++ = Index( i, j + step ); numIndexes++; // original order: 1 } } // North stitching if ( north > 0 ) { numIndexes += StitchEdge( Neighbor.NORTH, mRenderLevel, mNeighbors[ (int)Neighbor.NORTH ].mRenderLevel, west > 0, east > 0, &pIdx ); } // East stitching if ( east > 0 ) { numIndexes += StitchEdge( Neighbor.EAST, mRenderLevel, mNeighbors[ (int)Neighbor.EAST ].mRenderLevel, north > 0, south > 0, &pIdx ); } // South stitching if ( south > 0 ) { numIndexes += StitchEdge( Neighbor.SOUTH, mRenderLevel, mNeighbors[ (int)Neighbor.SOUTH ].mRenderLevel, east > 0, west > 0, &pIdx ); } // West stitching if ( west > 0 ) { numIndexes += StitchEdge( Neighbor.WEST, mRenderLevel, mNeighbors[ (int)Neighbor.WEST ].mRenderLevel, south > 0, north > 0, &pIdx ); } indexData.indexBuffer.Unlock(); indexData.indexCount = numIndexes; indexData.indexStart = 0; return indexData; }
private void DestroyBuffers() { // LogManager.Instance.Write(string.Format("BillBoardSet.DestroyBuffers entered; vertexData {0}, indexData {1}, mainBuffer {2}", // vertexData == null ? "null" : vertexData.ToString(), // indexData == null ? "null" : indexData.ToString(), // mainBuffer == null ? "null" : mainBuffer.ToString())); this.vertexData = null; this.indexData = null; this.mainBuffer = null; this.buffersCreated = false; }
private void buildIndexData() { indexData = new IndexData(); int bufLength = width * height * 6; IndexType idxType = IndexType.Size32; if ((width * height) <= ushort.MaxValue) idxType = IndexType.Size16; indexData.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer( idxType, bufLength, BufferUsage.StaticWriteOnly); IntPtr indexBufferPtr = indexData.indexBuffer.Lock(0, indexData.indexBuffer.Size, BufferLocking.Discard); int indexCount = 0; int pos = 0; int i = 0; unsafe { if (idxType == IndexType.Size16) { ushort* indexBuffer = (ushort*)indexBufferPtr.ToPointer(); for (int z = 0; z < height - 1; z++) { for (int x = 0; x < width - 1; x++) { indexBuffer[pos++] = (ushort)i; indexBuffer[pos++] = (ushort)(i + width); indexBuffer[pos++] = (ushort)(i + 1); indexBuffer[pos++] = (ushort)(i + width); indexBuffer[pos++] = (ushort)(i + 1 + width); indexBuffer[pos++] = (ushort)(i + 1); i++; indexCount += 6; } i++; } } else { uint* indexBuffer = (uint*)indexBufferPtr.ToPointer(); for (int z = 0; z < height - 1; z++) { for (int x = 0; x < width - 1; x++) { indexBuffer[pos++] = (uint)i; indexBuffer[pos++] = (uint)(i + width); indexBuffer[pos++] = (uint)(i + 1); indexBuffer[pos++] = (uint)(i + width); indexBuffer[pos++] = (uint)(i + 1 + width); indexBuffer[pos++] = (uint)(i + 1); i++; indexCount += 6; } i++; } } } indexData.indexBuffer.Unlock(); indexData.indexCount = indexCount; indexData.indexStart = 0; return; }
/// <summary> /// Add a set of index geometry data to the edge builder. /// </summary> /// <remarks> /// You must add at least one set of index data to the builder before invoking the /// <see name="Build"/> method. /// </remarks> /// <param name="indexData">The index information which describes the triangles.</param> /// <param name="vertexSet"> /// The vertex data set this index data refers to; you only need to alter this /// if you have added multiple sets of vertices. /// </param> /// <param name="opType"></param> public void AddIndexData(IndexData indexData, int vertexSet, OperationType opType) { this.indexDataList.Add(indexData); this.indexDataVertexDataSetList.Add(vertexSet); this.operationTypes.Add(opType); }
/// <summary> /// Add a set of index geometry data to the edge builder. /// </summary> /// <remarks> /// You must add at least one set of index data to the builder before invoking the /// <see name="Build"/> method. /// </remarks> /// <param name="indexData">The index information which describes the triangles.</param> /// <param name="vertexSet"> /// The vertex data set this index data refers to; you only need to alter this /// if you have added multiple sets of vertices. /// </param> /// <param name="opType"></param> public void AddIndexData( IndexData indexData, int vertexSet, OperationType opType ) { indexDataList.Add( indexData ); indexDataVertexDataSetList.Add( vertexSet ); operationTypes.Add( opType ); }
/// <summary> /// Populate with data as obtained from an IRenderable. /// </summary> /// <remarks> /// Will share the buffers. /// In case there are no index data associated with the <see cref="IRenderable"/>, i.e. <see cref="RenderOperation.useIndices"/> is false, /// custom software index buffer is created to provide default index data to the builder. /// This makes it possible for derived classes to handle the data in a convenient way. /// </remarks> public void AddObject(IRenderable obj) { if (obj == null) { throw new ArgumentNullException(); } var renderOp = obj.RenderOperation; IndexData indexData; if (renderOp.useIndices) { indexData = renderOp.indexData; } else { //Create custom index buffer var vertexCount = renderOp.vertexData.vertexCount; var itype = vertexCount > UInt16.MaxValue ? IndexType.Size32 : IndexType.Size16; var ibuf = new DefaultHardwareIndexBuffer(itype, vertexCount, BufferUsage.Static); this.customIndexBufferList.Add(ibuf); //to be disposed later indexData = new IndexData(); indexData.indexBuffer = ibuf; indexData.indexCount = vertexCount; indexData.indexStart = 0; //Fill buffer with indices var ibuffer = indexData.indexBuffer.Lock(BufferLocking.Normal); try { #if !AXIOM_SAFE_ONLY unsafe #endif { var ibuf16 = ibuffer.ToShortPointer(); var ibuf32 = ibuffer.ToIntPointer(); for (var i = 0; i < indexData.indexCount; i++) { if (itype == IndexType.Size16) { ibuf16[i] = (Int16)i; } else { ibuf32[i] = i; } } } //unsafe } finally { indexData.indexBuffer.Unlock(); } } AddVertexData(renderOp.vertexData); AddIndexData(indexData, this.vertexDataList.Count - 1, renderOp.operationType); }
/// <summary> /// Builds the progressive mesh with the specified number of levels. /// </summary> public void Build(ushort numLevels, List<IndexData> lodFaceList, VertexReductionQuota quota, float reductionValue) { ComputeAllCosts(); // Init currNumIndexes = (uint)indexData.indexCount; // Use COMMON vert count, not original vert count // Since collapsing 1 common vert position is equivalent to collapsing them all uint numVerts = numCommonVertices; uint numCollapses = 0; bool abandon = false; while (numLevels-- != 0) { // NB if 'abandon' is set, we stop reducing // However, we still bake the number of LODs requested, even if it // means they are the same if (!abandon) { if (quota == VertexReductionQuota.Proportional) numCollapses = (uint)(numVerts * reductionValue); else numCollapses = (uint)reductionValue; // Minimum 3 verts! if ((numVerts - numCollapses) < 3) numCollapses = numVerts - 3; // Store new number of verts numVerts = numVerts - numCollapses; Debug.Assert(numVerts >= 3); while (numCollapses-- != 0 && !abandon) { int nextIndex = GetNextCollapser(); // Collapse on every buffer foreach (PMWorkingData data in workingDataList) { PMVertex collapser = data.vertList[nextIndex]; // This will reduce currNumIndexes and recalc costs as required if (collapser.collapseTo == null) { // Must have run out of valid collapsables abandon = true; break; } Debug.Assert(collapser.collapseTo.removed == false); Collapse(collapser); } } } // Bake a new LOD and add it to the list IndexData newLod = new IndexData(); BakeNewLOD(newLod); lodFaceList.Add(newLod); } }
/// <summary> /// Internal method for building PMWorkingData from geometry data /// </summary> void AddWorkingData(VertexData vertexData, IndexData indexData) { // Insert blank working data, then fill PMWorkingData work = new PMWorkingData(); this.workingDataList.Add(work); // Build vertex list // Resize face list (this will always be this big) work.faceVertList = new PMFaceVertex[vertexData.vertexCount]; // Also resize common vert list to max, to avoid reallocations work.vertList = new PMVertex[vertexData.vertexCount]; // locate position element & the buffer to go with it VertexElement posElem = vertexData.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Position); HardwareVertexBuffer vbuf = vertexData.vertexBufferBinding.GetBuffer(posElem.Source); // lock the buffer for reading IntPtr bufPtr = vbuf.Lock(BufferLocking.ReadOnly); uint numCommon = 0; unsafe { byte *pVertex = (byte *)bufPtr.ToPointer(); float* pFloat; Vector3 pos; // Map for identifying duplicate position vertices Dictionary<Vector3, uint> commonVertexMap = new Dictionary<Vector3,uint>(); for (uint i = 0; i < vertexData.vertexCount; ++i, pVertex += vbuf.VertexSize) { pFloat = (float *)(pVertex + posElem.Offset); pos.x = *pFloat++; pos.y = *pFloat++; pos.z = *pFloat++; work.faceVertList[(int)i] = new PMFaceVertex(); // Try to find this position in the existing map if (!commonVertexMap.ContainsKey(pos)) { // Doesn't exist, so create it PMVertex commonVert = new PMVertex(); commonVert.SetDetails(pos, numCommon); commonVert.removed = false; commonVert.toBeRemoved = false; commonVert.seam = false; // Add it to our working set work.vertList[(int)numCommon] = commonVert; // Enter it in the map commonVertexMap.Add(pos, numCommon); // Increment common index ++numCommon; work.faceVertList[(int)i].commonVertex = commonVert; work.faceVertList[(int)i].realIndex = i; } else { // Exists already, reference it PMVertex existingVert = work.vertList[(int)commonVertexMap[pos]]; work.faceVertList[(int)i].commonVertex = existingVert; work.faceVertList[(int)i].realIndex = i; // Also tag original as a seam since duplicates at this location work.faceVertList[(int)i].commonVertex.seam = true; } } } vbuf.Unlock(); numCommonVertices = numCommon; // Build tri list uint numTris = (uint)indexData.indexCount / 3; HardwareIndexBuffer ibuf = indexData.indexBuffer; bool use32bitindexes = (ibuf.Type == IndexType.Size32); IntPtr indexBufferPtr = ibuf.Lock(BufferLocking.ReadOnly); unsafe { ushort* pShort = null; uint* pInt = null; if (use32bitindexes) { pInt = (uint *)indexBufferPtr.ToPointer(); } else { pShort = (ushort *)indexBufferPtr.ToPointer(); } work.triList = new PMTriangle[(int)numTris]; // assumed tri list for (uint i = 0; i < numTris; ++i) { // use 32-bit index always since we're not storing uint vindex = use32bitindexes ? *pInt++ : *pShort++; PMFaceVertex v0 = work.faceVertList[(int)vindex]; vindex = use32bitindexes ? *pInt++ : *pShort++; PMFaceVertex v1 = work.faceVertList[(int)vindex]; vindex = use32bitindexes ? *pInt++ : *pShort++; PMFaceVertex v2 = work.faceVertList[(int)vindex]; work.triList[(int)i] = new PMTriangle(); work.triList[(int)i].SetDetails(i, v0, v1, v2); work.triList[(int)i].removed = false; } } ibuf.Unlock(); }
public BillboardChain( string name, int maxElements, int numberOfChains, bool useTextureCoords, bool useColors, bool dynamic ) : base( name ) { this.maxElementsPerChain = maxElements; this.chainCount = numberOfChains; this.useTexCoords = useTextureCoords; this.useVertexColor = useColors; this.dynamic = dynamic; this.vertexDeclDirty = true; this.buffersNeedRecreating = true; this.boundsDirty = true; this.indexContentDirty = true; this.radius = 0.0f; this.texCoordDirection = TexCoordDirection.U; this.vertexData = new VertexData(); this.indexData = new IndexData(); this.otherTexCoordRange[ 0 ] = 0.0f; this.otherTexCoordRange[ 1 ] = 1.0f; this.SetupChainContainers(); this.vertexData.vertexStart = 0; // index data setup later // set basic white material this.MaterialName = "BaseWhiteNoLighting"; }
/// <summary> /// Internal method builds an new LOD based on the current state /// </summary> /// <param name="indexData">Index data which will have an index buffer created and initialized</param> void BakeNewLOD(IndexData indexData) { Debug.Assert(currNumIndexes > 0, "No triangles to bake!"); // Zip through the tri list of any working data copy and bake indexData.indexCount = (int)currNumIndexes; indexData.indexStart = 0; // Base size of indexes on original bool use32bitindexes = (this.indexData.indexBuffer.Type == IndexType.Size32); // Create index buffer, we don't need to read it back or modify it a lot indexData.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer(this.indexData.indexBuffer.Type, indexData.indexCount, BufferUsage.StaticWriteOnly, false); IntPtr bufPtr = indexData.indexBuffer.Lock(BufferLocking.Discard); unsafe { ushort* pShort = null; uint* pInt = null; if (use32bitindexes) pInt = (uint *)bufPtr.ToPointer(); else pShort = (ushort *)bufPtr.ToPointer(); // Use the first working data buffer, they are all the same index-wise PMWorkingData work = this.workingDataList[0]; foreach (PMTriangle tri in work.triList) { if (!tri.removed) { if (use32bitindexes) { *pInt++ = tri.vertex[0].realIndex; *pInt++ = tri.vertex[1].realIndex; *pInt++ = tri.vertex[2].realIndex; } else { *pShort++ = (ushort)tri.vertex[0].realIndex; *pShort++ = (ushort)tri.vertex[1].realIndex; *pShort++ = (ushort)tri.vertex[2].realIndex; } } } } indexData.indexBuffer.Unlock(); }
/// <summary> /// Populate with data as obtained from an IRenderable. /// </summary> /// <remarks> /// Will share the buffers. /// In case there are no index data associated with the <see cref="IRenderable"/>, i.e. <see cref="RenderOperation.useIndices"/> is false, /// custom software index buffer is created to provide default index data to the builder. /// This makes it possible for derived classes to handle the data in a convenient way. /// </remarks> public void AddObject( IRenderable obj ) { if ( obj == null ) { throw new ArgumentNullException(); } var renderOp = obj.RenderOperation; IndexData indexData; if ( renderOp.useIndices ) { indexData = renderOp.indexData; } else { //Create custom index buffer var vertexCount = renderOp.vertexData.vertexCount; var itype = vertexCount > UInt16.MaxValue ? IndexType.Size32 : IndexType.Size16; var ibuf = new DefaultHardwareIndexBuffer( itype, vertexCount, BufferUsage.Static ); this.customIndexBufferList.Add( ibuf ); //to be disposed later indexData = new IndexData(); indexData.indexBuffer = ibuf; indexData.indexCount = vertexCount; indexData.indexStart = 0; //Fill buffer with indices var ibuffer = indexData.indexBuffer.Lock( BufferLocking.Normal ); try { #if !AXIOM_SAFE_ONLY unsafe #endif { var ibuf16 = ibuffer.ToShortPointer(); var ibuf32 = ibuffer.ToIntPointer(); for ( var i = 0; i < indexData.indexCount; i++ ) { if ( itype == IndexType.Size16 ) { ibuf16[ i ] = (Int16)i; } else { ibuf32[ i ] = i; } } } //unsafe } finally { indexData.indexBuffer.Unlock(); } } AddVertexData( renderOp.vertexData ); AddIndexData( indexData, this.vertexDataList.Count - 1, renderOp.operationType ); }
/// <summary> /// Constructor, takes the geometry data and index buffer. /// </summary> /// <remarks> /// DO NOT pass write-only, unshadowed buffers to this method! They will not /// work. Pass only shadowed buffers, or better yet perform mesh reduction as /// an offline process using DefaultHardwareBufferManager to manage vertex /// buffers in system memory. /// </remarks> /// <param name="vertexData"></param> /// <param name="indexData"></param> public ProgressiveMesh(VertexData vertexData, IndexData indexData) { AddWorkingData(vertexData, indexData); this.vertexData = vertexData; this.indexData = indexData; }
protected void AddSubmeshIndexData(IndexData indexData) { HardwareIndexBuffer indexBuffer = indexData.indexBuffer; IntPtr indices = indexBuffer.Lock(BufferLocking.ReadOnly); unsafe { if (indexBuffer.IndexSize == sizeof(ushort)) { ushort *pIdx = (ushort*)indices.ToPointer(); for (int i = 0; i < indexData.indexCount; ++i) { uint index = pIdx[indexData.indexStart + i]; if (!vertexIdMap.ContainsKey(index)) { uint nextId = (uint)vertexIdMap.Count; vertexIdMap[index] = nextId; } } } else if (indexBuffer.IndexSize == sizeof(uint)) { uint *pIdx = (uint*)indices.ToPointer(); for (int i = 0; i < indexData.indexCount; ++i) { uint index = pIdx[indexData.indexStart + i]; if (!vertexIdMap.ContainsKey(index)) { uint nextId = (uint)vertexIdMap.Count; vertexIdMap[index] = nextId; } } } else { Debug.Assert(false, "Invalid index buffer index size"); } } indexBuffer.Unlock(); }
/// <summary> /// Internal constructor, only allows creation of StitchRenderables within the scene manager. /// </summary> internal StitchRenderable(TerrainPatch terrainPatch, VertexData vertexData, IndexData indexData, int numSamples, int southMetersPerSample, int eastMetersPerSample) { renderDetail = SceneDetailLevel.Solid; parent = terrainPatch; renderOp = new RenderOperation(); renderOp.operationType = OperationType.TriangleList; renderOp.useIndices = true; renderOp.vertexData = vertexData; renderOp.indexData = indexData; isVisible = true; this.numSamples = numSamples; this.southMetersPerSample = southMetersPerSample; this.eastMetersPerSample = eastMetersPerSample; }
/// Internal method for generating triangle list terrain indexes public IndexData GenerateTriListIndexes( long stitchFlags, long RenderLevel, Renderable[] neighbors) { long step = (1L << (int)RenderLevel); long north = ((stitchFlags & (long)Stitch_Direction.North) != 0 ? step : 0); long south = ((stitchFlags & (long)Stitch_Direction.South) != 0 ? step : 0); long east = ((stitchFlags & (long)Stitch_Direction.East) != 0 ? step : 0); long west = ((stitchFlags & (long)Stitch_Direction.West) != 0 ? step : 0); long new_length = ( tileSize * tileSize * 6 ) / step; IndexData indexData = new IndexData(); indexData.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer(IndexType.Size16, (int)new_length, BufferUsage.StaticWriteOnly); cache.Add( indexData ); /** Returns the index into the height array for the given coordinates. */ IntPtr ipIdx = indexData.indexBuffer.Lock(0,indexData.indexBuffer.Size,BufferLocking.Discard); numIndexes = 0; long pos = 0; long step_offset = step * tileSize; long height_count = north * tileSize; unsafe { ushort* pIdx = (ushort *)ipIdx.ToPointer(); for (long j = north; j < tileSize - 1 - south; j += step ) { for (long i = west; i < tileSize - 1 - east; i += step ) { //triangles pIdx[pos++] = (ushort) (i + height_count); numIndexes++; pIdx[pos++] = (ushort) (i + height_count + step_offset); numIndexes++; pIdx[pos++] = (ushort) (i + step + height_count); numIndexes++; pIdx[pos++] = (ushort) (i + height_count + step_offset); numIndexes++; pIdx[pos++] = (ushort) (i + step + height_count + step_offset); numIndexes++; pIdx[pos++] = (ushort) (i + step + height_count); numIndexes++; } height_count += step_offset; } } // North stitching if ( north != 0 ) { numIndexes += StitchEdge(Neighbor.North, RenderLevel, neighbors[(int)Neighbor.North].RenderLevel, west > 0 , east > 0 , ipIdx,ref pos); } // East stitching if ( east != 0 ) { numIndexes += StitchEdge(Neighbor.East, RenderLevel, neighbors[(int)Neighbor.East].RenderLevel, north > 0, south > 0, ipIdx,ref pos); } // South stitching if ( south != 0 ) { numIndexes += StitchEdge(Neighbor.South, RenderLevel, neighbors[(int)Neighbor.South].RenderLevel, east > 0 , west > 0, ipIdx,ref pos); } // West stitching if ( west != 0 ) { numIndexes += StitchEdge(Neighbor.West, RenderLevel, neighbors[(int)Neighbor.West].RenderLevel, south > 0 , north > 0, ipIdx,ref pos); } indexData.indexBuffer.Unlock(); indexData.indexCount = (int)numIndexes; indexData.indexStart = 0; return indexData; }
public IndexData GenerateTriStripIndexes( uint stitchFlags ) { // The step used for the current level var step = 1 << this.mRenderLevel; // The step used for the lower level var lowstep = 1 << ( this.mRenderLevel + 1 ); var numIndexes = 0; // Calculate the number of indexes required // This is the number of 'cells' at this detail level x 2 // plus 3 degenerates to turn corners var numTrisAcross = ( ( ( this.mOptions.tileSize - 1 )/step )*2 ) + 3; // Num indexes is number of tris + 2 var new_length = numTrisAcross*( ( this.mOptions.tileSize - 1 )/step ) + 2; //this is the maximum for a level. It wastes a little, but shouldn't be a problem. var indexData = new IndexData(); indexData.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer( IndexType.Size16, new_length, BufferUsage.StaticWriteOnly ); //, false); this.mTerrainZone.IndexCache.mCache.Add( indexData ); #if !AXIOM_SAFE_ONLY unsafe #endif { var pIdx = indexData.indexBuffer.Lock( 0, indexData.indexBuffer.Size, BufferLocking.Discard ).ToUShortPointer(); var idx = 0; // Stripified mesh for ( var j = 0; j < this.mOptions.tileSize - 1; j += step ) { int i; // Forward strip // We just do the |/ here, final | done after for ( i = 0; i < this.mOptions.tileSize - 1; i += step ) { var x = new int[4]; var y = new int[4]; x[ 0 ] = x[ 1 ] = i; x[ 2 ] = x[ 3 ] = i + step; y[ 0 ] = y[ 2 ] = j; y[ 1 ] = y[ 3 ] = j + step; if ( j == 0 && ( stitchFlags & STITCH_NORTH ) != 0 ) { // North reduction means rounding x[0] and x[2] if ( x[ 0 ]%lowstep != 0 ) { // Since we know we only drop down one level of LOD, // removing 1 step of higher LOD should return to lower x[ 0 ] -= step; } if ( x[ 2 ]%lowstep != 0 ) { x[ 2 ] -= step; } } // Never get a south tiling on a forward strip (always finish on // a backward strip) if ( i == 0 && ( stitchFlags & STITCH_WEST ) != 0 ) { // West reduction means rounding y[0] / y[1] if ( y[ 0 ]%lowstep != 0 ) { y[ 0 ] -= step; } if ( y[ 1 ]%lowstep != 0 ) { y[ 1 ] -= step; } } if ( i == ( this.mOptions.tileSize - 1 - step ) && ( stitchFlags & STITCH_EAST ) != 0 ) { // East tiling means rounding y[2] & y[3] if ( y[ 2 ]%lowstep != 0 ) { y[ 2 ] -= step; } if ( y[ 3 ]%lowstep != 0 ) { y[ 3 ] -= step; } } //triangles if ( i == 0 ) { // Starter pIdx[ idx++ ] = (ushort)Index( x[ 0 ], y[ 0 ] ); numIndexes++; } pIdx[ idx++ ] = (ushort)Index( x[ 1 ], y[ 1 ] ); numIndexes++; pIdx[ idx++ ] = (ushort)Index( x[ 2 ], y[ 2 ] ); numIndexes++; if ( i == this.mOptions.tileSize - 1 - step ) { // Emit extra index to finish row pIdx[ idx++ ] = (ushort)Index( x[ 3 ], y[ 3 ] ); numIndexes++; if ( j < this.mOptions.tileSize - 1 - step ) { // Emit this index twice more (this is to turn around without // artefacts) // ** Hmm, looks like we can drop this and it's unnoticeable // *pIdx++ = ( ushort ) Index( x[ 3 ], y[ 3 ] ); numIndexes++; // *pIdx++ = ( ushort ) Index( x[ 3 ], y[ 3 ] ); numIndexes++; } } } // Increment row j += step; // Backward strip for ( i = this.mOptions.tileSize - 1; i > 0; i -= step ) { var x = new int[4]; var y = new int[4]; x[ 0 ] = x[ 1 ] = i; x[ 2 ] = x[ 3 ] = i - step; y[ 0 ] = y[ 2 ] = j; y[ 1 ] = y[ 3 ] = j + step; // Never get a north tiling on a backward strip (always // start on a forward strip) if ( j == ( this.mOptions.tileSize - 1 - step ) && ( stitchFlags & STITCH_SOUTH ) != 0 ) { // South reduction means rounding x[1] / x[3] if ( x[ 1 ]%lowstep != 0 ) { x[ 1 ] -= step; } if ( x[ 3 ]%lowstep != 0 ) { x[ 3 ] -= step; } } if ( i == step && ( stitchFlags & STITCH_WEST ) != 0 ) { // West tiling on backward strip is rounding of y[2] / y[3] if ( y[ 2 ]%lowstep != 0 ) { y[ 2 ] -= step; } if ( y[ 3 ]%lowstep != 0 ) { y[ 3 ] -= step; } } if ( i == this.mOptions.tileSize - 1 && ( stitchFlags & STITCH_EAST ) != 0 ) { // East tiling means rounding y[0] and y[1] on backward strip if ( y[ 0 ]%lowstep != 0 ) { y[ 0 ] -= step; } if ( y[ 1 ]%lowstep != 0 ) { y[ 1 ] -= step; } } //triangles if ( i == this.mOptions.tileSize ) { // Starter pIdx[ idx++ ] = (ushort)Index( x[ 0 ], y[ 0 ] ); numIndexes++; } pIdx[ idx++ ] = (ushort)Index( x[ 1 ], y[ 1 ] ); numIndexes++; pIdx[ idx++ ] = (ushort)Index( x[ 2 ], y[ 2 ] ); numIndexes++; if ( i == step ) { // Emit extra index to finish row pIdx[ idx++ ] = (ushort)Index( x[ 3 ], y[ 3 ] ); numIndexes++; if ( j < this.mOptions.tileSize - 1 - step ) { // Emit this index once more (this is to turn around) pIdx[ idx++ ] = (ushort)Index( x[ 3 ], y[ 3 ] ); numIndexes++; } } } } } indexData.indexBuffer.Unlock(); indexData.indexCount = numIndexes; indexData.indexStart = 0; return indexData; }
/// <summary> /// Allocate / reallocate vertex data /// Note that we allocate enough space for ALL the billboards in the pool, but only issue /// rendering operations for the sections relating to the active billboards /// </summary> private void CreateBuffers() { /* Alloc positions ( 1 or 4 verts per billboard, 3 components ) colours ( 1 x RGBA per vertex ) indices ( 6 per billboard ( 2 tris ) if not point rendering ) tex. coords ( 2D coords, 1 or 4 per billboard ) */ // LogManager.Instance.Write(string.Format("BillBoardSet.CreateBuffers entered; vertexData {0}, indexData {1}, mainBuffer {2}", // vertexData == null ? "null" : vertexData.ToString(), // indexData == null ? "null" : indexData.ToString(), // mainBuffer == null ? "null" : mainBuffer.ToString())); // Warn if user requested an invalid setup // Do it here so it only appears once if ( this.pointRendering && this.billboardType != BillboardType.Point ) { LogManager.Instance.Write( "Warning: BillboardSet {0} has point rendering enabled but is using a type " + "other than BillboardType.Point, this may not give you the results you " + "expect.", this.name ); } this.vertexData = new VertexData(); if ( this.pointRendering ) { this.vertexData.vertexCount = this.poolSize; } else { this.vertexData.vertexCount = this.poolSize * 4; } this.vertexData.vertexStart = 0; // Vertex declaration VertexDeclaration decl = this.vertexData.vertexDeclaration; VertexBufferBinding binding = this.vertexData.vertexBufferBinding; int offset = 0; decl.AddElement( 0, offset, VertexElementType.Float3, VertexElementSemantic.Position ); offset += VertexElement.GetTypeSize( VertexElementType.Float3 ); decl.AddElement( 0, offset, VertexElementType.Color, VertexElementSemantic.Diffuse ); offset += VertexElement.GetTypeSize( VertexElementType.Color ); // Texture coords irrelevant when enabled point rendering (generated // in point sprite mode, and unused in standard point mode) if ( !this.pointRendering ) { decl.AddElement( 0, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 0 ); } this.mainBuffer = HardwareBufferManager.Instance.CreateVertexBuffer( decl.Clone( 0 ), this.vertexData.vertexCount, BufferUsage.DynamicWriteOnlyDiscardable ); // bind position and diffuses binding.SetBinding( 0, this.mainBuffer ); if ( !this.pointRendering ) { this.indexData = new IndexData(); // calc index buffer size this.indexData.indexStart = 0; this.indexData.indexCount = this.poolSize * 6; // create the index buffer this.indexData.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer( IndexType.Size16, this.indexData.indexCount, BufferUsage.StaticWriteOnly ); /* Create indexes (will be the same every frame) Using indexes because it means 1/3 less vertex transforms (4 instead of 6) Billboard layout relative to camera: 0-----1 | /| | / | |/ | 2-----3 */ // lock the index buffer IntPtr idxPtr = this.indexData.indexBuffer.Lock( BufferLocking.Discard ); unsafe { ushort* pIdx = (ushort*)idxPtr.ToPointer(); for ( int idx, idxOffset, bboard = 0; bboard < this.poolSize; ++bboard ) { // Do indexes idx = bboard * 6; idxOffset = bboard * 4; pIdx[ idx ] = (ushort)idxOffset; // + 0;, for clarity pIdx[ idx + 1 ] = (ushort)( idxOffset + 2 ); pIdx[ idx + 2 ] = (ushort)( idxOffset + 1 ); pIdx[ idx + 3 ] = (ushort)( idxOffset + 1 ); pIdx[ idx + 4 ] = (ushort)( idxOffset + 2 ); pIdx[ idx + 5 ] = (ushort)( idxOffset + 3 ); } // for } // unsafe // unlock the buffers this.indexData.indexBuffer.Unlock(); } this.buffersCreated = true; }
public IndexData GenerateTriListIndexes( uint stitchFlags ) #endif { var numIndexes = 0; var step = 1 << this.mRenderLevel; IndexData indexData; var north = ( stitchFlags & STITCH_NORTH ) != 0 ? step : 0; var south = ( stitchFlags & STITCH_SOUTH ) != 0 ? step : 0; var east = ( stitchFlags & STITCH_EAST ) != 0 ? step : 0; var west = ( stitchFlags & STITCH_WEST ) != 0 ? step : 0; var new_length = ( this.mOptions.tileSize/step )*( this.mOptions.tileSize/step )*2*2*2; //this is the maximum for a level. It wastes a little, but shouldn't be a problem. indexData = new IndexData(); indexData.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer( IndexType.Size16, new_length, BufferUsage.StaticWriteOnly ); //, false); this.mTerrainZone.IndexCache.mCache.Add( indexData ); var ppIdx = indexData.indexBuffer.Lock( 0, indexData.indexBuffer.Size, BufferLocking.Discard ); var pIdx = ppIdx.ToUShortPointer(); var idx = 0; // Do the core vertices, minus stitches for ( var j = north; j < this.mOptions.tileSize - 1 - south; j += step ) { for ( var i = west; i < this.mOptions.tileSize - 1 - east; i += step ) { //triangles pIdx[ idx++ ] = Index( i, j + step ); numIndexes++; // original order: 2 pIdx[ idx++ ] = Index( i + step, j ); numIndexes++; // original order: 3 pIdx[ idx++ ] = Index( i, j ); numIndexes++; // original order: 1 pIdx[ idx++ ] = Index( i + step, j + step ); numIndexes++; // original order: 2 pIdx[ idx++ ] = Index( i + step, j ); numIndexes++; // original order: 3 pIdx[ idx++ ] = Index( i, j + step ); numIndexes++; // original order: 1 } } ppIdx.Ptr += idx*sizeof ( ushort ); // North stitching if ( north > 0 ) { numIndexes += StitchEdge( Neighbor.NORTH, this.mRenderLevel, this.mNeighbors[ (int)Neighbor.NORTH ].mRenderLevel, west > 0, east > 0, ppIdx ); } // East stitching if ( east > 0 ) { numIndexes += StitchEdge( Neighbor.EAST, this.mRenderLevel, this.mNeighbors[ (int)Neighbor.EAST ].mRenderLevel, north > 0, south > 0, ppIdx ); } // South stitching if ( south > 0 ) { numIndexes += StitchEdge( Neighbor.SOUTH, this.mRenderLevel, this.mNeighbors[ (int)Neighbor.SOUTH ].mRenderLevel, east > 0, west > 0, ppIdx ); } // West stitching if ( west > 0 ) { numIndexes += StitchEdge( Neighbor.WEST, this.mRenderLevel, this.mNeighbors[ (int)Neighbor.WEST ].mRenderLevel, south > 0, north > 0, ppIdx ); } indexData.indexBuffer.Unlock(); indexData.indexCount = numIndexes; indexData.indexStart = 0; return indexData; }
protected virtual void ReadMeshLodUsageGenerated( BinaryReader reader, int lodNum, ref MeshLodUsage usage ) { usage.ManualName = ""; usage.ManualMesh = null; // get one set of detail per submesh MeshChunkID chunkId; for ( var i = 0; i < this.mesh.SubMeshCount; i++ ) { chunkId = ReadChunk( reader ); if ( chunkId != MeshChunkID.MeshLODGenerated ) { throw new AxiomException( "Missing MeshLodGenerated chunk in '{0}'", this.mesh.Name ); } // get the current submesh var sm = this.mesh.GetSubMesh( i ); // drop another index data object into the list var indexData = new IndexData(); sm.lodFaceList[ lodNum - 1 ] = indexData; // number of indices indexData.indexCount = ReadInt( reader ); var is32bit = ReadBool( reader ); // create an appropriate index buffer and stuff in the data if ( is32bit ) { indexData.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer( IndexType.Size32, indexData.indexCount, this.mesh.IndexBufferUsage, this.mesh.UseIndexShadowBuffer ); // lock the buffer var data = indexData.indexBuffer.Lock( BufferLocking.Discard ); // stuff the data into the index buffer ReadInts( reader, indexData.indexCount, data ); // unlock the index buffer indexData.indexBuffer.Unlock(); } else { indexData.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer( IndexType.Size16, indexData.indexCount, this.mesh.IndexBufferUsage, this.mesh.UseIndexShadowBuffer ); // lock the buffer var data = indexData.indexBuffer.Lock( BufferLocking.Discard ); // stuff the data into the index buffer ReadShorts( reader, indexData.indexCount, data ); // unlock the index buffer indexData.indexBuffer.Unlock(); } } }
/// <summary> /// /// </summary> protected void Initialize() { // Create geometry int nvertices = this.slices*4; // n+1 planes int elemsize = 3*3; int dsize = elemsize*nvertices; int x; var indexData = new IndexData(); var vertexData = new VertexData(); var vertices = new float[dsize]; var coords = new float[4,2] { { 0.0f, 0.0f }, { 0.0f, 1.0f }, { 1.0f, 0.0f }, { 1.0f, 1.0f } }; for ( x = 0; x < this.slices; x++ ) { for ( int y = 0; y < 4; y++ ) { float xcoord = coords[ y, 0 ] - 0.5f; float ycoord = coords[ y, 1 ] - 0.5f; float zcoord = -( (float)x/(float)( this.slices - 1 ) - 0.5f ); // 1.0f .. a/(a+1) // coordinate vertices[ x*4*elemsize + y*elemsize + 0 ] = xcoord*( this.size/2.0f ); vertices[ x*4*elemsize + y*elemsize + 1 ] = ycoord*( this.size/2.0f ); vertices[ x*4*elemsize + y*elemsize + 2 ] = zcoord*( this.size/2.0f ); // normal vertices[ x*4*elemsize + y*elemsize + 3 ] = 0.0f; vertices[ x*4*elemsize + y*elemsize + 4 ] = 0.0f; vertices[ x*4*elemsize + y*elemsize + 5 ] = 1.0f; // tex vertices[ x*4*elemsize + y*elemsize + 6 ] = xcoord*Utility.Sqrt( 3.0f ); vertices[ x*4*elemsize + y*elemsize + 7 ] = ycoord*Utility.Sqrt( 3.0f ); vertices[ x*4*elemsize + y*elemsize + 8 ] = zcoord*Utility.Sqrt( 3.0f ); } } var faces = new short[this.slices*6]; for ( x = 0; x < this.slices; x++ ) { faces[ x*6 + 0 ] = (short)( x*4 + 0 ); faces[ x*6 + 1 ] = (short)( x*4 + 1 ); faces[ x*6 + 2 ] = (short)( x*4 + 2 ); faces[ x*6 + 3 ] = (short)( x*4 + 1 ); faces[ x*6 + 4 ] = (short)( x*4 + 2 ); faces[ x*6 + 5 ] = (short)( x*4 + 3 ); } //setup buffers vertexData.vertexStart = 0; vertexData.vertexCount = nvertices; VertexDeclaration decl = vertexData.vertexDeclaration; VertexBufferBinding bind = vertexData.vertexBufferBinding; int offset = 0; offset += decl.AddElement( 0, 0, VertexElementType.Float3, VertexElementSemantic.Position ).Size; offset += decl.AddElement( 0, offset, VertexElementType.Float3, VertexElementSemantic.Normal ).Size; offset += decl.AddElement( 0, offset, VertexElementType.Float3, VertexElementSemantic.TexCoords ).Size; HardwareVertexBuffer vertexBuffer = HardwareBufferManager.Instance.CreateVertexBuffer( decl, nvertices, BufferUsage.StaticWriteOnly ); bind.SetBinding( 0, vertexBuffer ); HardwareIndexBuffer indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer( IndexType.Size16, this.slices*6, BufferUsage.StaticWriteOnly ); indexData.indexBuffer = indexBuffer; indexData.indexCount = this.slices*6; indexData.indexStart = 0; indexBuffer.WriteData( 0, indexBuffer.Size, faces, true ); vertexBuffer.WriteData( 0, vertexBuffer.Size, vertices ); vertices = null; faces = null; // Now make the render operation renderOperation.operationType = OperationType.TriangleList; renderOperation.indexData = indexData; renderOperation.vertexData = vertexData; renderOperation.useIndices = true; // Create a brand new private material if ( !ResourceGroupManager.Instance.GetResourceGroups().Contains( "VolumeRendable" ) ) { ResourceGroupManager.Instance.CreateResourceGroup( "VolumeRendable" ); } var material = (Material)MaterialManager.Instance.Create( this.texture, "VolumeRendable" ); // Remove pre-created technique from defaults material.RemoveAllTechniques(); // Create a techinique and a pass and a texture unit Technique technique = material.CreateTechnique(); Pass pass = technique.CreatePass(); TextureUnitState textureUnit = pass.CreateTextureUnitState(); // Set pass parameters pass.SetSceneBlending( SceneBlendType.TransparentAlpha ); pass.DepthWrite = false; pass.CullingMode = CullingMode.None; pass.LightingEnabled = false; textureUnit.SetTextureAddressingMode( TextureAddressing.Clamp ); textureUnit.SetTextureName( this.texture, TextureType.ThreeD ); textureUnit.SetTextureFiltering( TextureFiltering.Trilinear ); this.unit = textureUnit; base.material = material; }
/// <summary> /// Clones this vertex data, potentially including replicating any index buffers. /// </summary> /// <param name="copyData"> /// If true, makes a copy the index buffer in addition to the definition. /// If false, the clone will refer to the same index buffer this object refers to. /// </param> /// <returns>A copy of this IndexData object.</returns> public IndexData Clone( bool copyData ) { IndexData clone = new IndexData(); if ( indexBuffer != null ) { if ( copyData ) { clone.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer( indexBuffer.Type, indexBuffer.IndexCount, indexBuffer.Usage, indexBuffer.HasShadowBuffer ); // copy all the existing buffer data clone.indexBuffer.CopyData( indexBuffer, 0, 0, indexBuffer.Size, true ); } else { clone.indexBuffer = indexBuffer; } } clone.indexStart = indexStart; clone.indexCount = indexCount; return clone; }
protected void buildVertexData() { // accumulate the number of verts and triangles from the patches int numVerts = 0; int numTriangles = 0; for (int z = 0; z < numTiles; z++) { for (int x = 0; x < numTiles; x++) { numVerts += terrainPatches[x, z].NumVerts; numTriangles += terrainPatches[x, z].NumTriangles; } } // // Create the vertex buffer // VertexData localVertexData = new VertexData(); localVertexData.vertexCount = numVerts; localVertexData.vertexStart = 0; // free the original vertex declaration to avoid a leak HardwareBufferManager.Instance.DestroyVertexDeclaration(localVertexData.vertexDeclaration); localVertexData.vertexDeclaration = terrainVertexDeclaration; // create the hardware vertex buffer and set up the buffer binding HardwareVertexBuffer hvBuffer = HardwareBufferManager.Instance.CreateVertexBuffer( localVertexData.vertexDeclaration.GetVertexSize(0), localVertexData.vertexCount, BufferUsage.StaticWriteOnly, false); localVertexData.vertexBufferBinding.SetBinding(0, hvBuffer); renderOp.vertexData = localVertexData; // // Create the index buffer // IndexData localIndexData = new IndexData(); localIndexData.indexCount = numTriangles * 3; localIndexData.indexStart = 0; localIndexData.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer( IndexType.Size16, localIndexData.indexCount, BufferUsage.StaticWriteOnly); renderOp.indexData = localIndexData; // lock the vertex and index buffers IntPtr vertexBufferPtr = hvBuffer.Lock(BufferLocking.Discard); IntPtr indexBufferPtr = localIndexData.indexBuffer.Lock(BufferLocking.Discard); int vertOff = 0; int indexOff = 0; for (int z = 0; z < numTiles; z++) { for (int x = 0; x < numTiles; x++) { TerrainPatch patch = terrainPatches[x, z]; int nv = patch.NumVerts; int nt = patch.NumTriangles; patch.BuildVertexIndexData(vertexBufferPtr, vertOff, indexBufferPtr, indexOff); // update buffer offsets vertOff += nv * VertexSize; indexOff += (3 * nt); } } // unlock the buffers localIndexData.indexBuffer.Unlock(); hvBuffer.Unlock(); }
public void AddIndexData( IndexData indexData, int vertexSet ) { AddIndexData( indexData, vertexSet, OperationType.TriangleList ); }
private void BuildBuffers() { // // Build the vertex buffer // List<Vector2> points = boundary.Points; List<int[]> indices = boundary.Triangles; VertexData vertexData = new VertexData(); vertexData.vertexCount = boundary.Points.Count; vertexData.vertexStart = 0; // set up the vertex declaration int vDecOffset = 0; vertexData.vertexDeclaration.AddElement(0, vDecOffset, VertexElementType.Float3, VertexElementSemantic.Position); vDecOffset += VertexElement.GetTypeSize(VertexElementType.Float3); vertexData.vertexDeclaration.AddElement(0, vDecOffset, VertexElementType.Float3, VertexElementSemantic.Normal); vDecOffset += VertexElement.GetTypeSize(VertexElementType.Float3); vertexData.vertexDeclaration.AddElement(0, vDecOffset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 0); vDecOffset += VertexElement.GetTypeSize(VertexElementType.Float2); // create the hardware vertex buffer and set up the buffer binding HardwareVertexBuffer hvBuffer = HardwareBufferManager.Instance.CreateVertexBuffer( vertexData.vertexDeclaration.GetVertexSize(0), vertexData.vertexCount, BufferUsage.StaticWriteOnly, false); vertexData.vertexBufferBinding.SetBinding(0, hvBuffer); // lock the vertex buffer IntPtr ipBuf = hvBuffer.Lock(BufferLocking.Discard); int bufferOff = 0; float minx = boundary.Bounds.Minimum.x; float minz = boundary.Bounds.Minimum.z; unsafe { float* buffer = (float*)ipBuf.ToPointer(); for (int v = 0; v < vertexData.vertexCount; v++) { // Position buffer[bufferOff++] = points[v].x; buffer[bufferOff++] = height; buffer[bufferOff++] = points[v].y; // normals buffer[bufferOff++] = 0; buffer[bufferOff++] = 1; buffer[bufferOff++] = 0; // Texture float tmpu = ( points[v].x - minx ) / (128 * TerrainManager.oneMeter); float tmpv = ( points[v].y - minz )/ (128 * TerrainManager.oneMeter); buffer[bufferOff++] = tmpu; buffer[bufferOff++] = tmpv; } } hvBuffer.Unlock(); // // build the index buffer // IndexData indexData = new IndexData(); int numIndices = indices.Count * 3; indexData.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer( IndexType.Size16, numIndices, BufferUsage.StaticWriteOnly); IntPtr indexBufferPtr = indexData.indexBuffer.Lock(0, indexData.indexBuffer.Size, BufferLocking.Discard); unsafe { ushort* indexBuffer = (ushort*)indexBufferPtr.ToPointer(); for (int i = 0; i < indices.Count; i++) { indexBuffer[i * 3] = (ushort)indices[i][0]; indexBuffer[i * 3 + 1] = (ushort)indices[i][1]; indexBuffer[i * 3 + 2] = (ushort)indices[i][2]; } } indexData.indexBuffer.Unlock(); indexData.indexCount = numIndices; indexData.indexStart = 0; renderOp = new RenderOperation(); renderOp.vertexData = vertexData; renderOp.indexData = indexData; renderOp.operationType = OperationType.TriangleList; renderOp.useIndices = true; }
/// <summary> /// Populate with data as obtained from an IRenderable. /// </summary> /// <remarks> /// Will share the buffers. /// In case there are no index data associated with the <see cref="IRenderable"/>, i.e. <see cref="RenderOperation.useIndices"/> is false, /// custom software index buffer is created to provide default index data to the builder. /// This makes it possible for derived classes to handle the data in a convenient way. /// </remarks> public void AddObject( IRenderable obj ) { if ( obj == null ) throw new ArgumentNullException(); RenderOperation renderOp = obj.RenderOperation; IndexData indexData; if ( renderOp.useIndices ) { indexData = renderOp.indexData; } else { //Create custom index buffer int vertexCount = renderOp.vertexData.vertexCount; IndexType itype = vertexCount > UInt16.MaxValue ? IndexType.Size32 : IndexType.Size16; DefaultHardwareIndexBuffer ibuf = new DefaultHardwareIndexBuffer( itype, vertexCount, BufferUsage.Static ); customIndexBufferList.Add( ibuf ); //to be disposed later indexData = new IndexData(); indexData.indexBuffer = ibuf; indexData.indexCount = vertexCount; indexData.indexStart = 0; //Fill buffer with indices IntPtr ibuffer = indexData.indexBuffer.Lock( BufferLocking.Normal ); try { unsafe { Int16* ibuf16 = (Int16*)ibuffer; Int32* ibuf32 = (Int32*)ibuffer; for ( int i = 0; i < indexData.indexCount; i++ ) { if ( itype == IndexType.Size16 ) { ibuf16[ i ] = (Int16)i; } else { ibuf32[ i ] = i; } } } //unsafe } finally { indexData.indexBuffer.Unlock(); } } AddVertexData( renderOp.vertexData ); AddIndexData( indexData, vertexDataList.Count - 1, renderOp.operationType ); }
/// <summary> /// /// </summary> /// <param name="indexSet"></param> /// <param name="vertexSet"></param> protected void BuildTrianglesEdges(int indexSet, int vertexSet) { IndexData indexData = (IndexData)indexDataList[indexSet]; OperationType opType = operationTypes[indexSet]; int iterations = 0; switch (opType) { case OperationType.TriangleList: iterations = indexData.indexCount / 3; break; case OperationType.TriangleFan: case OperationType.TriangleStrip: iterations = indexData.indexCount - 2; break; } // locate postion element & the buffer to go with it VertexData vertexData = (VertexData)vertexDataList[vertexSet]; VertexElement posElem = vertexData.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Position); HardwareVertexBuffer posBuffer = vertexData.vertexBufferBinding.GetBuffer(posElem.Source); IntPtr posPtr = posBuffer.Lock(BufferLocking.ReadOnly); IntPtr idxPtr = indexData.indexBuffer.Lock(BufferLocking.ReadOnly); unsafe { byte *pBaseVertex = (byte *)posPtr.ToPointer(); short *p16Idx = null; int * p32Idx = null; // counters used for pointer indexing int count16 = 0; int count32 = 0; if (indexData.indexBuffer.Type == IndexType.Size16) { p16Idx = (short *)idxPtr.ToPointer(); } else { p32Idx = (int *)idxPtr.ToPointer(); } float *pReal = null; int triStart = edgeData.triangles.Count; // iterate over all the groups of 3 indices edgeData.triangles.Capacity = triStart + iterations; for (int t = 0; t < iterations; t++) { EdgeData.Triangle tri = new EdgeData.Triangle(); tri.indexSet = indexSet; tri.vertexSet = vertexSet; int[] index = new int[3]; Vector3[] v = new Vector3[3]; for (int i = 0; i < 3; i++) { // Standard 3-index read for tri list or first tri in strip / fan if (opType == OperationType.TriangleList || t == 0) { if (indexData.indexBuffer.Type == IndexType.Size32) { index[i] = p32Idx[count32++]; } else { index[i] = p16Idx[count16++]; } } else { // Strips and fans are formed from last 2 indexes plus the // current one for triangles after the first if (indexData.indexBuffer.Type == IndexType.Size32) { index[i] = p32Idx[i - 2]; } else { index[i] = p16Idx[i - 2]; } // Perform single-index increment at the last tri index if (i == 2) { if (indexData.indexBuffer.Type == IndexType.Size32) { count32++; } else { count16++; } } } // populate tri original vertex index tri.vertIndex[i] = index[i]; // Retrieve the vertex position byte *pVertex = pBaseVertex + (index[i] * posBuffer.VertexSize); pReal = (float *)(pVertex + posElem.Offset); v[i].x = *pReal++; v[i].y = *pReal++; v[i].z = *pReal++; // find this vertex in the existing vertex map, or create it tri.sharedVertIndex[i] = FindOrCreateCommonVertex(v[i], vertexSet, indexSet, index[i]); } // Calculate triangle normal (NB will require recalculation for // skeletally animated meshes) tri.normal = MathUtil.CalculateFaceNormal(v[0], v[1], v[2]); // Add triangle to list edgeData.triangles.Add(tri); try { // create edges from common list if (tri.sharedVertIndex[0] < tri.sharedVertIndex[1]) { CreateEdge(vertexSet, triStart + t, tri.vertIndex[0], tri.vertIndex[1], tri.sharedVertIndex[0], tri.sharedVertIndex[1]); } if (tri.sharedVertIndex[1] < tri.sharedVertIndex[2]) { CreateEdge(vertexSet, triStart + t, tri.vertIndex[1], tri.vertIndex[2], tri.sharedVertIndex[1], tri.sharedVertIndex[2]); } if (tri.sharedVertIndex[2] < tri.sharedVertIndex[0]) { CreateEdge(vertexSet, triStart + t, tri.vertIndex[2], tri.vertIndex[0], tri.sharedVertIndex[2], tri.sharedVertIndex[0]); } } catch (Exception ex) { //Debug.WriteLine(ex.ToString()); //Debug.WriteLine(ex.StackTrace); // unlock those buffers! indexData.indexBuffer.Unlock(); posBuffer.Unlock(); throw ex; } } // for iterations } // unsafe // unlock those buffers! indexData.indexBuffer.Unlock(); posBuffer.Unlock(); }