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 }