[SDL] How to get constant framerates without busywaits ...
David Olofson
david.olofson at reologica.se
Tue Mar 19 11:27:01 PST 2002
On Tuesday 19 March 2002 19:36, Stephen Anthony wrote:
[...]
> OK, you lost me again here :( What are you considering a flip to be?
> Are you assuming double-buffering? Because right now I don't use
> double-buffering. Are you saying that this method will only work if
> the hardware supports retrace sync'ed flips?
A "flip" here can be whatever mentod you use of making a frame visible.
It *will* work better if you're running at full frame rate with retrace
sync, but it's not critical.
[...]
> How do I interpret this last table? What does the 0 and 1 in the
> engine frame represent? The fact that you should use buffer 0 or
> buffer 1? Or that you should not / should do the next logic frame??
Sorry; it's "Engine frames" - simply the number of logic/engine frames to
"run" before you render the output frame. You calculate this once per
output frame, after checking the current time.
> Also, does this solve the problem of busy-waiting? Where / how would
> you use a sleep call?
No. There's still no way to do that, short of retrace sync properly
implemented in the driver.
> I'm sorry if I seem a bit dense here. I really want to understand how
> this works.
It seems trivial to me, but it's still hard to explain - and I'm not
particularly good at describing anything right now, it seems... *heh*
> Maybe you could provide a simple example in pseudocode? I
> sort of understand what you're saying, I just don't know how to go
> about writing it :)
There are many ways to write it... Here's some code from the Spitfire
Engine, used in Kobo Deluxe:
---8<-----------------------------------------------------------
void cs_engine_advance(cs_engine_t *e, float to_frame)
{
if(to_frame > 0)
{
int frames = floor(to_frame) - floor(e->time);
if(frames > 0)
{
while(frames--)
{
__run_all(e);
e->on_frame(e);
}
}
}
e->time = to_frame;
if(e->wx || e->wy)
__wrap_all(e);
__update_points(e, to_frame - floor(to_frame));
}
----------------------------------------------------------->8---
__run_all() updates all "object" (sprites and "points" for scrolling etc)
positions, based on their velocity and acceleration values, evaluates
collisions and stuff. (None of this is used in Kobo Deluxe.)
on_frame() is your logic/engine callback - this is where you hook your
emulator frame() function in. (Actually, this is wrapped by the C++ API,
so you "hook the callback in" by deriving from gfxengine_t and throwing
in your own frame() method in your new class.)
__wrap_all() "fixes" object coordinates for wrapping levels, like those
in Kobo Deluxe.
__update_points() implements the interpolation; this is where the actual
graphics coordinates for all objects are calculated for each rendered
frame.
---8<-----------------------------------------------------------
void gfxengine_t::run()
{
open();
show();
start_engine();
is_running = 1;
while(is_running)
{
int tick = SDL_GetTicks() - start_tick;
float toframe = (float)tick / ticks_per_frame;
cs_engine_advance(csengine, toframe);
pre_render();
window->select();
cs_engine_render(csengine);
post_render();
if(autoinvalidate)
window->invalidate();
flip();
}
stop_engine();
}
----------------------------------------------------------->8---
The first two lines in the loop is where I check the time, and translate
that into a fractional time, expressed in logic frames. That is, the
integer part is which frame I want to render, and the fractional part
says how close we are to the *next* logic frame.
Next, I call cs_engine_advance() (above), to run the whole game logic
until the right frame.
cs_engine_render() renders all objects (sprites) into the output
"window", whereas pre_render() and post_render() are hooks for the game
to render stuff before and after the objects are rendered, respectively.
(Kobo Deluxe uses the first one for the background, and the second for
overlay text, any debugging stuff and finally, the frame with the rounded
corners.)
flip() can perform SDL_UpdateRects(), SDL_FlipSurface() and other stuff,
depending on the selected engine "buffer mode".
//David Olofson --- Programmer, Reologica Instruments AB
.- M A I A -------------------------------------------------.
| Multimedia Application Integration Architecture |
| A Free/Open Source Plugin API for Professional Multimedia |
`----------------------------> http://www.linuxdj.com/maia -'
.- David Olofson -------------------------------------------.
| Audio Hacker - Open Source Advocate - Singer - Songwriter |
`-------------------------------------> http://olofson.net -'
More information about the SDL
mailing list