1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      OpenGL implementation of some of the primitive routines.
12  *
13  *
14  *      By Pavel Sountsov.
15  *
16  *      See readme.txt for copyright information.
17  */
18 
19 #define ALLEGRO_INTERNAL_UNSTABLE
20 
21 #include "allegro5/allegro.h"
22 #include "allegro5/allegro_primitives.h"
23 #include "allegro5/allegro_opengl.h"
24 #include "allegro5/internal/aintern_prim_opengl.h"
25 #include "allegro5/internal/aintern_prim_soft.h"
26 #include "allegro5/platform/alplatf.h"
27 #include "allegro5/internal/aintern_prim.h"
28 
29 #ifdef ALLEGRO_CFG_OPENGL
30 
31 #include "allegro5/allegro_opengl.h"
32 #include "allegro5/internal/aintern_opengl.h"
33 
convert_storage(ALLEGRO_PRIM_STORAGE storage,GLenum * type,int * ncoord,bool * normalized)34 static void convert_storage(ALLEGRO_PRIM_STORAGE storage, GLenum* type, int* ncoord, bool* normalized)
35 {
36    switch(storage) {
37       case ALLEGRO_PRIM_FLOAT_2:
38          *type = GL_FLOAT;
39          *ncoord = 2;
40          *normalized = false;
41          break;
42       case ALLEGRO_PRIM_FLOAT_3:
43          *type = GL_FLOAT;
44          *ncoord = 3;
45          *normalized = false;
46          break;
47       case ALLEGRO_PRIM_SHORT_2:
48          *type = GL_SHORT;
49          *ncoord = 2;
50          *normalized = false;
51          break;
52       case ALLEGRO_PRIM_FLOAT_1:
53          *type = GL_FLOAT;
54          *ncoord = 1;
55          *normalized = false;
56          break;
57       case ALLEGRO_PRIM_FLOAT_4:
58          *type = GL_FLOAT;
59          *ncoord = 4;
60          *normalized = false;
61          break;
62       case ALLEGRO_PRIM_UBYTE_4:
63          *type = GL_UNSIGNED_BYTE;
64          *ncoord = 4;
65          *normalized = false;
66          break;
67       case ALLEGRO_PRIM_SHORT_4:
68          *type = GL_SHORT;
69          *ncoord = 4;
70          *normalized = false;
71          break;
72       case ALLEGRO_PRIM_NORMALIZED_UBYTE_4:
73          *type = GL_UNSIGNED_BYTE;
74          *ncoord = 4;
75          *normalized = true;
76          break;
77       case ALLEGRO_PRIM_NORMALIZED_SHORT_2:
78          *type = GL_SHORT;
79          *ncoord = 2;
80          *normalized = true;
81          break;
82       case ALLEGRO_PRIM_NORMALIZED_SHORT_4:
83          *type = GL_SHORT;
84          *ncoord = 4;
85          *normalized = true;
86          break;
87       case ALLEGRO_PRIM_NORMALIZED_USHORT_2:
88          *type = GL_UNSIGNED_SHORT;
89          *ncoord = 2;
90          *normalized = true;
91          break;
92       case ALLEGRO_PRIM_NORMALIZED_USHORT_4:
93          *type = GL_UNSIGNED_SHORT;
94          *ncoord = 4;
95          *normalized = true;
96          break;
97 #ifndef ALLEGRO_CFG_OPENGLES
98       case ALLEGRO_PRIM_HALF_FLOAT_2:
99          *type = GL_HALF_FLOAT;
100          *ncoord = 2;
101          *normalized = false;
102          break;
103       case ALLEGRO_PRIM_HALF_FLOAT_4:
104          *type = GL_HALF_FLOAT;
105          *ncoord = 4;
106          *normalized = false;
107          break;
108 #endif
109       default:
110          ASSERT(0);
111    }
112 }
113 
setup_state(const char * vtxs,const ALLEGRO_VERTEX_DECL * decl,ALLEGRO_BITMAP * texture)114 static void setup_state(const char* vtxs, const ALLEGRO_VERTEX_DECL* decl, ALLEGRO_BITMAP* texture)
115 {
116    ALLEGRO_DISPLAY *display = al_get_current_display();
117    GLenum type;
118    int ncoord;
119    bool normalized;
120 
121    if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) {
122 #ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE
123       if(decl) {
124          ALLEGRO_VERTEX_ELEMENT* e;
125          int i;
126 
127          e = &decl->elements[ALLEGRO_PRIM_POSITION];
128          if(e->attribute) {
129             convert_storage(e->storage, &type, &ncoord, &normalized);
130 
131             if (display->ogl_extras->varlocs.pos_loc >= 0) {
132                glVertexAttribPointer(display->ogl_extras->varlocs.pos_loc, ncoord, type, normalized, decl->stride, vtxs + e->offset);
133                glEnableVertexAttribArray(display->ogl_extras->varlocs.pos_loc);
134             }
135          } else {
136             if (display->ogl_extras->varlocs.pos_loc >= 0) {
137                glDisableVertexAttribArray(display->ogl_extras->varlocs.pos_loc);
138             }
139          }
140 
141          e = &decl->elements[ALLEGRO_PRIM_TEX_COORD];
142          if(!e->attribute)
143             e = &decl->elements[ALLEGRO_PRIM_TEX_COORD_PIXEL];
144          if(e->attribute) {
145             convert_storage(e->storage, &type, &ncoord, &normalized);
146 
147             if (display->ogl_extras->varlocs.texcoord_loc >= 0) {
148                glVertexAttribPointer(display->ogl_extras->varlocs.texcoord_loc, ncoord, type, normalized, decl->stride, vtxs + e->offset);
149                glEnableVertexAttribArray(display->ogl_extras->varlocs.texcoord_loc);
150             }
151          } else {
152             if (display->ogl_extras->varlocs.texcoord_loc >= 0) {
153                glDisableVertexAttribArray(display->ogl_extras->varlocs.texcoord_loc);
154             }
155          }
156 
157          e = &decl->elements[ALLEGRO_PRIM_COLOR_ATTR];
158          if(e->attribute) {
159             if (display->ogl_extras->varlocs.color_loc >= 0) {
160                glVertexAttribPointer(display->ogl_extras->varlocs.color_loc, 4, GL_FLOAT, true, decl->stride, vtxs + e->offset);
161                glEnableVertexAttribArray(display->ogl_extras->varlocs.color_loc);
162             }
163          } else {
164             if (display->ogl_extras->varlocs.color_loc >= 0) {
165                glDisableVertexAttribArray(display->ogl_extras->varlocs.color_loc);
166             }
167          }
168 
169          for (i = 0; i < _ALLEGRO_PRIM_MAX_USER_ATTR; i++) {
170             e = &decl->elements[ALLEGRO_PRIM_USER_ATTR + i];
171             if (e->attribute) {
172                convert_storage(e->storage, &type, &ncoord, &normalized);
173 
174                if (display->ogl_extras->varlocs.user_attr_loc[i] >= 0) {
175                   glVertexAttribPointer(display->ogl_extras->varlocs.user_attr_loc[i], ncoord, type, normalized, decl->stride, vtxs + e->offset);
176                   glEnableVertexAttribArray(display->ogl_extras->varlocs.user_attr_loc[i]);
177                }
178             } else {
179                if (display->ogl_extras->varlocs.user_attr_loc[i] >= 0) {
180                   glDisableVertexAttribArray(display->ogl_extras->varlocs.user_attr_loc[i]);
181                }
182             }
183          }
184       } else {
185          if (display->ogl_extras->varlocs.pos_loc >= 0) {
186             glVertexAttribPointer(display->ogl_extras->varlocs.pos_loc, 3, GL_FLOAT, false, sizeof(ALLEGRO_VERTEX), vtxs + offsetof(ALLEGRO_VERTEX, x));
187             glEnableVertexAttribArray(display->ogl_extras->varlocs.pos_loc);
188          }
189 
190          if (display->ogl_extras->varlocs.texcoord_loc >= 0) {
191             glVertexAttribPointer(display->ogl_extras->varlocs.texcoord_loc, 2, GL_FLOAT, false, sizeof(ALLEGRO_VERTEX), vtxs + offsetof(ALLEGRO_VERTEX, u));
192             glEnableVertexAttribArray(display->ogl_extras->varlocs.texcoord_loc);
193          }
194 
195          if (display->ogl_extras->varlocs.color_loc >= 0) {
196             glVertexAttribPointer(display->ogl_extras->varlocs.color_loc, 4, GL_FLOAT, true, sizeof(ALLEGRO_VERTEX), vtxs + offsetof(ALLEGRO_VERTEX, color));
197             glEnableVertexAttribArray(display->ogl_extras->varlocs.color_loc);
198          }
199       }
200 #endif
201    }
202    else {
203 #ifdef ALLEGRO_CFG_OPENGL_FIXED_FUNCTION
204       if(decl) {
205          ALLEGRO_VERTEX_ELEMENT* e;
206          e = &decl->elements[ALLEGRO_PRIM_POSITION];
207          if(e->attribute) {
208             glEnableClientState(GL_VERTEX_ARRAY);
209 
210             convert_storage(e->storage, &type, &ncoord, &normalized);
211 
212             glVertexPointer(ncoord, type, decl->stride, vtxs + e->offset);
213          } else {
214             glDisableClientState(GL_VERTEX_ARRAY);
215          }
216 
217          e = &decl->elements[ALLEGRO_PRIM_TEX_COORD];
218          if(!e->attribute)
219             e = &decl->elements[ALLEGRO_PRIM_TEX_COORD_PIXEL];
220          if(texture && e->attribute) {
221             glEnableClientState(GL_TEXTURE_COORD_ARRAY);
222 
223             convert_storage(e->storage, &type, &ncoord, &normalized);
224 
225             glTexCoordPointer(ncoord, type, decl->stride, vtxs + e->offset);
226          } else {
227             glDisableClientState(GL_TEXTURE_COORD_ARRAY);
228          }
229 
230          e = &decl->elements[ALLEGRO_PRIM_COLOR_ATTR];
231          if(e->attribute) {
232             glEnableClientState(GL_COLOR_ARRAY);
233 
234             glColorPointer(4, GL_FLOAT, decl->stride, vtxs + e->offset);
235          } else {
236             glDisableClientState(GL_COLOR_ARRAY);
237             glColor4f(1, 1, 1, 1);
238          }
239       } else {
240          glEnableClientState(GL_COLOR_ARRAY);
241          glEnableClientState(GL_VERTEX_ARRAY);
242          glEnableClientState(GL_TEXTURE_COORD_ARRAY);
243          if (!(display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE))
244             glDisableClientState(GL_NORMAL_ARRAY);
245 
246          glVertexPointer(3, GL_FLOAT, sizeof(ALLEGRO_VERTEX), vtxs + offsetof(ALLEGRO_VERTEX, x));
247          glColorPointer(4, GL_FLOAT, sizeof(ALLEGRO_VERTEX), vtxs + offsetof(ALLEGRO_VERTEX, color));
248          glTexCoordPointer(2, GL_FLOAT, sizeof(ALLEGRO_VERTEX), vtxs + offsetof(ALLEGRO_VERTEX, u));
249       }
250 #endif
251    }
252 
253    if (texture) {
254       GLuint gl_texture = al_get_opengl_texture(texture);
255       int true_w, true_h;
256       int tex_x, tex_y;
257       float mat[4][4] = {
258          {1,  0,  0, 0},
259          {0, -1,  0, 0},
260          {0,  0,  1, 0},
261          {0,  0,  0, 1}
262       };
263       int height;
264 
265       if (texture->parent)
266          height = texture->parent->h;
267       else
268          height = texture->h;
269 
270       al_get_opengl_texture_size(texture, &true_w, &true_h);
271       al_get_opengl_texture_position(texture, &tex_x, &tex_y);
272 
273       mat[3][0] = (float)tex_x / true_w;
274       mat[3][1] = (float)(height - tex_y) / true_h;
275 
276       if(decl) {
277          if(decl->elements[ALLEGRO_PRIM_TEX_COORD_PIXEL].attribute) {
278             mat[0][0] = 1.0f / true_w;
279             mat[1][1] = -1.0f / true_h;
280          } else {
281             mat[0][0] = (float)al_get_bitmap_width(texture) / true_w;
282             mat[1][1] = -(float)al_get_bitmap_height(texture) / true_h;
283          }
284       } else {
285          mat[0][0] = 1.0f / true_w;
286          mat[1][1] = -1.0f / true_h;
287       }
288 
289       if (!(display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE)) {
290          glBindTexture(GL_TEXTURE_2D, gl_texture);
291       }
292 
293       if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) {
294 #ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE
295          GLint handle;
296 
297          handle = display->ogl_extras->varlocs.tex_matrix_loc;
298          if (handle >= 0)
299             glUniformMatrix4fv(handle, 1, false, (float *)mat);
300 
301          handle = display->ogl_extras->varlocs.use_tex_matrix_loc;
302          if (handle >= 0)
303             glUniform1i(handle, 1);
304 
305          if (display->ogl_extras->varlocs.use_tex_loc >= 0) {
306             glUniform1i(display->ogl_extras->varlocs.use_tex_loc, 1);
307          }
308          if (display->ogl_extras->varlocs.tex_loc >= 0) {
309             glActiveTexture(GL_TEXTURE0);
310             glBindTexture(GL_TEXTURE_2D, al_get_opengl_texture(texture));
311             glUniform1i(display->ogl_extras->varlocs.tex_loc, 0); // 0th sampler
312          }
313          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
314          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
315 #endif
316       }
317       else {
318 #ifdef ALLEGRO_CFG_OPENGL_FIXED_FUNCTION
319          glMatrixMode(GL_TEXTURE);
320          glLoadMatrixf(mat[0]);
321          glMatrixMode(GL_MODELVIEW);
322 
323          glEnable(GL_TEXTURE_2D);
324          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
325          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
326 #endif
327       }
328    } else {
329       /* Don't unbind the texture here if shaders are used, since the user may
330        * have set the 0'th texture unit manually via the shader API. */
331       if (!(display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE)) {
332          glBindTexture(GL_TEXTURE_2D, 0);
333       }
334    }
335 }
336 
revert_state(ALLEGRO_BITMAP * texture)337 static void revert_state(ALLEGRO_BITMAP* texture)
338 {
339    ALLEGRO_DISPLAY *display = al_get_current_display();
340 
341    if(texture) {
342       if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) {
343 #ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE
344          float identity[16] = {
345             1, 0, 0, 0,
346             0, 1, 0, 0,
347             0, 0, 1, 0,
348             0, 0, 0, 1
349          };
350          GLint handle;
351          handle = display->ogl_extras->varlocs.tex_matrix_loc;
352          if (handle >= 0)
353             glUniformMatrix4fv(handle, 1, false, identity);
354          handle = display->ogl_extras->varlocs.use_tex_matrix_loc;
355          if (handle >= 0)
356             glUniform1i(handle, 0);
357          if (display->ogl_extras->varlocs.use_tex_loc >= 0)
358             glUniform1i(display->ogl_extras->varlocs.use_tex_loc, 0);
359 #endif
360       }
361       else {
362 #ifdef ALLEGRO_CFG_OPENGL_FIXED_FUNCTION
363          glDisable(GL_TEXTURE_2D);
364          glMatrixMode(GL_TEXTURE);
365          glLoadIdentity();
366          glMatrixMode(GL_MODELVIEW);
367 #endif
368       }
369    }
370 
371    if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) {
372 #ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE
373       if (display->ogl_extras->varlocs.pos_loc >= 0)
374          glDisableVertexAttribArray(display->ogl_extras->varlocs.pos_loc);
375       if (display->ogl_extras->varlocs.color_loc >= 0)
376          glDisableVertexAttribArray(display->ogl_extras->varlocs.color_loc);
377       if (display->ogl_extras->varlocs.texcoord_loc >= 0)
378          glDisableVertexAttribArray(display->ogl_extras->varlocs.texcoord_loc);
379 #endif
380    }
381    else {
382 #ifdef ALLEGRO_CFG_OPENGL_FIXED_FUNCTION
383       glDisableClientState(GL_COLOR_ARRAY);
384       glDisableClientState(GL_VERTEX_ARRAY);
385       glDisableClientState(GL_TEXTURE_COORD_ARRAY);
386 #endif
387    }
388 }
389 
draw_prim_raw(ALLEGRO_BITMAP * target,ALLEGRO_BITMAP * texture,ALLEGRO_VERTEX_BUFFER * vertex_buffer,const void * vtx,const ALLEGRO_VERTEX_DECL * decl,int start,int end,int type)390 static int draw_prim_raw(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture,
391    ALLEGRO_VERTEX_BUFFER* vertex_buffer,
392    const void* vtx, const ALLEGRO_VERTEX_DECL* decl,
393    int start, int end, int type)
394 {
395    int num_primitives = 0;
396    ALLEGRO_DISPLAY *disp = _al_get_bitmap_display(target);
397    ALLEGRO_BITMAP *opengl_target = target;
398    ALLEGRO_BITMAP_EXTRA_OPENGL *extra;
399    int num_vtx = end - start;
400 
401    if (target->parent) {
402        opengl_target = target->parent;
403    }
404    extra = opengl_target->extra;
405 
406    if ((!extra->is_backbuffer && disp->ogl_extras->opengl_target !=
407       opengl_target) || al_is_bitmap_locked(target)) {
408       if (vertex_buffer) {
409          return _al_draw_buffer_common_soft(vertex_buffer, texture, NULL, start, end, type);
410       }
411       else {
412          return _al_draw_prim_soft(texture, vtx, decl, start, end, type);
413       }
414    }
415 
416    if (vertex_buffer) {
417       glBindBuffer(GL_ARRAY_BUFFER, (GLuint)vertex_buffer->common.handle);
418    }
419 
420    _al_opengl_set_blender(disp);
421    setup_state(vtx, decl, texture);
422 
423    switch (type) {
424       case ALLEGRO_PRIM_LINE_LIST: {
425          glDrawArrays(GL_LINES, start, num_vtx);
426          num_primitives = num_vtx / 2;
427          break;
428       };
429       case ALLEGRO_PRIM_LINE_STRIP: {
430          glDrawArrays(GL_LINE_STRIP, start, num_vtx);
431          num_primitives = num_vtx - 1;
432          break;
433       };
434       case ALLEGRO_PRIM_LINE_LOOP: {
435          glDrawArrays(GL_LINE_LOOP, start, num_vtx);
436          num_primitives = num_vtx;
437          break;
438       };
439       case ALLEGRO_PRIM_TRIANGLE_LIST: {
440          glDrawArrays(GL_TRIANGLES, start, num_vtx);
441          num_primitives = num_vtx / 3;
442          break;
443       };
444       case ALLEGRO_PRIM_TRIANGLE_STRIP: {
445          glDrawArrays(GL_TRIANGLE_STRIP, start, num_vtx);
446          num_primitives = num_vtx - 2;
447          break;
448       };
449       case ALLEGRO_PRIM_TRIANGLE_FAN: {
450          glDrawArrays(GL_TRIANGLE_FAN, start, num_vtx);
451          num_primitives = num_vtx - 2;
452          break;
453       };
454       case ALLEGRO_PRIM_POINT_LIST: {
455          glDrawArrays(GL_POINTS, start, num_vtx);
456          num_primitives = num_vtx;
457          break;
458       };
459    }
460 
461    revert_state(texture);
462 
463    if (vertex_buffer) {
464       glBindBuffer(GL_ARRAY_BUFFER, 0);
465    }
466 
467    return num_primitives;
468 }
469 
draw_prim_indexed_raw(ALLEGRO_BITMAP * target,ALLEGRO_BITMAP * texture,ALLEGRO_VERTEX_BUFFER * vertex_buffer,const void * vtx,const ALLEGRO_VERTEX_DECL * decl,ALLEGRO_INDEX_BUFFER * index_buffer,const int * indices,int start,int end,int type)470 static int draw_prim_indexed_raw(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture,
471    ALLEGRO_VERTEX_BUFFER* vertex_buffer,
472    const void* vtx, const ALLEGRO_VERTEX_DECL* decl,
473    ALLEGRO_INDEX_BUFFER* index_buffer,
474    const int* indices,
475    int start, int end, int type)
476 {
477    int num_primitives = 0;
478    ALLEGRO_DISPLAY *disp = _al_get_bitmap_display(target);
479    ALLEGRO_BITMAP *opengl_target = target;
480    ALLEGRO_BITMAP_EXTRA_OPENGL *extra;
481    const char* idx = (const char*)indices;
482    int start_offset = 0;
483    GLenum idx_size = GL_UNSIGNED_INT;
484    bool use_buffers = index_buffer != NULL;
485    int num_vtx = end - start;
486 #if defined ALLEGRO_IPHONE
487    GLushort* iphone_idx = NULL;
488 #endif
489 
490    if (use_buffers) {
491       idx_size = index_buffer->index_size == 4 ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
492       start_offset = start * index_buffer->index_size;
493    }
494 
495    if (target->parent) {
496       opengl_target = target->parent;
497    }
498    extra = opengl_target->extra;
499 
500    if ((!extra->is_backbuffer && disp->ogl_extras->opengl_target !=
501       opengl_target) || al_is_bitmap_locked(target)) {
502       if (use_buffers) {
503          return _al_draw_buffer_common_soft(vertex_buffer, texture, index_buffer, start, end, type);
504       }
505       else {
506          return _al_draw_prim_indexed_soft(texture, vtx, decl, indices, num_vtx, type);
507       }
508    }
509 
510 #if defined ALLEGRO_IPHONE
511    if (!use_buffers) {
512       int ii;
513       iphone_idx = al_malloc(num_vtx * sizeof(GLushort));
514       for (ii = start; ii < end; ii++) {
515          iphone_idx[ii] = (GLushort)indices[ii];
516       }
517       idx = iphone_idx;
518       start = 0;
519       idx_size = GL_UNSIGNED_SHORT;
520    }
521 #endif
522 
523    _al_opengl_set_blender(disp);
524 
525    if (use_buffers) {
526       glBindBuffer(GL_ARRAY_BUFFER, (GLuint)vertex_buffer->common.handle);
527       glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)index_buffer->common.handle);
528    }
529 
530    setup_state(vtx, decl, texture);
531 
532    switch (type) {
533       case ALLEGRO_PRIM_LINE_LIST: {
534          glDrawElements(GL_LINES, num_vtx, idx_size, idx + start_offset);
535          num_primitives = num_vtx / 2;
536          break;
537       };
538       case ALLEGRO_PRIM_LINE_STRIP: {
539          glDrawElements(GL_LINE_STRIP, num_vtx, idx_size, idx + start_offset);
540          num_primitives = num_vtx - 1;
541          break;
542       };
543       case ALLEGRO_PRIM_LINE_LOOP: {
544          /* Unimplemented, as it's too hard to do for Direct3D */
545          break;
546       };
547       case ALLEGRO_PRIM_TRIANGLE_LIST: {
548          glDrawElements(GL_TRIANGLES, num_vtx, idx_size, idx + start_offset);
549          num_primitives = num_vtx / 3;
550          break;
551       };
552       case ALLEGRO_PRIM_TRIANGLE_STRIP: {
553          glDrawElements(GL_TRIANGLE_STRIP, num_vtx, idx_size, idx + start_offset);
554          num_primitives = num_vtx - 2;
555          break;
556       };
557       case ALLEGRO_PRIM_TRIANGLE_FAN: {
558          glDrawElements(GL_TRIANGLE_FAN, num_vtx, idx_size, idx + start_offset);
559          num_primitives = num_vtx - 2;
560          break;
561       };
562       case ALLEGRO_PRIM_POINT_LIST: {
563          /* Unimplemented, as it's too hard to do for Direct3D */
564          break;
565       };
566    }
567 
568    revert_state(texture);
569 
570    if (use_buffers) {
571       glBindBuffer(GL_ARRAY_BUFFER, 0);
572       glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
573    }
574 
575 #if defined ALLEGRO_IPHONE
576    al_free(iphone_idx);
577 #endif
578 
579    return num_primitives;
580 }
581 
582 #endif /* ALLEGRO_CFG_OPENGL */
583 
_al_draw_prim_opengl(ALLEGRO_BITMAP * target,ALLEGRO_BITMAP * texture,const void * vtxs,const ALLEGRO_VERTEX_DECL * decl,int start,int end,int type)584 int _al_draw_prim_opengl(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, const void* vtxs, const ALLEGRO_VERTEX_DECL* decl, int start, int end, int type)
585 {
586 #ifdef ALLEGRO_CFG_OPENGL
587    return draw_prim_raw(target, texture, 0, vtxs, decl, start, end, type);
588 #else
589    (void)target;
590    (void)texture;
591    (void)vtxs;
592    (void)start;
593    (void)end;
594    (void)type;
595    (void)decl;
596 
597    return 0;
598 #endif
599 }
600 
_al_draw_vertex_buffer_opengl(ALLEGRO_BITMAP * target,ALLEGRO_BITMAP * texture,ALLEGRO_VERTEX_BUFFER * vertex_buffer,int start,int end,int type)601 int _al_draw_vertex_buffer_opengl(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, ALLEGRO_VERTEX_BUFFER* vertex_buffer, int start, int end, int type)
602 {
603 #ifdef ALLEGRO_CFG_OPENGL
604    return draw_prim_raw(target, texture, vertex_buffer, 0, vertex_buffer->decl, start, end, type);
605 #else
606    (void)target;
607    (void)texture;
608    (void)vertex_buffer;
609    (void)start;
610    (void)end;
611    (void)type;
612 
613    return 0;
614 #endif
615 }
616 
_al_draw_prim_indexed_opengl(ALLEGRO_BITMAP * target,ALLEGRO_BITMAP * texture,const void * vtxs,const ALLEGRO_VERTEX_DECL * decl,const int * indices,int num_vtx,int type)617 int _al_draw_prim_indexed_opengl(ALLEGRO_BITMAP *target, ALLEGRO_BITMAP* texture, const void* vtxs, const ALLEGRO_VERTEX_DECL* decl, const int* indices, int num_vtx, int type)
618 {
619 #ifdef ALLEGRO_CFG_OPENGL
620    return draw_prim_indexed_raw(target, texture, NULL, vtxs, decl, NULL, indices, 0, num_vtx, type);
621 #else
622    (void)target;
623    (void)texture;
624    (void)vtxs;
625    (void)decl;
626    (void)indices;
627    (void)num_vtx;
628    (void)type;
629 
630    return 0;
631 #endif
632 }
633 
_al_draw_indexed_buffer_opengl(ALLEGRO_BITMAP * target,ALLEGRO_BITMAP * texture,ALLEGRO_VERTEX_BUFFER * vertex_buffer,ALLEGRO_INDEX_BUFFER * index_buffer,int start,int end,int type)634 int _al_draw_indexed_buffer_opengl(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, ALLEGRO_VERTEX_BUFFER* vertex_buffer, ALLEGRO_INDEX_BUFFER* index_buffer, int start, int end, int type)
635 {
636 #ifdef ALLEGRO_CFG_OPENGL
637    return draw_prim_indexed_raw(target, texture, vertex_buffer, NULL, vertex_buffer->decl, index_buffer, NULL, start, end, type);
638 #else
639    (void)target;
640    (void)texture;
641    (void)vertex_buffer;
642    (void)index_buffer;
643    (void)start;
644    (void)end;
645    (void)type;
646 
647    return 0;
648 #endif
649 }
650 
651 #ifdef ALLEGRO_CFG_OPENGL
create_buffer_common(ALLEGRO_BUFFER_COMMON * common,GLenum type,const void * initial_data,int size,int flags)652 static bool create_buffer_common(ALLEGRO_BUFFER_COMMON* common, GLenum type, const void* initial_data, int size, int flags)
653 {
654    GLuint vbo;
655    GLenum usage;
656 
657    switch (flags)
658    {
659 #if !defined ALLEGRO_CFG_OPENGLES
660       case ALLEGRO_PRIM_BUFFER_STREAM:
661          usage = GL_STREAM_DRAW;
662          break;
663 #endif
664       case ALLEGRO_PRIM_BUFFER_STATIC:
665          usage = GL_STATIC_DRAW;
666          break;
667       case ALLEGRO_PRIM_BUFFER_DYNAMIC:
668          usage = GL_DYNAMIC_DRAW;
669          break;
670       default:
671          usage = GL_STATIC_DRAW;
672    }
673 
674    glGenBuffers(1, &vbo);
675    glBindBuffer(type, vbo);
676    glBufferData(type, size, initial_data, usage);
677    glBindBuffer(type, 0);
678 
679    if (glGetError())
680       return false;
681 
682    common->handle = vbo;
683    common->local_buffer_length = 0;
684    return true;
685 }
686 #endif
687 
_al_create_vertex_buffer_opengl(ALLEGRO_VERTEX_BUFFER * buf,const void * initial_data,size_t num_vertices,int flags)688 bool _al_create_vertex_buffer_opengl(ALLEGRO_VERTEX_BUFFER* buf, const void* initial_data, size_t num_vertices, int flags)
689 {
690 #ifdef ALLEGRO_CFG_OPENGL
691    int stride = buf->decl ? buf->decl->stride : (int)sizeof(ALLEGRO_VERTEX);
692 
693    return create_buffer_common(&buf->common, GL_ARRAY_BUFFER, initial_data, num_vertices * stride, flags);
694 #else
695    (void)buf;
696    (void)initial_data;
697    (void)num_vertices;
698    (void)flags;
699 
700    return false;
701 #endif
702 }
703 
_al_create_index_buffer_opengl(ALLEGRO_INDEX_BUFFER * buf,const void * initial_data,size_t num_indices,int flags)704 bool _al_create_index_buffer_opengl(ALLEGRO_INDEX_BUFFER* buf, const void* initial_data, size_t num_indices, int flags)
705 {
706 #ifdef ALLEGRO_CFG_OPENGL
707    return create_buffer_common(&buf->common, GL_ELEMENT_ARRAY_BUFFER, initial_data, num_indices * buf->index_size, flags);;
708 #else
709    (void)buf;
710    (void)initial_data;
711    (void)num_indices;
712    (void)flags;
713 
714    return false;
715 #endif
716 }
717 
_al_destroy_vertex_buffer_opengl(ALLEGRO_VERTEX_BUFFER * buf)718 void _al_destroy_vertex_buffer_opengl(ALLEGRO_VERTEX_BUFFER* buf)
719 {
720 #ifdef ALLEGRO_CFG_OPENGL
721    glDeleteBuffers(1, (GLuint*)&buf->common.handle);
722    al_free(buf->common.locked_memory);
723 #else
724    (void)buf;
725 #endif
726 }
727 
_al_destroy_index_buffer_opengl(ALLEGRO_INDEX_BUFFER * buf)728 void _al_destroy_index_buffer_opengl(ALLEGRO_INDEX_BUFFER* buf)
729 {
730 #ifdef ALLEGRO_CFG_OPENGL
731    glDeleteBuffers(1, (GLuint*)&buf->common.handle);
732    al_free(buf->common.locked_memory);
733 #else
734    (void)buf;
735 #endif
736 }
737 
738 #ifdef ALLEGRO_CFG_OPENGL
lock_buffer_common(ALLEGRO_BUFFER_COMMON * common,GLenum type)739 static void* lock_buffer_common(ALLEGRO_BUFFER_COMMON* common, GLenum type)
740 {
741    if (common->local_buffer_length < common->lock_length) {
742       common->locked_memory = al_realloc(common->locked_memory, common->lock_length);
743       common->local_buffer_length = common->lock_length;
744    }
745 
746    if (common->lock_flags != ALLEGRO_LOCK_WRITEONLY) {
747 #if !defined ALLEGRO_CFG_OPENGLES
748       glBindBuffer(type, (GLuint)common->handle);
749       glGetBufferSubData(type, common->lock_offset, common->lock_length, common->locked_memory);
750       glBindBuffer(type, 0);
751       if (glGetError())
752          return 0;
753 #else
754       (void)type;
755       return 0;
756 #endif
757    }
758    return common->locked_memory;
759 }
760 #endif
761 
_al_lock_vertex_buffer_opengl(ALLEGRO_VERTEX_BUFFER * buf)762 void* _al_lock_vertex_buffer_opengl(ALLEGRO_VERTEX_BUFFER* buf)
763 {
764 #ifdef ALLEGRO_CFG_OPENGL
765    return lock_buffer_common(&buf->common, GL_ARRAY_BUFFER);
766 #else
767    (void)buf;
768 
769    return 0;
770 #endif
771 }
772 
_al_lock_index_buffer_opengl(ALLEGRO_INDEX_BUFFER * buf)773 void* _al_lock_index_buffer_opengl(ALLEGRO_INDEX_BUFFER* buf)
774 {
775 #ifdef ALLEGRO_CFG_OPENGL
776    return lock_buffer_common(&buf->common, GL_ELEMENT_ARRAY_BUFFER);
777 #else
778    (void)buf;
779 
780    return 0;
781 #endif
782 }
783 
784 #ifdef ALLEGRO_CFG_OPENGL
unlock_buffer_common(ALLEGRO_BUFFER_COMMON * common,GLenum type)785 static void unlock_buffer_common(ALLEGRO_BUFFER_COMMON* common, GLenum type)
786 {
787    if (common->lock_flags != ALLEGRO_LOCK_READONLY) {
788       glBindBuffer(type, (GLuint)common->handle);
789       glBufferSubData(type, common->lock_offset, common->lock_length, common->locked_memory);
790       glBindBuffer(type, 0);
791    }
792 }
793 #endif
794 
_al_unlock_vertex_buffer_opengl(ALLEGRO_VERTEX_BUFFER * buf)795 void _al_unlock_vertex_buffer_opengl(ALLEGRO_VERTEX_BUFFER* buf)
796 {
797 #ifdef ALLEGRO_CFG_OPENGL
798    unlock_buffer_common(&buf->common, GL_ARRAY_BUFFER);
799 #else
800    (void)buf;
801 #endif
802 }
803 
_al_unlock_index_buffer_opengl(ALLEGRO_INDEX_BUFFER * buf)804 void _al_unlock_index_buffer_opengl(ALLEGRO_INDEX_BUFFER* buf)
805 {
806 #ifdef ALLEGRO_CFG_OPENGL
807    unlock_buffer_common(&buf->common, GL_ELEMENT_ARRAY_BUFFER);
808 #else
809    (void)buf;
810 #endif
811 }
812