/// <summary> /// Sets the vertex data from an array source. /// </summary> /// <typeparam name="T">The type of data in the vertex buffer.</typeparam> /// <param name="data">Array that holds the vertex data</param> /// <param name="startIndex">Starting index of the element in the array at which to start copying from</param> /// <param name="elementCount">Number of elements to copy from the array</param> /// <param name="writeOptions">Writing options for the vertex buffer. None, discard, or no overwrite.</param> /// <exception cref="System.ArgumentNullException">Thrown if the data is null.</exception> /// <exception cref="Tesla.Core.TeslaException">Thrown if there is an error writing to the vertex buffer /// or arguments are invalid, check the inner exception for additional details.</exception> /// <remarks>See implementors for details on other exceptions that can be thrown.</remarks> public void SetData <T>(T[] data, int startIndex, int elementCount, DataWriteOptions writeOptions) where T : struct { if (data == null || data.Length == 0) { throw new ArgumentNullException("Data cannot be null."); } try { _impl.SetData <T>(data, startIndex, elementCount, 0, 0, writeOptions); } catch (Exception e) { throw new TeslaException("Error writing to vertex buffer: \n" + e.Message, e); } }
/// <summary> /// Sets the vertex data from an array source. /// </summary> /// <typeparam name="T">The type of data in the vertex buffer.</typeparam> /// <param name="data">Array that holds the vertex data</param> /// <param name="startIndex">Starting index of the element in the array at which to start copying from</param> /// <param name="elementCount">Number of elements to copy from the array</param> /// <param name="offsetInBytes">Offset in bytes from the beginning of the vertex buffer to the data.</param> /// <param name="vertexStride">Size of an element in bytes.</param> /// <param name="writeOptions">Writing options for the vertex buffer. None, discard, or no overwrite.</param> /// <remarks>See implementors for exceptions that may occur.</remarks> public abstract void SetData <T>(T[] data, int startIndex, int elementCount, int offsetInBytes, int vertexStride, DataWriteOptions writeOptions) where T : struct;
private void OnRenderBatch(Texture2D texture, Sprite[] sprites, int index, int numBatches) { float scaleWidth = 1f / (float)texture.Width; float scaleHeight = 1f / (float)texture.Height; //Setup the vertices for all the batches. The vertexbuffer acts like a wrap around queue while (numBatches > 0) { DataWriteOptions writeOptions = DataWriteOptions.NoOverwrite; int actCount = numBatches; if (actCount > MaxBatchSize - _spriteVbPos) { //Need to split up, so set actual count to the remaining space actCount = MaxBatchSize - _spriteVbPos; //Need to check if actually we've reached the end of the VB, //if so we need to wrap around and set discard if (_spriteVbPos % MaxBatchSize == 0) { writeOptions = DataWriteOptions.Discard; _spriteVbPos = 0; //Reset actual count to the maximum space available, either //requested batch number, or max batch size - whichever is smallest actCount = System.Math.Min(MaxBatchSize, numBatches); } } //Loop through sprite array, create the geometry for (int i = index, j = 0; i < index + actCount; i++) { Sprite sprite = sprites[i]; float cos = 1.0f; float sin = 0.0f; float angle = sprite.Angle; if (angle != 0.0f) { cos = (float)System.Math.Cos(angle); sin = (float)System.Math.Sin(angle); } Vector4 scOffsets = sprite.ScreenOffsets; float sx = scOffsets.X; float sy = scOffsets.Y; float sw = scOffsets.Z; float sh = scOffsets.W; Vector4 texOffsets = sprite.TextureOffsets; float tu = texOffsets.X * scaleWidth; float tv = texOffsets.Y * scaleHeight; float tw = texOffsets.Z * scaleWidth; float th = texOffsets.W * scaleHeight; Vector2 origin = sprite.Origin; float oriX = origin.X / texOffsets.Z; float oriY = origin.Y / texOffsets.W; bool flipH = (sprite.FlipEffect & SpriteFlipEffect.FlipHorizontally) == SpriteFlipEffect.FlipHorizontally; bool flipV = (sprite.FlipEffect & SpriteFlipEffect.FlipVertically) == SpriteFlipEffect.FlipVertically; float z = sprite.OrthoOrder; //Apply change of origin to screen width/height for rotations float sw1 = -oriX * sw; float sw2 = (1 - oriX) * sw; float sh1 = -oriY * sh; float sh2 = (1 - oriY) * sh; //top-left Vector3 v = new Vector3((sx + (sw1 * cos)) - (sh1 * sin), (sy + (sw1 * sin)) + (sh1 * cos), z); Vector2 uv = new Vector2(tu, tv); if (flipH) { uv.X = 1.0f - uv.X; } if (flipV) { uv.Y = 1.0f - uv.Y; } _vertices[j++] = new VertexPositionColorTexture( v, sprite.Color, uv ); //lower-left v = new Vector3((sx + (sw1 * cos)) - (sh2 * sin), (sy + (sw1 * sin)) + (sh2 * cos), z); uv = new Vector2(tu, tv + th); if (flipH) { uv.X = 1.0f - uv.X; } if (flipV) { uv.Y = 1.0f - uv.Y; } _vertices[j++] = new VertexPositionColorTexture( v, sprite.Color, uv ); //lower-right v = new Vector3((sx + (sw2 * cos)) - (sh2 * sin), (sy + (sw2 * sin)) + (sh2 * cos), z); uv = new Vector2(tu + tw, tv + th); if (flipH) { uv.X = 1.0f - uv.X; } if (flipV) { uv.Y = 1.0f - uv.Y; } _vertices[j++] = new VertexPositionColorTexture( v, sprite.Color, uv ); //upper-right v = new Vector3((sx + (sw2 * cos)) - (sh1 * sin), (sy + (sw2 * sin)) + (sh1 * cos), z); uv = new Vector2(tu + tw, tv); if (flipH) { uv.X = 1.0f - uv.X; } if (flipV) { uv.Y = 1.0f - uv.Y; } _vertices[j++] = new VertexPositionColorTexture( v, sprite.Color, uv ); } //Write to VB int stride = VertexPositionColorTexture.SizeInBytes; int offset = _spriteVbPos * stride * 4; _vertexBuffer.SetData <VertexPositionColorTexture>(_vertices, 0, actCount * 4, offset, stride, writeOptions); //Render _renderer.DrawIndexed(PrimitiveType.TriangleList, actCount * 6, _spriteVbPos * 6, 0); index += actCount; _spriteVbPos += actCount; numBatches -= actCount; } }
public override void SetData <T>(T[] data, int startIndex, int elementCount, int offsetInBytes, DataWriteOptions writeOptions) { throw new NotImplementedException(); }
/// <summary> /// Writes data from the array to the index buffer. /// </summary> /// <typeparam name="T">The type of data in the index buffer - int or short.</typeparam> /// <param name="data">Array to copy the data from</param> /// <param name="startIndex">Starting index in the array at which to start copying from</param> /// <param name="elementCount">Number of indices to write</param> /// <param name="offsetInBytes">Offset from the start of the index buffer at which to start writing at</param> /// <param name="writeOptions">Write options, used only if this is a dynamic buffer. None, discard, no overwrite</param> /// <remarks>See implementors for exceptions that may occur.</remarks> public override void SetData <T>(T[] data, int startIndex, int elementCount, int offsetInBytes, DataWriteOptions writeOptions) { if (_buffer == null || _buffer.Disposed) { throw new ObjectDisposedException(GetType().Name); } //Throws null or out of range exception D3D10Helper.CheckArrayBounds(data, startIndex, elementCount); int numBytes = MemoryHelper.SizeOf <T>(); int ibSize = base.IndexCount * ((base.IndexFormat == IndexFormat.SixteenBits) ? 2 : 4); int dataSize = elementCount * numBytes; if (offsetInBytes < 0 || offsetInBytes > ibSize) { throw new ArgumentOutOfRangeException("offsetInBytes", "Byte offset is out of range."); } if ((offsetInBytes + dataSize) > ibSize) { throw new ArgumentOutOfRangeException("data", "Byte offset and the number of elements to write will cause a buffer overflow."); } bool usesStaging = false; if (base.BufferUsage == ResourceUsage.Static || writeOptions == DataWriteOptions.None) { CreateStaging(); usesStaging = true; } try { if (usesStaging) { using (SDX.DataStream ds = _staging.Map(D3D.MapMode.Write, D3D.MapFlags.None)) { ds.Position = offsetInBytes; ds.WriteRange <T>(data, startIndex, elementCount); _staging.Unmap(); //If we're writing to the entire IB just copy the whole thing if (offsetInBytes == 0 && startIndex == 0 && dataSize == ibSize) { _graphicsDevice.CopyResource(_staging, _buffer); } else { D3D.ResourceRegion region = new D3D.ResourceRegion(); region.Left = offsetInBytes; region.Right = offsetInBytes + dataSize; region.Front = region.Top = 0; region.Back = region.Bottom = 1; _graphicsDevice.CopySubresourceRegion(_staging, 0, region, _buffer, 0, offsetInBytes, 0, 0); } } } else { D3D.MapMode mode = (writeOptions == DataWriteOptions.Discard) ? D3D.MapMode.WriteDiscard : D3D.MapMode.WriteNoOverwrite; using (SDX.DataStream ds = _buffer.Map(mode, D3D.MapFlags.None)) { ds.Position = offsetInBytes; ds.WriteRange <T>(data, startIndex, elementCount); _buffer.Unmap(); } } } catch (Exception e) { throw new TeslaException("Error writing to D3D10 Buffer.", e); } }
/// <summary> /// Draws a portion of the mesh's tangent basis. /// </summary> /// <param name="mesh">Mesh to accumulate data from</param> /// <param name="renderer">The renderer</param> /// <param name="basisIndex">Specifies which lines to render: 0 for normals, 1 for tangents, 2 for binormals.</param> public void Draw(Mesh mesh, IRenderer renderer, int basisIndex) { //Check if we have the proper data MeshData md = mesh.MeshData; if (md == null) { return; } DataBuffer <Vector3> positions = md.Positions; DataBuffer <Vector3> normals = null; switch (basisIndex) { case 0: normals = md.Normals; break; case 1: normals = md.Tangents; break; case 2: normals = md.Binormals; break; } if (positions == null || normals == null) { return; } bool useIndices = md.UseIndexedPrimitives; bool useShortIndices = md.UsingShortIndices; DataBuffer indices = md.Indices; //Setup scaling float scale = 1.0f; if (mesh.WorldBounding != null) { _measureBox.Set(mesh.WorldBounding); scale = _scaleRatio * (_measureBox.Extents.Length() / 6); } else { scale *= 5f; } //Apply material _material.ApplyMaterial(renderer, mesh); renderer.SetVertexBuffer(_vertexBuffer); //Setup batches + render int numBatches = (useIndices) ? md.IndexCount : md.VertexCount; int index = 0; while (numBatches > 0) { DataWriteOptions options = DataWriteOptions.NoOverwrite; int actCount = numBatches; //Check if we need to split up if (actCount > MaxBatchSize - _lineVbPos) { //Need to split up, so get the available space actCount = MaxBatchSize - _lineVbPos; //Need to check if we've reached the end of the VB, if so //must have write discard to not cause a pipeline stall if (_lineVbPos % MaxBatchSize == 0) { options = DataWriteOptions.Discard; _lineVbPos = 0; //Reset actual count to the maximum space available, either //requested batch number, or max batch size - whichever is smallest actCount = System.Math.Min(MaxBatchSize, numBatches); } } if (useIndices) { if (useShortIndices) { DataBuffer <short> shortIndices = (DataBuffer <short>)indices; //Loop through mesh vertices and create the geometry for (int i = index, j = 0; i < index + actCount; i++) { Vector3 position = positions.Get(shortIndices.Get(i)); Vector3 normal = normals.Get(shortIndices.Get(i)); Vector3 position2; Vector3.Multiply(ref normal, scale, out position2); Vector3.Add(ref position, ref position2, out position2); _vertices[j++] = new VertexPositionColor(position, _baseColor); _vertices[j++] = new VertexPositionColor(position2, _tipColor); } } else { DataBuffer <int> intIndices = (DataBuffer <int>)indices; //Loop through mesh vertices and create the geometry for (int i = index, j = 0; i < index + actCount; i++) { Vector3 position = positions.Get(intIndices.Get(i)); Vector3 normal = normals.Get(intIndices.Get(i)); Vector3 position2; Vector3.Multiply(ref normal, scale, out position2); Vector3.Add(ref position, ref position2, out position2); _vertices[j++] = new VertexPositionColor(position, _baseColor); _vertices[j++] = new VertexPositionColor(position2, _tipColor); } } } else { //Loop through mesh vertices and create the geometry for (int i = index, j = 0; i < index + actCount; i++) { Vector3 position = positions.Get(i); Vector3 normal = normals.Get(i); Vector3 position2; Vector3.Multiply(ref normal, scale, out position2); Vector3.Add(ref position, ref position2, out position2); _vertices[j++] = new VertexPositionColor(position, _baseColor); _vertices[j++] = new VertexPositionColor(position2, _tipColor); } } //Write to VB int stride = VertexPositionColor.SizeInBytes; int offset = _lineVbPos * stride * 2; _vertexBuffer.SetData <VertexPositionColor>(_vertices, 0, actCount * 2, offset, stride, options); //Render for (int i = 0; i < _material.PassCount; i++) { _material.ApplyPass(renderer, i); renderer.Draw(PrimitiveType.LineList, actCount * 2, _lineVbPos * 2); } //Increment/decrement and prepare for the next iteration index += actCount; _lineVbPos += actCount; numBatches -= actCount; } }
/// <summary> /// Writes data from the array to the index buffer. /// </summary> /// <typeparam name="T">The type of data in the index buffer - int or short.</typeparam> /// <param name="data">Array to copy the data from</param> /// <param name="startIndex">Starting index in the array at which to start copying from</param> /// <param name="elementCount">Number of indices to write</param> /// <param name="offsetInBytes">Offset from the start of the index buffer at which to start writing at</param> /// <param name="writeOptions">Write options, used only if this is a dynamic buffer. None, discard, no overwrite</param> /// <remarks>See implementors for exceptions that may occur.</remarks> public override void SetData <T>(T[] data, int startIndex, int elementCount, int offsetInBytes, DataWriteOptions writeOptions) { if (base.BufferUsage == ResourceUsage.Static) { _indexBuffer.SetData <T>(offsetInBytes, data, startIndex, elementCount); } else { if (writeOptions == DataWriteOptions.None) { ((XFG.DynamicIndexBuffer)_indexBuffer).SetData <T>(offsetInBytes, data, startIndex, elementCount, XFG.SetDataOptions.None); } else { XFG.SetDataOptions mode = (writeOptions == DataWriteOptions.Discard) ? XFG.SetDataOptions.Discard : XFG.SetDataOptions.NoOverwrite; ((XFG.DynamicIndexBuffer)_indexBuffer).SetData <T>(offsetInBytes, data, startIndex, elementCount, mode); } } }
/// <summary> /// Sets the vertex data from an array source. /// </summary> /// <typeparam name="T">The type of data in the vertex buffer.</typeparam> /// <param name="data">Array that holds the vertex data</param> /// <param name="startIndex">Starting index of the element in the array at which to start copying from</param> /// <param name="elementCount">Number of elements to copy from the array</param> /// <param name="offsetInBytes">Offset in bytes from the beginning of the vertex buffer to the data.</param> /// <param name="vertexStride">Size of an element in bytes.</param> /// <param name="writeOptions">Writing options for the vertex buffer. None, discard, or no overwrite.</param> /// <exception cref="System.ObjectDisposedException">Thrown if Dispose() has been called.</exception> /// <exception cref="System.InvalidOperationException">Thrown if the write options are incompatible with the resource usage of the buffer.</exception> /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the data's vertex stride is too small, the offset in bytes is out of range, /// or the byte offset and number of elements to write will cause overflow.</exception> /// <exception cref="Tesla.Core.TeslaException">Thrown if there was an error writing to the buffer.</exception> public override void SetData <T>(T[] data, int startIndex, int elementCount, int offsetInBytes, int vertexStride, DataWriteOptions writeOptions) { if (_buffer == null || _buffer.Disposed) { throw new ObjectDisposedException(GetType().Name); } //Throw an error if an invalid write options is specified if (base.BufferUsage == ResourceUsage.Static && writeOptions != DataWriteOptions.None) { throw new InvalidOperationException("Can only specify write options other than DataWriteOptions.None for dynamic vertex buffers."); } //Check if array bounds are out of range D3D10Helper.CheckArrayBounds(data, startIndex, elementCount); VertexDeclaration vertexDecl = base.VertexDeclaration; int vertexCount = base.VertexCount; int vbSize = vertexCount * vertexDecl.VertexStride; int elemSize = MemoryHelper.SizeOf <T>(); int dataSize = elementCount * elemSize; int vertexStep = vertexStride; if (vertexStride != 0) { vertexStep -= elemSize; if (vertexStep < 0) { throw new ArgumentOutOfRangeException("vertexStride", "Vertex stride is too small for requested data size."); } //If we get this far, we need to make sure the actual bytes we're going to look at matches up, //since we can grab specific parts of a vertex and not the whole thing if (elementCount > 1) { dataSize = ((elementCount - 1) * vertexStep) + dataSize; } } //Prevent overflow out of range errors if ((offsetInBytes < 0) || (offsetInBytes > vbSize)) { throw new ArgumentOutOfRangeException("offsetInbytes", "Byte offset is out of range."); } if ((offsetInBytes + dataSize) > vbSize) { throw new ArgumentOutOfRangeException("data", "Byte offset and elements to write will cause in buffer overflow."); } //Create scratch buffer, if it hasn't been created already bool usesStaging = false; if (base.BufferUsage == ResourceUsage.Static || writeOptions == DataWriteOptions.None) { CreateStaging(); usesStaging = true; } try { if (usesStaging) { //If we're not going to be writing the entire vertex structure, we need to first //copy the contents of the affected vertex data into the staging buffer if (vertexStep != vertexStride) { //If we're going to be working with all the verts, no need to copy a subresource region if (offsetInBytes == 0 && startIndex == 0 && vertexCount == data.Length) { _graphicsDevice.CopyResource(_buffer, _staging); } else { D3D.ResourceRegion region = new D3D.ResourceRegion(); region.Left = offsetInBytes; region.Right = offsetInBytes + dataSize; region.Front = region.Top = 0; region.Back = region.Bottom = 1; _graphicsDevice.CopySubresourceRegion(_buffer, 0, region, _staging, 0, offsetInBytes, 0, 0); } } using (SDX.DataStream ds = _staging.Map(D3D.MapMode.Read, D3D.MapFlags.None)) { //If the step is zero, that means we're dealing with the entire vertex and not a subset of it if (vertexStep == 0) { ds.Position = offsetInBytes; ds.WriteRange <T>(data, startIndex, elementCount); } else { ds.Position = offsetInBytes; int count = elementCount - 1; int index = startIndex; ds.Write <T>(data[index++]); while (count > 0) { ds.Position += vertexStep; ds.Write <T>(data[index]); count--; index++; } } _staging.Unmap(); //If we're writing to the entire VB just copy the whole thing if (offsetInBytes == 0 && startIndex == 0 && dataSize == vbSize) { _graphicsDevice.CopyResource(_staging, _buffer); } else { D3D.ResourceRegion region = new D3D.ResourceRegion(); region.Left = offsetInBytes; region.Right = offsetInBytes + dataSize; region.Front = region.Top = 0; region.Back = region.Bottom = 1; _graphicsDevice.CopySubresourceRegion(_staging, 0, region, _buffer, 0, offsetInBytes, 0, 0); } } //Dynamic vertex buffers only } else { D3D.MapMode mode = (writeOptions == DataWriteOptions.Discard) ? D3D.MapMode.WriteDiscard : D3D.MapMode.WriteNoOverwrite; using (SDX.DataStream ds = _buffer.Map(mode, D3D.MapFlags.None)) { //If the step is zero, that means we're dealing with the entire vertex and not a subset of it if (vertexStep == 0) { ds.Position = offsetInBytes; ds.WriteRange <T>(data, startIndex, elementCount); } else { ds.Position = offsetInBytes; int count = elementCount - 1; int index = startIndex; ds.Write <T>(data[index++]); while (count > 0) { ds.Position += vertexStep; ds.Write <T>(data[index]); count--; index++; } } _buffer.Unmap(); } } } catch (Exception e) { throw new TeslaException("Error reading from D3D10 Buffer.", e); } }