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