|
Screen Update API |
23yrold3yrold
Member #1,134
March 2001
|
(DISCLAIMER: this post is being edited as comments are made ...) I'm just throwing this out for feedback; it's my set of functions for updating the screen. I guess it half belongs in the Depot, since it's kind of a gift (to the newbs; most of you probably have no use for this ), but I also want suggestions and most importantly, bug reports. If it looks good and DLH wants it, I'll gift-wrap it for the AGDN. Header: 1// screen.h
2
3#ifdef __cplusplus
4extern "C" {
5#endif
6
7void InitializeScreenUpdate(int i);
8void ShutDownScreenUpdate();
9void SwapBuffers();
10BITMAP* GetBuffer();
11BITMAP* GetScreen();
12void EnableVSync();
13void DisableVSync();
14bool VSyncEnabled();
15int GetScreenUpdateMethod();
16
17#define TRIPLEBUFFER 1
18#define PAGEFLIP 2
19#define SYSTEMBUFFER 3
20#define DOUBLEBUFFER 4
21
22#ifdef __cplusplus
23}
24#endif
Source file: 1// screen.c
2
3static int updatemethod = 0;
4static bool waitforvsync = 0;
5static BITMAP *pages[3] = {NULL, NULL, NULL}, *active_page, *current_page;
6
7// helper function
8static BITMAP* erase_bitmap(BITMAP *bmp) {
9 destroy_bitmap(bmp);
10 return NULL;
11}
12
13void InitializeScreenUpdate(int i){
14 if(i < TRIPLEBUFFER || i > DOUBLEBUFFER) i = TRIPLEBUFFER;
15
16 switch(i)
17 {
18 case TRIPLEBUFFER:
19 if (!(gfx_capabilities & GFX_CAN_TRIPLE_BUFFER))
20 enable_triple_buffer();
21
22 if((gfx_capabilities & GFX_CAN_TRIPLE_BUFFER))
23 {
24 pages[0] = create_video_bitmap(SCREEN_W, SCREEN_H);
25 pages[1] = create_video_bitmap(SCREEN_W, SCREEN_H);
26 pages[2] = create_video_bitmap(SCREEN_W, SCREEN_H);
27 if(pages[0] && pages[1] && pages[2])
28 {
29 clear_bitmap(pages[0]);
30 clear_bitmap(pages[1]);
31 clear_bitmap(pages[2]);
32 active_page = pages[0];
33 current_page = pages[2];
34 show_video_bitmap(current_page);
35 updatemethod = TRIPLEBUFFER;
36 return;
37 }
38 else
39 {
40 if(pages[0]) { pages[0] = erase_bitmap(pages[0]); }
41 if(pages[1]) { pages[1] = erase_bitmap(pages[1]); }
42 if(pages[2]) { pages[2] = erase_bitmap(pages[2]); }
43 }
44 }
45 // fall through if triple buffering isn't supported
46
47 case PAGEFLIP:
48 pages[0] = create_video_bitmap(SCREEN_W, SCREEN_H); if(!pages[0]) return;
49 pages[1] = create_video_bitmap(SCREEN_W, SCREEN_H); if(!pages[1]) { destroy_bitmap(pages[0]); return; }
50 if(pages[0] && pages[1])
51 {
52 clear_bitmap(pages[0]);
53 clear_bitmap(pages[1]);
54 active_page = pages[0];
55 current_page = pages[1];
56 show_video_bitmap(current_page);
57 updatemethod = PAGEFLIP;
58 return;
59 }
60 else
61 {
62 if(pages[0]) { pages[0] = erase_bitmap(pages[0]); }
63 if(pages[1]) { pages[1] = erase_bitmap(pages[1]); }
64 }
65 // fall through if page flipping isn't supported
66
67 case SYSTEMBUFFER:
68 active_page = create_system_bitmap(SCREEN_W, SCREEN_H); if(!active_page) return;
69 current_page = create_video_bitmap(SCREEN_W, SCREEN_H); if(!current_page) { destroy_bitmap(active_page); return; }
70 clear_bitmap(active_page);
71 clear_bitmap(current_page);
72 show_video_bitmap(current_page);
73 updatemethod = SYSTEMBUFFER;
74 return;
75
76 case DOUBLEBUFFER:
77 active_page = create_bitmap(SCREEN_W, SCREEN_H); if(!active_page) return;
78 current_page = create_video_bitmap(SCREEN_W, SCREEN_H); if(!current_page) { destroy_bitmap(active_page); return; }
79 clear_bitmap(active_page);
80 clear_bitmap(current_page);
81 show_video_bitmap(current_page);
82 updatemethod = DOUBLEBUFFER;
83 return;
84 }
85}
86
87void SwapBuffers(){
88 switch(updatemethod)
89 {
90 case TRIPLEBUFFER:
91 do { } while (poll_scroll());
92 current_page = active_page;
93 request_video_bitmap(current_page);
94
95 if(active_page == pages[0])
96 active_page = pages[1];
97 else if(active_page == pages[1])
98 active_page = pages[2];
99 else
100 active_page = pages[0];
101 return;
102
103 case PAGEFLIP:
104 current_page = active_page;
105 show_video_bitmap(current_page);
106 if (active_page == pages[0]) active_page = pages[1]; else active_page = pages[0];
107 return;
108
109 case SYSTEMBUFFER:
110 case DOUBLEBUFFER:
111 if(waitforvsync) vsync();
112 blit(active_page, current_page, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
113 return;
114 }
115}
116
117void ShutDownScreenUpdate() {
118 if(pages[0]) pages[0] = erase_bitmap(pages[0]);
119 if(pages[1]) pages[1] = erase_bitmap(pages[0]);
120 if(pages[2]) pages[2] = erase_bitmap(pages[0]);
121
122 if(updatemethod == DOUBLEBUFFER || updatemethod == SYSTEMBUFFER)
123 {
124 active_page = erase_bitmap(active_page );
125 current_page = erase_bitmap(current_page);
126 }
127}
128
129BITMAP* GetBuffer() { return active_page; }
130BITMAP* GetScreen() { return current_page; }
131void EnableVSync() { waitforvsync = true; }
132void DisableVSync() { waitforvsync = false; }
133bool VSyncEnabled() { return waitforvsync; }
134int GetScreenUpdateMethod() { return updatemethod; }
I'm kind of hacking this out of my game engine so I may have made a mistake up there Now that I look at it, it's practically C code, huh? Here's my old "simple game" demo to demonstrate use: 1#include <allegro.h>
2#include "screen.h"
3
4class CPlayer {
5 public:
6 int xpos, ypos, speed;
7 BITMAP *sprite;
8
9 CPlayer(): xpos(0), ypos(0), speed(5) { sprite = load_bitmap("test.bmp", NULL); }
10 ~CPlayer() { destroy_bitmap(sprite); }
11
12 void GetControls()
13 {
14 if(key[KEY_UP]) { if(ypos - speed < 0) ypos = 0; else ypos -= speed; }
15 if(key[KEY_DOWN]) { if(ypos + speed + sprite->h > SCREEN_H) ypos = SCREEN_H - sprite->h; else ypos += speed; }
16 if(key[KEY_LEFT]) { if(xpos - speed < 0) xpos = 0; else xpos -= speed; }
17 if(key[KEY_RIGHT]) { if(xpos + speed + sprite->w > SCREEN_W) xpos = SCREEN_W - sprite->w; else xpos += speed; }
18 }
19
20 void Draw(BITMAP* b) { draw_sprite(b, sprite, xpos, ypos); }
21};
22volatile int game_time = 0;
23void Timer(void) { game_time++; } END_OF_FUNCTION(Timer); // end Timer()
24
25
26int main() {
27 allegro_init();
28 install_keyboard();
29 set_color_depth(16);
30 set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0);
31 InitializeScreenUpdate(PAGEFLIP);
32
33 LOCK_VARIABLE(game_time);
34 LOCK_FUNCTION((void*)Timer);
35 install_int_ex(Timer, BPS_TO_TIMER(60));
36
37 CPlayer MyPlayer;
38 BITMAP* buffer;
39
40 do{
41 while(game_time > 0)
42 {
43 MyPlayer.GetControls();
44 game_time--;
45 }
46
47 // the buffer variable is optional, but probably quicker :P
48 buffer = GetBuffer();
49 clear(buffer);
50 MyPlayer.Draw(buffer);
51 SwapBuffers();
52 while(game_time <= 0){}
53 }
54 while(!key[KEY_ESC]);
55
56 ShutDownScreenUpdate();
57 return 0;
58}
59END_OF_MAIN();
Look good? -- |
Matt Smith
Member #783
November 2000
|
When you gift-wrap it, do it as C with the extern "C" {} flourish in screen.h |
Steve Terry
Member #1,989
March 2002
|
I do nearly the same thing with my video.c file, but the only problem is switching between triple buffering and page flipping, my program randomly crashes on that switch. I was just wondering if your example allows mode switching on the fly and if so, does it crash on switching as mine does.... [edit] ___________________________________ |
MiquelFire
Member #3,110
January 2003
|
Would be nice if InitializeScreenUpdate() returned something so you can do something like this: if (InitializeScreenUpdate(TRIPLEBUFFER) != 0) { // try next supported mode for game and what not } // go on as normal Just a suggestion (don't like the idea of calling another function just to see if another one worked) --- |
23yrold3yrold
Member #1,134
March 2001
|
Actually MB, InitializeScreenUpdate() will go through the supported modes itself I notice just now that it only does that if triple buffering fails; I must have forgotten to add the check for page flipping ST: I've tried "switching" during runtime; doesn't work too good does it? My game, if you change the update method in the Options menu, simply informs you that the changes will take effect if you quit and restart. And dirty rectangles is up to you; you should be able to do that for the double buffer system yourself (don't think it would work too well for page fliping or triple buffering ...) MS: Isn't there an #ifdef way to do that? I forget the define though .... -- |
amarillion
Member #940
January 2001
|
Quote:
Actually MB, InitializeScreenUpdate() will go through the supported modes itself I notice just now that it only does that if triple buffering fails; I must have That assumes that all the supported screen modes are acceptable. But what if the code is highly optimized for double buffering, and not for page flipping? You have to be able to control which update method you end up with. -- |
23yrold3yrold
Member #1,134
March 2001
|
If you ask for double buffering, you get double buffering. If you ask for triple buffering, the function will try it and resort to another method if triple buffering isn't supported. If you don't venture a preference, the function will try them all (starting with TB) until it finds one that works (I still need to add the error check to page flipping; triple buffer is the only one doing that right now). Did anyone actually read the function? And what's that #define? I know I've seen the code; I just forget it. Something like this: #ifdef __CPP__ extern "C" { #endif ...... #ifdef __CPP__ } #endif Something like that. BTW, why do I need it again? I'm a bit fuzzy on the reasons for "C"{}, and this code works fine in my C++ program ... -- |
Goodbytes
Member #448
June 2000
|
First of all, it's _cplusplus, not _CPP. Secondly, and IIRC, you need the extern "C" code for two reasons:
By the way, the Allegro 5 API will automatically handle all these different screen update modes for you, on top of dirty rectangling, so your code will only be needed for another 6.3 millenia. Then, when Allegro 5 is released, it will have to be thrown into a hyperentropy bin by your distant descendants. |
23yrold3yrold
Member #1,134
March 2001
|
Quote: First of all, it's __cplusplus, not __CPP__. Thank you. I'm going to edit the header; somone tell me if I did it wrong ... Quote: You obviously wouldn't have done this, but it's a second reason. So there. Okay, I think I get it Is the source file pure C now? I don't think I left any C++ elements in it ... EDIT: I added the page flipping check, and my erase_bitmap() helper function (which I had forgotten). I think it's good and done now ... -- |
Goodbytes
Member #448
June 2000
|
23yrold3yrold asked, and saying many things while asking, he said: Is the source file pure C now? I don't think I left any C++ elements in it ... This could be incorrect, but... I don't think that C has default arguments (re int i = -1) and I don't think that C has the bool type (re some functions which I'm too lazy to scroll up and check). Of course, with C99, many crazy, scary things have been happening. For instance, I heard that a boolean type is supported, but some people have said that it's not bool, it's _Boolean. Which is ghey. But... I'm not sure. Ask your pineal gland. |
23yrold3yrold
Member #1,134
March 2001
|
Quote: I don't think that C has default arguments ACK! Right. Must fix. No bool?! Truely? -- |
Goodbytes
Member #448
June 2000
|
Dude... your reply came like... three minutes after mine! Amazing... 23yrold3yrold fell out of his chair and said: No bool?! Truely? Well, being the helpful guy that I am, I decided to google for you, and I found this code in a sourceforge project which claimed to be C99: bool write_inode = false; So... maybe bool is C99, Chris. Maybe bool is C99. |
|