Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Screen Update API

This thread is locked; no one can reply to it. rss feed Print
Screen Update API
23yrold3yrold
Member #1,134
March 2001
avatar

(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:

#SelectExpand
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:

#SelectExpand
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 :P Now that I look at it, it's practically C code, huh? Here's my old "simple game" demo to demonstrate use:

#SelectExpand
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?

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

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
avatar

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]
oh and don't forget DIRTY_RECTANGELS as a possible flag, here you would just create a single buffer, but do nothing for the update or whatever.
[/edit]

___________________________________
[ Facebook ]
Microsoft is not the Borg collective. The Borg collective has got proper networking. - planetspace.de
Bill Gates is in fact Shawn Hargreaves' ßî+çh. - Gideon Weems

MiquelFire
Member #3,110
January 2003
avatar

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)

---
Febreze (and other air fresheners actually) is just below perfumes/colognes, and that's just below dead skunks in terms of smells that offend my nose.
MiquelFire.red
If anyone is of the opinion that there is no systemic racism in America, they're either blind, stupid, or racist too. ~Edgar Reynaldo

23yrold3yrold
Member #1,134
March 2001
avatar

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 :-X

ST: I've tried "switching" during runtime; doesn't work too good does it? :P 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 ....

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

amarillion
Member #940
January 2001
avatar

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
forgotten to add the check for page flipping

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
avatar

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 ...

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

Goodbytes
Member #448
June 2000
avatar

First of all, it's _cplusplus, not _CPP.

Secondly, and IIRC, you need the extern "C" code for two reasons:

  • C and C++ name mangling can be different, due to C++ requiring special name mangling for overloaded function names, so if you make this screen update API into a fully-fledged library, you may get some "undefined reference" errors when using the lib in a C++ project.

  • Sometimes, people write C code that is not valid C++, for instance, by using implicit void* pointer casts or by declaring identifiers with such names as 'virtual' or 'new', which are, as you know, keywords in C++. You obviously wouldn't have done this, but it's a second reason. So there.

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.


--
~Goodbytes

23yrold3yrold
Member #1,134
March 2001
avatar

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 ...

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

Goodbytes
Member #448
June 2000
avatar

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.


--
~Goodbytes

23yrold3yrold
Member #1,134
March 2001
avatar

Quote:

I don't think that C has default arguments

ACK! Right. Must fix.

No bool?! Truely?

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

Goodbytes
Member #448
June 2000
avatar

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.


--
~Goodbytes

Go to: