void setup_projection() { // setup the render settings al_set_render_state(ALLEGRO_DEPTH_TEST, 1); al_set_render_state(ALLEGRO_WRITE_MASK, ALLEGRO_MASK_DEPTH | ALLEGRO_MASK_RGBA); al_clear_depth_buffer(1); ALLEGRO_TRANSFORM t; camera.reverse_position_transform(&t); float aspect_ratio = (float)al_get_bitmap_height(backbuffer_sub_bitmap) / al_get_bitmap_width(backbuffer_sub_bitmap); al_perspective_transform(&t, -1, aspect_ratio, 1, 1, -aspect_ratio, 1000); //al_set_target_bitmap(backbuffer_sub_bitmap); << I don't think this is necessairy, it also occours just prior to this function al_use_projection_transform(&t); }
void set_projection(ALLEGRO_BITMAP *bitmap, ALLEGRO_TRANSFORM *t) { float aspect_ratio = (float)al_get_bitmap_height(bitmap) / al_get_bitmap_width(bitmap); al_perspective_transform(t, -1, aspect_ratio, 1, 1, -aspect_ratio, 100); al_use_projection_transform(t); }
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 main(void) { ALLEGRO_VERTEX v[8]; ALLEGRO_DISPLAY * display; ALLEGRO_TRANSFORM perst; ALLEGRO_TRANSFORM camt; ALLEGRO_BITMAP * texture, * texture2; ALLEGRO_EVENT_QUEUE * queue; ALLEGRO_EVENT event; ALLEGRO_FONT * font; int busy = 1; float cx = 0; float cy = -2; // 128; float cz = 0; int face = 0; int hori = 0; float angle = 0; float theta = 0; float near = 2; float far = 8192; float zoom = 1; float scale = 1.0; float us = 20; float ratio = 480.0 / 640.0; al_init(); al_init_image_addon(); al_init_font_addon(); al_install_keyboard(); font = al_create_builtin_font(); queue = al_create_event_queue(); al_set_new_display_option(ALLEGRO_DEPTH_SIZE, 16, ALLEGRO_SUGGEST); display = al_create_display(640, 480); al_register_event_source(queue, al_get_keyboard_event_source()); texture = al_load_bitmap("tile_1.png"); texture2 = al_load_bitmap("tile_2.png"); /* Allegro coordinates: +Y is down, +X is to the right, * and +Z comes "out of" the screen. * */ while (busy) { init_vertex(v+0, 0, 0, 0, 0, 0, 1, 0, 0, 1); init_vertex(v+1, 0, 0, us, 0, 256, 0, 1, 0, 1); init_vertex(v+2, us, 0, us, 256, 256, 0, 0, 1, 1); init_vertex(v+3, us, 0, 0, 256, 0, 1, 1, 0, 1); init_vertex(v+4, us, -us, 0, 256, 256, 1, 0, 1, 1); init_vertex(v+5, 0, -us, 0, 256, 0, 0, 1, 1, 1); init_vertex(v+6, 0, -us, us, 256, 256, 0, 0, 0, 1); init_vertex(v+7, 0, 0, us, 0, 256, 1, 1, 1, 1); al_identity_transform(&camt); al_scale_transform_3d(&camt, scale, scale, scale); al_translate_transform_3d(&camt, cx, cy, cz); angle = face * 0.125 * ALLEGRO_PI; al_rotate_transform_3d(&camt, 0, -1, 0, angle); theta = hori * 0.125 * ALLEGRO_PI; al_rotate_transform_3d(&camt, -1, 0, 0, theta); al_use_transform(&camt); // al_set_projection_transform(display, &perst); al_clear_to_color(al_map_rgb_f(0.75, 0.75, 0.95)); al_set_render_state(ALLEGRO_DEPTH_TEST, 1); al_clear_depth_buffer(far); al_identity_transform(&perst); al_perspective_transform(&perst, -1, ratio, near, 1, -ratio, far); al_use_projection_transform(&perst); al_draw_filled_rectangle(0, 0, 4, 5, al_map_rgb_f(0, 0.25, 0.25)); al_draw_prim(v, NULL, texture, 0, 8, ALLEGRO_PRIM_TRIANGLE_FAN); draw_textured_colored_rectangle_3d(0 , -us, 0, us, us, 0, 1.0, 1.0, texture2, al_map_rgb_f(1,1,1)); draw_textured_colored_rectangle_3d(0 , -us, 0, 0, us, us, 1.0, 1.0, texture2, al_map_rgb_f(1,1,1)); draw_textured_colored_rectangle_3d(0 , 0, 0, us, 0, us, 1.0, 1.0, texture2, al_map_rgb_f(1,1,1)); al_identity_transform(&perst); al_orthographic_transform(&perst, 0, 0, -1.0, 640, 480, 1.0); al_identity_transform(&camt); al_use_projection_transform(&perst); al_use_transform(&camt); al_draw_filled_rectangle(111, 22, 133, 44, al_map_rgb_f(0.25, 0.25, 0)); al_draw_multiline_textf(font, al_map_rgb_f(1,1,1), 10, 10, 620, 0, 0, "Coords: (%f %f %f)\nAngle: (%f %f)\nView: [%f %f %f %f]\nScale: %f", cx, cy, cz, angle, theta, near, far, zoom, scale); al_flip_display(); al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_KEY_DOWN) { switch (event.keyboard.keycode) { case ALLEGRO_KEY_RIGHT: cx += 8; break; case ALLEGRO_KEY_LEFT: cx -= 8; break; case ALLEGRO_KEY_UP: cy += 8; break; case ALLEGRO_KEY_DOWN: cy -= 8; break; case ALLEGRO_KEY_HOME: cz += 8; break; case ALLEGRO_KEY_END: cz -= 8; break; case ALLEGRO_KEY_R: face++; break; case ALLEGRO_KEY_L: face--; break; case ALLEGRO_KEY_H: hori++; break; case ALLEGRO_KEY_G: hori--; break; case ALLEGRO_KEY_N: near *= 2.0; break; case ALLEGRO_KEY_M: near /= 2.0; break; case ALLEGRO_KEY_F: far += 64; break; case ALLEGRO_KEY_V: far -= 64; break; case ALLEGRO_KEY_Z: zoom *= 2.0f; break; case ALLEGRO_KEY_S: zoom /= 2.0f; break; case ALLEGRO_KEY_A: scale *= 2.0f; break; case ALLEGRO_KEY_Q: scale /= 2.0f; break; case ALLEGRO_KEY_ESCAPE: busy = 0 ; break; default: break; } } } al_destroy_bitmap(texture); al_destroy_bitmap(texture2); return 0; }
/** Applies an orthographic transformation for the UI. */ void camera_apply_orthographic(Camera * self, ALLEGRO_DISPLAY * display) { al_use_projection_transform(&self->orthographic_transform); }
/** Applies a perspective transformation */ void camera_apply_perspective(Camera * self, ALLEGRO_DISPLAY * display) { al_use_projection_transform(&self->perspective_transform); }
// Render function. // (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop) void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data) { // Backup Allegro state that will be modified ALLEGRO_TRANSFORM last_transform = *al_get_current_transform(); ALLEGRO_TRANSFORM last_projection_transform = *al_get_current_projection_transform(); int last_clip_x, last_clip_y, last_clip_w, last_clip_h; al_get_clipping_rectangle(&last_clip_x, &last_clip_y, &last_clip_w, &last_clip_h); int last_blender_op, last_blender_src, last_blender_dst; al_get_blender(&last_blender_op, &last_blender_src, &last_blender_dst); // Setup render state al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA); // Setup orthographic projection matrix // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). { float L = draw_data->DisplayPos.x; float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; float T = draw_data->DisplayPos.y; float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y; ALLEGRO_TRANSFORM transform; al_identity_transform(&transform); al_use_transform(&transform); al_orthographic_transform(&transform, L, T, 1.0f, R, B, -1.0f); al_use_projection_transform(&transform); } for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; // Allegro's implementation of al_draw_indexed_prim() for DX9 is completely broken. Unindex our buffers ourselves. // FIXME-OPT: Unfortunately Allegro doesn't support 32-bits packed colors so we have to convert them to 4 float as well.. static ImVector<ImDrawVertAllegro> vertices; vertices.resize(cmd_list->IdxBuffer.Size); for (int i = 0; i < cmd_list->IdxBuffer.Size; i++) { const ImDrawVert* src_v = &cmd_list->VtxBuffer[cmd_list->IdxBuffer[i]]; ImDrawVertAllegro* dst_v = &vertices[i]; dst_v->pos = src_v->pos; dst_v->uv = src_v->uv; unsigned char* c = (unsigned char*)&src_v->col; dst_v->col = al_map_rgba(c[0], c[1], c[2], c[3]); } const int* indices = NULL; if (sizeof(ImDrawIdx) == 2) { // FIXME-OPT: Unfortunately Allegro doesn't support 16-bit indices.. You can '#define ImDrawIdx int' in imconfig.h to request Dear ImGui to output 32-bit indices. // Otherwise, we convert them from 16-bit to 32-bit at runtime here, which works perfectly but is a little wasteful. static ImVector<int> indices_converted; indices_converted.resize(cmd_list->IdxBuffer.Size); for (int i = 0; i < cmd_list->IdxBuffer.Size; ++i) indices_converted[i] = (int)cmd_list->IdxBuffer.Data[i]; indices = indices_converted.Data; } else if (sizeof(ImDrawIdx) == 4) { indices = (const int*)cmd_list->IdxBuffer.Data; } // Render command lists int idx_offset = 0; ImVec2 clip_off = draw_data->DisplayPos; for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback) { pcmd->UserCallback(cmd_list, pcmd); } else { ALLEGRO_BITMAP* texture = (ALLEGRO_BITMAP*)pcmd->TextureId; al_set_clipping_rectangle(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y, pcmd->ClipRect.z - pcmd->ClipRect.x, pcmd->ClipRect.w - pcmd->ClipRect.y); al_draw_prim(&vertices[0], g_VertexDecl, texture, idx_offset, idx_offset + pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST); } idx_offset += pcmd->ElemCount; } } // Restore modified Allegro state al_set_blender(last_blender_op, last_blender_src, last_blender_dst); al_set_clipping_rectangle(last_clip_x, last_clip_y, last_clip_w, last_clip_h); al_use_transform(&last_transform); al_use_projection_transform(&last_projection_transform); }