static void ogl_draw_pixel(ALLEGRO_DISPLAY *d, float x, float y, ALLEGRO_COLOR *color) { ALLEGRO_BITMAP *target = al_get_target_bitmap(); ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_target; GLfloat vert[2]; GLfloat color_array[4]; /* For sub-bitmaps */ if (target->parent) { target = target->parent; } ogl_target = target->extra; if ((!ogl_target->is_backbuffer && d->ogl_extras->opengl_target != target) || target->locked || !_al_opengl_set_blender(d)) { _al_draw_pixel_memory(target, x, y, color); return; } vert[0] = x; vert[1] = y; color_array[0] = color->r; color_array[1] = color->g; color_array[2] = color->b; color_array[3] = color->a; vert_ptr_on(d, 2, GL_FLOAT, 2*sizeof(float), vert); color_ptr_on(d, 4, GL_FLOAT, 4*sizeof(float), color_array); // Should this be here if it's in the if above? if (!_al_opengl_set_blender(d)) { return; } glDrawArrays(GL_POINTS, 0, 1); vert_ptr_off(d); color_ptr_off(d); }
bool _al_opengl_set_blender(ALLEGRO_DISPLAY *ogl_disp) { int op, src_color, dst_color, op_alpha, src_alpha, dst_alpha; const int blend_modes[8] = { GL_ZERO, GL_ONE, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_COLOR, GL_DST_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_ONE_MINUS_DST_COLOR }; const int blend_equations[3] = { GL_FUNC_ADD, GL_FUNC_SUBTRACT, GL_FUNC_REVERSE_SUBTRACT }; (void)ogl_disp; al_get_separate_blender(&op, &src_color, &dst_color, &op_alpha, &src_alpha, &dst_alpha); /* glBlendFuncSeparate was only included with OpenGL 1.4 */ /* (And not in OpenGL ES) */ #if !defined ALLEGRO_GP2XWIZ #if !defined ALLEGRO_IPHONE && !defined ALLEGRO_ANDROID if (ogl_disp->ogl_extras->ogl_info.version >= _ALLEGRO_OPENGL_VERSION_1_4) { #else if (ogl_disp->ogl_extras->ogl_info.version >= _ALLEGRO_OPENGL_VERSION_2_0) { #endif glEnable(GL_BLEND); glBlendFuncSeparate(blend_modes[src_color], blend_modes[dst_color], blend_modes[src_alpha], blend_modes[dst_alpha]); if (ogl_disp->ogl_extras->ogl_info.version >= _ALLEGRO_OPENGL_VERSION_2_0) { glBlendEquationSeparate( blend_equations[op], blend_equations[op_alpha]); } else { glBlendEquation(blend_equations[op]); } } else { if (src_color == src_alpha && dst_color == dst_alpha) { glEnable(GL_BLEND); glBlendFunc(blend_modes[src_color], blend_modes[dst_color]); } else { ALLEGRO_ERROR("Blender unsupported with this OpenGL version (%d %d %d %d %d %d)\n", op, src_color, dst_color, op_alpha, src_alpha, dst_alpha); return false; } } #else glEnable(GL_BLEND); glBlendFunc(blend_modes[src_color], blend_modes[dst_color]); #endif return true; } /* These functions make drawing calls use shaders or the fixed pipeline * based on what the user has set up. FIXME: OpenGL only right now. */ static void vert_ptr_on(ALLEGRO_DISPLAY *display, int n, GLint t, int stride, void *v) { /* Only use this shader stuff with GLES2+ or equivalent */ if (display->flags & ALLEGRO_USE_PROGRAMMABLE_PIPELINE) { #ifndef ALLEGRO_CFG_NO_GLES2 if (display->ogl_extras->pos_loc >= 0) { glVertexAttribPointer(display->ogl_extras->pos_loc, n, t, false, stride, v); glEnableVertexAttribArray(display->ogl_extras->pos_loc); } #endif } else { glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(n, t, stride, v); } } static void vert_ptr_off(ALLEGRO_DISPLAY *display) { if (display->flags & ALLEGRO_USE_PROGRAMMABLE_PIPELINE) { #ifndef ALLEGRO_CFG_NO_GLES2 if (display->ogl_extras->pos_loc >= 0) { glDisableVertexAttribArray(display->ogl_extras->pos_loc); } #endif } else { glDisableClientState(GL_VERTEX_ARRAY); } } static void color_ptr_on(ALLEGRO_DISPLAY *display, int n, GLint t, int stride, void *v) { if (display->flags & ALLEGRO_USE_PROGRAMMABLE_PIPELINE) { #ifndef ALLEGRO_CFG_NO_GLES2 if (display->ogl_extras->color_loc >= 0) { glVertexAttribPointer(display->ogl_extras->color_loc, n, t, false, stride, v); glEnableVertexAttribArray(display->ogl_extras->color_loc); } #endif } else { glEnableClientState(GL_COLOR_ARRAY); glColorPointer(n, t, stride, v); } } static void color_ptr_off(ALLEGRO_DISPLAY *display) { if (display->flags & ALLEGRO_USE_PROGRAMMABLE_PIPELINE) { #ifndef ALLEGRO_CFG_NO_GLES2 if (display->ogl_extras->color_loc >= 0) { glDisableVertexAttribArray(display->ogl_extras->color_loc); } #endif } else { glDisableClientState(GL_COLOR_ARRAY); } } static void tex_ptr_on(ALLEGRO_DISPLAY *display, int n, GLint t, int stride, void *v) { if (display->flags & ALLEGRO_USE_PROGRAMMABLE_PIPELINE) { #ifndef ALLEGRO_CFG_NO_GLES2 if (display->ogl_extras->texcoord_loc >= 0) { glVertexAttribPointer(display->ogl_extras->texcoord_loc, n, t, false, stride, v); glEnableVertexAttribArray(display->ogl_extras->texcoord_loc); } #endif } else { glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(n, t, stride, v); } } static void tex_ptr_off(ALLEGRO_DISPLAY *display) { if (display->flags & ALLEGRO_USE_PROGRAMMABLE_PIPELINE) { #ifndef ALLEGRO_CFG_NO_GLES2 if (display->ogl_extras->texcoord_loc >= 0) { glDisableVertexAttribArray(display->ogl_extras->texcoord_loc); } #endif } else { glDisableClientState(GL_TEXTURE_COORD_ARRAY); } } /* Dummy implementation of clear. */ static void ogl_clear(ALLEGRO_DISPLAY *d, ALLEGRO_COLOR *color) { ALLEGRO_DISPLAY *ogl_disp = (void *)d; ALLEGRO_BITMAP *target = al_get_target_bitmap(); ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_target; float r, g, b, a; if (target->parent) target = target->parent; ogl_target = target->extra; if ((!ogl_target->is_backbuffer && ogl_disp->ogl_extras->opengl_target != target) || target->locked) { _al_clear_memory(color); return; } al_unmap_rgba_f(*color, &r, &g, &b, &a); /* There's a very nasty bug in Android 2.1 that makes glClear cause * screen flicker (appears to me it's swapping buffers.) Work around * by drawing two triangles instead on that OS. */ #ifdef ALLEGRO_ANDROID if (ogl_target->is_backbuffer && _al_android_is_os_2_1()) { GLfloat v[8] = { 0, d->h, 0, 0, d->w, d->h, d->w, 0 }; GLfloat c[16] = { r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a }; ALLEGRO_TRANSFORM bak1, bak2, t; al_copy_transform(&bak1, &d->proj_transform); al_copy_transform(&bak2, al_get_current_transform()); al_identity_transform(&t); al_ortho_transform(&t, 0, d->w, d->h, 0, -1, 1); al_set_projection_transform(d, &t); al_identity_transform(&t); al_use_transform(&t); _al_opengl_set_blender(d); vert_ptr_on(d, 2, GL_FLOAT, 2*sizeof(float), v); color_ptr_on(d, 4, GL_FLOAT, 4*sizeof(float), c); if (!(d->flags & ALLEGRO_USE_PROGRAMMABLE_PIPELINE)) { glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } glDisable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); vert_ptr_off(d); color_ptr_off(d); al_set_projection_transform(d, &bak1); al_use_transform(&bak2); return; } #endif glClearColor(r, g, b, a); glClear(GL_COLOR_BUFFER_BIT); }
bool _al_opengl_set_blender(ALLEGRO_DISPLAY *ogl_disp) { int op, src_color, dst_color, op_alpha, src_alpha, dst_alpha; ALLEGRO_COLOR const_color; const int blend_modes[10] = { GL_ZERO, GL_ONE, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_COLOR, GL_DST_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_ONE_MINUS_DST_COLOR, #if defined(ALLEGRO_CFG_OPENGLES2) || !defined(ALLEGRO_CFG_OPENGLES) GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR #else GL_ONE, GL_ONE #endif }; const int blend_equations[3] = { GL_FUNC_ADD, GL_FUNC_SUBTRACT, GL_FUNC_REVERSE_SUBTRACT }; (void)ogl_disp; al_get_separate_blender(&op, &src_color, &dst_color, &op_alpha, &src_alpha, &dst_alpha); const_color = al_get_blend_color(); /* glBlendFuncSeparate was only included with OpenGL 1.4 */ #if !defined ALLEGRO_CFG_OPENGLES if (ogl_disp->ogl_extras->ogl_info.version >= _ALLEGRO_OPENGL_VERSION_1_4) { #else /* FIXME: At this time (09/2014) there are a lot of Android phones that * don't support glBlendFuncSeparate even though they claim OpenGL ES 2.0 * support. Rather than not work on 20-25% of phones, we just don't support * separate blending on Android for now. */ #ifdef ALLEGRO_ANDROID if (false) { #else if (ogl_disp->ogl_extras->ogl_info.version >= _ALLEGRO_OPENGL_VERSION_2_0) { #endif #endif glEnable(GL_BLEND); #if defined(ALLEGRO_CFG_OPENGLES2) || !defined(ALLEGRO_CFG_OPENGLES) #ifndef ALLEGRO_ANDROID_HACK_X86_64 glBlendColor(const_color.r, const_color.g, const_color.b, const_color.a); #endif #endif glBlendFuncSeparate(blend_modes[src_color], blend_modes[dst_color], blend_modes[src_alpha], blend_modes[dst_alpha]); if (ogl_disp->ogl_extras->ogl_info.version >= _ALLEGRO_OPENGL_VERSION_2_0) { glBlendEquationSeparate( blend_equations[op], blend_equations[op_alpha]); } else { glBlendEquation(blend_equations[op]); } } else { if (src_color == src_alpha && dst_color == dst_alpha) { glEnable(GL_BLEND); #if defined(ALLEGRO_CFG_OPENGLES2) || !defined(ALLEGRO_CFG_OPENGLES) #ifndef ALLEGRO_ANDROID_HACK_X86_64 glBlendColor(const_color.r, const_color.g, const_color.b, const_color.a); #endif #endif glBlendFunc(blend_modes[src_color], blend_modes[dst_color]); } else { ALLEGRO_ERROR("Blender unsupported with this OpenGL version (%d %d %d %d %d %d)\n", op, src_color, dst_color, op_alpha, src_alpha, dst_alpha); return false; } } return true; } /* These functions make drawing calls use shaders or the fixed pipeline * based on what the user has set up. FIXME: OpenGL only right now. */ static void vert_ptr_on(ALLEGRO_DISPLAY *display, int n, GLint t, int stride, void *v) { /* Only use this shader stuff with GLES2+ or equivalent */ if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { #ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE if (display->ogl_extras->varlocs.pos_loc >= 0) { glVertexAttribPointer(display->ogl_extras->varlocs.pos_loc, n, t, false, stride, v); glEnableVertexAttribArray(display->ogl_extras->varlocs.pos_loc); } #endif } else { glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(n, t, stride, v); } } static void vert_ptr_off(ALLEGRO_DISPLAY *display) { if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { #ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE if (display->ogl_extras->varlocs.pos_loc >= 0) { glDisableVertexAttribArray(display->ogl_extras->varlocs.pos_loc); } #endif } else { glDisableClientState(GL_VERTEX_ARRAY); } } static void color_ptr_on(ALLEGRO_DISPLAY *display, int n, GLint t, int stride, void *v) { if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { #ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE if (display->ogl_extras->varlocs.color_loc >= 0) { glVertexAttribPointer(display->ogl_extras->varlocs.color_loc, n, t, false, stride, v); glEnableVertexAttribArray(display->ogl_extras->varlocs.color_loc); } #endif } else { glEnableClientState(GL_COLOR_ARRAY); glColorPointer(n, t, stride, v); } } static void color_ptr_off(ALLEGRO_DISPLAY *display) { if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { #ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE if (display->ogl_extras->varlocs.color_loc >= 0) { glDisableVertexAttribArray(display->ogl_extras->varlocs.color_loc); } #endif } else { glDisableClientState(GL_COLOR_ARRAY); } } static void tex_ptr_on(ALLEGRO_DISPLAY *display, int n, GLint t, int stride, void *v) { if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { #ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE if (display->ogl_extras->varlocs.texcoord_loc >= 0) { glVertexAttribPointer(display->ogl_extras->varlocs.texcoord_loc, n, t, false, stride, v); glEnableVertexAttribArray(display->ogl_extras->varlocs.texcoord_loc); } #endif } else { glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(n, t, stride, v); } } static void tex_ptr_off(ALLEGRO_DISPLAY *display) { if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { #ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE if (display->ogl_extras->varlocs.texcoord_loc >= 0) { glDisableVertexAttribArray(display->ogl_extras->varlocs.texcoord_loc); } #endif } else { glDisableClientState(GL_TEXTURE_COORD_ARRAY); } } /* There's a very nasty bug in Android 2.1 that makes glClear cause * screen flicker (appears to me it's swapping buffers.) Work around * by drawing two triangles instead on that OS. */ static void ogl_clear_android_2_1_workaround(ALLEGRO_DISPLAY *d, float r, float g, float b, float a) { GLfloat v[8] = { 0, d->h, 0, 0, d->w, d->h, d->w, 0 }; GLfloat c[16] = { r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a }; ALLEGRO_TRANSFORM bak1, bak2, t; al_copy_transform(&bak1, al_get_current_projection_transform()); al_copy_transform(&bak2, al_get_current_transform()); al_identity_transform(&t); al_orthographic_transform(&t, 0, 0, -1, d->w, d->h, 1); al_use_projection_transform(&t); al_identity_transform(&t); al_use_transform(&t); _al_opengl_set_blender(d); vert_ptr_on(d, 2, GL_FLOAT, 2*sizeof(float), v); color_ptr_on(d, 4, GL_FLOAT, 4*sizeof(float), c); if (!(d->flags & ALLEGRO_PROGRAMMABLE_PIPELINE)) { glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } glDisable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); vert_ptr_off(d); color_ptr_off(d); al_use_projection_transform(&bak1); al_use_transform(&bak2); } static void ogl_clear(ALLEGRO_DISPLAY *d, ALLEGRO_COLOR *color) { ALLEGRO_DISPLAY *ogl_disp = (void *)d; ALLEGRO_BITMAP *target = al_get_target_bitmap(); ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_target; float r, g, b, a; if (target->parent) target = target->parent; ogl_target = target->extra; if ((!ogl_target->is_backbuffer && ogl_disp->ogl_extras->opengl_target != target) || target->locked) { _al_clear_bitmap_by_locking(target, color); return; } al_unmap_rgba_f(*color, &r, &g, &b, &a); if (ogl_target->is_backbuffer && IS_ANDROID_AND(_al_android_is_os_2_1())) { ogl_clear_android_2_1_workaround(d, r, g, b, a); return; } glClearColor(r, g, b, a); glClear(GL_COLOR_BUFFER_BIT); }
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) { #ifdef ALLEGRO_CFG_OPENGL int num_primitives = 0; ALLEGRO_DISPLAY *ogl_disp = target->display; ALLEGRO_BITMAP_OGL *ogl_target = (ALLEGRO_BITMAP_OGL *)target; const void* vtx; const void* idx = indices; GLenum idx_size; #if defined ALLEGRO_GP2XWIZ || defined ALLEGRO_IPHONE GLushort ind[num_vtx]; int ii; #endif if (target->parent) { ogl_target = (ALLEGRO_BITMAP_OGL *)target->parent; } if ((!ogl_target->is_backbuffer && ogl_disp->ogl_extras->opengl_target != ogl_target) || al_is_bitmap_locked(target)) { return _al_draw_prim_indexed_soft(texture, decl, vtxs, indices, num_vtx, type); } vtx = vtxs; _al_opengl_set_blender(ogl_disp); setup_state(vtx, decl, texture); if(texture) { glEnable(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } #if defined ALLEGRO_GP2XWIZ || defined ALLEGRO_IPHONE for (ii = 0; ii < num_vtx; ii++) { ind[ii] = (GLushort)indices[ii]; } idx = ind; idx_size = GL_UNSIGNED_SHORT; #else idx_size = GL_UNSIGNED_INT; #endif switch (type) { case ALLEGRO_PRIM_LINE_LIST: { glDrawElements(GL_LINES, num_vtx, idx_size, idx); num_primitives = num_vtx / 2; break; }; case ALLEGRO_PRIM_LINE_STRIP: { glDrawElements(GL_LINE_STRIP, num_vtx, idx_size, idx); num_primitives = num_vtx - 1; break; }; case ALLEGRO_PRIM_LINE_LOOP: { glDrawElements(GL_LINE_LOOP, num_vtx, idx_size, idx); num_primitives = num_vtx; break; }; case ALLEGRO_PRIM_TRIANGLE_LIST: { glDrawElements(GL_TRIANGLES, num_vtx, idx_size, idx); num_primitives = num_vtx / 3; break; }; case ALLEGRO_PRIM_TRIANGLE_STRIP: { glDrawElements(GL_TRIANGLE_STRIP, num_vtx, idx_size, idx); num_primitives = num_vtx - 2; break; }; case ALLEGRO_PRIM_TRIANGLE_FAN: { glDrawElements(GL_TRIANGLE_FAN, num_vtx, idx_size, idx); num_primitives = num_vtx - 2; break; }; case ALLEGRO_PRIM_POINT_LIST: { glDrawElements(GL_POINTS, num_vtx, idx_size, idx); num_primitives = num_vtx; break; }; } if(texture) { glDisable(GL_TEXTURE_2D); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); } glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); return num_primitives; #else (void)target; (void)texture; (void)vtxs; (void)decl; (void)indices; (void)num_vtx; (void)type; return 0; #endif }
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) { #ifdef ALLEGRO_CFG_OPENGL int num_primitives = 0; ALLEGRO_DISPLAY *ogl_disp = target->display; ALLEGRO_BITMAP_OGL *ogl_target = (ALLEGRO_BITMAP_OGL *)target; const void* vtx; int stride = decl ? decl->stride : (int)sizeof(ALLEGRO_VERTEX); int num_vtx; if (target->parent) { ogl_target = (ALLEGRO_BITMAP_OGL *)target->parent; } if ((!ogl_target->is_backbuffer && ogl_disp->ogl_extras->opengl_target != ogl_target) || al_is_bitmap_locked(target)) { return _al_draw_prim_soft(texture, vtxs, decl, start, end, type); } vtx = (const char*)vtxs + start * stride; num_vtx = end - start; _al_opengl_set_blender(ogl_disp); setup_state(vtx, decl, texture); if(texture) { glEnable(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } switch (type) { case ALLEGRO_PRIM_LINE_LIST: { glDrawArrays(GL_LINES, 0, num_vtx); num_primitives = num_vtx / 2; break; }; case ALLEGRO_PRIM_LINE_STRIP: { glDrawArrays(GL_LINE_STRIP, 0, num_vtx); num_primitives = num_vtx - 1; break; }; case ALLEGRO_PRIM_LINE_LOOP: { glDrawArrays(GL_LINE_LOOP, 0, num_vtx); num_primitives = num_vtx; break; }; case ALLEGRO_PRIM_TRIANGLE_LIST: { glDrawArrays(GL_TRIANGLES, 0, num_vtx); num_primitives = num_vtx / 3; break; }; case ALLEGRO_PRIM_TRIANGLE_STRIP: { glDrawArrays(GL_TRIANGLE_STRIP, 0, num_vtx); num_primitives = num_vtx - 2; break; }; case ALLEGRO_PRIM_TRIANGLE_FAN: { glDrawArrays(GL_TRIANGLE_FAN, 0, num_vtx); num_primitives = num_vtx - 2; break; }; case ALLEGRO_PRIM_POINT_LIST: { glDrawArrays(GL_POINTS, 0, num_vtx); num_primitives = num_vtx; break; }; } if(texture) { glDisable(GL_TEXTURE_2D); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); } glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); return num_primitives; #else (void)target; (void)texture; (void)vtxs; (void)decl; (void)start; (void)end; (void)type; return 0; #endif }