Banjo API 1.0.0-rc.2
Low-level C99 game development API
Loading...
Searching...
No Matches
Application
Collaboration diagram for Application:

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)

Detailed Description

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.

#include <banjo/app.h>
#include <banjo/memory.h>
typedef struct { /* your app state *&zwj;/ } my_state;
static void* my_setup(struct bj_app* app, void* init_data) {
(void)init_data;
my_state* s = bj_alloc(sizeof(my_state));
/* initialise s ... *&zwj;/
return s;
}
static void my_step(struct bj_app* app, struct bj_tick_info tick, void* ud) {
my_state* s = ud;
(void)tick;
/* one iteration using s ... *&zwj;/
}
static void my_teardown(struct bj_app* app, void* ud) {
bj_free(ud);
}
int main(int argc, char* argv[]) {
(void)argc; (void)argv;
return bj_run_app(my_setup, my_step, NULL, my_teardown, NULL);
}
Application lifecycle: callback-driven setup, step, and teardown.
All memory-related functions, including custom allocators.

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.


Data Structure Documentation

◆ bj_tick_info

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)

What alpha is for

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

/* in step: *&zwj;/
bj_real x = prev_x + (curr_x - prev_x) * tick.alpha;
bj_real y = prev_y + (curr_y - prev_y) * tick.alpha;
/* draw at (x, y), perfectly placed between the last two physics ticks *&zwj;/

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.

See also
https://gafferongames.com/post/fix_your_timestep/
Examples
audio_pcm.c, bitmap_blit.c, bitmap_blit_colorkey.c, drawing_2d.c, drawing_text.c, event_callbacks.c, event_polling.c, interpolation.c, load_bmp.c, physics_kinematics.c, physics_particle.c, pong.c, random_distribution.c, shaders.c, sprite_animation.c, start.c, template_callbacks.c, and window.c.

Definition at line 106 of file app.h.

Data Fields
bj_real alpha
bj_real delta

Typedef Documentation

◆ bj_app_fixed_step_fn

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.

Parameters
appThe running application; pass to bj_quit_app.
tickTiming snapshot. tick.delta is the fixed step duration (1/hz); tick.alpha is always 0.
user_dataThe pointer assigned in the setup callback.
See also
bj_tick_info, bj_set_fixed_step_rate

Definition at line 192 of file app.h.

◆ bj_app_setup_fn

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.

Parameters
appThe running application; pass to bj_quit_app or bj_set_frame_rate.
init_dataThe pointer passed to bj_run_app. Use this to receive configuration from main(). Can be NULL.
Returns
Your allocated application state, passed to other callbacks. Teardown is responsible for freeing it.

Definition at line 142 of file app.h.

◆ bj_app_step_fn

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.

Parameters
appThe running application; pass to bj_quit_app.
tickTiming 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_dataThe pointer assigned in the setup callback.
See also
bj_tick_info

Definition at line 165 of file app.h.

◆ bj_app_teardown_fn

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.

Parameters
appThe application that is shutting down.
user_dataThe pointer assigned in the setup callback.

Definition at line 208 of file app.h.

◆ bj_tick_info

typedef struct bj_tick_info bj_tick_info

Definition at line 111 of file app.h.

Function Documentation

◆ bj_app_fixed_step_rate()

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.

Parameters
appThe application to query.
Returns
The fixed-step rate, in calls per second.
See also
bj_set_fixed_step_rate

◆ bj_app_frame_rate()

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.

Parameters
appThe application to query.
Returns
The frame-rate cap in iterations per second, or 0 if uncapped.
See also
bj_set_frame_rate

◆ bj_quit_app()

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.

Parameters
appThe application to signal.
exit_codeThe integer to be returned by bj_run_app.
See also
bj_run_app
Examples
audio_pcm.c, bitmap_blit.c, bitmap_blit_colorkey.c, drawing_2d.c, drawing_text.c, event_callbacks.c, event_polling.c, interpolation.c, load_bmp.c, physics_kinematics.c, physics_particle.c, pong.c, random_distribution.c, shaders.c, sprite_animation.c, start.c, template_callbacks.c, and window.c.

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

◆ bj_run_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 )

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.

Parameters
setupCalled once at start; allocate resources here. Receives init_data and returns user_data for other callbacks.
stepCalled every iteration of the loop.
fixed_stepCalled at a fixed rate (default 60Hz); use for deterministic simulation. Pass NULL if unused.
teardownCalled once after the loop ends; cleanup here.
init_dataPassed to setup callback. Use to pass configuration from main(). Can be NULL.
Returns
The exit code requested via bj_quit_app, or 0.
See also
bj_quit_app, bj_set_frame_rate, bj_set_fixed_step_rate
Examples
audio_pcm.c, bitmap_blit.c, bitmap_blit_colorkey.c, drawing_2d.c, drawing_text.c, event_callbacks.c, event_polling.c, interpolation.c, load_bmp.c, physics_kinematics.c, physics_particle.c, pong.c, random_distribution.c, shaders.c, sprite_animation.c, start.c, template_callbacks.c, and window.c.

Referenced by main().

◆ bj_set_fixed_step_rate()

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.

Parameters
appThe application to configure. NULL is a no-op.
hzTarget fixed-step rate, in calls per second. Must be > 0.
See also
bj_app_fixed_step_fn, bj_app_fixed_step_rate
Examples
interpolation.c, and physics_particle.c.

Referenced by setup(), and setup().

◆ bj_set_frame_rate()

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.

Parameters
appThe application to configure. NULL is a no-op.
hzTarget loop rate in iterations per second, or 0 to run uncapped. The default is 60. Negative values are ignored.
Note
No effect on platforms where the OS owns the loop (Emscripten): there the host drives the per-frame callback and this setting is ignored.
See also
bj_app_frame_rate, bj_run_app, bj_set_fixed_step_rate