SBgl 0.1.0
A graphics framework in C99
Loading...
Searching...
No Matches
SBgl Input System Architecture

The input system provides access to physical device state through the engine context. It utilizes an internal "key map" pattern tied to the engine context.


Contextual Encapsulation

Unlike systems that use global state or OS-specific polling, SBgl stores all physical input state within the opaque sbgl_InternalContext.

typedef struct sbgl_Context {
void* inner; // <--- Physical state lives inside here
struct sbgl_Context sbgl_Context
Engine context.
sbgl_Result
Result codes for engine operations.
Definition sbgl_types.h:214
Engine context.
Definition sbgl_types.h:268
void * inner
Opaque pointer to the internal engine state.
Definition sbgl_types.h:278
sbgl_Result result
Status of the last major operation.
Definition sbgl_types.h:286

This design ensures that:

  • Input state is thread-safe relative to the context.
  • The state is always available internally without making system calls.
  • Multiple windows can have independent input states.
  • The public API remains strictly controlled.

The Key Map Pattern

Internally, the sbgl_InputState structure contains fixed-size boolean arrays for every possible physical key and mouse button.

  • keysDown: A bit-array or boolean array representing the current physical state of keys.
  • keysPressed: A specialized array that is set to true only on the frame a key was first pressed.
  • mouseDown: Current state of the mouse buttons.

When the OS sends a message (e.g., WM_KEYDOWN on Windows or wl_keyboard.key on Wayland), the Platform Layer translates the native scancode into an SBgl scancode (defined in sbgl.h) and updates the corresponding index in these internal arrays.

Input HAL Implementation

The Platform Layer (Wayland, X11, Win32) is responsible for filling the key map during the sbgl_os_PollEvents phase.

Mouse Deltas

Mouse movement is tracked using absolute coordinates (mouseX, mouseY) and relative deltas. Deltas are calculated during the event poll by comparing the current position with the position from the previous frame stored in internal tracking variables within the sbgl_InputState (_internalMouseX, _internalMouseY). This ensures deltas are calculated accurately even when frames are skipped or delayed.

Frame Lifecycle

Pressed states (keysPressed) are automatically reset at the end of every frame in sbgl_EndDrawing. This ensures that a "pressed" event is only visible to the application for exactly one frame.

Application Integration

The system provides a Data-Oriented API for batch processing.

Data-Oriented API (Batch Access)

The sbgl_GetInputState function provides a read-only pointer to the contiguous sbgl_InputState structure. Fetching the pointer once per frame enables batch processing.

Keyboard Example

The keysDown (held) or keysPressed (one-shot) boolean arrays are queried directly.

const sbgl_InputState* input = sbgl_GetInputState(ctx);
// Continuous movement check
if (input->keysDown[SBGL_KEY_W]) pos_y -= speed;
// One-shot toggle check
if (input->keysPressed[SBGL_KEY_SPACE]) is_jumping = true;
const sbgl_InputState * sbgl_GetInputState(sbgl_Context *ctx)
Retrieves the input state for the current frame.
Definition sbgl_core.c:413
#define SBGL_KEY_SPACE
Definition sbgl.h:87
#define SBGL_KEY_W
Definition sbgl.h:64
Represents the real-time state of physical inputs.
Definition sbgl_input.h:165
bool keysPressed[SBGL_SCANCODE_MAX]
Definition sbgl_input.h:167
bool keysDown[SBGL_SCANCODE_MAX]
Definition sbgl_input.h:166

Mouse Example

Access real-time coordinates, deltas, and button states.

const sbgl_InputState* input = sbgl_GetInputState(ctx);
// Direct access to coordinates and movement deltas
int x = input->mouseX;
int y = input->mouseY;
int dx = input->mouseDeltaX;
// Mouse button checks
if (input->mouseDown[SBGL_MOUSE_LEFT]) {
spawn_particle_at(x, y);
}
#define SBGL_MOUSE_LEFT
Definition sbgl.h:96
bool mouseDown[SBGL_MOUSE_BUTTON_MAX]
Definition sbgl_input.h:168

Mouse Modes

The engine supports three distinct modes for controlling the cursor's visibility and movement behavior.

Mode Behavior Use Case
SBGL_MOUSE_MODE_NORMAL Standard OS cursor, visible and free to move. 2D UIs, Desktop-style apps.
SBGL_MOUSE_MODE_HIDDEN Cursor is invisible but moves freely. Custom software cursors.
SBGL_MOUSE_MODE_CAPTURED Cursor is invisible and locked to the window center. 3D navigation, FPS cameras.

Controlling the Mouse Mode

Use sbgl_SetMouseMode to switch between behaviors. The engine ensures that modes like CAPTURED are persistent; if the window loses and then regains focus, the engine automatically re-locks the cursor.

// Toggle between standard and FPS-style camera
if (input->keysPressed[SBGL_KEY_TAB]) {
is_fps_mode = !is_fps_mode;
}
@ SBGL_MOUSE_MODE_NORMAL
Definition sbgl_input.h:154
@ SBGL_MOUSE_MODE_CAPTURED
Definition sbgl_input.h:156
void sbgl_SetMouseMode(sbgl_Context *ctx, sbgl_MouseMode mode)
Sets the cursor behavior and visibility.
Definition sbgl_core.c:422
#define SBGL_KEY_TAB
Definition sbgl.h:86

The design adheres to Data-Oriented Design principles by:

  • Maximizing Cache Efficiency: Providing direct access to the underlying arrays (keysDown, keysPressed, mouseDown) allows the CPU to prefetch data effectively during batch processing loops.
  • Eliminating Call Overhead: Fetching the entire state once per frame avoids the overhead of multiple function calls for individual key checks.
  • Ensuring Stability: The API returns a pointer to a static, zero-initialized dummy state if the context is invalid, preventing null-pointer dereferences.

By exposing the state as a contiguous block of data, the engine enables iteration and transformation of input data without the overhead of object-oriented getters.

Input-to-Transform Mapping

The Data-Oriented API facilitates direct mapping of scancodes to transformation data, enabling efficient camera or entity controls without branching logic.

const sbgl_InputState* input = sbgl_GetInputState(ctx);
// Calculate velocity vector from key map bit-mask
float speed = 5.0f * delta_time;
sbgl_Vec3 velocity = sbgl_Vec3Set(0, 0, 0);
if (input->keysDown[SBGL_KEY_W]) velocity.z += speed;
if (input->keysDown[SBGL_KEY_S]) velocity.z -= speed;
if (input->keysDown[SBGL_KEY_A]) velocity.x -= speed;
if (input->keysDown[SBGL_KEY_D]) velocity.x += speed;
// Map directly to a transformation matrix
entity->transform = sbgl_Mat4Mul(
entity->transform,
);
#define SBGL_KEY_A
Definition sbgl.h:42
#define SBGL_KEY_S
Definition sbgl.h:60
#define SBGL_KEY_D
Definition sbgl.h:45
static sbgl_Vec3 sbgl_Vec3Set(float x, float y, float z)
Creates a Vec3, correctly padded.
Definition sbgl_math.h:93
static sbgl_Mat4 sbgl_Mat4Translate(sbgl_Vec3 v)
Creates a translation matrix.
Definition sbgl_math.h:260
static sbgl_Mat4 sbgl_Mat4Mul(sbgl_Mat4 a, sbgl_Mat4 b)
Multiplies two matrices.
Definition sbgl_math.h:240
3D Vector, 16-byte aligned and padded for SIMD safety.
Definition sbgl_math.h:49
float z
Definition sbgl_math.h:52
float x
Definition sbgl_math.h:52

Technical Summary

Feature Implementation Benefit
State Storage Embedded in sbgl_InternalContext Strict encapsulation and thread-safety.
Polling Event-driven (Async) Zero OS overhead during frame logic.
Data Layout Tightly packed fixed arrays Cache efficiency and batch-processing support.
Memory O(1) Allocation (Arena) No dynamic allocation during input events.