1 #region Copyright & License Information 2 /* 3 * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) 4 * This file is part of OpenRA, which is free software. It is made 5 * available to you under the terms of the GNU General Public License 6 * as published by the Free Software Foundation, either version 3 of 7 * the License, or (at your option) any later version. For more 8 * information, see COPYING. 9 */ 10 #endregion 11 12 using System; 13 using System.Runtime.InteropServices; 14 15 namespace OpenRA.Platforms.Default 16 { 17 sealed class VertexBuffer<T> : ThreadAffine, IVertexBuffer<T> 18 where T : struct 19 { 20 static readonly int VertexSize = Marshal.SizeOf(typeof(T)); 21 uint buffer; 22 bool disposed; 23 VertexBuffer(int size)24 public VertexBuffer(int size) 25 { 26 OpenGL.glGenBuffers(1, out buffer); 27 OpenGL.CheckGLError(); 28 Bind(); 29 30 // Generates a buffer with uninitialized memory. 31 OpenGL.glBufferData(OpenGL.GL_ARRAY_BUFFER, 32 new IntPtr(VertexSize * size), 33 IntPtr.Zero, 34 OpenGL.GL_DYNAMIC_DRAW); 35 OpenGL.CheckGLError(); 36 37 // We need to zero all the memory. Let's generate a smallish array and copy that over the whole buffer. 38 var zeroedArrayElementSize = Math.Min(size, 2048); 39 var ptr = GCHandle.Alloc(new T[zeroedArrayElementSize], GCHandleType.Pinned); 40 try 41 { 42 for (var offset = 0; offset < size; offset += zeroedArrayElementSize) 43 { 44 var length = Math.Min(zeroedArrayElementSize, size - offset); 45 OpenGL.glBufferSubData(OpenGL.GL_ARRAY_BUFFER, 46 new IntPtr(VertexSize * offset), 47 new IntPtr(VertexSize * length), 48 ptr.AddrOfPinnedObject()); 49 OpenGL.CheckGLError(); 50 } 51 } 52 finally 53 { 54 ptr.Free(); 55 } 56 } 57 SetData(T[] data, int length)58 public void SetData(T[] data, int length) 59 { 60 SetData(data, 0, length); 61 } 62 SetData(T[] data, int start, int length)63 public void SetData(T[] data, int start, int length) 64 { 65 Bind(); 66 67 var ptr = GCHandle.Alloc(data, GCHandleType.Pinned); 68 try 69 { 70 OpenGL.glBufferSubData(OpenGL.GL_ARRAY_BUFFER, 71 new IntPtr(VertexSize * start), 72 new IntPtr(VertexSize * length), 73 ptr.AddrOfPinnedObject()); 74 } 75 finally 76 { 77 ptr.Free(); 78 } 79 80 OpenGL.CheckGLError(); 81 } 82 SetData(IntPtr data, int start, int length)83 public void SetData(IntPtr data, int start, int length) 84 { 85 Bind(); 86 OpenGL.glBufferSubData(OpenGL.GL_ARRAY_BUFFER, 87 new IntPtr(VertexSize * start), 88 new IntPtr(VertexSize * length), 89 data); 90 OpenGL.CheckGLError(); 91 } 92 Bind()93 public void Bind() 94 { 95 VerifyThreadAffinity(); 96 OpenGL.glBindBuffer(OpenGL.GL_ARRAY_BUFFER, buffer); 97 OpenGL.CheckGLError(); 98 OpenGL.glVertexAttribPointer(Shader.VertexPosAttributeIndex, 3, OpenGL.GL_FLOAT, false, VertexSize, IntPtr.Zero); 99 OpenGL.CheckGLError(); 100 OpenGL.glVertexAttribPointer(Shader.TexCoordAttributeIndex, 4, OpenGL.GL_FLOAT, false, VertexSize, new IntPtr(12)); 101 OpenGL.CheckGLError(); 102 OpenGL.glVertexAttribPointer(Shader.TexMetadataAttributeIndex, 2, OpenGL.GL_FLOAT, false, VertexSize, new IntPtr(28)); 103 OpenGL.CheckGLError(); 104 } 105 Dispose()106 public void Dispose() 107 { 108 Dispose(true); 109 GC.SuppressFinalize(this); 110 } 111 Dispose(bool disposing)112 void Dispose(bool disposing) 113 { 114 if (disposed) 115 return; 116 disposed = true; 117 OpenGL.glDeleteBuffers(1, ref buffer); 118 OpenGL.CheckGLError(); 119 } 120 } 121 } 122