/// <summary> /// Sets the data contained by the index buffer. /// </summary> /// <param name="data">An array containing the data to set in the index buffer.</param> public override void SetData <T>(T[] data) { Contract.Require(data, nameof(data)); Contract.Ensure(data.Length <= IndexCount, OpenGLStrings.DataTooLargeForBuffer); var handle = GCHandle.Alloc(data, GCHandleType.Pinned); try { using (OpenGLState.ScopedBindElementArrayBuffer(buffer)) { var size = new IntPtr(GetElementSize() * data.Length); gl.NamedBufferSubData(buffer, gl.GL_ELEMENT_ARRAY_BUFFER, IntPtr.Zero, size, handle.AddrOfPinnedObject().ToPointer()); gl.ThrowIfError(); } } finally { handle.Free(); } }
/// <inheritdoc/> public override void SetDataAligned <T>(T[] data, Int32 dataOffset, Int32 dataCount, Int32 bufferOffset, out Int32 bufferSize, SetDataOptions options) { Contract.Require(data, nameof(data)); Contract.EnsureRange(dataCount > 0, nameof(dataCount)); Contract.EnsureRange(dataOffset >= 0 && dataOffset + dataCount <= data.Length, nameof(dataOffset)); Contract.EnsureRange(bufferOffset >= 0, nameof(bufferOffset)); Contract.Ensure(dataCount <= IndexCount, OpenGLStrings.DataTooLargeForBuffer); var indexStride = GetElementSize(); bufferSize = indexStride * dataCount; var handle = GCHandle.Alloc(data, GCHandleType.Pinned); try { var caps = (OpenGLGraphicsCapabilities)Ultraviolet.GetGraphics().Capabilities; if (caps.SupportsMapBufferRange && caps.MinMapBufferAlignment > 0) { bufferSize = Math.Min(Math.Max(caps.MinMapBufferAlignment, MathUtil.FindNextPowerOfTwo(bufferSize)), SizeInBytes - bufferOffset); } using (OpenGLState.ScopedBindElementArrayBuffer(buffer)) { var isPartialUpdate = (bufferOffset > 0 || bufferSize < SizeInBytes); var isDiscarding = (options == SetDataOptions.Discard); if (isDiscarding || !isPartialUpdate) { gl.NamedBufferData(buffer, gl.GL_ELEMENT_ARRAY_BUFFER, this.size, isPartialUpdate ? null : handle.AddrOfPinnedObject().ToPointer(), usage); gl.ThrowIfError(); } if (isPartialUpdate) { if (caps.SupportsMapBufferRange) { var bufferRangeAccess = gl.GL_MAP_WRITE_BIT | (options == SetDataOptions.NoOverwrite ? gl.GL_MAP_UNSYNCHRONIZED_BIT : 0); var bufferRangePtr = (Byte *)gl.MapNamedBufferRange(buffer, gl.GL_ELEMENT_ARRAY_BUFFER, (IntPtr)bufferOffset, (IntPtr)bufferSize, bufferRangeAccess); gl.ThrowIfError(); var sourceRangePtr = (Byte *)handle.AddrOfPinnedObject() + (dataOffset * indexStride); var sourceSizeInBytes = dataCount * indexStride; for (int i = 0; i < sourceSizeInBytes; i++) { *bufferRangePtr++ = *sourceRangePtr++; } gl.UnmapNamedBuffer(buffer, gl.GL_ELEMENT_ARRAY_BUFFER); gl.ThrowIfError(); } else { gl.NamedBufferSubData(buffer, gl.GL_ELEMENT_ARRAY_BUFFER, (IntPtr)bufferOffset, (IntPtr)bufferSize, (Byte *)handle.AddrOfPinnedObject().ToPointer() + (dataOffset * indexStride)); gl.ThrowIfError(); } } } } finally { handle.Free(); } }