Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » A5 - printing text to memory bitmap

Credits go to SiegeLord for helping out!
This thread is locked; no one can reply to it. rss feed Print
A5 - printing text to memory bitmap
Kirr
Member #5,060
September 2004
avatar

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!

--
"Go to the NW of Stonemarket Plaza to the Blue Glyph Keeper Library door and enter."
- Lunabean's Thief Deadly Shadows Walkthrough, day eight

torhu
Member #2,727
September 2002
avatar

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
Member #23
April 2000

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

edit: what the hell am I thinking

torhu
Member #2,727
September 2002
avatar

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

SiegeLord
Member #7,827
October 2006
avatar

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

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

Kris Asick
Member #1,424
July 2001

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.

--- Kris Asick (Gemini)
--- http://www.pixelships.com

Kirr
Member #5,060
September 2004
avatar

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.

--
"Go to the NW of Stonemarket Plaza to the Blue Glyph Keeper Library door and enter."
- Lunabean's Thief Deadly Shadows Walkthrough, day eight

torhu
Member #2,727
September 2002
avatar

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
Member #1,424
July 2001

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. ::)

--- Kris Asick (Gemini)
--- http://www.pixelships.com

Kirr
Member #5,060
September 2004
avatar

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.

--
"Go to the NW of Stonemarket Plaza to the Blue Glyph Keeper Library door and enter."
- Lunabean's Thief Deadly Shadows Walkthrough, day eight

Thomas Fjellstrom
Member #476
June 2000
avatar

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

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Peter Wang
Member #23
April 2000

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

Kirr
Member #5,060
September 2004
avatar

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

--
"Go to the NW of Stonemarket Plaza to the Blue Glyph Keeper Library door and enter."
- Lunabean's Thief Deadly Shadows Walkthrough, day eight

Thomas Fjellstrom
Member #476
June 2000
avatar

I was more talking around multiple calls to draw_text.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Kris Asick
Member #1,424
July 2001

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?

--- Kris Asick (Gemini)
--- http://www.pixelships.com

Kirr
Member #5,060
September 2004
avatar

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?

--
"Go to the NW of Stonemarket Plaza to the Blue Glyph Keeper Library door and enter."
- Lunabean's Thief Deadly Shadows Walkthrough, day eight

Go to: