Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Scaling down runtime created bitmaps makes them transparent

This thread is locked; no one can reply to it. rss feed Print
Scaling down runtime created bitmaps makes them transparent
trictonicmp
Member #16,611
December 2016

Hi everybody, it's me again with another question.

In my spare time, I like to write little pieces of code that could help me in the future, this time I was working on a "vertical game renderer" (I made this thing), you might be asking "what the hell is that?" well, a little time ago I played "Bird climb" (a game that's available on the Microsoft store) on my pc and noticed something really cool, despite that the game is in portrait mode (cause it was first made for mobile phones), the developers found a cool workaround to play this gem on landscape mode, and this by just adding bars to the sides of the game itself but that's not the cool part, the cool part is that you can scale the window and the game scales keeping its aspect ratio, ok I'm not explaining my self as I would like to, take a look at the attachments.

my idea to recreate this is to create a bitmap, render everything there and then render this bitmap scaled in the middle of the window, this seemed fine until I realized that if I create a bitmap with higher resolutions (for scale purposes)and then scale this bitmap down to fit the screen, the bitmap (let's call this "game buffer")for some reason turns transparent.

here is my code

#SelectExpand
1//-----------------------------------Main.cpp----------------------------------- 2#define ALLEGRO_UNSTABLE 3 4#include <allegro5/allegro.h> 5 6 7//-----------------------------function declaration---------------------------- 8void draw_to_gameBuffer(ALLEGRO_BITMAP *gameBuffer, ALLEGRO_DISPLAY *display); 9//---------------------------function declaration END-------------------------- 10 11 12//***************************************************************************** 13//----------------------------------MAIN--------------------------------------- 14//***************************************************************************** 15int main() 16{ 17 bool done = false; 18 bool redraw = true; 19 20 //----------------------------Screen settings----------------------------- 21 static int WIDTH = 1280; 22 static int HEIGHT = 720; 23 24 static int MIN_WIDTH = 405; 25 static int MIN_HEIGHT = 720; 26 27 static int gameBufferWidth = 720; 28 static int gameBufferHeight = 1280; 29 30 static int gameBufferWidthScaled = 405; 31 static int gameBufferHeightScaled = 720; 32 33 float gameBufferX = (WIDTH / 2) - (gameBufferWidthScaled / 2); 34 float gameBufferY = (HEIGHT / 2) - (gameBufferHeightScaled / 2);; 35 36 static float FPS = 60; 37 //--------------------------Screen settings END--------------------------- 38 39 40 //--------------------------Pointers declaration-------------------------- 41 ALLEGRO_DISPLAY *display = nullptr; 42 ALLEGRO_EVENT_QUEUE *eventQueue = nullptr; 43 ALLEGRO_TIMER *timer = nullptr; 44 45 ALLEGRO_BITMAP *gameBuffer = nullptr; 46 //------------------------Pointers declaration END------------------------ 47 48 49 //--------------------------Initialize elements--------------------------- 50 al_init(); 51 //------------------------Initialize elements END------------------------- 52 53 54 //----------------------------Display options----------------------------- 55 al_set_new_display_flags(ALLEGRO_WINDOWED | ALLEGRO_RESIZABLE | ALLEGRO_OPENGL); 56 al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, 2, ALLEGRO_SUGGEST); 57 al_set_new_display_option(ALLEGRO_SAMPLES, 4, ALLEGRO_SUGGEST); 58 //--------------------------Display options END--------------------------- 59 60 61 //----------------------------Setting Pointers---------------------------- 62 display = al_create_display(WIDTH, HEIGHT); 63 al_apply_window_constraints(display, true); 64 65 //limits the window to a minimum width and height 66 al_set_window_constraints(display, MIN_WIDTH, MIN_HEIGHT, 0, 0); 67 68 timer = al_create_timer(1.0f / FPS); 69 eventQueue = al_create_event_queue(); 70 71 //creating game buffer 72 al_set_new_bitmap_flags(ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR | ALLEGRO_MIPMAP); 73 al_set_new_bitmap_samples(4); 74 al_set_new_bitmap_format(0); 75 gameBuffer = al_create_bitmap(gameBufferWidth, gameBufferHeight); 76 //--------------------------Setting Pointers END-------------------------- 77 78 79 //----------------------------Register events----------------------------- 80 al_register_event_source(eventQueue, al_get_display_event_source(display)); 81 al_register_event_source(eventQueue, al_get_timer_event_source(timer)); 82 al_start_timer(timer); 83 //--------------------------Register events END--------------------------- 84 85 86 //-------------------------------Main loop-------------------------------- 87 while (!done) 88 { 89 do 90 { 91 //------------------------Getting events-------------------------- 92 ALLEGRO_EVENT event; 93 al_wait_for_event(eventQueue, &event); 94 95 if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) 96 done = true; 97 98 if (event.type == ALLEGRO_EVENT_DISPLAY_RESIZE) 99 { 100 al_acknowledge_resize(display); 101 102 //new game buffer scale 103 float windowHeight = al_get_display_height(display); 104 105 gameBufferHeightScaled = windowHeight; 106 //16:9 aspect ratio 107 gameBufferWidthScaled = (windowHeight / 16) * 9; 108 109 //center the game buffer 110 gameBufferX = (al_get_display_width(display) / 2) - (gameBufferWidthScaled / 2); 111 gameBufferY = (al_get_display_height(display) / 2) - (gameBufferHeightScaled / 2); 112 } 113 114 115 if (event.type == ALLEGRO_EVENT_TIMER) 116 { 117 redraw = true; 118 } 119 //-----------------------Getting events END----------------------- 120 } while (!al_is_event_queue_empty(eventQueue)); 121 122 123 //-------------------------Redrawing elements------------------------- 124 if (redraw) 125 { 126 al_clear_to_color(al_map_rgb(235, 235, 235)); 127 128 draw_to_gameBuffer(gameBuffer, display); 129 130 al_draw_scaled_bitmap 131 ( 132 gameBuffer, 133 0, 0, //source X | Y 134 gameBufferWidth, gameBufferHeight, //source W | H 135 gameBufferX, gameBufferY, //destiny X | Y 136 gameBufferWidthScaled, gameBufferHeightScaled, //destiny W | H 137 0 //flags 138 ); 139 140 al_flip_display(); 141 redraw = false; 142 } 143 //-----------------------Redrawing elements END----------------------- 144 } 145 //-----------------------------Main loop END------------------------------ 146 147 148 //--------------------------Destroying elements--------------------------- 149 al_destroy_display(display); 150 al_destroy_event_queue(eventQueue); 151 al_destroy_timer(timer); 152 al_destroy_bitmap(gameBuffer); 153 al_uninstall_mouse(); 154 al_uninstall_keyboard(); 155 al_uninstall_system(); 156 //------------------------Destroying elements END------------------------- 157 158 159 //------------------------------Program END------------------------------- 160 return 0; 161} 162 163 164//-------------------------Functions definitions------------------------------ 165void draw_to_gameBuffer(ALLEGRO_BITMAP *gameBuffer, ALLEGRO_DISPLAY *display) 166{ 167 al_set_target_bitmap(gameBuffer); 168 al_clear_to_color(al_map_rgb(0, 0, 0)); 169 al_set_target_backbuffer(display); 170} 171//-----------------------Functions definitions END----------------------------

any idea of what could be causing this?

Todd Cope
Member #998
November 2000
avatar

My guess would be MIP mapping. Try disabling that flag before creating gameBuffer.

André Silva
Member #11,991
May 2010
avatar

Todd likely hit the nail on the head. If you want to keep mipmaps on, then after you finish creating your new bitmap, create a clone and use that. The clone will have the mipmaps generated on its creation. Remember to delete the original!

trictonicmp
Member #16,611
December 2016

It seems that mipmapping is causing this as you both mentioned, but why mipmapping causes this? well, maybe I'll never understand, thank you so much for your fast response guys, you are the best. 8-) ;D

Now all I need to do is to translate my mouse position to the gameBuffer but I guess that's not gonna be a problem.

Mark Oates
Member #1,146
March 2001
avatar

but why mipmapping causes this?

Mipmapping is when the graphics system creates multiple smaller resized versions of the bitmap for performance (and aesthetics) and cross-fades between them as they transition between the differently needed versions.

When a mipmap is not correctly working (because it wasn't setup correctly for whatever reason), then it will sometimes crossfade into a blank bitmap, thus appearing transparent.

Edgar Reynaldo
Member #8,592
May 2007
avatar

trictonicmp
Member #16,611
December 2016

It seems that is indeed a well-known issue and it's really nice that you, people that work on the source code of Allegro are working to fix this, I really appreciate this community and the support from you to new developers and adventurers that love to work with Allegro, thank you <3.

Edgar Reynaldo
Member #8,592
May 2007
avatar

If it isn't clear, you can refresh the mip maps by using al_clone_bitmap.

An example :

#SelectExpand
1 al_set_new_bitmap_flags(ALLEGRO_VIDEO_BITMAP); 2 3 ALLEGRO_BITMAP* img = al_load_bitmap("FluffyTheDragon.png"); 4 ALLEGRO_BITMAP* buf = al_create_bitmap(BUFWIDTH , BUFHEIGHT); 5 /* 6 Do various things to img here, or draw img to a buffer 7 */ 8 9 al_set_new_bitmap_flags(ALLEGRO_MIPMAP | ALLEGRO_VIDEO_BITMAP); 10 ALLEGRO_BITMAP* temp = al_clone_bitmap(buf); 11 12 al_destroy_bitmap(img); 13 al_destroy_bitmap(buf); 14 buf = temp; 15 temp = 0; 16 img = 0;

The issue is on Github here :
https://github.com/liballeg/allegro5/issues/559

André Silva
Member #11,991
May 2010
avatar

The "why" is fairly simple. When you load a bitmap from the disk, for instance, the mipmaps get generated then, because it makes sense to do so: there's actually content to create a mipmap with, and chances are you're not going to toy with it any more. So it's the perfect time to both load the bitmap into memory as well as generate and store its mipmaps.

When you create a new bitmap, the mipmaps are generated too, but they're empty. Creating a new bitmap is mostly useless unless you're going to make changes. But then how would the system know that it's time to generate the mipmaps based on the changes you've made? It can't generate them every time you make a change to the bitmap, otherwise you'd be kissing your performance goodbye. So... it just never does.

I guess the ideal way would be to, after you're done editing the new bitmap, tell Allegro that you're finished, and that it should do cleanup and preparations on the bitmap, like mipmap generation. Since we don't have that, you have to do it manually: cloning the bitmap counts as creating a new one, which triggers the mipmap generation.

trictonicmp
Member #16,611
December 2016

So many thanks for the code Edgar, it helped me a lot and thanks to you André for the explanation, it seems that this "issue" is something that everybody knew except by me ;D.

Go to: