Achieving Resolution Independence
This tutorial will teach you two techniques to achieve resolution independence using Allegro 5.
By resolution independence we mean that, for example, if you design your game for a resolution of 640x480 and you want to support fullscreen resolutions it shouldn't matter what resolution the player actually uses, you just stretch the intended resolution of 640x480 so it fits with whatever resolution the player is using.
These techniques of course also applies to whether you simply want a low resolution but want to stretch it in a windowed display too. For example, if you're designing a retro game with a target resolution of 320x240 and want the game to be windowed at a size of say 800x600, then you do basically the same things as described below.
This technique is preferred if your game is using a lot of primitives.
We create a fullscreen windowed display, which means that we create a window that covers the entire screen and thus automatically using the user's native resolution. We then calculate the scaling factors (sx and sy) by dividing the width and height of the created display by the width and height of the resolution we're designing the game for. Then we scale the display using a transformation. This needs to only be done once during initialization.
al_set_new_display_flags(ALLEGRO_FULLSCREEN_WINDOW); display = al_create_display(windowWidth, windowHeight); windowWidth = al_get_display_width(display); windowHeight = al_get_display_height(display); int screenWidth = 640; int screenHeight = 480; float sx = windowWidth / (float)screenWidth; float sy = windowHeight / (float)screenHeight; ALLEGRO_TRANSFORM trans; al_identity_transform(&trans); al_scale_transform(&trans, sx, sy); al_use_transform(&trans);
Using a stretched buffer
This technique is preferred if your game is using a lot of bitmaps.
We make use of a bitmap buffer which we then scale to cover the screen using al_draw_scaled_bitmap(). We need some more complex scaling calculations here, as we're essentially doing something called letterboxing. We can't just stretch the buffer onto the entire resolution as a game designed for 4:3 screens will look weird on widescreens and vice versa. Thus, we calculate the maximum we can stretch the buffer - and if it doesn't fit the entire screen then we're simply left with black bars on top and bottom and/or left and right.
// initialization al_set_new_display_flags(ALLEGRO_FULLSCREEN_WINDOW); display = al_create_display(windowWidth, windowHeight); buffer = al_create_bitmap(screenWidth, screenHeight); // calculate scaling factor int sx = windowWidth / screenWidth; int sy = windowHeight / screenHeight; int scale = std::min(sx, sy); // calculate how much the buffer should be scaled scaleW = screenWidth * scale; scaleH = screenHeight * scale; scaleX = (windowWidth - scaleW) / 2; scaleY = (windowHeight - scaleH) / 2;
So, the last four variables are what we use when we update the screen every frame:
// render a frame al_set_target_bitmap(buffer); al_clear_to_color(al_map_rgb(0, 0, 0)); // draw everything in between here al_set_target_backbuffer(display); al_clear_to_color(al_map_rgb(0, 0, 0)); al_draw_scaled_bitmap(buffer, 0, 0, screenWidth, screenHeight, scaleX, scaleY, scaleW, scaleH, 0);