Drawing antialiased primitives to bitmaps?
trictonicmp

I'm working on a little project using C++ and Allegro 5, my question is

Is there a way to draw antialiased primitives to a bitmap using Allegro 5? I mean I'm using this function

#SelectExpand
1void draw_to_gameBuffer(ALLEGRO_BITMAP *&gameBuffer, ALLEGRO_DISPLAY *&display) 2{ 3 static float x = 0; 4 5 al_set_target_bitmap(gameBuffer); 6 al_draw_filled_rectangle(0,0, 350, 622, al_map_rgb(130, 80, 120)); 7 al_draw_filled_circle(x, 200, 100, al_map_rgb(12, 138, 129)); 8 al_draw_filled_triangle(0, 0, 100, 0, 50, 100, al_map_rgb(12, 138, 129)); 9 10 x += 2.7; 11 if(x > 350 + 100) 12 x = -250; 13 14 al_set_target_backbuffer(display); 15}

to draw a cicle and a triangle (testing purposes) over a target bitmap as shown, on the project display options I have

#SelectExpand
1al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, 4, ALLEGRO_SUGGEST); 2al_set_new_display_option(ALLEGRO_SAMPLES, 8, ALLEGRO_SUGGEST);

to enable antialiasing, the problem is that all primitives rendered on the gameBuffer have jaggies but the primitives rendered off the gameBuffer are perfectly smooth, how can I solve that? Or It's there a way to do what I'm doing and get smooth primitives?

SiegeLord

Yes, it can be done using al_set_new_bitmap_samples before creating your bitmap. Unfortunately it is not currently implemented for Direct3D, so you'll need to force OpenGL via the ALLEGRO_OPENGL flag in al_set_new_display_flags. As this feature is experimental, you'll need to define ALLEGRO_UNSTABLE before including Allegro's headers.

trictonicmp

I'm trying to implement this but it seems that it's not working or at least that's what I feel, I have this:

#SelectExpand
1#define ALLEGRO_UNSTABLE 2 3#include <allegro5/allegro.h> 4#include <allegro5/allegro_primitives.h> 5#include <allegro5/allegro_image.h> 6 7//------------------------------------Display options------------------------------------- 8 al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, 2, ALLEGRO_SUGGEST); //antialias stuff 9 al_set_new_display_option(ALLEGRO_SAMPLES, 8, ALLEGRO_SUGGEST); //antialias stuff 10 al_set_new_display_flags(ALLEGRO_OPENGL); 11 al_set_new_display_flags(ALLEGRO_WINDOWED); 12 al_set_new_display_flags(ALLEGRO_RESIZABLE); 13 //----------------------------------Display options END----------------------------------- 14 15 16 //------------------------------------Setting Pointers------------------------------------ 17 display = al_create_display(WIDTH, HEIGHT); 18 al_apply_window_constraints(display, true); 19 //limits the window to a minimum width and height 20 al_set_window_constraints(display, MIN_WIDTH, MIN_HEIGHT, 0, 0); 21 22 timer = al_create_timer(1.0 / 60); 23 event_queue = al_create_event_queue(); 24 25 26 //-------------------------------------Bitmap loading------------------------------------- 27 al_set_new_bitmap_samples(4); 28 gameBuffer = al_create_bitmap(gameBufferWidth, gameBufferHeight); 29 gameBufferHeight = al_get_display_height(display); //initial scale 30 gameBufferWidth = (gameBufferHeight / 16) * 9; //initial scale 31 //-----------------------------------Bitmap loading END-----------------------------------

Obviously I have more code in between but nothing that matters to this issue
I can share my entire code, I don't have any than the main and the function to draw to the bitmap

Edgar Reynaldo

al_set_new_display_flags(ALLEGRO_OPENGL); al_set_new_display_flags(ALLEGRO_WINDOWED); al_set_new_display_flags(ALLEGRO_RESIZABLE);

Only the last call to al_set_new_display_flags is having any effect. You're overwriting the value you just set. Combine the flags using a bitwise OR.

al_set_new_display_flags(ALLEGRO_OPENGL | ALLEGRO_WINDOWED | ALLEGRO_RESIZABLE);

I'm working on testing this on my machine at the moment.

Anti-aliased primitives drawn to non backbuffer bitmaps appear to be working for me :

Upper left corner is backbuffer drawing, clockwise from top right is 8, 4, and 2 multi-sampled bitmaps.
{"name":"611193","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/8\/0\/80d807e5b7c2fa6c47362aa89008f0d6.png","w":1202,"h":941,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/8\/0\/80d807e5b7c2fa6c47362aa89008f0d6"}611193

#SelectExpand
1 2#define ALLEGRO_UNSTABLE 3 4#include "allegro5/allegro.h" 5#include "allegro5/allegro_primitives.h" 6 7 8 9int ww = 1200; 10int wh = 900; 11 12ALLEGRO_DISPLAY* d = 0; 13 14void DrawSomePrimitives() { 15 ALLEGRO_BITMAP* bmp = al_get_target_bitmap(); 16 int bw = al_get_bitmap_width(bmp); 17 int bh = al_get_bitmap_height(bmp); 18 19 al_clear_to_color(al_map_rgb(0,0,96)); 20 21 al_draw_filled_rectangle(0.25*bw , 0.25*bh , 0.75*bw , 0.75*bh , al_map_rgb(0,96,0)); 22 al_draw_rectangle(0.25*bw , 0.25*bh , 0.75*bw , 0.75*bh , al_map_rgb(0,127,127) , 5.0); 23 24 al_draw_filled_triangle(0.0*bw , 0.5*bh , 0.5*bw , 0.0*bh , 0.75*bw , 0.75*bh , al_map_rgb(255,255,255)); 25 al_draw_triangle(0.2*bw , 0.4*bh , 0.4*bw , 0.2*bh , 0.65*bw , 0.65*bh , al_map_rgb(0,0,0) , 3.0); 26 27 al_draw_filled_circle(0.5*bw , 0.5*bh , 0.15*bw , al_map_rgb(255,0,0)); 28 al_draw_circle(0.5*bw , 0.5*bh , 0.15*bw , al_map_rgb(0,255,0) , 5.0); 29} 30 31 32 33void RecreateBitmaps(ALLEGRO_BITMAP* buf[3]) { 34 ww = al_get_display_width(d); 35 wh = al_get_display_height(d); 36 37 if (buf[0]) {al_destroy_bitmap(buf[0]);} 38 if (buf[1]) {al_destroy_bitmap(buf[1]);} 39 if (buf[2]) {al_destroy_bitmap(buf[2]);} 40 41 al_set_new_bitmap_samples(8); 42 buf[0] = al_create_bitmap(ww/2,wh/2); 43 al_set_new_bitmap_samples(4); 44 buf[1] = al_create_bitmap(ww/2,wh/2); 45 al_set_new_bitmap_samples(2); 46 buf[2] = al_create_bitmap(ww/2,wh/2); 47} 48 49 50 51int main(int argc , char** argv) { 52 53 54 if (!al_init()) {return 1;} 55 if (!al_init_primitives_addon()) {return 2;} 56 57 if (!al_install_keyboard()) {return 10;} 58 59 al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS , ALLEGRO_SUGGEST , 2); 60 al_set_new_display_option(ALLEGRO_SAMPLES , ALLEGRO_SUGGEST , 8); 61 62 al_set_new_display_flags(ALLEGRO_OPENGL | ALLEGRO_WINDOWED | ALLEGRO_RESIZABLE); 63 64 d = al_create_display(ww,wh); 65 66 if (!d) {return -1;} 67 68 ALLEGRO_TIMER* t = al_create_timer(1.0/60.0); 69 70 ALLEGRO_EVENT_QUEUE* q = al_create_event_queue(); 71 72 al_register_event_source(q , al_get_display_event_source(d)); 73 al_register_event_source(q , al_get_keyboard_event_source()); 74 al_register_event_source(q , al_get_timer_event_source(t)); 75 76 ALLEGRO_BITMAP* buf[3] = {0}; 77 78 RecreateBitmaps(buf); 79 80 al_start_timer(t); 81 82 bool redraw = true; 83 bool quit = false; 84 85 while (!quit) { 86 if (redraw) { 87 al_set_target_backbuffer(d); 88 al_clear_to_color(al_map_rgb(0,0,0)); 89 90 ALLEGRO_BITMAP* sub = al_create_sub_bitmap(al_get_backbuffer(d) , 0 , 0 , ww/2 , wh/2); 91 92 ALLEGRO_BITMAP* bmps[4] = {sub , buf[0] , buf[1] , buf[2]}; 93 94 for (int i = 0 ; i < 4 ; ++i) { 95 al_set_target_bitmap(bmps[i]); 96 DrawSomePrimitives(); 97 } 98 al_set_target_bitmap(al_get_backbuffer(d)); 99 al_draw_bitmap(buf[0] , ww/2 , 0 , 0); 100 al_draw_bitmap(buf[1] , ww/2 , wh/2 , 0); 101 al_draw_bitmap(buf[2] , 0 , wh/2 , 0); 102 103 al_flip_display(); 104 105 al_destroy_bitmap(sub); 106 107 redraw = false; 108 } 109 do { 110 ALLEGRO_EVENT ev; 111 al_wait_for_event(q , &ev); 112 113 if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { 114 quit = true; 115 } 116 if (ev.type == ALLEGRO_EVENT_KEY_DOWN && ev.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { 117 quit = true; 118 } 119 if (ev.type == ALLEGRO_EVENT_TIMER) { 120 redraw = true; 121 } 122 if (ev.type == ALLEGRO_EVENT_DISPLAY_RESIZE) { 123 al_acknowledge_resize(d); 124 RecreateBitmaps(buf); 125 } 126 } while (!al_is_event_queue_empty(q)); 127 128 } 129 130 return 0; 131}

trictonicmp

I didn't know that display flags must be combined, It worked well but it's so slow compared to rendering directly to the backbuffer.

is there a way to do the same thing without the heaviness? :-[ if there's no better way I think I'll stick to a simple fixed-size window with the resizable flag

with "is there a way to do the same thing without the heaviness?" I mean, having a buffer where I can render everything then render the buffer to the middle of the display, this way I can resize the buffer without affecting the buffer aspect ratio? ???

[edit]
I've been testing everything and it seems that OpenGl is slowing the rendering and input for some reason, my OpenGl version is 3.3 but my graphic card is NVS 3100M with 512Mb ???

Mark Oates
SiegeLord said:

al_set_new_bitmap_samples

This is actually my favorite Allegro feature. To me, it makes Allegro complete. :) Allegro can do anything.

The key here is that now I can render to offscreen surfaces with the same quality as the display bitmap, and use that to generate cool effects. An immediate example that comes to mind is a screen transition that composites between different states in the game, like menu and gameplay.

Chris Katko

Here's a full feature list of your card:

http://feedback.wildfiregames.com/report/opengl/device/NVS%203100M

It should be fast enough to do some stuff. Make sure your drivers are current. But it has a whopping 16 CUDA cores. (read: very few) Is this Windows or Linux?

Run glxgears if you're on Linux, or some other 3D apps. Can you run anything fast?

Also, use _REQUIRE not _SUGGEST because you want to be SURE that the settings you're testing are turned on. Allegro intentionally will fail to create the display if the required setting fails, so you know whether it's using it or not.

trictonicmp

I know, I was hoping to use this feature, it really makes allegro a full graphics library for multimedia stuff but I'm not able to use it, or at least that's the issue now.

my drivers are up to date (Windows 10), I tried forcing OpenGl without the antialiasing and it keeps running slow for some reason.

I ran GFXBench GL and the results were between 20 - 40 fps on the tests done, I have to add that I normally use 3D packages to do some stuff (3d modelling/animation/texturing/rendering) with no problems but It seems that OpenGl with Allegro 5 doesn't work for me for a reason. :(

Mark Oates

Have you tried running the ex_multisample.c and ex_multisample_target.c
example programs?

SiegeLord

It is generally true that OpenGL is a little slower than DirectX on Windows, but not to the extent that it's unusably slower. Aside from the drivers (which I take are fine), I'm not sure what could be wrong.

trictonicmp

Nope, I ran the example given by Edgar Reynaldo and ran slow too
I'll try to tun these examples to see if it changes something

It's not the rendering that is slow (or at least that's what I think), in the program I made, I was drawing a circle over the mouse positions but the rendering was delayed by 2 - 4 secs, so, whenever I moved the mouse the rendering was at the same speed of my mouse but delayed some secs, even closing the window was delayed by the same fraction of time.

Anyway I changed my project's main architecture to be just a scalable window but if I can get this to work I'll switch it again in the future, I'll try the examples above :)

Mark Oates

It's not the rendering that is slow (or at least that's what I think), in the program I made, I was drawing a circle over the mouse positions but the rendering was delayed by 2 - 4 secs, so, whenever I moved the mouse the rendering was at the same speed of my mouse but delayed some secs, even closing the window was delayed by the same fraction of time.

Oh, I know what it is. Your event queue is getting clogged up and laggy by timer events. You can fix it by dropping sequential timer events with al_drop_next_event.

See these lines from the AllegroFlare Framework class as an example.

Edgar Reynaldo

If my example ran slow too, then there is something else wrong, because my example processes all events as soon as they occur.

trictonicmp

There must be something wrong:( with my computer then, just enabling ALLEGRO_OPENGL flag delays the redrawing, I'll try "al_drop_next_event" as suggested to see if it changes something.

Edgar Reynaldo

You can also try updating your graphics drivers to the latest version and see if that fixes it. It can often be the problem.

trictonicmp

I guess It's my GPU or something that doesn't handle OpenGl

Edgar Reynaldo

Which is why updating your graphics drivers might fix it.

Chris Katko

GFXBench GL and the results were between 20 - 40 fps on the tests done,

That does sound like a really horrible result...

From here:

https://gfxbench.com/result.jsp

There are Intel integrated graphics cards in that list that get >25 FPS. That's around a GTX 460 mobile.

Is your "NVS 3100M" a Quattro? Because that same benchmark shows a Quattro 3100M at 62 FPS. So if that's the case, it's possible your card may be throttling itself from overheating or something.

I don't know. Seems like you need to do some further testing on your system to see if Allegro is actually running slow, or it's just running as fast as can be expected.

A quick benchmark to test is in GPU-Z. It's like the popular CPU-Z program, and it basically tells you a lot of stats about your card as well as whether the clock frequency is dropping. It includes a quick benchmark setting. If say, your card is benching slower than my lowly old chromebook with integrated graphics, then something is definitely wrong.

https://www.techpowerup.com/gpuz/

There ARE rare driver issues with cards that nVidia / et al have fixed in the past where certain programs will run too slow because the card doesn't recognize an app properly so it doesn't leave "low power" state and ramp up to full clock speed. But I thought they had fixed all those issues. (And also, the opposite, where games like Starcraft 2 would actually destroy videocards because the drivers were incorrectly having them run hotter than supposed to back in 2010. Lulz.)

You said you were using Windows 10, but are you using the MOST RECENT drivers FROM NVIDIA, or just stock Windows 10 drivers?

trictonicmp

Oh, I know what it is. Your event queue is getting clogged up and laggy by timer events. You can fix it by dropping sequential timer events with al_drop_next_event.

See these lines from the AllegroFlare Framework class as an example.

Guys I hadn't tried this until now, as I said before, my drawing was fine (I mean, no lag or low framerate) with ALLEGRO_OPENGL enabled but the input was delayed a bit, It seems that this is the solution to it, I won't be able to test if it works fine with al_set_new_bitmap_samples() but enabling OpenGl with the code mentioned above my program runs fine, I'll try to test with my initial project to see if this is the real answer to all this issue and save this post for future refferences.

BTW my drivers weren't up to date but this didn't change anything in my program, I tried with both drivers (old and new) and the result is the same without al_drop_next_event and the code in the link.

#SelectExpand
1//--------------------------after 2ALLEGRO_EVENT event, nextEvent; 3if (event.type == ALLEGRO_EVENT_TIMER) 4{ 5 while (al_peek_next_event(eventQueue, &nextEvent) 6 && nextEvent.type == ALLEGRO_EVENT_TIMER 7 && nextEvent.timer.source == event.timer.source) 8 al_drop_next_event(eventQueue); 9 10 redraw = true; 11} 12//--------------------------Before 13 14ALLEGRO_EVENT event; 15 16if (event.type == ALLEGRO_EVENT_TIMER) 17{ 18 //I have some code here but practically this 19 redraw = true; 20}

this is the only thing my program has changed and the ALLEGRO_OPENGL flag obviously.

[edit]
Ok guys I've just tested with my initial project settings and everything is working just as expected, I really appreciate your help, you are such a beautiful community to work with <3

Edgar Reynaldo

You shouldn't need to drop any events. Usually, you just start and stop your timer when you don't want it to run.

Show your old and new event loops, if you would, I'm curious now.

trictonicmp

Well, your first example ran slow too for some reason even though I know you did handle the events with no errors, here is my code for the main loop

#SelectExpand
1 2//---------------------------------------Main loop---------------------------------------- 3 while(!done) 4 { 5 //-----------------------------------Getting events----------------------------------- 6 ALLEGRO_EVENT event, nextEvent; 7 al_wait_for_event(eventQueue, &event); 8 9 if(event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) 10 done = true; 11 12 if(event.type == ALLEGRO_EVENT_DISPLAY_RESIZE) 13 { 14 al_acknowledge_resize(display); 15 16 currentGameBufferH = al_get_display_height(display); 17 currentGameBufferW = currentGameBufferH * 0.67; 18 19 //center the game buffer 20 gameBufferX = (al_get_display_width(display) / 2) - (currentGameBufferW / 2); 21 gameBufferY = 0; 22 } 23 24 25 //-----------------------------Getting mouse clic and axes---------------------------- 26 if(event.type == ALLEGRO_EVENT_MOUSE_AXES) 27 { 28 mouseX = event.mouse.x; 29 mouseY = event.mouse.y; 30 } 31 32 if(event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) 33 if(event.mouse.button & 1) 34 clic = true; 35 36 if(event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) 37 if(event.mouse.button & 1) 38 clic = false; 39 //---------------------------Getting mouse clic and axes END-------------------------- 40 41 ScreenManager::get_instance().handle_input(event); 42 43 if (event.type == ALLEGRO_EVENT_TIMER) 44 { 45 while (al_peek_next_event(eventQueue, &nextEvent) 46 && nextEvent.type == ALLEGRO_EVENT_TIMER 47 && nextEvent.timer.source == event.timer.source) 48 al_drop_next_event(eventQueue); 49 //--------------------------------Updating elements------------------------------- 50 ScreenManager::get_instance().update(event); 51 //------------------------------Updating elements END----------------------------- 52 redraw = true; 53 } 54 //---------------------------------Getting events END--------------------------------- 55 56 57 //---------------------------------Redrawing elements--------------------------------- 58 if(redraw) 59 { 60 al_clear_to_color(al_map_rgb(235, 235, 235)); 61 62 al_draw_filled_rectangle(7, 85, 499, 815, al_map_rgb(235, 235, 235)); 63 64 65 //game rendering part 66 al_draw_bitmap(example, 0, 74, 0); 67 68 draw_to_gameBuffer(gameBuffer, display); 69 al_draw_scaled_bitmap(gameBuffer, 0, 0, gameBufferWidth, gameBufferHeight, gameBufferX, gameBufferY, currentGameBufferW, currentGameBufferH, 0); 70 71 al_flip_display(); 72 redraw = false; 73 } 74 //-------------------------------Redrawing elements END------------------------------- 75 } 76 //-------------------------------------Main loop END--------------------------------------

the only thing it changed in the whole code it's the "nextEvent" stuff shown in my previous reply.

Edgar Reynaldo

The thing is, my example drops extra timer events automatically. It only draws once, even if there are multiple timer events. It just counts them all as one.

trictonicmp

Edgar and you all guys, I've been lying to you and I feel so dumb now but it's good to have my dumbness here this way people can learn from my mistakes (I don't think there's someone out there that can make more or the same amount of mistakes than me but ok), your example (Edgar Reynaldo) never ran slow, it took a while to execute but runtime was never slow neither had had the input delay, although I thought it was running slow due to the time it took to show something on screen (5 secs maybe?) my code, the one that had the input delay (event queue clogged by the timer events as Mark Oates mentioned) took the same amount of time to show my drawings on screen, therefore, I thought your example had the same issue but I was in a huge mistake, I knew my example had an input delay because the circle I was drawing on the mouse positions had a delay but I never tried the same with your example until now and guess what? yup, you example runs smooth with no delays nor lag and the circle drawn to the mouse positions moves as fast as I move the mouse cursor so... I actually don't need the "al_drop_next_event()" procedure I just have to have an event loop to iterate while the event queue has something inside, this way I won't have events left on the queue making every iteration bigger and bigger to iterate through.

As I said before, you are such a beautiful community to work with and I really appreciate your help and patience with me and my dumbness.

Edgar Reynaldo

So then, I'm not sure what delay you're experiencing. Startup? It doesn't display anything for a few seconds? Can you give an example program that does this? With debugging symbols for gdb?

It may be a little slow to resize the window, due to recreating the bitmaps on each resize, but drawing normally should be pretty quick. The texture changes don't help.

trictonicmp

Nothing to worry it just takes a while to start (my pc is slow with OpenGl flag), the input delay I'm talking about it was in my previous code that clogged the event queue, the resizing it's fine, with no delays or slowness just the startup takes some seconds to start, I'll try to create two examples, one with my old game loop and another with the new one.

Thread #617204. Printed from Allegro.cc