|
Banjo API 1.0.0-rc.2
Low-level C99 game development API
|
Hello, Window: open a window, draw shapes, react to ESC.
Hello, Window: open a window, draw shapes, react to ESC. This is the canonical first program in Banjo. It opens a 640×480 window and registers a draw callback that paints a red circle and a cyan rectangle, then runs an event loop until the user closes the window or presses ESC.
bj_close_on_escape).bj_render_target_bitmap, clear it, and draw 2D primitives.You need CMake 3.21+, a C99 compiler, and (on Linux) the platform development headers. See the Prerequisites topic for the one-shot install command for your distro.
Create a new directory:
Drop this file in as main.c, then create CMakeLists.txt:
Build and run:
(On Windows the binary lives under build\Debug\ or build\Release\.)
Every banjo program is driven by an application handle. main itself is small and uniform across tutorials: bj_run_app receives the setup, step, and teardown callbacks directly, creates an internal app handle, drives the loop, and releases the handle on return. Everything interesting happens inside the three callbacks.
On Linux/macOS/Windows bj_run_app is a plain loop. On Emscripten it hands the step callback to the browser's run loop instead. Your callbacks don't need to know which.
bj_begin starts the requested subsystems, here just video. It returns BJ_FALSE if no backend was selected (see Windows for the fall-through chain). On failure, calling bj_quit_app then returning tells the run loop to skip the step phase and proceed straight to teardown.
bj_bind_window opens a 640×480 window titled "My First Banjo App" and allocates the per-window framebuffer behind it; there's no separate renderer object to manage.
bj_set_key_callback with bj_close_on_escape is a one-liner shortcut: it installs a built-in callback that closes the active window when ESC is pressed.
bj_set_draw_callback registers on_draw as the function banjo fires whenever the window has pending damage. bj_invalidate_window marks the whole window dirty so banjo paints it on the next natural-cadence event (compositor frame callback, WM_PAINT, drawRect:, requestAnimationFrame, whichever the backend uses).
Banjo passes the callback a bj_render_target. Reach the software framebuffer with bj_render_target_bitmap, then draw with the regular Bitmap and Drawing functions: bj_clear_bitmap fills it with the current clear colour, bj_make_bitmap_pixel converts an (R, G, B) triple into a packed pixel value matching the bitmap's pixel mode (so the same code works whether the framebuffer is RGB565 or XRGB8888), and bj_draw_filled_circle / bj_draw_rectangle mutate the framebuffer. The backend presents what you drew after the callback returns; you never call a present.
The dirty argument carries the damaged region: a sub-rect when only part of the window needs repainting (uncovered from behind another window, OS resize, etc.), or NULL when the whole window is dirty. This tutorial just repaints the whole scene each call; load_bmp.c shows the partial-damage path.
The step callback receives a bj_tick_info giving real wall-clock delta (seconds since the previous step) and a [0, 1) alpha interpolation factor against the configured fixed-step rate. This program ignores both since it doesn't run physics; the physics examples (physics_kinematics.c, physics_particle.c) and the interpolation.c demo put them to use.
bj_dispatch_events drains the event queue and fires registered event callbacks (including the ESC handler installed in setup). Calling bj_quit_app from inside the step exits the loop on the next iteration; here we forward the window's close request from bj_should_close_window.
Notice there is no manual sleep here. bj_run_app paces the loop for you at 60 iterations per second by default, yielding the CPU between iterations so a windowed program doesn't pin a core. Change or remove the cap with bj_set_frame_rate (pass 0 to run uncapped).
Because the scene is static, step does not invalidate the window each iteration; banjo only fires the draw callback when there's damage. A real animated program would bj_invalidate_window every step to drive its redraws.
Release in reverse order: bj_unbind_window, then bj_end. The test harness's allocator tracking will scream if any of these are skipped. See the error management topic (Error Management) for the leak diagnostic. The app handle is released automatically when bj_run_app returns.
event_callbacks.c and event_polling.c: handle input more richly than just ESC-to-quit.drawing_2d.c and drawing_text.c: every primitive and the text renderer.bitmap_blit.c, load_bmp.c, sprite_animation.c: bring images into your framebuffer.audio_pcm.c: add sound.See the Windows and Audio topics for the subsystem rundowns.