Gawain: remove GL enum from vertex format API
[blender.git] / intern / gawain / src / batch.c
1
2 // Gawain geometry batch
3 //
4 // This code is part of the Gawain library, with modifications
5 // specific to integration with Blender.
6 //
7 // Copyright 2016 Mike Erwin
8 //
9 // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
10 // the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
11
12 #include "batch.h"
13 #include "buffer_id.h"
14 #include <stdlib.h>
15
16 // necessary functions from matrix API
17 extern void gpuBindMatrices(GLuint program);
18 extern bool gpuMatricesDirty(void); // how best to use this here?
19
20 Batch* Batch_create(PrimitiveType prim_type, VertexBuffer* verts, ElementList* elem)
21         {
22         Batch* batch = calloc(1, sizeof(Batch));
23
24         Batch_init(batch, prim_type, verts, elem);
25
26         return batch;
27         }
28
29 void Batch_init(Batch* batch, PrimitiveType prim_type, VertexBuffer* verts, ElementList* elem)
30         {
31 #if TRUST_NO_ONE
32         assert(verts != NULL);
33         // assert(prim_type == PRIM_POINTS || prim_type == PRIM_LINES || prim_type == PRIM_TRIANGLES);
34         // we will allow other primitive types in a future update
35 #endif
36
37         batch->verts[0] = verts;
38         for (int v = 1; v < BATCH_MAX_VBO_CT; ++v)
39                 batch->verts[v] = NULL;
40         batch->elem = elem;
41         batch->prim_type = prim_type;
42         batch->phase = READY_TO_DRAW;
43         }
44
45 void Batch_discard(Batch* batch)
46         {
47         if (batch->vao_id)
48                 vao_id_free(batch->vao_id);
49
50         free(batch);
51         }
52
53 void Batch_discard_all(Batch* batch)
54         {
55         for (int v = 0; v < BATCH_MAX_VBO_CT; ++v)
56                 {
57                 if (batch->verts[v] == NULL)
58                         break;
59                 VertexBuffer_discard(batch->verts[v]);
60                 }
61
62         if (batch->elem)
63                 ElementList_discard(batch->elem);
64
65         Batch_discard(batch);
66         }
67
68 int Batch_add_VertexBuffer(Batch* batch, VertexBuffer* verts)
69         {
70         for (unsigned v = 0; v < BATCH_MAX_VBO_CT; ++v)
71                 {
72                 if (batch->verts[v] == NULL)
73                         {
74 #if TRUST_NO_ONE
75                         // for now all VertexBuffers must have same vertex_ct
76                         assert(verts->vertex_ct == batch->verts[0]->vertex_ct);
77                         // in the near future we will enable instanced attribs which have their own vertex_ct
78 #endif
79                         batch->verts[v] = verts;
80                         // TODO: mark dirty so we can keep attrib bindings up-to-date
81                         return v;
82                         }
83                 }
84         
85         // we only make it this far if there is no room for another VertexBuffer
86 #if TRUST_NO_ONE
87         assert(false);
88 #endif
89         return -1;
90         }
91
92 void Batch_set_program(Batch* batch, GLuint program)
93         {
94 #if TRUST_NO_ONE
95         assert(glIsProgram(program));
96 #endif
97
98         batch->program = program;
99         batch->program_dirty = true;
100
101         Batch_use_program(batch); // hack! to make Batch_Uniform* simpler
102         }
103
104 static void Batch_update_program_bindings(Batch* batch)
105         {
106         // disable all as a precaution
107         // why are we not using prev_attrib_enabled_bits?? see immediate.c
108         for (unsigned a_idx = 0; a_idx < MAX_VERTEX_ATTRIBS; ++a_idx)
109                 glDisableVertexAttribArray(a_idx);
110
111         for (int v = 0; v < BATCH_MAX_VBO_CT; ++v)
112                 {
113                 VertexBuffer* verts = batch->verts[v];
114                 if (verts == NULL)
115                         break;
116
117                 const VertexFormat* format = &verts->format;
118
119                 const unsigned attrib_ct = format->attrib_ct;
120                 const unsigned stride = format->stride;
121
122                 VertexBuffer_use(verts);
123
124                 for (unsigned a_idx = 0; a_idx < attrib_ct; ++a_idx)
125                         {
126                         const Attrib* a = format->attribs + a_idx;
127
128                         const GLvoid* pointer = (const GLubyte*)0 + a->offset;
129
130                         const GLint loc = glGetAttribLocation(batch->program, a->name);
131
132                         if (loc == -1) continue;
133
134                         glEnableVertexAttribArray(loc);
135
136                         switch (a->fetch_mode)
137                                 {
138                                 case KEEP_FLOAT:
139                                 case CONVERT_INT_TO_FLOAT:
140                                         glVertexAttribPointer(loc, a->comp_ct, a->gl_comp_type, GL_FALSE, stride, pointer);
141                                         break;
142                                 case NORMALIZE_INT_TO_FLOAT:
143                                         glVertexAttribPointer(loc, a->comp_ct, a->gl_comp_type, GL_TRUE, stride, pointer);
144                                         break;
145                                 case KEEP_INT:
146                                         glVertexAttribIPointer(loc, a->comp_ct, a->gl_comp_type, stride, pointer);
147                                 }
148                         }
149                 }
150
151         batch->program_dirty = false;
152         }
153
154 void Batch_use_program(Batch* batch)
155         {
156         // NOTE: use_program & done_using_program are fragile, depend on staying in sync with
157         //       the GL context's active program. use_program doesn't mark other programs as "not used".
158         // TODO: make not fragile (somehow)
159
160         if (!batch->program_in_use)
161                 {
162                 glUseProgram(batch->program);
163                 batch->program_in_use = true;
164                 }
165         }
166
167 void Batch_done_using_program(Batch* batch)
168         {
169         if (batch->program_in_use)
170                 {
171                 glUseProgram(0);
172                 batch->program_in_use = false;
173                 }
174         }
175
176 void Batch_Uniform1i(Batch* batch, const char* name, int value)
177         {
178         int loc = glGetUniformLocation(batch->program, name);
179
180 #if TRUST_NO_ONE
181         assert(loc != -1);
182 #endif
183
184         glUniform1i(loc, value);
185         }
186
187 void Batch_Uniform1b(Batch* batch, const char* name, bool value)
188         {
189         int loc = glGetUniformLocation(batch->program, name);
190
191 #if TRUST_NO_ONE
192         assert(loc != -1);
193 #endif
194
195         glUniform1i(loc, value ? GL_TRUE : GL_FALSE);
196         }
197
198 void Batch_Uniform2f(Batch* batch, const char* name, float x, float y)
199         {
200         int loc = glGetUniformLocation(batch->program, name);
201
202 #if TRUST_NO_ONE
203         assert(loc != -1);
204 #endif
205
206         glUniform2f(loc, x, y);
207         }
208
209 void Batch_Uniform3f(Batch* batch, const char* name, float x, float y, float z)
210         {
211         int loc = glGetUniformLocation(batch->program, name);
212
213 #if TRUST_NO_ONE
214         assert(loc != -1);
215 #endif
216
217         glUniform3f(loc, x, y, z);
218         }
219
220 void Batch_Uniform4f(Batch* batch, const char* name, float x, float y, float z, float w)
221         {
222         int loc = glGetUniformLocation(batch->program, name);
223
224 #if TRUST_NO_ONE
225         assert(loc != -1);
226 #endif
227
228         glUniform4f(loc, x, y, z, w);
229         }
230
231 void Batch_Uniform1f(Batch* batch, const char* name, float x)
232         {
233         int loc = glGetUniformLocation(batch->program, name);
234
235 #if TRUST_NO_ONE
236         assert(loc != -1);
237 #endif
238
239         glUniform1f(loc, x);
240         }
241
242 void Batch_Uniform3fv(Batch* batch, const char* name, const float data[3])
243         {
244         int loc = glGetUniformLocation(batch->program, name);
245
246 #if TRUST_NO_ONE
247         assert(loc != -1);
248 #endif
249
250         glUniform3fv(loc, 1, data);
251         }
252
253 void Batch_Uniform4fv(Batch* batch, const char* name, const float data[4])
254         {
255         int loc = glGetUniformLocation(batch->program, name);
256
257 #if TRUST_NO_ONE
258         assert(loc != -1);
259 #endif
260
261         glUniform4fv(loc, 1, data);
262         }
263
264 static void Batch_prime(Batch* batch)
265         {
266         batch->vao_id = vao_id_alloc();
267         glBindVertexArray(batch->vao_id);
268
269         for (int v = 0; v < BATCH_MAX_VBO_CT; ++v)
270                 {
271                 if (batch->verts[v] == NULL)
272                         break;
273                 VertexBuffer_use(batch->verts[v]);
274                 }
275
276         if (batch->elem)
277                 ElementList_use(batch->elem);
278
279         // vertex attribs and element list remain bound to this VAO
280         }
281
282 void Batch_draw(Batch* batch)
283         {
284 #if TRUST_NO_ONE
285         assert(batch->phase == READY_TO_DRAW);
286         assert(glIsProgram(batch->program));
287 #endif
288
289         if (batch->vao_id)
290                 glBindVertexArray(batch->vao_id);
291         else
292                 Batch_prime(batch);
293
294         if (batch->program_dirty)
295                 Batch_update_program_bindings(batch);
296
297         Batch_use_program(batch);
298
299         gpuBindMatrices(batch->program);
300
301         if (batch->elem)
302                 {
303                 const ElementList* el = batch->elem;
304
305 #if TRACK_INDEX_RANGE
306                 if (el->base_index)
307                         glDrawRangeElementsBaseVertex(batch->prim_type, el->min_index, el->max_index, el->index_ct, el->index_type, 0, el->base_index);
308                 else
309                         glDrawRangeElements(batch->prim_type, el->min_index, el->max_index, el->index_ct, el->index_type, 0);
310 #else
311                 glDrawElements(batch->prim_type, el->index_ct, GL_UNSIGNED_INT, 0);
312 #endif
313                 }
314         else
315                 glDrawArrays(batch->prim_type, 0, batch->verts[0]->vertex_ct);
316
317         Batch_done_using_program(batch);
318         glBindVertexArray(0);
319         }
320
321
322
323 // clement : temp stuff
324 void Batch_draw_stupid(Batch* batch)
325 {
326         if (batch->vao_id)
327                 glBindVertexArray(batch->vao_id);
328         else
329                 Batch_prime(batch);
330
331         if (batch->program_dirty)
332                 Batch_update_program_bindings(batch);
333
334         // Batch_use_program(batch);
335
336         //gpuBindMatrices(batch->program);
337
338         if (batch->elem)
339                 {
340                 const ElementList* el = batch->elem;
341
342 #if TRACK_INDEX_RANGE
343                 if (el->base_index)
344                         glDrawRangeElementsBaseVertex(batch->prim_type, el->min_index, el->max_index, el->index_ct, el->index_type, 0, el->base_index);
345                 else
346                         glDrawRangeElements(batch->prim_type, el->min_index, el->max_index, el->index_ct, el->index_type, 0);
347 #else
348                 glDrawElements(batch->prim_type, el->index_ct, GL_UNSIGNED_INT, 0);
349 #endif
350                 }
351         else
352                 glDrawArrays(batch->prim_type, 0, batch->verts[0]->vertex_ct);
353
354         // Batch_done_using_program(batch);
355         glBindVertexArray(0);
356 }
357
358 // clement : temp stuff
359 void Batch_draw_stupid_instanced(Batch* batch, unsigned int instance_vbo, int instance_count,
360                                  int attrib_nbr, int attrib_stride, int attrib_size[16], int attrib_loc[16])
361 {
362         if (batch->vao_id)
363                 glBindVertexArray(batch->vao_id);
364         else
365                 Batch_prime(batch);
366
367         if (batch->program_dirty)
368                 Batch_update_program_bindings(batch);
369
370         glBindBuffer(GL_ARRAY_BUFFER, instance_vbo);
371         int ptr_ofs = 0;
372         for (int i = 0; i < attrib_nbr; ++i) {
373                 int size = attrib_size[i];
374                 int loc = attrib_loc[i];
375                 int atr_ofs = 0;
376
377                 while (size > 0) {
378                         glEnableVertexAttribArray(loc + atr_ofs);
379                         glVertexAttribPointer(loc + atr_ofs, (size > 4) ? 4 : size, GL_FLOAT, GL_FALSE,
380                                               sizeof(float) * attrib_stride, (GLvoid*)(sizeof(float) * ptr_ofs));
381                         glVertexAttribDivisor(loc + atr_ofs, 1);
382                         atr_ofs++;
383                         ptr_ofs += (size > 4) ? 4 : size;
384                         size -= 4;
385                 }
386         }
387         glBindBuffer(GL_ARRAY_BUFFER, 0);
388
389         // Batch_use_program(batch);
390
391         //gpuBindMatrices(batch->program);
392
393         if (batch->elem)
394                 {
395                 const ElementList* el = batch->elem;
396
397                 glDrawElementsInstanced(batch->prim_type, el->index_ct, GL_UNSIGNED_INT, 0, instance_count);
398                 }
399         else
400                 glDrawArraysInstanced(batch->prim_type, 0, batch->verts[0]->vertex_ct, instance_count);
401
402         // Batch_done_using_program(batch);
403         glBindVertexArray(0);
404 }
405