Sokol

repository·master·Indexed 27 days ago

https://github.com/floooh/sokol

A collection of lightweight, STB-style cross-platform C libraries for graphics, audio, app framework, and utilities. Designed for high portability with first-class support for WebAssembly, it includes core headers such as sokol_gfx.h for 3D-API wrapping, sokol_app.h for window and input management, sokol_audio.h for buffer-streaming audio, and sokol_fetch.h for asynchronous data streaming. The library provides a minimal footprint and supports multiple backends including GL, Metal, D3D11, and WebGPU.

Tokens
3.7K
Snippets
11
Records
16
Agent score
95%

What's inside Sokol

  1. Overview of Sokol libraries

    master
    Sokol is a collection of simple, STB-style cross-platform libraries written in C for C and C++ developers. It is designed with WebAssembly as a first-class citizen, providing minimal footprint on the web while remaining highly performant on native platforms. The core headers are standalone and can be used independently.
  2. Parse arguments with sokol_args.h

    master

    sokol_args.h provides unified argument parsing for both native applications (using argc/argv) and web applications (using URL query strings).

    Example: https://example.com/?type=kc85_4 is parsed identically to the command line argument type=kc85_4.

    #include "sokol_args.h"
    
    int main(int argc, char* argv[]) {
        sargs_setup(&(sargs_desc){ .argc=argc, .argv=argv });
        
        if (sargs_exists("type")) {
            if (sargs_equals("type", "kc85_4")) {
                // logic for kc85_4
            }
        }
        
        sargs_shutdown();
        return 0;
    }
  3. Update language bindings using gen_all.py

    master

    To update the language bindings for various languages (Zig, Nim, Odin, Rust, D, Jai, C3), ensure that clang and python3 are installed and available in your system PATH.

    Follow these steps:

    1. Navigate to the sokol/bindgen directory.
    2. Clone the target language repositories (e.g., sokol-zig, sokol-nim, etc.).
    3. Execute the generation script python3 gen_all.py.
    cd sokol/bindgen
    git clone https://github.com/floooh/sokol-zig
    git clone https://github.com/floooh/sokol-nim
    git clone https://github.com/floooh/sokol-odin
    git clone https://github.com/floooh/sokol-rust
    git clone https://github.com/floooh/sokol-d
    git clone https://github.com/colinbellino/sokol-jai
    git clone https://github.com/floooh/sokol-c3
    python3 gen_all.py
  4. Use sokol_app.h for cross-platform application wrapping

    master

    sokol_app.h provides a unified application entry point and window/canvas management for 3D rendering. It supports multiple platforms (Win32, MacOS, Linux, iOS, WASM, Android, UWP) and 3D APIs (GL3.3, Metal, D3D11, GLES3/WebGL2).

    To use it, implement a sokol_main function that returns a sapp_desc structure containing callbacks for initialization (init_cb), per-frame updates (frame_cb), and cleanup (cleanup_cb).

    #include "sokol_app.h"
    #include "sokol_gfx.h"
    #include "sokol_log.h"
    #include "sokol_glue.h"
    #include "triangle-sapp.glsl.h"
    
    static void init(void) {
        // initialization logic
    }
    
    void frame(void) {
        // per-frame rendering logic
    }
    
    void cleanup(void) {
        // cleanup logic
    }
    
    sapp_desc sokol_main(int argc, char* argv[]) {
        (void)argc; (void)argv;
        return (sapp_desc){
            .init_cb = init,
            .frame_cb = frame,
            .cleanup_cb = cleanup,
            .width = 640,
            .height = 480,
            .window_title = "Triangle",
            .icon.sokol_default = true,
            .logger.func = slog_func,
        };
    }
  5. Regenerate embedded shaders with shdgen

    master

    The shdgen script is a helper used to regenerate embedded shaders. It requires deno to be available in your system path and a logged-in gh (GitHub CLI) client, as it generates HLSL binaries remotely using a GitHub Actions Windows VM.

    macOS Setup: Clone https://github.com/floooh/sokol-tools-bin to a location adjacent to the sokol directory before running the script.

    Warning: This tool is intended for internal use only and may not function correctly on all local environments.

    deno run --allow-all shdgen.ts
  6. Use sokol_audio.h for audio streaming

    master

    sokol_audio.h is a minimal API for streaming 32-bit float mono or stereo samples. It supports WASAPI (Windows), CoreAudio (macOS/iOS), ALSA (Linux), and WebAudio (Emscripten).

    There are two models for providing audio data:

    1. Callback Model: Provide a stream_cb function that is called in the audio thread to fill the buffer directly.
    2. Push Model: Use saudio_push() from your main loop or a separate thread to send small packets of audio data.
  7. Use sokol_fetch.h to load files or stream HTTP data

    master

    sokol_fetch.h allows loading files from the local filesystem (native) or streaming data over HTTP (WASM/Emscripten).

    Key Requirements:

    • Call sfetch_setup() during initialization.
    • Call sfetch_dowork() once per frame to process asynchronous requests.
    • Call sfetch_shutdown() during cleanup.
    • Use sfetch_send() to initiate a request. The response is handled in a callback function.
    #include "sokol_fetch.h"
    #include "sokol_log.h"
    
    static void response_callback(const sfetch_response_t* response);
    
    #define MAX_FILE_SIZE (1024*1024)
    static uint8_t buffer[MAX_FILE_SIZE];
    
    static void init(void) {
        sfetch_setup(&(sfetch_desc_t){ .logger.func = slog_func });
    
        sfetch_send(&(sfetch_request_t){
            .path = "hello_world.txt",
            .callback = response_callback,
            .buffer_ptr = buffer,
            .buffer_size = sizeof(buffer)
        });
    }
    
    static void frame(void) {
        sfetch_dowork();
    }
    
    static void response_callback(const sfetch_response_t* response) {
        if (response->fetched) {
            const void* data = response->buffer_ptr;
            uint64_t data_size = response->fetched_size;
        }
        if (response->failed) {
            switch (response->error_code) {
                case SFETCH_ERROR_FILE_NOT_FOUND: ...
                case SFETCH_ERROR_BUFFER_TOO_SMALL: ...
            }
        }
    }
    
    static void shutdown(void) {
        sfetch_shutdown();
    }
  8. Troubleshoot Sokol build and link errors

    master

    If your Sokol integration fails to compile or link, check the following common configuration mismatches:

    Implementation Definition

    Define SOKOL_IMPL (or the specific per-header SOKOL_*_IMPL) in exactly one C or C++ translation unit before including the headers. All other files should include the headers without this define.

    Backend Selection

    Select exactly one rendering backend in your implementation translation unit. Common defines include:

    • SOKOL_GLCORE (uses GLX on Linux by default; use SOKOL_FORCE_EGL for EGL)
    • SOKOL_GLES3 (requires -s USE_WEBGL2=1 for Emscripten WebGL2 builds)
    • SOKOL_D3D11 (MinGW/MSYS2 may need -ld3d11)
    • SOKOL_METAL (macOS/iOS: compile implementation as Objective-C/Objective-C++ .m or .mm and link required frameworks)
    • SOKOL_WGPU (WebGPU)
    • SOKOL_VULKAN

    Note: If using sokol_gfx.h and sokol_app.h together, they must use the same backend define.

    Shader Compatibility

    Ensure generated shader headers are from a sokol-shdc version compatible with your Sokol headers and were generated for the same backend(s) selected at compile time.

  9. Run Zig samples after updating bindings

    master

    After updating the bindings, you can test the Zig implementation by running the provided samples using the Zig build system.

    cd sokol/bindgen/sokol-zig
    zig build run-clear
    zig build run-triangle
    zig build run-cube
  10. Implement the sokol_audio.h callback model

    master

    Use the callback model to generate audio directly in the audio thread. This is efficient for continuous streams like oscillators.

    // the sample callback, running in audio thread
    static void stream_cb(float* buffer, int num_frames, int num_channels) {
        assert(1 == num_channels);
        static uint32_t count = 0;
        for (int i = 0; i < num_frames; i++) {
            buffer[i] = (count++ & (1<<3)) ? 0.5f : -0.5f;
        }
    }
    
    int main() {
        // init sokol-audio with default params
        saudio_setup(&(saudio_desc){
            .stream_cb = stream_cb,
            .logger.func = slog_func,
        });
    
        // run main loop
        ...
    
        // shutdown sokol-audio
        saudio_shutdown();
        return 0;
    }