My game calls the rest command to reduce CPU usage. However, after calling save_bitmap (called by a specific keypress to take snapshots), trouble begins. About 10 seconds after making the call to save_bitmap, my palette goes all wonky. I haven't studied it very closely, but I think it may be reverting to the system palette. Any ideas why? If I don't call save_bitmap (just return from the snapshot code) or remove the call to rest, everything is fine.
Sounds like memory problems. Accessing memory haven't allocated, broken pointers, dangling pointers, etc.
I've whittled down the code to about 100 lines (including several blank lines) and am still getting the error. Can anyone take a look and see if they get the same problem?
1 | #include <allegro.h> |
2 | |
3 | bool quit=false; |
4 | int d_nbmenu_proc(int msg,DIALOG *d,int c); |
5 | |
6 | |
7 | int onExit() |
8 | { |
9 | exit(0); |
10 | } |
11 | |
12 | static MENU the_menu[] = |
13 | { |
14 | { "&Exit", onExit, NULL }, |
15 | { NULL } |
16 | }; |
17 | |
18 | int onSnapshot() |
19 | { |
20 | BITMAP *screen2 = create_bitmap_ex(8,320,240); |
21 | char buf[20]; |
22 | int num=0; |
23 | do |
24 | { |
25 | sprintf(buf, "test%03d.bmp", ++num); |
26 | } while(num<999 && exists(buf)); |
27 | |
28 | blit(screen,screen2,0,0,0,0,320,240); |
29 | PALETTE temppal; |
30 | get_palette(temppal); |
31 | save_bitmap(buf,screen2,temppal); |
32 | destroy_bitmap(screen2); |
33 | return D_O_K; |
34 | } |
35 | |
36 | static DIALOG dialogs[] = |
37 | { |
38 | { d_nbmenu_proc, 0, 0, 0, 13, 0, 0, 0, D_USER, 0, 0, (void *) the_menu }, |
39 | { d_keyboard_proc, 0, 0, 0, 0, 0, 0, 'z', 0, 0, 0, (void *) onSnapshot }, |
40 | { d_keyboard_proc, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, (void *) onExit },// |
41 | { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL } |
42 | }; |
43 | |
44 | int main(int argc,char **argv) |
45 | { |
46 | allegro_init(); |
47 | |
48 | if(install_timer() < 0) |
49 | { |
50 | al_trace(allegro_error); |
51 | exit(1); |
52 | } |
53 | |
54 | if(install_keyboard() < 0) |
55 | { |
56 | al_trace(allegro_error); |
57 | exit(1); |
58 | } |
59 | |
60 | if(install_mouse() < 0) |
61 | { |
62 | al_trace(allegro_error); |
63 | exit(1); |
64 | } |
65 | |
66 | set_color_depth(8); |
67 | if(set_gfx_mode(GFX_AUTODETECT_FULLSCREEN,320,240,0,0)!=0) |
68 | { |
69 | al_trace(allegro_error); |
70 | exit(1); |
71 | } |
72 | else |
73 | { |
74 | al_trace("OK\n"); |
75 | } |
76 | DIALOG_PLAYER *player=init_dialog(dialogs,-1); |
77 | show_mouse(screen); |
78 | quit=!update_dialog(player); |
79 | while(!quit) |
80 | { |
81 | quit = !update_dialog(player); |
82 | } |
83 | return 0; |
84 | } |
85 | |
86 | END_OF_MAIN() |
87 | |
88 | int d_nbmenu_proc(int msg,DIALOG *d,int c) |
89 | { |
90 | rest (1); |
91 | return d_menu_proc(msg,d,c); |
92 | } |
93 | |
94 | /* end */ |
I compiled it with:
g++ -o test.exe test.cpp -lalleg
When you run it, hit the Z key on the keyboard. After about 5 to 10 seconds, the mouse will change colors. I have a strange feeling that it's because I have a rest command inside of a dialog procedure. Is that the problem? Is there a way to make it work? I've even tried replacing the nbmenu_proc with rest_proc, which I defined as:
This still gives me the same bug.
It finds the first unused testXXX.bmp filename.
I even tried taking that part out and just using a static filename. Same bug.
I even copied the update_dialog function into my code and whittled it down as much as possible while still keeping the bug. I even took out the keyboard_proc and replaced it with specific functions. After doing that and a little more whittling, here is the current incarnation:
1 | #include <allegro.h> |
2 | |
3 | bool quit=false; |
4 | int d_rest_proc(int msg,DIALOG *d,int c); |
5 | |
6 | |
7 | int onExit() |
8 | { |
9 | exit(0); |
10 | } |
11 | |
12 | int onSnapshot() |
13 | { |
14 | PALETTE temppal; |
15 | get_palette(temppal); |
16 | save_bitmap("test.bmp",screen,temppal); |
17 | return D_O_K; |
18 | } |
19 | |
20 | int d_exit_proc(int msg, DIALOG *d, int c) |
21 | { |
22 | if (msg==MSG_KEY) exit(0); |
23 | return D_O_K; |
24 | } |
25 | |
26 | int d_snapshot_proc(int msg, DIALOG *d, int c) |
27 | { |
28 | if (msg==MSG_KEY) |
29 | { |
30 | PALETTE temppal; |
31 | get_palette(temppal); |
32 | save_bitmap("test.bmp",screen,temppal); |
33 | } |
34 | return D_O_K; |
35 | } |
36 | |
37 | static DIALOG dialogs[] = |
38 | { |
39 | { d_rest_proc, 0, 0, 0, 13, 0, 0, 0, D_USER, 0, 0, NULL }, |
40 | { d_snapshot_proc, 0, 0, 0, 0, 0, 0, 'z', 0, 0, 0, NULL }, |
41 | { d_exit_proc, 0, 0, 0, 0, 0, 0, 'x', 0, 0, 0, NULL }, |
42 | { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL } |
43 | }; |
44 | |
45 | int update_dialog2(DIALOG_PLAYER *player) |
46 | { |
47 | int c, cascii, cscan, ccombo, r, ret; |
48 | |
49 | /* deal with keyboard input */ |
50 | if (keypressed()) |
51 | { |
52 | cascii = readkey()&0xFF; |
53 | |
54 | /* keyboard shortcut? */ |
55 | for (c=0; player->dialog[c].proc; c++) |
56 | { |
57 | if (utolower(player->dialog[c].key) == utolower(cascii)) |
58 | { |
59 | object_message(player->dialog+c, MSG_KEY, cascii); |
60 | goto getout; |
61 | } |
62 | } |
63 | } |
64 | |
65 | /* send idle messages */ |
66 | player->res |= dialog_message(player->dialog, MSG_IDLE, 0, &player->obj); |
67 | |
68 | getout: |
69 | |
70 | return 1; |
71 | } |
72 | |
73 | |
74 | int main(int argc,char **argv) |
75 | { |
76 | allegro_init(); |
77 | |
78 | if(install_timer() < 0) |
79 | { |
80 | al_trace(allegro_error); |
81 | exit(1); |
82 | } |
83 | |
84 | if(install_keyboard() < 0) |
85 | { |
86 | al_trace(allegro_error); |
87 | exit(1); |
88 | } |
89 | |
90 | if(install_mouse() < 0) |
91 | { |
92 | al_trace(allegro_error); |
93 | exit(1); |
94 | } |
95 | |
96 | set_color_depth(8); |
97 | if(set_gfx_mode(GFX_AUTODETECT_FULLSCREEN,320,240,0,0)!=0) |
98 | { |
99 | al_trace(allegro_error); |
100 | exit(1); |
101 | } |
102 | else |
103 | { |
104 | al_trace("OK\n"); |
105 | } |
106 | DIALOG_PLAYER *player=init_dialog(dialogs,-1); |
107 | show_mouse(screen); |
108 | quit=!update_dialog2(player); |
109 | while(!quit) |
110 | { |
111 | quit = !update_dialog2(player); |
112 | } |
113 | return 0; |
114 | } |
115 | |
116 | END_OF_MAIN() |
117 | |
118 | int d_rest_proc(int msg,DIALOG *d,int c) |
119 | { |
120 | rest (1); |
121 | return D_O_K; |
122 | } |
123 | |
124 | /* end */ |
Thoughts? The bug seems to have something to do with MSG_IDLE messages. When I take out this line from update_dialog2:
player->res |= dialog_message(player->dialog, MSG_IDLE, 0, &player->obj);
...the bug goes away.
Edit: I just ran my original code and put a graphical display of the current palette on the screen. All of the colors change to what seems to be the default palette. What's worse, when I do a set_palette from a master palette I set up, the last 10 palette entries won't change. Odder still is the fact that if I output (through al_trace) the palette entries before and after the odd palette change, the values are the same. But, for some reason, the wrong colors are being displayed on the screen.