Framerate questions
Fasine

Greetings again! Since my last post I found an index online with all the GNU standard C libraries and gave myself a crash course in using them. I reformatted my attendance program to use standard functions instead of Borland's, so now it works in all my compilers. Now I've begun work on the game I'm planning and have run into a problem: how do I maintain a set frame rate? I looked through the example programs and found one that uses the rest_callback() function, but it still fluctuates between 87 and 93 fps when I pass a value of 8.

First off: will a fluctuation like this affect the way my game plays (or looks?) if so, is there another way to fix it? I tried using the clock() function to check to make sure a certain number of milliseconds had passed since the beginning of the game loop, with an empty while{} loop iterating indefinitely until it passed that number, and had some success. It wasn't perfect, but it was only 26 seconds off what it should have been after 10 minutes, which I thought was a success, until I opened my task manager and realized it was using 100% CPU that whole time (duh!)

So what do you all usually do to ensure a good rate of timing for your game? I had planned to use the fact that the game only iterates X times per second to modify timer variables (i.e. a 10 second effect should start at 600, if running at 60 fps, then subtract 1 during each iteration) but if the fps doesn't remain static, then this won't be accurate (assuming I use numbers large enough that it would have an impact, if it's 5 minutes off after 30 minutes, that could cause problems)

Albin Engström

well, don't you use allegro? there's alot of handy timing functions for allegro.

i don't like having the graphics routine executed more times than necessary so heres what i do when vsync isn't involved:

make a function.
void blabla_timer();

install the allegro timer functions.
install_timer();

lock the variables changed by the timer.
LOCK_VARIABLE(blabla_timer);

lock the function thats going to be executed by the timer.
LOCK_FUNCTION(blabla_timer);

Then start the timer, and it can be done in many ways:

install_int(blabla_timer, 1); specify the delay in milliseconds.'
install_int_ex(blabla_timer,BPS_TO_TIMER(75)); runs 75 times per second,
so install_int_ex(blabla_timer,BPS_TO_TIMER(sfps));

read here for a more detailed version "http://allegro.cc/manual/api/timer-routines/install_int_ex"

Then you can probably figure the rest out yourself :P

Read this: "http://allegro.cc/manual/api/timer-routines/"

Ninkazu

Here's another thread that goes over this
http://www.allegro.cc/forums/thread/589396

GullRaDriel
Fasine

Alright, I don't think I'm doing this properly. When I use the interrupt handler, the program runs at 100% CPU, which I assume is caused by the rest(0) command, which is alright, since it gives any leftover CPU to other processes, but is that normal? Also, it executes at 80 frames per second regardless of the value I pass to BPS_TO_TIMER(). I tried from 30 to 70 and it all ran at between 76 and 83. Additionally, at the end of the program I call a function to set a flag equal to the amount of time left (17 - amountoftimepassed) for each loop, and it was returning numbers between 17 and -14. Meaning some loops executed in less than 1ms and others took 31ms. Am I doing something wrong here? The interrupt handler and its declarations are here.

    //interrupt function (should I put something else here?)
    void interrupt()
    {
         rest(0);
    }
//then main begins...
    install_timer();
    install_int_ex(interrupt, BPS_TO_TIMER(30));
    LOCK_FUNCTION(interrupt);
//I don't lock any variables since the timer function uses none.

And at the bottom is the full source of the program I'm working with, 95 lines or so. Not huge, but you may not need to wade through it to answer my question either.

One additional question: when I compile my program, it brings up two windows, the traditional C++ window that is used for text programs in addition to a Windows-style window that contains all the graphics and stuff I'm executing. It's not a problem since they both close together and whatnot, but I know there's a way to keep that from happening as well. Can anyone fill me in? Thanks a ton for your replies!

1#include <cstdlib>
2#define ALLEGRO_STATICLINK
3#include "allegro.h"
4 
5 //declare bitmaps
6 BITMAP *buffer;
7 BITMAP *background;
8
9 
10 int count=0;
11 int interval=0;
12 int timebuffer=0;
13 volatile int framerate;
14 volatile int timer=0;
15 int timepassed;
16
17 //define some colors for use later on.
18#define BLACK makecol(0,0,0)
19#define WHITE makecol(255,255,255)
20
21 
22 //background image is drawn to the buffer, then debug messages are drawn on top.
23 void drawbuffer(void)
24 {
25 acquire_bitmap(buffer);
26 blit(background, buffer, 0, 0, 0, 0, 1200, 800);
27 release_bitmap(buffer);
28 textprintf_ex(buffer,font,20,10,BLACK,-1, "Framerate: %i", framerate);
29 textprintf_ex(buffer,font,20,22,BLACK,-1, "Time Buffer: %i", timepassed);
30 }
31
32 //screen is acquired and buffer is blitted to it.
33 void drawscreen(void)
34 {
35 acquire_screen();
36 scare_mouse();
37 blit(buffer, screen, 0, 0, 0, 0, 1200, 800);
38 release_screen();
39 unscare_mouse();
40}
41
42 //interrupt function (should I put something else here?)
43 void interrupt()
44 {
45 rest(0);
46 }
47
48
49int main()
50{
51 allegro_init();
52 install_keyboard();
53 install_timer();
54 //install_int_ex(timer1, BPS_TO_TIMER(60));
55 set_color_depth(16);
56 set_gfx_mode(GFX_AUTODETECT_WINDOWED, 1200, 800, 0, 0);
57
58 //install interrupt
59 install_int_ex(interrupt, BPS_TO_TIMER(30));
60 LOCK_FUNCTION(interrupt);
61 
62 //create bitmaps
63 buffer = create_bitmap(1600, 1250);
64 background = load_bitmap("grass.bmp", NULL);
65
66 //set this variable for timing the framerate later in the loop
67 interval = clock();
68 timebuffer = clock();
69
70 while(!keypressed())
71 {
72 count++;
73 //sets framerate variable for use in the debug display
74 if(clock() - interval > 1000)
75 {
76 interval = clock();
77 framerate = count;
78 count = 0;
79 }
80
81 //used to find number of milliseconds left when loop is finished
82 timer = clock();
83
84 //bitmap is blitted to the buffer, along with debug messages
85 //then the buffer is blitted to the screen.
86 drawbuffer();
87 drawscreen();
88
89 //stores the amount of time that has passed for displaying as a debug message
90 if(clock() - timebuffer > 1000)
91 {
92 timepassed = 17 - (clock() - timer);
93 timebuffer = clock();
94 }
95
96 //This is the timer system I was using before
97 //if 17 milliseconds haven't passed since the beginning of the loop, this loop delays it
98 /*while(clock() - timer < 17)
99 {
100 rest(1);
101 }*/
102}
103}
104END_OF_MAIN()

Neil Walker

your extra window is because you have your compiler set as a console app.

acquire_bitmap serves no purpose for single lines of code, and should only be used for memory buffers.

I have no comment on the rest of the code, save there are much much easier and better ways of handing framerate than what you're doing :)

Fasine
Quote:

I have no comment on the rest of the code, save there are much much easier and better ways of handing framerate than what you're doing

Neil.

Well in that code I used one of the allegro commands that's supposed to set the framerate to a certain number of frames per second (install_int_ex(interrupt, BPS_TO_TIMER(30)) and it didn't, so I'm not sure what else to do. I don't fully understand how the interrupt timers work though, so it's entirely possible I could be doing this wrong. I'm assuming it just waits to reiterate the program until a certain amount of time has passed, but I'm not sure why this function isn't working properly...

************************Scratch all that!****************************

I figured it out: the timer function runs on a separate thread (basically as if it were a separate program altogether) and iterates itself at the intervals you pass to it in the install_int command. This is what I have and it now works:

    void interrupt()
    {
         counter++;
    }
    END_OF_FUNCTION(interrupt);

then at the beginning of the main loop, I set a flag variable equal to counter, then check at the end of the loop to see if they are still equal and uses a while() loop to rest(0) until they're different. If the interrupt has been iterated since the beginning of the loop, they won't be equal and the program will proceed, setting the flag variable equal to counter again when it begins once more. I thought the interrupt commands were supposed to delay your program until the predetermined amount of time had passed before starting over, but you apparently have to work with them a little. And now we know! =)

Thread #589659. Printed from Allegro.cc