/// <summary> /// Copies data from a source <see cref="DataBufferSubset{T}"/> to a destination <see cref="DataBufferSubset{T}"/>. /// </summary> /// <param name="source">The <see cref="DataBufferSubset{T}"/> to copy data from.</param> /// <param name="sourceOffset">The index of the first element to copy from the source subset.</param> /// <param name="dest">The <see cref="DataBufferSubset{T}"/> to write data to.</param> /// <param name="destOffset">The index of of the first element to write on the dest subset.</param> /// <param name="dataLength">The amount of elements to copy.</param> public static void CopyBuffers <T>(DataBufferSubset <T> source, uint sourceOffset, DataBufferSubset <T> dest, uint destOffset, uint dataLength) where T : unmanaged { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (dest == null) { throw new ArgumentNullException(nameof(dest)); } GraphicsDevice g = source.Buffer.GraphicsDevice; if (g != dest.Buffer.GraphicsDevice) { throw new InvalidOperationException("You can't copy data between buffers from different " + nameof(GraphicsDevice) + "-s"); } if (sourceOffset < 0 || sourceOffset > source.StorageLength) { throw new ArgumentOutOfRangeException(nameof(sourceOffset), sourceOffset, nameof(sourceOffset) + " must be in the range [0, " + nameof(source.StorageLength) + ")"); } if (destOffset < 0 || destOffset > dest.StorageLength) { throw new ArgumentOutOfRangeException(nameof(destOffset), destOffset, nameof(destOffset) + " must be in the range [0, " + nameof(dest.StorageLength) + ")"); } if (sourceOffset + dataLength > source.StorageLength) { throw new BufferCopyException("There isn't enough data in the source buffer to copy " + nameof(dataLength) + " elements"); } if (destOffset + dataLength > dest.StorageLength) { throw new BufferCopyException("There isn't enough data in the dest buffer to copy " + nameof(dataLength) + " elements"); } uint elementSize = source.ElementSize; int sourceStart = (int)(source.StorageOffsetInBytes + sourceOffset * elementSize); int destStart = (int)(dest.StorageOffsetInBytes + destOffset * elementSize); if (source.Buffer == dest.Buffer) { // We're copying from and to the same buffer? Let's ensure the sections don't overlap then int dataLengthBytes = (int)(dataLength * elementSize); if (sourceStart < destStart + dataLengthBytes && sourceStart + dataLengthBytes > destStart) { throw new BufferCopyException("When copying to and from the same " + nameof(BufferObject) + ", the ranges must not overlap"); } } // Everything looks fine, let's perform the copy operation! g.CopyReadBuffer = source.Buffer; g.CopyWriteBuffer = dest.Buffer; source.Buffer.GL.CopyBufferSubData(CopyBufferSubDataTarget.CopyReadBuffer, CopyBufferSubDataTarget.CopyWriteBuffer, sourceStart, destStart, dataLength * elementSize); }
/// <summary> /// Copies all the data from a source <see cref="DataBufferSubset{T}"/> to a destination <see cref="DataBufferSubset{T}"/>. /// </summary> /// <param name="source">The <see cref="DataBufferSubset{T}"/> to copy data from.</param> /// <param name="dest">The <see cref="DataBufferSubset{T}"/> to write data to.</param> public static void CopyBuffers <T>(DataBufferSubset <T> source, DataBufferSubset <T> dest) where T : unmanaged { if (source == null) { throw new ArgumentNullException(nameof(source)); } CopyBuffers(source, 0, dest, 0, source.StorageLength); }
private static VertexAttribSource[] MakeAttribList(DataBufferSubset bufferSubset, ReadOnlySpan <VertexAttribDescription> attribDescriptions) { VertexAttribSource[] sources = new VertexAttribSource[attribDescriptions.Length]; for (int i = 0; i < sources.Length; i++) { sources[i] = new VertexAttribSource(bufferSubset, attribDescriptions[i]); } return(sources); }
/// <summary> /// Creates a <see cref="VertexAttribSource"/> that represents padding. This means that the created /// <see cref="VertexAttribSource"/> will not indicate a buffer to read data from or use a vertex /// attribute index, it will just leave an ignored space between other attributes. /// </summary> /// <param name="bufferSubset">The <see cref="BufferObjectSubset"/> where the padding will be added.</param> /// <param name="paddingBytes">The amount of space to leave empty, measured in bytes.</param> public VertexAttribSource(DataBufferSubset bufferSubset, uint paddingBytes) { if (bufferSubset == null) { throw new ArgumentNullException(nameof(bufferSubset)); } if (bufferSubset.BufferTarget != BufferTargetARB.ArrayBuffer) { throw new ArgumentException("The specified BufferObjectSubset must be usable as vertex attrib data. Try using a VertexDataBufferSubset", nameof(bufferSubset)); } BufferSubset = bufferSubset; AttribDescription = new VertexAttribDescription(paddingBytes); }
/// <summary> /// Creates a <see cref="VertexAttribSource"/> with a given <see cref="BufferObjectSubset"/> /// and the given <see cref="VertexAttribDescription"/>. /// </summary> /// <param name="bufferSubset">The <see cref="BufferObjectSubset"/> where the vertex attrib data is located. Must be a subset usable for vertex data.</param> /// <param name="attribDesc">The <see cref="VertexAttribDescription"/> describing the vertex attribute.</param> public VertexAttribSource(DataBufferSubset bufferSubset, VertexAttribDescription attribDesc) { if (bufferSubset == null) { throw new ArgumentNullException(nameof(bufferSubset)); } if (bufferSubset.BufferTarget != BufferTarget.ArrayBuffer) { throw new ArgumentException("The specified " + nameof(BufferObjectSubset) + " must be usable as vertex attrib data. Try using a VertexDataBufferSubset", nameof(bufferSubset)); } BufferSubset = bufferSubset; AttribDescription = attribDesc; }
/// <summary> /// Creates a <see cref="VertexAttribSource"/> with a given <see cref="BufferObjectSubset"/> and specifies /// a vertex attribute where the data format in the shader and the buffer don't match and need conversion. /// </summary> /// <param name="bufferSubset">The <see cref="BufferObjectSubset"/> where the vertex attrib data is located. Must be a subset usable for vertex data.</param> /// <param name="attribType">The type of attribute declared in the shader.</param> /// <param name="normalized">Whether the data needs to be normalized (uint/ushort/byte -> float between 0 and 1, or int/short/sbyte -> float between -1 and 1).</param> /// <param name="dataBaseType">The base type of the data found on the buffer. If normalized is true, this must be an integer type.</param> /// <param name="attribDivisor">The divisor that defines how reading this attribute advances on instanced rendering.</param> public VertexAttribSource(DataBufferSubset bufferSubset, AttributeType attribType, bool normalized, VertexAttribPointerType dataBaseType, uint attribDivisor = 0) : this(bufferSubset, new VertexAttribDescription(attribType, normalized, dataBaseType, attribDivisor)) { }
/// <summary> /// Creates a <see cref="VertexAttribSource"/> with a given <see cref="BufferObjectSubset"/> and specifies a /// vertex attribute where the data format in the shader and the buffer match and don't need conversion. /// </summary> /// <param name="bufferSubset">The <see cref="BufferObjectSubset"/> where the vertex attrib data is located. Must be a subset usable for vertex data.</param> /// <param name="attribType">The type of attribute declared in the shader.</param> /// <param name="attribDivisor">The divisor that defines how reading this attribute advances on instanced rendering.</param> public VertexAttribSource(DataBufferSubset bufferSubset, AttributeType attribType, uint attribDivisor = 0) : this(bufferSubset, new VertexAttribDescription(attribType, attribDivisor)) { }
/// <summary> /// Creates a <see cref="VertexAttribSource"/> that specifies padding for the amount /// of bytes used by a specified <see cref="AttributeType"/>. /// </summary> /// <param name="bufferSubset">The buffer subset in which the padding will be applied.</param> /// <param name="attribType">The type of the attribute, for calculating paddign.</param> /// <remarks> /// Padding indicators ignore padding based on type that occurs when using compensation /// for struct padding (which is the default behavior in <see cref="VertexArray"/>). /// </remarks> public static VertexAttribSource CreatePadding(DataBufferSubset bufferSubset, AttributeType attribType) { return(new VertexAttribSource(bufferSubset, VertexAttribDescription.CreatePadding(attribType))); }
/// <summary> /// Creates a <see cref="VertexAttribSource"/> that specifies padding for an /// amount of bytes calculated based on the baseType and size parameters. /// </summary> /// <param name="bufferSubset">The buffer subset in which the padding will be applied.</param> /// <param name="baseType">The base type of the attribute.</param> /// <param name="size">The size of the attribute.</param> public static VertexAttribSource CreatePadding(DataBufferSubset bufferSubset, VertexAttribPointerType baseType, uint size) { return(new VertexAttribSource(bufferSubset, VertexAttribDescription.CreatePadding(baseType, size))); }
/// <summary> /// Creates a <see cref="VertexArray"/> in which all the vertex attributes come interleaved from the same data buffer. /// </summary> /// <param name="graphicsDevice">The <see cref="GraphicsDevice"/> this resource will use.</param> /// <param name="bufferSubset">The data buffer that stores all the vertex attributes.</param> /// <param name="attribDescriptions">The descriptions of the vertex attributes.</param> /// <param name="indexBuffer">An index buffer to attach to the vertex array, null if none is desired.</param> /// <param name="compensateStructPadding">Whether to compensate for struct padding. Default is true.</param> /// <param name="paddingPackValue">The struct packing value for compensating for padding. Default is 4.</param> public VertexArray(GraphicsDevice graphicsDevice, DataBufferSubset bufferSubset, ReadOnlySpan <VertexAttribDescription> attribDescriptions, IndexBufferSubset indexBuffer = null, bool compensateStructPadding = true, uint paddingPackValue = 4) : this(graphicsDevice, MakeAttribList(bufferSubset, attribDescriptions), indexBuffer, compensateStructPadding, paddingPackValue) { }
/// <summary> /// Creates a <see cref="VertexArray"/> for the specified vertex type, where all of the vertex attributes come interleaved from the same buffer subset. /// </summary> /// <typeparam name="T">The type of vertex to use.</typeparam> /// <param name="graphicsDevice">The <see cref="GraphicsDevice"/> this resource will use.</param> /// <param name="dataBuffer">The buffer from which all attributes come from.</param> /// <param name="indexBuffer">An index buffer to attach to the vertex array, null if none is desired.</param> /// <param name="compensateStructPadding">Whether to compensate for struct padding. Default is true.</param> /// <param name="paddingPackValue">The struct packing value for compensating for padding. Default is 4.</param> public static VertexArray CreateSingleBuffer <T>(GraphicsDevice graphicsDevice, DataBufferSubset dataBuffer, IndexBufferSubset indexBuffer = null, bool compensateStructPadding = true, uint paddingPackValue = 4) where T : unmanaged, IVertex { T t = default; int attribCount = t.AttribDescriptionCount; Span <VertexAttribDescription> attribDescriptions = attribCount > 32 ? new VertexAttribDescription[attribCount] : stackalloc VertexAttribDescription[attribCount]; t.WriteAttribDescriptions(attribDescriptions); return(new VertexArray(graphicsDevice, dataBuffer, attribDescriptions, indexBuffer, compensateStructPadding, paddingPackValue)); }