static ALLEGRO_COLOR reference_implementation( ALLEGRO_COLOR src_col, ALLEGRO_COLOR dst_col, ALLEGRO_COLOR blend_col, int src_format, int dst_format, int src_mode, int dst_mode, int src_alpha, int dst_alpha, int operation) { float sr, sg, sb, sa; float br, bg, bb, ba; float dr, dg, db, da; float r, g, b, a; float src, dst, asrc, adst; al_unmap_rgba_f(src_col, &sr, &sg, &sb, &sa); al_unmap_rgba_f(blend_col, &br, &bg, &bb, &ba); al_unmap_rgba_f(dst_col, &dr, &dg, &db, &da); /* Do we even have source alpha? */ if (operation == 0) { if (!has_alpha(src_format)) { sa = 1; } } r = sr * br; g = sg * bg; b = sb * bb; a = sa * ba; src = get_factor(src_mode, a); dst = get_factor(dst_mode, a); asrc = get_factor(src_alpha, a); adst = get_factor(dst_alpha, a); r = r * src + dr * dst; g = g * src + dg * dst; b = b * src + db * dst; a = a * asrc + da * adst; r = CLAMP(r); g = CLAMP(g); b = CLAMP(b); a = CLAMP(a); /* Do we even have destination alpha? */ if (!has_alpha(dst_format)) { a = 1; } return al_map_rgba_f(r, g, b, a); }
static bool same_color(ALLEGRO_COLOR c1, ALLEGRO_COLOR c2) { float r1, g1, b1, a1; float r2, g2, b2, a2; float dr, dg, db, da; float d; al_unmap_rgba_f(c1, &r1, &g1, &b1, &a1); al_unmap_rgba_f(c2, &r2, &g2, &b2, &a2); dr = r1 - r2; dg = g1 - g2; db = b1 - b2; da = a1 - a2; d = sqrt(dr * dr + dg * dg + db * db + da * da); if (d < 0.01) return true; else return false; }
static ALLEGRO_COLOR blendColor(ALLEGRO_COLOR c2, ALLEGRO_COLOR c1, float trans) { // blend two colors on a particle ALLEGRO_COLOR result; float r; float g; float b; float a; float r2; float g2; float b2; float a2; al_unmap_rgba_f(c1, &r, &g, &b, &a); al_unmap_rgba_f(c2, &r2, &g2, &b2, &a2); result = al_map_rgba_f( (r * trans) + (r2 * (1 - trans)), (g * trans) + (g2 * (1 - trans)), (b * trans) + (b2 * (1 - trans)), (a * trans) + (a2 * (1 - trans)) ); return result; }
void shal_unmap_rgba_f(float color_r, float color_g, float color_b, float color_a, float * r, float * g, float * b, float * a) { ALLEGRO_COLOR color; color.r = color_r; color.g = color_g; color.b = color_b; color.a = color_a; return al_unmap_rgba_f(color, r, g, b, a); }
static void _al_draw_orthogonal_tile_layer(ALLEGRO_MAP_LAYER *layer, ALLEGRO_MAP *map, ALLEGRO_COLOR tint, float sx, float sy, float sw, float sh, float dx, float dy, int flags) { if (!layer->visible) { return; } float r, g, b, a; al_unmap_rgba_f(tint, &r, &g, &b, &a); ALLEGRO_COLOR color = al_map_rgba_f(r, g, b, a * layer->opacity); int mx, my; int ystart = sy / map->tile_height, yend = (sy + sh) / map->tile_height; int xstart = sx / map->tile_width, xend = (sx + sw) / map->tile_width; // defer rendering until everything is drawn al_hold_bitmap_drawing(true); for (my = ystart; my <= yend; my++) { for (mx = xstart; mx <= xend; mx++) { ALLEGRO_MAP_TILE *tile = al_get_single_tile(map, layer, mx, my); flags = 0; if (!tile) { continue; } float x = mx*(map->tile_width) - sx + dx; float y = my*(map->tile_height) - sy + dy; if (flipped_vertically(layer, mx, my)) flags ^= ALLEGRO_FLIP_VERTICAL; if (flipped_horizontally(layer, mx, my)) flags ^= ALLEGRO_FLIP_HORIZONTAL; if (flipped_diagonally(layer, mx, my)) { int tile_center_h = map->tile_width / 2; int tile_center_w = map->tile_height / 2; flags ^= ALLEGRO_FLIP_VERTICAL; al_draw_tinted_rotated_bitmap(tile->bitmap, color, tile_center_w, tile_center_h, x + tile_center_h, y + tile_center_w, -ALLEGRO_PI/2, flags); } else { al_draw_tinted_bitmap(tile->bitmap, color, x, y, flags); } } } al_hold_bitmap_drawing(false); }
static mrb_value color_unmap_rgba_f(mrb_state *mrb, mrb_value self) { ALLEGRO_COLOR *c; float r; float g; float b; float a; mrb_value ary; c = mrb_data_get_ptr(mrb, self, &mrbal_color_data_type); al_unmap_rgba_f(*c, &r, &g, &b, &a); ary = mrb_ary_new_capa(mrb, 4); mrb_ary_push(mrb, ary, mrb_float_value(mrb, r)); mrb_ary_push(mrb, ary, mrb_float_value(mrb, g)); mrb_ary_push(mrb, ary, mrb_float_value(mrb, b)); mrb_ary_push(mrb, ary, mrb_float_value(mrb, a)); return ary; }
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_OGL *ogl_target; float r, g, b, a; if (target->parent) target = target->parent; ogl_target = (void *)target; if ((!ogl_target->is_backbuffer && ogl_disp->ogl_extras->opengl_target != ogl_target) || target->locked) { _al_clear_memory(color); return; } al_unmap_rgba_f(*color, &r, &g, &b, &a); glClearColor(r, g, b, a); glClear(GL_COLOR_BUFFER_BIT); }
static void _al_draw_orthogonal_object_layer(ALLEGRO_MAP_LAYER *layer, ALLEGRO_MAP *map, ALLEGRO_COLOR tint, float sx, float sy, float sw, float sh, float dx, float dy, int flags) { if (!layer->visible) { return; } float r, g, b, a; al_unmap_rgba_f(tint, &r, &g, &b, &a); ALLEGRO_COLOR color = al_map_rgba_f(r, g, b, a * layer->opacity); // defer rendering until everything is drawn al_hold_bitmap_drawing(true); GSList *objects = layer->objects; while (objects) { ALLEGRO_MAP_OBJECT *object = (ALLEGRO_MAP_OBJECT*)objects->data; objects = g_slist_next(objects); // no need to draw invisible objects if (!object->bitmap) { continue; } int x = object->x - sx; int y = object->y - sy; // make sure it's on-screen; if it's not, don't draw it if ((x + object->width) < 0 || x > sw || y < 0 || (y - object->height) > sh) { continue; } al_draw_tinted_bitmap(object->bitmap, color, x, y-object->height, flags); } al_hold_bitmap_drawing(false); }
/* Generates a bitmap with transparent background and the logo text. * The bitmap will have screen size. If 'bumpmap' is not NULL, it will * contain another bitmap which is a white, blurred mask of the logo * which we use for the flash effect. */ static ALLEGRO_BITMAP *generate_logo(char const *text, char const *fontname, int font_size, float shadow_offset, float blur_radius, float blur_factor, float light_red, float light_green, float light_blue, ALLEGRO_BITMAP **bumpmap) { ALLEGRO_COLOR transparent = al_map_rgba_f(0, 0, 0, 0); int xp, yp, w, h, i, j, x, y, br, bw, dw, dh; ALLEGRO_COLOR c; ALLEGRO_FONT *logofont; ALLEGRO_STATE state; ALLEGRO_BITMAP *blur, *light, *logo; int left, right, top, bottom; float cx, cy; dw = al_get_bitmap_width(al_get_target_bitmap()); dh = al_get_bitmap_height(al_get_target_bitmap()); cx = dw * 0.5; cy = dh * 0.5; logofont = al_load_font(fontname, -font_size, 0); al_get_text_dimensions(logofont, text, &xp, &yp, &w, &h); al_store_state(&state, ALLEGRO_STATE_TARGET_BITMAP | ALLEGRO_STATE_BLENDER); /* Cheap blur effect to create a bump map. */ blur = al_create_bitmap(dw, dh); al_set_target_bitmap(blur); al_clear_to_color(transparent); br = blur_radius; bw = br * 2 + 1; c = al_map_rgba_f(1, 1, 1, 1.0 / (bw * bw * blur_factor)); al_set_separate_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE); for (i = -br; i <= br; i++) { for (j = -br; j <= br; j++) { al_draw_text(logofont, c, cx - xp * 0.5 - w * 0.5 + i, cy - yp * 0.5 - h * 0.5 + j, 0, text); } } left = cx - xp * 0.5 - w * 0.5 - br + xp; top = cy - yp * 0.5 - h * 0.5 - br + yp; right = left + w + br * 2; bottom = top + h + br * 2; if (left < 0) left = 0; if (top < 0) top = 0; if (right > dw - 1) right = dw - 1; if (bottom > dh - 1) bottom = dh - 1; /* Cheap light effect. */ light = al_create_bitmap(dw, dh); al_set_target_bitmap(light); al_clear_to_color(transparent); al_lock_bitmap(blur, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY); al_lock_bitmap_region(light, left, top, 1 + right - left, 1 + bottom - top, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_WRITEONLY); for (y = top; y <= bottom; y++) { for (x = left; x <= right; x++) { float r1, g1, b1, a1; float r2, g2, b2, a2; float r, g, b, a; float d; ALLEGRO_COLOR c = al_get_pixel(blur, x, y); ALLEGRO_COLOR c1 = al_get_pixel(blur, x - 1, y - 1); ALLEGRO_COLOR c2 = al_get_pixel(blur, x + 1, y + 1); al_unmap_rgba_f(c, &r, &g, &b, &a); al_unmap_rgba_f(c1, &r1, &g1, &b1, &a1); al_unmap_rgba_f(c2, &r2, &g2, &b2, &a2); d = r2 - r1 + 0.5; r = clamp(d * light_red); g = clamp(d * light_green); b = clamp(d * light_blue); c = al_map_rgba_f(r, g, b, a); al_put_pixel(x, y, c); } } al_unlock_bitmap(light); al_unlock_bitmap(blur); if (bumpmap) *bumpmap = blur; else al_destroy_bitmap(blur); /* Create final logo */ logo = al_create_bitmap(dw, dh); al_set_target_bitmap(logo); al_clear_to_color(transparent); /* Draw a shadow. */ c = al_map_rgba_f(0, 0, 0, 0.5 / 9); al_set_separate_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE); for (i = -1; i <= 1; i++) for (j = -1; j <= 1; j++) al_draw_text(logofont, c, cx - xp * 0.5 - w * 0.5 + shadow_offset + i, cy - yp * 0.5 - h * 0.5 + shadow_offset + j, 0, text); /* Then draw the lit text we made before on top. */ al_set_separate_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_draw_bitmap(light, 0, 0, 0); al_destroy_bitmap(light); al_restore_state(&state); al_destroy_font(logofont); return logo; }
static void render(void) { double t = al_get_time(); if (regenerate) { al_destroy_bitmap(logo); al_destroy_bitmap(logo_flash); logo = NULL; regenerate = false; } if (!logo) { /* Generate a new logo. */ ALLEGRO_BITMAP *fullflash; ALLEGRO_BITMAP *fulllogo = generate_logo(param_values[0], param_values[1], strtol(param_values[2], NULL, 10), strtod(param_values[3], NULL), strtod(param_values[4], NULL), strtod(param_values[5], NULL), strtod(param_values[6], NULL), strtod(param_values[7], NULL), strtod(param_values[8], NULL), &fullflash); ALLEGRO_BITMAP *crop; int x, y, left = 640, top = 480, right = -1, bottom = -1; /* Crop out the non-transparent part. */ al_lock_bitmap(fulllogo, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY); for (y = 0; y < 480; y++) { for (x = 0; x < 640; x++) { ALLEGRO_COLOR c = al_get_pixel(fulllogo, x, y); float r, g, b, a; al_unmap_rgba_f(c, &r, &g, &b, &a); if (a > 0) { if (x < left) left = x; if (y < top) top = y; if (x > right) right = x; if (y > bottom) bottom = y; } } } al_unlock_bitmap(fulllogo); if (right < left) right = left; if (bottom < top) bottom = top; crop = al_create_sub_bitmap(fulllogo, left, top, 1 + right - left, 1 + bottom - top); logo = al_clone_bitmap(crop); al_destroy_bitmap(crop); al_destroy_bitmap(fulllogo); crop = al_create_sub_bitmap(fullflash, left, top, 1 + right - left, 1 + bottom - top); logo_flash = al_clone_bitmap(crop); al_destroy_bitmap(crop); al_destroy_bitmap(fullflash); logo_x = left; logo_y = top; anim = t; } draw_background(); /* For half a second, display our flash animation. */ if (t - anim < 0.5) { ALLEGRO_STATE state; int w, h, i, j; float f = sin(ALLEGRO_PI * ((t - anim) / 0.5)); ALLEGRO_COLOR c = al_map_rgb_f(f * 0.3, f * 0.3, f * 0.3); w = al_get_bitmap_width(logo); h = al_get_bitmap_height(logo); al_store_state(&state, ALLEGRO_STATE_BLENDER); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_draw_tinted_bitmap(logo, al_map_rgba_f(1, 1, 1, 1 - f), logo_x, logo_y, 0); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE); for (j = -2; j <= 2; j += 2) { for (i = -2; i <= 2; i += 2) { al_draw_tinted_bitmap(logo_flash, c, logo_x + i, logo_y + j, 0); } } al_restore_state(&state); } else al_draw_bitmap(logo, logo_x, logo_y, 0); print_parameters(); }
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); }
static void print_color(ALLEGRO_COLOR c) { float r, g, b, a; al_unmap_rgba_f(c, &r, &g, &b, &a); printf("%.2f, %.2f, %.2f, %.2f", r, g, b, a); }
/* Function: al_unmap_rgb_f */ void al_unmap_rgb_f(ALLEGRO_COLOR color, float *r, float *g, float *b) { float tmp; al_unmap_rgba_f(color, r, g, b, &tmp); }