|
Banjo API 1.0.0-rc.2
Low-level C99 game development API
|
Data Structures | |
| struct | bj_tick_info |
Typedefs | |
| typedef struct bj_tick_info | bj_tick_info |
| typedef void *(* | bj_app_setup_fn) (struct bj_app *app, void *init_data) |
| typedef void(* | bj_app_step_fn) (struct bj_app *app, struct bj_tick_info tick, void *user_data) |
| typedef void(* | bj_app_fixed_step_fn) (struct bj_app *app, struct bj_tick_info tick, void *user_data) |
| typedef void(* | bj_app_teardown_fn) (struct bj_app *app, void *user_data) |
Functions | |
| void | bj_set_fixed_step_rate (struct bj_app *app, int hz) |
| int | bj_app_fixed_step_rate (const struct bj_app *app) |
| void | bj_set_frame_rate (struct bj_app *app, int hz) |
| int | bj_app_frame_rate (const struct bj_app *app) |
| int | bj_run_app (bj_app_setup_fn setup, bj_app_step_fn step, bj_app_fixed_step_fn fixed_step, bj_app_teardown_fn teardown, void *init_data) |
| void | bj_quit_app (struct bj_app *app, int exit_code) |
Drive a Banjo program through banjo-managed setup, step, and teardown callbacks.
Call bj_run_app with your callbacks to drive the lifecycle: setup once, step in a loop until bj_quit_app is called (or the platform's run loop signals completion), teardown once.
All callbacks share a single user_data pointer. The setup callback returns a void* which becomes the user_data for subsequent callbacks (step, fixed_step, teardown). The setup callback also receives init_data passed from bj_run_app, allowing configuration from main(). This ownership model guarantees the data outlives the run loop, which is critical on platforms where bj_run_app returns immediately (Emscripten).
The opaque bj_app pointer passed to callbacks allows per-app settings (bj_set_frame_rate, bj_set_fixed_step_rate) and signals (bj_quit_app), enabling multi-threaded apps to manage multiple instances independently.
| struct bj_tick_info |
Timing snapshot handed to the step and fixed-step callbacks.
One struct for both call sites. Passed by value so the runtime can keep the fields in registers and there's no per-iteration storage to worry about.
What each field means depends on which callback received it:
| Field | In bj_app_step_fn | In bj_app_fixed_step_fn |
|---|---|---|
delta | Real wall-clock seconds since the previous step call (capped at 0.25s) | Always equals 1/hz: the configured fixed step duration |
alpha | [0, 1) interpolation factor; see below | Always 0 (the call is at the tick boundary, no fraction to interpolate) |
alpha is forWhen a program runs physics at a fixed rate (e.g. 60Hz) and renders at whatever the display delivers (60? 144?), most render frames happen between physics ticks. The physics state is stale by alpha * (1/hz) seconds at render time. Keeping the previous physics state alongside the current one lets you interpolate at render time for visually smooth motion:
Programs that don't need interpolation can ignore alpha entirely and just use delta in step.
The accumulator pattern that produces these values follows Glenn Fiedler's article; see Acknowledgements.
| Data Fields | ||
|---|---|---|
| bj_real | alpha | |
| bj_real | delta | |
| typedef void(* bj_app_fixed_step_fn) (struct bj_app *app, struct bj_tick_info tick, void *user_data) |
Application fixed-rate step callback.
Banjo calls this at a configurable fixed rate (default 60Hz) using a time accumulator inside bj_run_app. Zero, one, or several fixed-step calls can happen between two consecutive bj_app_step_fn calls depending on how fast the main loop is running.
Use this slot for deterministic logic that must advance at a known rate (physics integration, network ticks, scripted timers) and leave variable-rate work (input reaction, rendering) in bj_app_step_fn.
| app | The running application; pass to bj_quit_app. |
| tick | Timing snapshot. tick.delta is the fixed step duration (1/hz); tick.alpha is always 0. |
| user_data | The pointer assigned in the setup callback. |
| typedef void *(* bj_app_setup_fn) (struct bj_app *app, void *init_data) |
Application setup callback.
Called once at the start of bj_run_app, before the first step. Allocate windows, devices, and any other resources here. Return a pointer to your application state; this pointer is then passed to bj_app_step_fn, bj_app_fixed_step_fn, and bj_app_teardown_fn.
Call bj_quit_app to abort startup; the run loop will skip the step phase and proceed directly to teardown.
| app | The running application; pass to bj_quit_app or bj_set_frame_rate. |
| init_data | The pointer passed to bj_run_app. Use this to receive configuration from main(). Can be NULL. |
| typedef void(* bj_app_step_fn) (struct bj_app *app, struct bj_tick_info tick, void *user_data) |
Application per-iteration callback.
Called every iteration of the run loop, after any fixed-step calls for the iteration. Put input handling, rendering hints, and any other variable-rate per-frame logic here. Call bj_quit_app to exit the loop.
| app | The running application; pass to bj_quit_app. |
| tick | Timing snapshot. tick.delta is the wall-clock seconds since the previous step call (capped to guard against spiral-of-death after a stall); tick.alpha is the [0, 1) interpolation factor between the last and next fixed-step call, useful if you render physics state that's advanced in bj_app_fixed_step_fn. |
| user_data | The pointer assigned in the setup callback. |
| typedef void(* bj_app_teardown_fn) (struct bj_app *app, void *user_data) |
Application teardown callback.
Called once after the run loop ends and before bj_run_app returns. Release whatever bj_app_setup_fn allocated.
| app | The application that is shutting down. |
| user_data | The pointer assigned in the setup callback. |
| int bj_app_fixed_step_rate | ( | const struct bj_app * | app | ) |
Return the configured fixed-step rate (in Hz) for app.
Returns 60 (the default) if app is NULL.
| app | The application to query. |
| int bj_app_frame_rate | ( | const struct bj_app * | app | ) |
Return the configured frame-rate cap (in Hz) for app.
Returns 60 (the default) if app is NULL. A return of 0 means the loop runs uncapped.
| app | The application to query. |
0 if uncapped.| void bj_quit_app | ( | struct bj_app * | app, |
| int | exit_code ) |
Signal the given application to exit on the next iteration.
Typically called from within a callback that received the app handle. The current iteration completes; the run loop then unwinds through teardown and bj_run_app returns exit_code.
Calling this on an app that is not currently running just pre-sets its quit flag; the next bj_run_app on that instance resets it before iterating, so it has no lasting effect.
Passing NULL is a silent no-op.
| app | The application to signal. |
| exit_code | The integer to be returned by bj_run_app. |
Referenced by setup(), setup(), setup(), setup(), setup(), setup(), setup(), setup(), setup(), setup(), setup(), setup(), setup(), setup(), setup(), setup(), setup(), setup(), step(), step(), step(), step(), step(), step(), step(), step(), step(), step(), step(), step(), step(), step(), step(), step(), step(), and step().
| int bj_run_app | ( | bj_app_setup_fn | setup, |
| bj_app_step_fn | step, | ||
| bj_app_fixed_step_fn | fixed_step, | ||
| bj_app_teardown_fn | teardown, | ||
| void * | init_data ) |
Drive the application lifecycle.
Creates an internal app instance, invokes the setup callback (if provided), runs the step callback in a loop until bj_quit_app is called (or the platform's run loop signals completion), then invokes the teardown callback and destroys the app. Returns the exit code passed to bj_quit_app, or 0 if the loop exited without one.
Pass NULL for any callback you don't need.
On platforms where the OS owns the run loop (Emscripten, future iOS), this function may register the callbacks with the platform loop and return immediately; the OS then drives step and teardown asynchronously.
| setup | Called once at start; allocate resources here. Receives init_data and returns user_data for other callbacks. |
| step | Called every iteration of the loop. |
| fixed_step | Called at a fixed rate (default 60Hz); use for deterministic simulation. Pass NULL if unused. |
| teardown | Called once after the loop ends; cleanup here. |
| init_data | Passed to setup callback. Use to pass configuration from main(). Can be NULL. |
0.Referenced by main().
| void bj_set_fixed_step_rate | ( | struct bj_app * | app, |
| int | hz ) |
Configure the fixed-step rate (in Hz) for app.
Defaults to 60 Hz. Setting a non-positive value is a silent no-op. Typically called before bj_run_app; changing it mid-run takes effect on the next iteration but leaves the accumulator in a slightly surprising state. Prefer setting it once at startup.
| app | The application to configure. NULL is a no-op. |
| hz | Target fixed-step rate, in calls per second. Must be > 0. |
| void bj_set_frame_rate | ( | struct bj_app * | app, |
| int | hz ) |
Cap the run loop to at most hz iterations per second.
At the end of every loop iteration bj_run_app measures how long the iteration took (everything your step callback did) and sleeps off only the remaining time needed to hit 1/hz seconds. This is the one place a Banjo program should pace its loop; it replaces the older habit of dropping a fixed bj_sleep at the bottom of the step callback.
Because it sleeps the remaining time rather than a fixed amount, a slow iteration simply sleeps less (or not at all) and the loop never overshoots the target.
This is a cap, not a precise clock. bj_sleep is millisecond grained and may oversleep, so expect a little jitter. For logic that must advance at an exact, machine-independent rate use the bj_app_fixed_step_fn callback instead: the frame rate paces what the user sees, the fixed-step rate paces the simulation.
| app | The application to configure. NULL is a no-op. |
| hz | Target loop rate in iterations per second, or 0 to run uncapped. The default is 60. Negative values are ignored. |