|
A5 - printing text to memory bitmap |
Kirr
Member #5,060
September 2004
|
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: When printing to memory bitmap I get this: Below is the code for both tests (configured by changing "DRAW_TO_MEMORY"): 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: I guess I'm probably confused about blending modes. I'll appreciate any hints or suggestions! -- |
torhu
Member #2,727
September 2002
|
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
|
edit: what the hell am I thinking
|
torhu
Member #2,727
September 2002
|
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
|
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 |
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) |
Kirr
Member #5,060
September 2004
|
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). Kris Asick said: 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. 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
Member #2,727
September 2002
|
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) |
Kirr
Member #5,060
September 2004
|
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
Member #476
June 2000
|
Just make sure you're also using the held drawing feature when rendering text. -- |
Peter Wang
Member #23
April 2000
|
It should be automatic, otherwise it's a bug.
|
Kirr
Member #5,060
September 2004
|
Can't see any effect from held drawing. Either it's automatic, or I'm doing it wrong (or both). -- |
Thomas Fjellstrom
Member #476
June 2000
|
I was more talking around multiple calls to draw_text. -- |
Kris Asick
Member #1,424
July 2001
|
Peter Wang said: 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) |
Kirr
Member #5,060
September 2004
|
The main loop looks like this: 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? -- |
|