A5 - printing text to memory bitmap
Kirr

Hi all! I'm playing with A5 and text output. Can't seem to figure this out: Printing to screen works fine, printing to memory bitmap doesn't.

I get this when printing random characters to screen, as expected:
{"name":"allegro5-test-printing-to-screen.png","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/8\/7\/8753beb6f2ac0ca206a7e9b48dbc18da.png","w":326,"h":228,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/8\/7\/8753beb6f2ac0ca206a7e9b48dbc18da"}allegro5-test-printing-to-screen.png
Note that the background of each character is transparent.

When printing to memory bitmap I get this:
{"name":"allegro5-test-printing-to-memory-bitmap.png","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/5\/b\/5b24779c4d5a6feefb8f5758a71a4784.png","w":326,"h":228,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/5\/b\/5b24779c4d5a6feefb8f5758a71a4784"}allegro5-test-printing-to-memory-bitmap.png
Here each character has solid black background. I hope to get transparent background in this case too.

Below is the code for both tests (configured by changing "DRAW_TO_MEMORY"):

#SelectExpand
1#include <allegro5/allegro.h> 2#include <allegro5/allegro_font.h> 3 4enum { W = 320, H = 200, DRAW_TO_MEMORY = 1 }; 5 6int main() 7{ 8 ALLEGRO_DISPLAY *display; 9 ALLEGRO_BITMAP *bmp; 10 ALLEGRO_FONT *font; 11 ALLEGRO_EVENT_QUEUE *eq; 12 13 al_init(); 14 al_init_font_addon(); 15 al_install_keyboard(); 16 if (!(display = al_create_display(W,H))) { exit(1); } 17 18 if (DRAW_TO_MEMORY) 19 { 20 al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); 21 al_set_new_bitmap_format(al_get_bitmap_format(al_get_backbuffer(display))); 22 bmp = al_create_bitmap(W,H); 23 al_set_target_bitmap(bmp); 24 } 25 26 al_clear_to_color(al_map_rgb(0,0,0)); 27 al_set_blender(ALLEGRO_ADD,ALLEGRO_ONE,ALLEGRO_INVERSE_ALPHA); 28 29 font = al_create_builtin_font(); 30 eq = al_create_event_queue(); 31 al_register_event_source(eq,al_get_keyboard_event_source()); 32 33 for (int i=0; i<10000; i++) 34 { 35 char s[2] = {(rand()%96+32),0}; 36 al_draw_text(font,al_map_rgb(rand()&0xFF,rand()&0xFF,rand()&0xFF),rand()%(W-20)+5,rand()%(H-20)+5,0,s); 37 } 38 if (DRAW_TO_MEMORY) 39 { 40 al_set_target_backbuffer(display); 41 al_set_blender(ALLEGRO_ADD,ALLEGRO_ONE,ALLEGRO_ZERO); 42 al_draw_bitmap(bmp,0,0,0); 43 } 44 al_flip_display(); 45 46 while (1) 47 { 48 ALLEGRO_EVENT e; 49 while (al_get_next_event(eq,&e)) { if (e.type == ALLEGRO_EVENT_KEY_DOWN) { return 0; } } 50 al_rest(0.001); 51 } 52}

I use Win 7, MinGW (GCC 4.8.1) and Allegro 5.0.10 (built from source, all examples and demos seem to work fine). Compiling command:
gcc -std=gnu99 -o test_a5.exe test_a5.c -lallegro.dll -lallegro_font.dll

I guess I'm probably confused about blending modes. I'll appreciate any hints or suggestions!

torhu

Try this: everytime you are drawing to the memory bitmap, call al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO) first. Then reset the blending mode to default before drawing to the backbuffer.

Peter Wang

<code>al_set_blender(ALLEGRO_ADD,ALLEGRO_ONE,ALLEGRO_ZERO);</code> is wrong.

edit: what the hell am I thinking

torhu

Yeah, it's right only when drawing the text, not when blitting to the backbuffer. Or I could be wrong again ::)

SiegeLord

I don't get the difference in output on Linux (both cases indicate transparent background). Could you try this with OpenGL?

Kris Asick

There shouldn't be a difference so there's clearly a bug going on. What that bug is though... I'm uncertain.

The only thing I can think of is that you're calling al_get_bitmap_format() so soon after setting the video mode that the video mode may not be completely set or initialized by the GPU by the time the CPU makes the call. An example of this is if you attempt to call al_create_display() a second time too soon after calling it once prior, you can cause some really nasty problems to occur. (At least on Windows.)

If your memory bitmap is thus getting a format that lacks an alpha channel, it's effectively the same as using ALLEGRO_ZERO instead of ALLEGRO_INVERSE_ALPHA for the destination pixels.

...actually, that's a good point. You should add some code to save the result of al_get_bitmap_format() into a variable so we can see what the result is on your system.

Kirr
torhu said:

Try this: everytime you are drawing to the memory bitmap, call al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO) first. Then reset the blending mode to default before drawing to the backbuffer.

This results in solid black background in both cases, as expected. It's the opposite of what I'm trying to do.

al_set_blender(ALLEGRO_ADD,ALLEGRO_ONE,ALLEGRO_ZERO) is supposed to set "no-blending" blending mode where the source bitmap is copied to destination verbatim. Thus I use it for the final blit to screen, but not for printing characters.

SiegeLord said:

I don't get the difference in output on Linux (both cases indicate transparent background). Could you try this with OpenGL?

With OpenGL it works correctly in both cases! (Transparent background).

The only thing I can think of is that you're calling al_get_bitmap_format() so soon after setting the video mode that the video mode may not be completely set or initialized by the GPU by the time the CPU makes the call. An example of this is if you attempt to call al_create_display() a second time too soon after calling it once prior, you can cause some really nasty problems to occur. (At least on Windows.)

I've just tried waiting for 5 seconds (al_rest(5)) after creating display - does not fix it.

Kris Asick said:

If your memory bitmap is thus getting a format that lacks an alpha channel, it's effectively the same as using ALLEGRO_ZERO instead of ALLEGRO_INVERSE_ALPHA for the destination pixels.

I was under impression that I don't need an alpha channel in the memory bitmap - it's the font glyphs that should have the alpha channel - for which there is no API to control.

Kris Asick said:

...actually, that's a good point. You should add some code to save the result of al_get_bitmap_format() into a variable so we can see what the result is on your system.

23, which should correspond to ALLEGRO_PIXEL_FORMAT_XRGB_8888.

EDIT: Simplified test code - now saves image to file instead of blitting to screen.

#SelectExpand
1#include <allegro5/allegro.h> 2#include <allegro5/allegro_image.h> 3#include <allegro5/allegro_font.h> 4 5enum { W = 320, H = 200, OPENGL = 0, DRAW_TO_MEMORY = 1 }; 6 7int main() 8{ 9 ALLEGRO_DISPLAY *display; 10 ALLEGRO_BITMAP *bmp; 11 12 al_init(); 13 al_init_image_addon(); 14 al_init_font_addon(); 15 if (OPENGL) { al_set_new_display_flags(ALLEGRO_OPENGL); } 16 if (!(display = al_create_display(W,H))) { exit(1); } 17 18 if (DRAW_TO_MEMORY) 19 { 20 al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); 21 al_set_new_bitmap_format(al_get_bitmap_format(al_get_backbuffer(display))); 22 bmp = al_create_bitmap(W,H); 23 al_set_target_bitmap(bmp); 24 } 25 else { bmp = al_get_backbuffer(display); } 26 27 al_clear_to_color(al_map_rgb(0,0,0)); 28 ALLEGRO_FONT *font = al_create_builtin_font(); 29 30 for (int i=0; i<10000; i++) 31 { 32 char s[2] = {(rand()%96+32),0}; 33 al_draw_text(font,al_map_rgb(rand()&0xFF,rand()&0xFF,rand()&0xFF),rand()%(W-20)+5,rand()%(H-20)+5,0,s); 34 } 35 36 al_save_bitmap("test_a5.png",bmp); 37}

With OPENGL = 1 all works fine (characters have transparent background) regardless of DRAW_TO_MEMORY setting. With DRAW_TO_MEMORY = 0 everything fine too.

With OPENGL = 0 and DRAW_TO_MEMORY = 1 it prints each character with solid black background (second screenshot in first post).

EDIT: Solved!

It seems I must create font before changing target bitmap to memory bitmap - then it produces correct result. Apparently al_create_builtin_font() is sensitive to pixel format of current target bitmap. I think the same applies to al_load_ttf_font(), because I first noticed this with TTF fonts.

If this is the intended behavior, perhaps it should be documented.

Thanks everyone! :)

EDIT: Actually it responds to setting bitmap format and flags, not to setting target bitmap. It seems that any grabbed or loaded font (including built-in one) is generated with currently set bitmap format and flags. So there is an API for controlling alpha channel in fonts. Just the documentation is lacking.

In particular, current flags control whether the font is loaded into video memory, which can have big impact on performance.

torhu

Cool. I think what I was thinking about was when you want the temporary bitmap to have transparency when blitting it onto the background. I was using it for something like that. Sorry if I created confusion ;)

Kris Asick
Kirr said:

Actually it responds to setting bitmap format and flags, not to setting target bitmap.

I missed that. Yeah, being able to set bitmap formats and flags for fonts is intended behaviour. ::)

Kirr

No problem and all is good now! I appreciate everyone's trying to help! I needed this for my benchmark of font rendering across different libs. I'm now adding A5, which is shockingly fast, at least when everything is in video memory.

Thomas Fjellstrom

Just make sure you're also using the held drawing feature when rendering text.

Peter Wang

It should be automatic, otherwise it's a bug.

Kirr

Can't see any effect from held drawing. Either it's automatic, or I'm doing it wrong (or both).

Thomas Fjellstrom

I was more talking around multiple calls to draw_text.

Kris Asick

It should be automatic, otherwise it's a bug.

Question: If it should be automatic, but you make a call to al_hold_bitmap_drawing(true) beforehand, will rendering text disable held bitmap drawing following, or will you still need to call al_hold_bitmap_drawing(false) afterwards as expected?

Kirr

The main loop looks like this:

#SelectExpand
1for (unsigned go=1,di=0; go;) 2{ 3 al_hold_bitmap_drawing(1); 4 for (unsigned i=100; i>0; i--) 5 { 6 TXT *t = &test_dataset[di]; 7 al_draw_text(f1,t->text_color,t->x,t->y,0,(char*)t->text); 8 char_count += t->length; 9 if (++di >= test_dataset_num_elements) { di = 0; } 10 } 11 al_hold_bitmap_drawing(0); 12 13 now1 = time(0); 14 if (now1!=now) { update(); now = now1; } 15 else { if (draw_to_screen) { al_flip_display(); } } 16 check_keyboard(); 17}

Here I don't see any speed increase from held drawing. Should I try to lock the bitmap instead?

Thread #613635. Printed from Allegro.cc