static Texture2D ConvertFromBitmap(Bitmap image) { System.Drawing.Imaging.BitmapData data = image.LockBits(new System.Drawing.Rectangle(0, 0, image.Width, image.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, image.PixelFormat); int bytes = data.Stride * image.Height; DataStream stream = new SlimDX.DataStream(bytes, true, true); stream.WriteRange(data.Scan0,bytes); stream.Position = 0; DataRectangle dRect = new SlimDX.DataRectangle(data.Stride, stream); SlimDX.DXGI.SampleDescription sampleDesc = new SlimDX.DXGI.SampleDescription(); sampleDesc.Count = 1; sampleDesc.Quality = 0; Texture2DDescription texDesc = new Texture2DDescription() { ArraySize = 1, MipLevels = 1, SampleDescription = sampleDesc, Format = SlimDX.DXGI.Format.R8G8B8A8_UNorm, CpuAccessFlags = CpuAccessFlags.Write, BindFlags = BindFlags.ShaderResource, Usage = ResourceUsage.Dynamic, Height = image.Height, Width = image.Width }; image.UnlockBits(data); image.Dispose(); return new Texture2D(RenderForm11.Device, texDesc, dRect); }
/// <summary> /// Renders all of our geometry each frame. /// </summary> public void DrawTriangleList(SlimDX.Vector3 loc) { _SB.Capture(); // Create the vertex buffer and fill with the triangle vertices. Vertices = new VertexBuffer(D3D.Device, 3 * D3D.Vertex.SizeBytes, Usage.WriteOnly, VertexFormat.None, Pool.Managed); SlimDX.DataStream stream = Vertices.Lock(0, 0, LockFlags.None); stream.WriteRange(D3D.BuildVertexData()); Vertices.Unlock(); var worldMatrix = SlimDX.Matrix.Translation(loc); D3D.Device.SetTransform(TransformState.World, worldMatrix); D3D.Device.VertexFormat = D3D.Vertex.Format; // Render the vertex buffer. D3D.Device.SetStreamSource(0, Vertices, 0, D3D.Vertex.SizeBytes); //D3D.Device.DrawPrimitives(PrimitiveType.LineStrip, 0, 1); D3D.Device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1); if (Vertices != null) { Vertices.Dispose(); } _SB.Apply(); }
/// <summary> /// Sets the data to the texture. /// </summary> /// <typeparam name="T">Type of data in the array.</typeparam> /// <param name="data">Array of data.</param> /// <param name="mipLevel">Mip map level to access.</param> /// <param name="subimage">Rectangle representing a sub-image of the 2D texture to write to, if null the whole image is written to.</param> /// <param name="startIndex">Starting index in the array to start reading from.</param> /// <param name="elementCount">Number of elements to write.</param> /// <exception cref="System.ArgumentException">Thrown if the format byte size of the type to write and the texture do not match, the subimage /// dimensions are invalid, or if the total size to write and the total size in the texture do not match</exception> /// <exception cref="Tesla.Core.TeslaException">Thrown if there was an error writing to the texture.</exception> public override void SetData <T>(T[] data, int mipLevel, Math.Rectangle?subimage, int startIndex, int elementCount) { if (_texture2D == null || _texture2D.Disposed) { throw new ObjectDisposedException(GetType().Name); } if (mipLevel < 0 || mipLevel >= _mipCount) { throw new ArgumentOutOfRangeException("mipLevel", String.Format("Mip level is out of range. Must be between 0 and {0}.", _mipCount.ToString())); } //Throws null or out of range exception D3D10Helper.CheckArrayBounds(data, startIndex, elementCount); int formatSize = D3D10Helper.FormatSize(base.Format); SurfaceFormat format = base.Format; int elemSize = MemoryHelper.SizeOf <T>(); CheckSizes(formatSize, elemSize); //Calc subresource dimensions int width = (int)MathHelper.Max(1, base.Width >> mipLevel); int height = (int)MathHelper.Max(1, base.Height >> mipLevel); //Get the dimensions, if its null we copy the whole texture Rectangle rect; if (subimage.HasValue) { rect = subimage.Value; CheckRectangle(rect, ref width, ref height); } else { rect = new Rectangle(0, 0, width, height); } CheckTotalSize(base.Format, ref formatSize, ref width, ref height, elemSize, elementCount); //Create staging for non-dynamic textures if (_usage == D3D.ResourceUsage.Default) { CreateStaging(); } try { if (_usage == D3D.ResourceUsage.Default) { SDX.DataRectangle dataRect = _staging.Map(mipLevel, D3D.MapMode.Write, D3D.MapFlags.None); SDX.DataStream ds = dataRect.Data; int row = rect.Y; int col = rect.X; int pitch = dataRect.Pitch; int index = startIndex; int count = elementCount; //Compute the actual number of elements based on the format size and the element size we're copying the bytes into int actWidth = (int)MathHelper.Floor(width * (formatSize / elemSize)); //Go row by row for (int i = row; i < height; i++) { //Set the position ds.Position = (i * pitch) + (col * formatSize); //Break if we've run out of elements or on the very last row that isn't complete if (count <= 0) { break; } else if (count < actWidth) { ds.WriteRange <T>(data, index, count); break; } //Otherwise, copy the whole row and increment/decrement the index and count ds.WriteRange <T>(data, index, actWidth); index += actWidth; count -= actWidth; } _staging.Unmap(mipLevel); //Do resource copy if (format == SurfaceFormat.DXT1 || format == SurfaceFormat.DXT3 || format == SurfaceFormat.DXT5) { _graphicsDevice.CopyResource(_staging, _texture2D); } else { D3D.ResourceRegion region = new D3D.ResourceRegion(); region.Left = col; region.Right = col + width; region.Top = row; region.Bottom = row + height; region.Front = 0; region.Back = 1; _graphicsDevice.CopySubresourceRegion(_staging, mipLevel, region, _texture2D, mipLevel, col, row, 0); } } else { SDX.DataRectangle dataRect = _texture2D.Map(mipLevel, D3D.MapMode.WriteDiscard, D3D.MapFlags.None); SDX.DataStream ds = dataRect.Data; int row = rect.Y; int col = rect.X; int pitch = dataRect.Pitch; int index = startIndex; int count = elementCount; //Compute the actual number of elements based on the format size and the element size we're copying the bytes into int actWidth = (int)MathHelper.Floor(width * (formatSize / elemSize)); //Go row by row for (int i = row; i < height; i++) { //Set the position ds.Position = (i * pitch) + (col * formatSize); //Break if we've run out of elements or on the very last row that isn't complete if (count <= 0) { break; } else if (count < actWidth) { ds.WriteRange <T>(data, index, count); break; } //Otherwise, copy the whole row and increment/decrement the index and count ds.WriteRange <T>(data, index, actWidth); index += actWidth; count -= actWidth; } _texture2D.Unmap(mipLevel); } } catch (Exception e) { throw new TeslaException("Error writing to D3D10 Texture2D.", e); } }
/// <summary> /// Sets the data from the texture. /// </summary> /// <typeparam name="T">Type of data in the array</typeparam> /// <param name="data">The array of data</param> /// <param name="mipLevel">Mip map level to read from</param> /// <param name="left">Right-most width position in the texture at which to acess. (0 or greater)</param> /// <param name="right">Right-most width position in the texture at which to acess. (width or less)</param> /// <param name="top">Top-most height position in the texture at which to acess. (0 or greater)</param> /// <param name="bottom">Bottom-most height position in the texture at which to acess. (height or less)</param> /// <param name="front">Front-most depth position in the texture at which to acess. (0 or greater)</param> /// <param name="back">Back-most depth position in the texture at which to acess. (depth or less)</param> /// <param name="startIndex">Starting index in the array to start reading from.</param> /// <param name="elementCount">Number of elements to write.</param> /// <exception cref="System.ArgumentException">Thrown if the format byte size of the type to write and the texture do not match, the subimage /// dimensions are invalid, or if the total size to write and the total size in the texture do not match</exception> /// <exception cref="Tesla.Core.TeslaException">Thrown if there was an error writing to the texture.</exception> public override void SetData <T>(T[] data, int mipLevel, int left, int right, int top, int bottom, int front, int back, int startIndex, int elementCount) { if (_texture3D == null || _texture3D.Disposed) { throw new ObjectDisposedException(GetType().Name); } if (mipLevel < 0 || mipLevel >= _mipCount) { throw new ArgumentOutOfRangeException("mipLevel", String.Format("Mip level is out of range. Must be between 0 and {0}.", _mipCount.ToString())); } //Throws null or out of range exception D3D10Helper.CheckArrayBounds(data, startIndex, elementCount); int formatSize = D3D10Helper.FormatSize(base.Format); int elemSize = MemoryHelper.SizeOf <T>(); CheckSizes(formatSize, elemSize); //Calc subresource dimensions int width = (int)MathHelper.Max(1, base.Width >> mipLevel); int height = (int)MathHelper.Max(1, base.Height >> mipLevel); int depth = (int)MathHelper.Max(1, base.Depth >> mipLevel); //Ensure box dimensions CheckBox(left, right, top, bottom, front, back, ref width, ref height, ref depth); CheckTotalSize(base.Format, ref formatSize, ref width, ref height, ref depth, elemSize, elementCount); //Create staging for non-dynamic textures if (_usage == D3D.ResourceUsage.Default) { CreateStaging(); } try { if (_usage == D3D.ResourceUsage.Default) { SDX.DataBox dataBox = _staging.Map(mipLevel, D3D.MapMode.Write, D3D.MapFlags.None); SDX.DataStream ds = dataBox.Data; int row = left; int col = top; int slice = front; int rowPitch = dataBox.RowPitch; int slicePitch = dataBox.SlicePitch; int index = startIndex; int count = elementCount; //Compute the actual number of elements based on the format size and the element size we're copying the bytes into int actWidth = (int)MathHelper.Floor(width * (formatSize / elemSize)); //Go slice by slice for (int k = slice; k < back; k++) { //Go row by row for (int i = row; i < bottom; i++) { //Set the position ds.Position = (k * slicePitch) + (i * rowPitch) + (col * formatSize); //Break if we've run out of elements or on the very last row that isn't complete if (count <= 0) { break; } else if (count < actWidth) { ds.WriteRange <T>(data, index, count); break; } //Otherwise, copy the whole row and increment/decrement the index and count ds.WriteRange <T>(data, index, actWidth); index += actWidth; count -= actWidth; } } _staging.Unmap(mipLevel); //Do resource copy if (base.Format == SurfaceFormat.DXT1 || base.Format == SurfaceFormat.DXT3 || base.Format == SurfaceFormat.DXT5) { _graphicsDevice.CopyResource(_staging, _texture3D); } else { D3D.ResourceRegion region = new D3D.ResourceRegion(); region.Left = col; region.Right = right; region.Top = row; region.Bottom = bottom; region.Front = slice; region.Back = back; _graphicsDevice.CopySubresourceRegion(_staging, mipLevel, region, _texture3D, mipLevel, col, row, slice); } } else { SDX.DataBox dataBox = _texture3D.Map(mipLevel, D3D.MapMode.Write, D3D.MapFlags.None); SDX.DataStream ds = dataBox.Data; int row = left; int col = top; int slice = front; int rowPitch = dataBox.RowPitch; int slicePitch = dataBox.SlicePitch; int index = startIndex; int count = elementCount; //Compute the actual number of elements based on the format size and the element size we're copying the bytes into int actWidth = (int)MathHelper.Floor(width * (formatSize / elemSize)); //Go slice by slice for (int k = slice; k < back; k++) { //Go row by row for (int i = row; i < bottom; i++) { //Set the position ds.Position = (k * slicePitch) + (i * rowPitch) + (col * formatSize); //Break if we've run out of elements or on the very last row that isn't complete if (count <= 0) { break; } else if (count < actWidth) { ds.WriteRange <T>(data, index, count); break; } //Otherwise, copy the whole row and increment/decrement the index and count ds.WriteRange <T>(data, index, actWidth); index += actWidth; count -= actWidth; } } _texture3D.Unmap(mipLevel); } } catch (Exception e) { throw new TeslaException("Error writing to D3D10 Texture3D.", e); } }
/// <summary> /// Sets the data from the array to the texture. /// </summary> /// <typeparam name="T">Type of data in the array.</typeparam> /// <param name="data">Array of data</param> /// <param name="mipLevel">Mip map level to access</param> /// <param name="left">The left-most position in the 1D texture at which to access.</param> /// <param name="right">The right-most position in the 1D texture at which to acess.</param> /// <param name="startIndex">Starting index in the array to start reading from.</param> /// <param name="elementCount">Number of elements to write.</param> public override void SetData <T>(T[] data, int mipLevel, int left, int right, int startIndex, int elementCount) { if (_texture1D.Disposed) { throw new ObjectDisposedException(GetType().Name); } if (mipLevel < 0 || mipLevel >= _mipCount) { throw new ArgumentOutOfRangeException("mipLevel", String.Format("Mip level is out of range. Must be between 0 and {0}.", _mipCount.ToString())); } //Throws null or out of range exception D3D10Helper.CheckArrayBounds(data, startIndex, elementCount); SurfaceFormat format = base.Format; int formatSize = D3D10Helper.FormatSize(format); int elemSize = MemoryHelper.SizeOf <T>(); CheckSizes(formatSize, elemSize); //Calc subresource dimensions int width = (int)MathHelper.Max(1, base.Width >> mipLevel); //Check the line CheckLine(ref width, left, right); CheckTotalSize(format, ref formatSize, ref width, elemSize, elementCount); //Create staging if (_usage == D3D.ResourceUsage.Default) { CreateStaging(); } try { if (_usage == D3D.ResourceUsage.Default) { SDX.DataStream ds = _staging.Map(mipLevel, D3D.MapMode.Write, D3D.MapFlags.None); //Compute the actual number of elements based on the format size and the element size we're copying the bytes into int actWidth = (int)MathHelper.Floor(width * (formatSize / elemSize)); //Read data ds.Position = left * formatSize; ds.WriteRange <T>(data, startIndex, actWidth); _staging.Unmap(mipLevel); //Copy from the staging to texture if (format == SurfaceFormat.DXT1 || format == SurfaceFormat.DXT3 || format == SurfaceFormat.DXT5) { _graphicsDevice.CopyResource(_staging, _texture1D); } else { D3D.ResourceRegion region = new D3D.ResourceRegion(); region.Left = left; region.Right = right; region.Top = 0; region.Bottom = 1; region.Front = 0; region.Back = 1; _graphicsDevice.CopySubresourceRegion(_staging, mipLevel, region, _texture1D, mipLevel, left, 0, 0); } } else { SDX.DataStream ds = _texture1D.Map(mipLevel, D3D.MapMode.WriteDiscard, D3D.MapFlags.None); //Compute the actual number of elements based on the format size and the element size we're copying the bytes into int actWidth = (int)MathHelper.Floor(width * (formatSize / elemSize)); //Read data ds.Position = left * formatSize; ds.WriteRange <T>(data, startIndex, actWidth); _texture1D.Unmap(mipLevel); } } catch (Exception e) { throw new TeslaException("Error writing to D3D10 Texture1D.", e); } }
public void UpdateResource(IPluginOut ForPin, Device OnDevice) { //Called by the PluginHost every frame for every device. Therefore a plugin should only do //device specific operations here and still keep node specific calculations in the Evaluate call. try { Mesh mrty = FDeviceMeshes[OnDevice]; if (update) RemoveResource(OnDevice); } catch { update = true; } if (update) { // Device dev = Device.FromPointer(new IntPtr(OnDevice)); try { Mesh nuMesh = new Mesh(OnDevice, numIndices / 3, numVertsOut, MeshFlags.Dynamic | MeshFlags.WriteOnly, VertexFormat.PositionNormal); sVx = nuMesh.LockVertexBuffer(LockFlags.Discard); sIx = nuMesh.LockIndexBuffer(LockFlags.Discard); unsafe { fixed (sVxBuffer* FixTemp = &VxBuffer[0]) { IntPtr VxPointer = new IntPtr(FixTemp); sVx.WriteRange(VxPointer, sizeof(sVxBuffer) * numVertsOut); } fixed (short* FixTemp = &IxBuffer[0]) { IntPtr IxPointer = new IntPtr(FixTemp); sIx.WriteRange(IxPointer, sizeof(short) * numIndices); } } nuMesh.UnlockVertexBuffer(); nuMesh.UnlockIndexBuffer(); FDeviceMeshes.Add(OnDevice, nuMesh); } finally { //dev.Dispose(); update = false; } } }
/// <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); } }
public static DX11VertexGeometry Text3d(DX11RenderContext device, string text, string fontName, float fontSize, float extrude, TextAlignment textAlignment, ParagraphAlignment paragraphAlignment) { //Dictionary<DX11RenderContext, DX11VertexGeometry> deviceDict = null; //if (TextGeometryCache.TryGetValue(text, out deviceDict)) //{ // DX11VertexGeometry geom; // if(deviceDict.TryGetValue(device, out geom)) // { // return geom; // } //} if (d2dFactory == null) { d2dFactory = new D2DFactory(); dwFactory = new DWriteFactory(SharpDX.DirectWrite.FactoryType.Shared); } TextFormat fmt = new TextFormat(dwFactory, fontName, fontSize); TextLayout tl = new TextLayout(dwFactory, text, fmt, 0.0f, .0f); tl.WordWrapping = WordWrapping.NoWrap; tl.TextAlignment = (SharpDX.DirectWrite.TextAlignment)textAlignment; tl.ParagraphAlignment = (SharpDX.DirectWrite.ParagraphAlignment)paragraphAlignment; OutlineRenderer renderer = new OutlineRenderer(d2dFactory); Extruder ex = new Extruder(d2dFactory); tl.Draw(renderer, 0.0f, 0.0f); var geo = renderer.GetGeometry(); var result = ex.GetVertices(geo, extrude).ToArray(); renderer.Dispose(); geo.Dispose(); fmt.Dispose(); tl.Dispose(); Vector3 min = new Vector3(float.MaxValue); Vector3 max = new Vector3(float.MinValue); foreach (var pn in result) { min.X = pn.Position.X < min.X ? pn.Position.X : min.X; min.Y = pn.Position.Y < min.Y ? pn.Position.Y : min.Y; min.Z = pn.Position.Z < min.Z ? pn.Position.Z : min.Z; max.X = pn.Position.X > max.X ? pn.Position.X : max.X; max.Y = pn.Position.Y > max.Y ? pn.Position.Y : max.Y; max.Z = pn.Position.Z > max.Z ? pn.Position.Z : max.Z; } SlimDX.DataStream ds = new SlimDX.DataStream(result.Length * Pos3Norm3VertexSDX.VertexSize, true, true); ds.Position = 0; ds.WriteRange(result); ds.Position = 0; var vbuffer = new SlimDX.Direct3D11.Buffer(device.Device, ds, new SlimDX.Direct3D11.BufferDescription() { BindFlags = SlimDX.Direct3D11.BindFlags.VertexBuffer, CpuAccessFlags = SlimDX.Direct3D11.CpuAccessFlags.None, OptionFlags = SlimDX.Direct3D11.ResourceOptionFlags.None, SizeInBytes = (int)ds.Length, Usage = SlimDX.Direct3D11.ResourceUsage.Default, }); ds.Dispose(); DX11VertexGeometry vg = new DX11VertexGeometry(device); vg.InputLayout = Pos3Norm3VertexSDX.Layout; vg.Topology = SlimDX.Direct3D11.PrimitiveTopology.TriangleList; vg.VertexBuffer = vbuffer; vg.VertexSize = Pos3Norm3VertexSDX.VertexSize; vg.VerticesCount = result.Length; vg.HasBoundingBox = true; vg.BoundingBox = new SlimDX.BoundingBox(new SlimDX.Vector3(min.X, min.Y, min.Z), new SlimDX.Vector3(max.X, max.Y, max.Z)); //if(deviceDict != null) //{ // deviceDict[device] = vg; //} //else //{ // deviceDict = new Dictionary<DX11RenderContext, DX11VertexGeometry>(); // deviceDict[device] = vg; // TextGeometryCache[text] = deviceDict; //} return(vg); }
/// <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); } }