Ejemplo n.º 1
0
        /// <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>
        /// 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);
            }
        }