1 module armos.graphics.buffer; 2 3 import derelict.opengl3.gl; 4 import armos.graphics.vao; 5 import armos.math; 6 import std.variant; 7 8 9 /++ 10 +/ 11 class Buffer { 12 public{ 13 14 /++ 15 BufferTypeを指定して初期化します. 16 +/ 17 this(in BufferType bufferType){ 18 glGenBuffers(1, cast(uint*)&_id); 19 _type = bufferType; 20 } 21 22 /// 23 ~this(){ 24 glDeleteBuffers(1, cast(uint*)&_id); 25 } 26 27 /++ 28 +/ 29 void begin(){ 30 int savedID; 31 glGetIntegerv(bindingEnum(_type), &savedID); 32 _savedIDs ~= savedID; 33 glBindBuffer(_type, _id); 34 } 35 36 /++ 37 +/ 38 void end(){ 39 import std.range; 40 glBindBuffer(_type, _savedIDs[$-1]); 41 if (_savedIDs.length == 0) { 42 assert(0, "stack is empty"); 43 }else{ 44 _savedIDs.popBack; 45 } 46 } 47 48 /// 49 Buffer array(T)(in T[] array, in size_t dimention = 1, 50 in BufferUsageFrequency freq = BufferUsageFrequency.Dynamic, 51 in BufferUsageNature nature = BufferUsageNature.Draw) 52 if(__traits(isArithmetic, T)){ 53 if(array.length == 0)return this; 54 55 _array = Algebraic!(const(int)[], const(float)[], const(double)[])(array); 56 _dimention = dimention; 57 _freq = freq; 58 _nature = nature; 59 60 updateGlBuffer; 61 return this; 62 } 63 64 /// 65 Buffer array(V)(in V[] array, 66 in BufferUsageFrequency freq = BufferUsageFrequency.Dynamic, 67 in BufferUsageNature nature = BufferUsageNature.Draw) 68 if(isVector!V){ 69 if(array.length == 0)return this; 70 V.elementType[] raw = new V.elementType[array.length*V.dimention]; 71 for (size_t i = 0, pos = 0, len = array.length; i < len; ++i, pos += V.dimention) { 72 raw[pos .. pos + V.dimention] = array[i].elements; 73 } 74 this.array(raw, V.dimention, freq, nature); 75 return this; 76 } 77 78 /// 79 Buffer updateGlBuffer(){ 80 if(_array.type == typeid(const(float)[])){ 81 updateGlBuffer!(const(float)); 82 }else if(_array.type == typeid(const(double)[])){ 83 updateGlBuffer!(const(double)); 84 }else if(_array.type == typeid(const(int)[])){ 85 updateGlBuffer!(const(int)); 86 } 87 return this; 88 } 89 90 /// 91 size_t size()const{return _size;} 92 93 /// 94 BufferType type()const{return _type;} 95 }//public 96 97 private{ 98 int _id; 99 int[] _savedIDs; 100 BufferType _type; 101 size_t _size; 102 size_t _dimention; 103 BufferUsageFrequency _freq; 104 BufferUsageNature _nature; 105 Algebraic!(const(int)[], const(float)[], const(double)[]) _array; 106 107 void updateGlBuffer(T)(){ 108 auto arr = _array.get!(T[]); 109 begin; 110 immutable currentSize = arr.length * arr[0].sizeof; 111 112 if(_size != currentSize){ 113 _size = currentSize; 114 glBufferData(_type, _size, arr.ptr, usageEnum(_freq, _nature)); 115 }else{ 116 glBufferSubData(_type, 0, _size, arr.ptr); 117 } 118 119 import std.conv; 120 if(_type != BufferType.ElementArray){ 121 static if(is(T == const(float))){ 122 GLenum glDataType = GL_FLOAT; 123 }else static if(is(T == const(double))){ 124 GLenum glDataType = GL_DOUBLE; 125 }else static if(is(T == const(int))){ 126 GLenum glDataType = GL_INT; 127 } 128 glVertexAttribPointer(0, 129 _dimention.to!int, 130 glDataType, 131 GL_FALSE, 132 0, 133 null); 134 } 135 end; 136 } 137 }//private 138 }//class Vbo 139 140 /++ 141 +/ 142 enum BufferType{ 143 Array = GL_ARRAY_BUFFER, /// Vertex attributes 144 AtomicCounter = GL_ATOMIC_COUNTER_BUFFER, /// Atomic counter storage 145 CopyRead = GL_COPY_READ_BUFFER, /// Buffer copy source 146 CopyWrite = GL_COPY_WRITE_BUFFER, /// Buffer copy destination 147 DispatchIndirect = GL_DISPATCH_INDIRECT_BUFFER, /// Indirect compute dispatch commands 148 DrawIndirect = GL_DRAW_INDIRECT_BUFFER, /// Indirect command arguments 149 ElementArray = GL_ELEMENT_ARRAY_BUFFER, /// Vertex array indices 150 PixelPack = GL_PIXEL_PACK_BUFFER, /// Pixel read target 151 PixelUnpack = GL_PIXEL_UNPACK_BUFFER, /// Texture data source 152 Query = GL_QUERY_BUFFER, /// Query result buffer 153 ShaderStorage = GL_SHADER_STORAGE_BUFFER, /// Read-write storage for shaders 154 Texture = GL_TEXTURE_BUFFER, /// Texture data buffer 155 TransformFeedback = GL_TRANSFORM_FEEDBACK_BUFFER, /// Transform feedback buffer 156 Uniform = GL_UNIFORM_BUFFER, /// Uniform block storage 157 } 158 159 private GLenum bindingEnum(in BufferType bufferType){ 160 GLenum bindingType; 161 switch (bufferType) { 162 case BufferType.Array: 163 bindingType = GL_ARRAY_BUFFER_BINDING; 164 break; 165 case BufferType.AtomicCounter: 166 bindingType = GL_ATOMIC_COUNTER_BUFFER_BINDING; 167 break; 168 case BufferType.CopyRead: 169 bindingType = GL_COPY_READ_BUFFER_BINDING; 170 break; 171 case BufferType.CopyWrite: 172 bindingType = GL_COPY_WRITE_BUFFER_BINDING; 173 break; 174 case BufferType.DispatchIndirect: 175 bindingType = GL_DISPATCH_INDIRECT_BUFFER_BINDING; 176 break; 177 case BufferType.DrawIndirect: 178 bindingType = GL_DRAW_INDIRECT_BUFFER_BINDING; 179 break; 180 case BufferType.ElementArray: 181 bindingType = GL_ELEMENT_ARRAY_BUFFER_BINDING; 182 break; 183 case BufferType.PixelPack: 184 bindingType = GL_PIXEL_PACK_BUFFER_BINDING; 185 break; 186 case BufferType.PixelUnpack: 187 bindingType = GL_PIXEL_UNPACK_BUFFER_BINDING; 188 break; 189 case BufferType.Query: 190 bindingType = GL_QUERY_BUFFER_BINDING; 191 break; 192 case BufferType.ShaderStorage: 193 bindingType = GL_SHADER_STORAGE_BUFFER_BINDING; 194 break; 195 case BufferType.Texture: 196 bindingType = GL_TEXTURE_BUFFER_BINDING; 197 break; 198 case BufferType.TransformFeedback: 199 bindingType = GL_TRANSFORM_FEEDBACK_BUFFER_BINDING; 200 break; 201 case BufferType.Uniform: 202 bindingType = GL_UNIFORM_BUFFER_BINDING; 203 break; 204 default : assert(0, "invalid value"); 205 } 206 return bindingType; 207 } 208 209 /++ 210 Bufferの更新頻度を表すenumです. 211 +/ 212 enum BufferUsageFrequency{ 213 Stream, /// 読み込みも書き込みも一度のみ 214 Static, /// 書き込みが一度だけで,読み込みは何度も行われる 215 Dynamic, /// 何度も読み書きが行われる 216 } 217 218 /++ 219 Bufferの読み書きの方法を表すenumです. 220 +/ 221 enum BufferUsageNature{ 222 Draw, /// アプリケーション側から書き込まれ,OpenGLが描画のために読み込む 223 Read, /// OpenGL側で書き込まれ,アプリケーション側で読み込む 224 Copy, /// OpenGL側で書き込まれ,描画に用いられる 225 } 226 227 private static GLenum[BufferUsageNature][BufferUsageFrequency] usageEnumsTable(){ 228 GLenum[BufferUsageNature][BufferUsageFrequency] enums; 229 enums[BufferUsageFrequency.Stream][BufferUsageNature.Draw] = GL_STREAM_DRAW; 230 enums[BufferUsageFrequency.Stream][BufferUsageNature.Read] = GL_STREAM_READ; 231 enums[BufferUsageFrequency.Stream][BufferUsageNature.Copy] = GL_STREAM_COPY; 232 233 enums[BufferUsageFrequency.Static][BufferUsageNature.Draw] = GL_STATIC_DRAW; 234 enums[BufferUsageFrequency.Static][BufferUsageNature.Read] = GL_STATIC_READ; 235 enums[BufferUsageFrequency.Static][BufferUsageNature.Copy] = GL_STATIC_COPY; 236 237 enums[BufferUsageFrequency.Dynamic][BufferUsageNature.Draw] = GL_DYNAMIC_DRAW; 238 enums[BufferUsageFrequency.Dynamic][BufferUsageNature.Read] = GL_DYNAMIC_READ; 239 enums[BufferUsageFrequency.Dynamic][BufferUsageNature.Copy] = GL_DYNAMIC_COPY; 240 return enums; 241 }; 242 243 static unittest{ 244 static assert(usageEnumsTable[BufferUsageFrequency.Static][BufferUsageNature.Draw] == GL_STATIC_DRAW); 245 } 246 247 private GLenum usageEnum(in BufferUsageFrequency freq, in BufferUsageNature nature){ 248 return usageEnumsTable[freq][nature]; 249 }