Timer and FPS control with SDL

Anything else
Post Reply
Re<<aL
Posts: 8
Joined: Wed Sep 05, 2012 6:40 am

Timer and FPS control with SDL

Post by Re<<aL » Wed Sep 05, 2012 8:33 am

Hi, i have a few questions....

First, how do i implement (which functions of SDL etc..) a timer with SDL? like a clock, so i can control the duration of the match or the fire rate of the weapons, the time to spawn, control the Logic Function (physics, sound, AI) etc..

and Second, i can't control the fps, i get the delta time of the frame and if it's less than 16,6 ms (60 fps) i do SDL_Delay(16,6 - deltaTime); But i get 120 fps or something like that.

my main loop is like

while(true)
{
input();
logic();

input->start();
render();
input->update();
}

void Input::update()
{


tick = currentTime - lastTime ;

if(tick > 50)
tick=0;

/* if(paused)
tick=0;*/

if(tick < (1000/65))
{
SDL_Delay(1000/65-tick);
}

deltas+= tick;
lastTime = currentTime;


CEGUI::System::getSingleton().injectTimePulse(static_cast<float>(tick*0.001));



frames++;
if (deltas > 1000)
{
fps = frames;
frames = 0;
deltas = 0 ;
}
}

Please i need help :S

Thank you :D

User avatar
Aaron
Posts: 595
Joined: Tue Feb 16, 2010 12:13 pm
Location: About 2 hours away from Anton
Contact:

Re: Timer and FPS control with SDL

Post by Aaron » Wed Sep 05, 2012 11:30 am

Hey!

There is a really good set of tutorials for SDL made by Lazy Foo (http://lazyfoo.net/SDL_tutorials/).

Specifically, you should check out tutorials 12-15.

Hopefully this helps :)

-Aaron

Edit: One thing I noticed which seems off is that when you increment 'deltas', you're only doing so by the value of tick (which does not necessarily represent the entire length of the frame). Try modifying it to be something like this:

Code: Select all

if(tick < (1000/65))
{
	// If we had extra time during the frame, and have to delay to compensate,
	// then the total time for this frame will be the value associated with
	// our desired framerate (tick + (1000/65 - tick)), which can be simplified
	// to 1000/65
	deltas += 1000/65;
	SDL_Delay(1000/65-tick);
}
else
{
	deltas += tick;
}

lastTime = currentTime;
If, for example, each of your frames were taking ~7ms, then adding up only the 'tick' value would cause about twice as many frames to be incremented before the fps variable would be updated, causing a false report of 120 fps. You want to make sure to increment the actual amount of time spent in order to get accurate results (accounting for both the time spent rendering the frame, and the time spent sleeping afterwards).

Re<<aL
Posts: 8
Joined: Wed Sep 05, 2012 6:40 am

Re: Timer and FPS control with SDL

Post by Re<<aL » Wed Sep 05, 2012 12:52 pm

Ok im going to implement that this night and im going to read the tutorial (which i read long time ago but i dont remeber them ;P)

Thank you very much Aaron

Edit: It works thank you very much, but i got 63 fps not 60 (1000/60) but i dont care now, i will investigate. Thank you very much i really appreciated it.

User avatar
Aaron
Posts: 595
Joined: Tue Feb 16, 2010 12:13 pm
Location: About 2 hours away from Anton
Contact:

Re: Timer and FPS control with SDL

Post by Aaron » Wed Sep 05, 2012 7:11 pm

Glad to hear its working! The reason you're getting 63 fps instead of 60 is most likely due to the integer division in determining the sleep time (ideally you want 16 and 2/3 ms of time for each frame, though due to integer division, 1000/60 equates to 16ms of sleep time). I've written up what should be a fix for this problem, which alternates sleeping for different amounts of time in order to achieve the desired framerate.

Code: Select all

const int FRAMERATE = 60;
bool firstPass = true;
int mainFrameTime, alternateFrameTime, alternateFrameInterval;

while(true)
{
	input();
	logic();
	
	input->start();
	render();
	input->update();
}

void Input::update()
{
	if(firstPass)
	{
		firstPass = false;
		calcFrameTimes(FRAMERATE, mainFrameTime, alternateFrameTime, alternateFrameInterval);
	}

	tick = currentTime - lastTime;
	
	if(tick > 50)
		tick=0;
	
	/* if(paused)
	tick=0;*/

	int frameTime;
	if(frames % alternateFrameInterval == 0)
	{
		frameTime = alternateFrameTime;
	}
	else
	{
		frameTime = mainFrameTime;
	}
	
	if(tick < frameTime)
	{
		// If we had extra time during the frame, and have to delay to compensate,
		// then the total time for this frame will be the value associated with
		// our desired framerate (tick + (frameTime - tick)), which can be simplified
		// to frameTime
		deltas += frameTime;
		SDL_Delay(frameTime - tick);
	}
	else
	{
		deltas += tick;
	}
	
	lastTime = currentTime;
	
	CEGUI::System::getSingleton().injectTimePulse(static_cast<float>(tick*0.001));
	
	frames++;
	if(deltas > 1000)
	{
		fps = frames;
		frames = 0;
		deltas = 0 ;
	}
}

void calcFrameTimes(int targetFramerate, int &mainFrameTime, int &alternateFrameTime, int &alternateFrameInterval)
{
    // Calculate the actual frame time, and the approximate (integer divided) frame time
	float realFrameTime = 1000.0f / targetFramerate;
	int approxFrameTime = 1000 / targetFramerate;
    
    // Find the fractional part of the real frame time, and use it to determine how many
    // frames should be rendered at the high frame time, and how many at the low frame time
	float frameTimeDiff = realFrameTime - approxFrameTime;
	int framesAtHigherTime = (int)(frameTimeDiff * targetFramerate + 0.5f);
	int framesAtLowerTime = targetFramerate - framesAtHigherTime;
    
	if(framesAtHigherTime >= framesAtLowerTime)
	{
        mainFrameTime = approxFrameTime + 1;
        alternateFrameTime = approxFrameTime;
        
		// Number of times to use the main amount before using the alternate amount, plus 1
		alternateFrameInterval = (int)(((float)framesAtHigherTime / framesAtLowerTime) + 0.5f) + 1;
	}
	else
	{
        mainFrameTime = approxFrameTime;
        alternateFrameTime = approxFrameTime + 1;
        
		// Number of times to use the main amount before using the alternate amount, plus 1
		alternateFrameInterval = (int)(((float)framesAtLowerTime / framesAtHigherTime) + 0.5f) + 1;
	}
}
I haven't thoroughly tested out this system yet, though it seems to be returning good values. Try giving it a shot, and let me know how it goes!

-Aaron

Re<<aL
Posts: 8
Joined: Wed Sep 05, 2012 6:40 am

Re: Timer and FPS control with SDL

Post by Re<<aL » Thu Sep 06, 2012 6:03 am

IT WORKS!!!!

Thank you very much for your help Aaron.

Your function works and i get a constant frame rate of 60 fps.


Thank you!!!!!

User avatar
Aaron
Posts: 595
Joined: Tue Feb 16, 2010 12:13 pm
Location: About 2 hours away from Anton
Contact:

Re: Timer and FPS control with SDL

Post by Aaron » Thu Sep 06, 2012 11:28 am

Great :) Good luck with your project!

Post Reply