al_draw_bitmap_region does not return
sasha199568

Simple background scrolling program.

It works almost fine on Ubuntu:
http://stackoverflow.com/questions/33064135/allegro-5-ubuntu-drawing-bitmap-from-system-memory-part-of-image-is-deformed

I am trying to make it work on Windows.
When I comment line al_draw_bitmap_region out game loop works. But with this function it freezes.

#SelectExpand
1 2#include <allegro5/allegro.h> 3#include <allegro5/allegro_image.h> 4 5#include <stdio.h> 6#include <stdlib.h> 7#include <time.h> 8 9#define EXITWITHERROR(E, R) { strcpy_s(error_buffer, E); quit(R); } 10 11ALLEGRO_DISPLAY *display = NULL; 12ALLEGRO_KEYBOARD_STATE kstate; 13char error_buffer[128] = { 0 }; 14ALLEGRO_BITMAP *background; 15ALLEGRO_DISPLAY_MODE *dm; 16int x = 0, y = 0, bw, bh; 17 18void init(); 19void gameLoop(); 20void quit(const char *reason); 21 22int main(int argc, char **argv) 23{ 24 init(); 25 while (true) gameLoop(); 26 return 0; 27} 28 29void quit(const char * r) 30{ 31 int errnumber = al_get_errno(); 32 al_destroy_display(display); 33 al_destroy_bitmap(background); 34 al_uninstall_system(); 35 if (!error_buffer[0]) 36 strcpy_s(error_buffer, "Everything is fine"); 37 fprintf(stderr, "%s\nerror message: %s\nerror number: %i\n", 38 r, error_buffer, errnumber); 39 getchar(); 40 exit(errnumber); 41} 42 43void gameLoop() 44{ 45 fprintf_s(stdout, "game loop\n"); 46 // process game world 47 if (x < 0) x = bw - dm->width; 48 if (x > bw - dm->width) x = 0; 49 if (y < 0) y = bh - dm->height; 50 if (y > bh - dm->height) y = 0; 51 52 // get and process input 53 al_get_keyboard_state(&kstate); 54 if (al_key_down(&kstate, ALLEGRO_KEY_ESCAPE)) { 55 fprintf_s(stdout, "escape pressed\n"); 56 quit("Execution finished"); 57 } 58 if (al_key_down(&kstate, ALLEGRO_KEY_LEFT)) x -= 10; 59 if (al_key_down(&kstate, ALLEGRO_KEY_UP)) y -= 10; 60 if (al_key_down(&kstate, ALLEGRO_KEY_RIGHT)) x += 10; 61 if (al_key_down(&kstate, ALLEGRO_KEY_DOWN)) y += 10; 62 63 // draw 64 al_draw_bitmap_region(background, x, y, dm->width, dm->height, 0, 0, 0); 65 fprintf_s(stdout, "bitmap drawn\n"); 66 al_flip_display(); 67} 68 69void init() 70{ 71 srand(time(NULL)); 72 if (!al_init()) EXITWITHERROR("al_init failed", "Init failed"); 73 if (!al_init_image_addon()) EXITWITHERROR("image addon cannot be init", "Init failed"); 74 ALLEGRO_DISPLAY_MODE ldm; 75 if (!(dm = al_get_display_mode(al_get_num_display_modes() - 1, &ldm))) 76 EXITWITHERROR("could not get display modes", "init failed"); 77 al_set_new_display_flags(ALLEGRO_FULLSCREEN); 78 display = al_create_display(dm->width, dm->height); 79 if (!display) EXITWITHERROR("Could not create Display", "Init failed"); 80 if (!al_install_keyboard()) EXITWITHERROR("keyboard cannot be installed", "Init failed"); 81 al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); 82 background = al_load_bitmap("map2.jpg"); 83 if (!background) EXITWITHERROR("Could not load map2.jpg", "Init failed"); 84 bw = al_get_bitmap_width(background); 85 bh = al_get_bitmap_height(background); 86 fprintf_s(stdout, "init successful\n"); 87}

I am using windows binaries from here http://liballeg.org/download.html
I tried to link with allegro.lib and allegro.dll, allegro_image.lib and allegro_image.dll; and only with allegro_monolith.lib allegro_monolith.dll

Also I just noticed. There are many weird things about Visual Studio. And here is one. Usually unless you explicitly state that you are ok with fprintf Visual Studio doesn't allow it. It says use fprintf_s instead. This time I just used fprintf_s everywhere. But in quit(const char *) function I used just fprintf and it said nothing.

Before using binaries I compiled from source. Basic programs worked. But when I tried al_load_bitmap Visual Studio showed NULL on top of the call stack. It wasn't that the function returned NULL. The issue was that next function on the stack was NULL. al_load_bitmap called two more functions. As I remember they were find_bitmap_flags and find_handler.

While I desperately was trying to please visual studio when it hit me with "access violation ... trying to execute 00000000" I wrote this line

if (!(dm = al_get_display_mode(al_get_num_display_modes() - 1, &ldm)))

with two variables dm and ldm instead of one.

and then I accessed display width like dm->width. But al_get_display_mode does not return valid display mode, therefore dm->width contained rubbish. I changed code to have only global ALLEGRO_DISPLAY_MODE and now I don't assign returned value to it. Also I access width with dot: dm.width
But documentation states that on success function returns pointer to its parameter and NULL on failure... Now I understand. ldm was local variable, although dm was global ldm was deleted when init finished. Therefore dm was pointing on garbage.

... That's a shame. I made such a mess in a simple program. It's not even a game, just a little test. I still wonder why would compiled from source version of allegro try to execute NULL when calling al_load_bitmap; and why there is this little glitch on Ubuntu.

Matias Persson

Works fine for me.
But one thing I can see you're forgetting is

#SelectExpand

#SelectExpand
1al_clear_to_color(al_map_rgb(0,0,0)); 2 3// Draw 4al_draw_bitmap_region(background, x, y, dm->width, dm->height, 0, 0, 0); 5fprintf_s(stdout, "bitmap drawn\n"); 6 7al_flip_display();

#SelectExpand
1al_clear_to_color(RGB); 2 3// ALWAYS DRAW IN BETWEEN HERE. 4 5al_flip_display();

Also here if you want it, it's a base you can use which I think is pretty neat;

Main function

#SelectExpand
1#include <fstream> 2#include <memory> 3#include <allegro5/allegro.h> 4 5int initializeAllegro(ALLEGRO_DISPLAY **display, ALLEGRO_EVENT_QUEUE **event_queue, ALLEGRO_TIMER **timer); 6 7void checkInput(ALLEGRO_EVENT &ev, int &running); 8 9void cleanUp(ALLEGRO_DISPLAY **display, ALLEGRO_EVENT_QUEUE **event_queue, ALLEGRO_TIMER **timer); 10 11int main() { 12 ALLEGRO_DISPLAY *display = NULL; 13 ALLEGRO_EVENT_QUEUE *event_queue = NULL; 14 ALLEGRO_TIMER *timer = NULL; 15 ALLEGRO_EVENT ev; 16 17 bool running = true; 18 19 std::unique_ptr<gameState> currentState = std::make_unique<menuState>(); 20 21 initializeAllegro(&display, &event_queue, &timer); 22 23 while (running) { 24 while (!al_is_event_queue_empty(event_queue)) { 25 al_wait_for_event(event_queue, &ev); 26 27 checkInput(ev, running); 28 29 if (ev.type == ALLEGRO_EVENT_TIMER) { 30 // Logics within any timer. 31 doTimedLogic(); 32 33 } 34 else if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { 35 running = false; 36 } 37 38 doUntimedLogic(); 39 } 40 41 // Render 42 render(); 43 44 // Rest for 0.001 sec 45 al_rest(0.001); 46 47 } 48 49 cleanUp(&display, &event_queue, &timer); 50 51 return 0; 52}

initializeAllegro function

#SelectExpand
1int initializeAllegro(ALLEGRO_DISPLAY **display, ALLEGRO_EVENT_QUEUE **event_queue, ALLEGRO_TIMER **timer) { 2 std::ofstream file("Log.txt"); 3 4 if (!al_init()) { 5 file << "Could not initialize Allegro 5" << std::endl; 6 return -1; 7 } 8 9 *display = al_create_display(640, 480); 10 al_set_window_title(*display, "Game"); 11 if (!display) { 12 al_destroy_display(*display); 13 file << "Could not create display" << std::endl; 14 return -1; 15 } 16 17 *event_queue = al_create_event_queue(); 18 if (!event_queue) { 19 al_destroy_event_queue(*event_queue); 20 file << "Could not create event queue" << std::endl; 21 return -1; 22 } 23 24 const float FPS = 60.0f; 25 *timer = al_create_timer(1.0 / FPS); 26 if (!timer) { 27 al_destroy_timer(*timer); 28 file << "Could not create game timer" << std::endl; 29 return -1; 30 } 31 32 al_install_keyboard(); 33 al_install_mouse(); 34 35 al_register_event_source(*event_queue, al_get_display_event_source(*display)); 36 al_register_event_source(*event_queue, al_get_timer_event_source(*timer)); 37 al_register_event_source(*event_queue, al_get_keyboard_event_source()); 38 al_register_event_source(*event_queue, al_get_mouse_event_source()); 39 40 al_start_timer(*timer); 41 42 return 0; 43}

checkInput function

#SelectExpand
1void checkInput(ALLEGRO_EVENT &ev, int &running) { 2 if (ev.type == ALLEGRO_EVENT_KEY_DOWN) 3 { 4 switch (ev.keyboard.keycode) 5 { 6 case ALLEGRO_KEY_ESCAPE: 7 running = false; 8 break; 9 } 10 } 11}

cleanUp function

#SelectExpand
1void cleanUp(ALLEGRO_DISPLAY **display, ALLEGRO_EVENT_QUEUE **event_queue, ALLEGRO_TIMER **timer) { 2 al_destroy_display(*display); 3 al_destroy_event_queue(*event_queue); 4 al_destroy_timer(*timer); 5}

RPG Hacker

But one thing I can see you're forgetting is al_clear_to_color(al_map_rgb(0,0,0));

Well, when drawing something to full screen size, al_clear_to_color() isn't necessarily needed. Since you're redrawing each pixel every frame, anyways, a clear is optional. In fact, you're saving a small amout of performance by skipping the clear. It's probably a neglectible amount, but I'm just saying.

Elias

ALLEGRO_DISPLAY_MODE ldm;

This is a local variable which gets destroyed when the init function returns. So any behavior after that is undefined, program crashes or other weird things are expected. This is the joy of C++, always be careful about memory allocation and lifetime, for every single variable you use :) Anyway, it could explain both the Linux and Windows issues.

Matias Persson

Well, when drawing something to full screen size, al_clear_to_color() isn't necessarily needed. Since you're redrawing each pixel every frame, anyways, a clear is optional. In fact, you're saving a small amout of performance by skipping the clear. It's probably a neglectible amount, but I'm just saying.

Oh, well that is good to know! :D

Thread #615810. Printed from Allegro.cc