graphics: cond-expand sokol_app/glue seam for a web (wasm32-wasi) target
Milestone 2 of graphics-on-web: let sigil-graphics reuse sokolgfx/sokolgp in the browser via the sigil-wasm-gles3 raw-GLES3 binding, WITHOUT disturbing the native build. The seam is gated on wasm (predefined by the wasm target), so native (SOKOLGLCORE + sokolapp + sigil-app) is byte-for-byte behaviour-identical.
sokol-graphics.c: on web define nothing extra here but include glshim.h (from sigil-wasm-gles3) before sokolgfx.h so every gl* resolves to a WASM import in the "gl" module; drop sokolapp.h / sokolglue.h (no windowing on web); provide slog_func (sigil-app is not linked on web). Native branch unchanged.
graphics.c: route the six sokolapp / sokolglue touch points (sgsetup environment, begin-frame window size, end-frame swapchain, clear fallback size, shader resolution uniform) through a siggfx* abstraction. Native expands to the exact sapp/sglue_ calls as before; web supplies a manual default-framebuffer sgenvironment/sgswapchain (lifted from the M1 wasm-sokol-sprite example) and sources the canvas size from the sigilwasmgles3 app-shell import module.
Verified: all five sigil-graphics C files compile clean for wasm32-wasi (web path) and native graphics.c compiles unchanged; the native diff is limited to behaviour-preserving inline wrappers.
src/c/graphics.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
src/c/sokol-graphics.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++-----------
2 files changed, 108 insertions(+), 18 deletions(-)src/c/graphics.cmodified
#include "sigil-internal.h"/* Sokol headers (implementation is in sokol.c) *//* Sokol headers (implementation is in sokol-graphics.c). * * On web (wasm32-wasi) there is no windowing system: sokol_app / sokol_glue are * replaced by the sigil-wasm-gles3 JS bridge (canvas + WebGL2 context + * swapchain). Those two headers are therefore excluded on the web build; every * sapp / sglue touch point is routed through the sig_gfx_ abstraction below, * whose native branch expands to the exact same calls as before. */#if !defined(__wasm__)#include "sokol_app.h"#endif#include "sokol_gfx.h"#if !defined(__wasm__)#include "sokol_glue.h"#endif#include "sokol_gp.h"#include "sokol_log.h"#include <string.h>#include <math.h>#include <time.h>#include <stdint.h>/* ---- platform abstraction: native (sokol_app/glue) vs web (GL bridge) ------- * These four accessors are the ONLY sokol_app/sokol_glue touch points in this * file. Native expands to the exact sapp / sglue calls used before, so the * native build is behaviour-identical. Web supplies the default framebuffer * swapchain manually (lifted from the Milestone-1 wasm-sokol-sprite example) and * sources the canvas size from the sigil_wasm_gles3 app-shell import module. */#if defined(__wasm__)__attribute__((import_module("sigil_wasm_gles3"), import_name("canvas_width")))extern int sigil_wasm_gles3_canvas_width(void);__attribute__((import_module("sigil_wasm_gles3"), import_name("canvas_height")))extern int sigil_wasm_gles3_canvas_height(void);static int sig_gfx_width(void) { return sigil_wasm_gles3_canvas_width(); }static int sig_gfx_height(void) { return sigil_wasm_gles3_canvas_height(); }static sg_environment sig_gfx_environment(void) { sg_environment env = {0}; env.defaults.color_format = SG_PIXELFORMAT_RGBA8; env.defaults.depth_format = SG_PIXELFORMAT_NONE; env.defaults.sample_count = 1; return env;}static sg_swapchain sig_gfx_swapchain(void) { sg_swapchain swap = {0}; swap.width = sig_gfx_width(); swap.height = sig_gfx_height(); swap.sample_count = 1; swap.color_format = SG_PIXELFORMAT_RGBA8; swap.depth_format = SG_PIXELFORMAT_NONE; swap.gl.framebuffer = 0; /* default framebuffer */ return swap;}#elsestatic inline int sig_gfx_width(void) { return sapp_width(); }static inline int sig_gfx_height(void) { return sapp_height(); }static inline sg_environment sig_gfx_environment(void) { return sglue_environment(); }static inline sg_swapchain sig_gfx_swapchain(void) { return sglue_swapchain(); }#endif#ifndef M_PI#define M_PI 3.14159265358979323846 /* Initialize sokol_gfx. Install slog_func so validation failures * print a useful diagnostic before sokol aborts. */ sg_desc desc = { .environment = sglue_environment(), .environment = sig_gfx_environment(), .logger.func = slog_func, }; sg_setup(&desc);{ (void)vm; (void)argc; (void)args; int window_w = sapp_width(); int window_h = sapp_height(); int window_w = sig_gfx_width(); int window_h = sig_gfx_height(); /* Begin sokol_gp frame with full window size */ sgp_begin(window_w, window_h); }; sg_pass pass = { .action = pass_action, .swapchain = sglue_swapchain() .swapchain = sig_gfx_swapchain() }; sg_begin_pass(&pass); if (virtual_viewport_enabled && virtual_width > 0 && virtual_height > 0) { sgp_draw_filled_rect(0, 0, (float)virtual_width, (float)virtual_height); } else { sgp_draw_filled_rect(0, 0, (float)sapp_width(), (float)sapp_height()); sgp_draw_filled_rect(0, 0, (float)sig_gfx_width(), (float)sig_gfx_height()); } /* Reset to white for subsequent drawing */ &t, sizeof(t)); } if (sh->u_resolution_index >= 0) { float res[2] = {(float)sapp_width(), (float)sapp_height()}; float res[2] = {(float)sig_gfx_width(), (float)sig_gfx_height()}; if (virtual_viewport_enabled) { res[0] = (float)virtual_width; res[1] = (float)virtual_height;src/c/sokol-graphics.cmodified
/* * sokol-graphics.c - Sokol implementation for sigil-graphics * * Implements sokol_gfx, sokol_gp, and sokol_glue. * sokol_glue bridges sokol_app (from sigil-app) to sokol_gfx. * Implements sokol_gfx and sokol_gp (and, on native, sokol_glue). * * Note: sokol_app.h is included for declarations only (implementation in sigil-app). * SOKOL_IMPL is only defined for the headers we implement here. * NATIVE (default): SOKOL_GLCORE. sokol_glue bridges sokol_app (implemented in * sigil-app) to sokol_gfx; sokol_app.h is included for declarations only, and * slog_func comes from sigil-app. * * WEB (wasm32-wasi, __wasm__): SOKOL_GLES3 + SOKOL_EXTERNAL_GL_LOADER (set via * the web build's -D flags). sokol's gl* calls resolve to WASM imports in the * "gl" module via gl_shim.h (shipped by sigil-wasm-gles3). There is no * sokol_app / sokol_glue on web — the canvas, WebGL2 context, and swapchain come * from the sigil-wasm-gles3 JS bridge (see graphics.c's sig_gfx_* abstraction), * so those headers are excluded and slog_func is provided here since sigil-app * is not linked on web. *//* SOKOL_GLCORE is defined via compiler flags *//* Bump sgp's uniform-block buffer to 64 floats (256 bytes) so custom shaders * have room for the auto-uniforms (u_time, u_resolution) plus a reasonable * budget of caller-set uniforms. The default 8 floats (32 bytes) doesn't even * fit the auto-uniforms plus a single vec4. */#define SGP_UNIFORM_CONTENT_SLOTS 64#if defined(__wasm__)/* Web: bind every gl* sokol calls as a WASM import in the "gl" module. Must be * included before sokol_gfx.h so GL types/constants/prototypes are visible. */#include "gl_shim.h"#define SOKOL_IMPL/* Order matters: gfx before gp. No sokol_glue (no sokol_app on web). */#include "sokol_gfx.h"#include "sokol_gp.h"/* slog_func is provided by sigil-app on native; on web sigil-app is not linked, * so supply it here. Routes to stderr (wasi fd_write -> console) so sokol * validation failures stay visible without any import beyond gl.* + wasi. */#include <stdio.h>#include <stdint.h>void slog_func(const char* tag, uint32_t log_level, uint32_t log_item_id, const char* message_or_null, uint32_t line_nr, const char* filename_or_null, void* user_data) { (void)log_item_id; (void)user_data; fprintf(stderr, "sokol[level=%u] %s:%u [%s] %s\n", log_level, filename_or_null ? filename_or_null : "?", line_nr, tag ? tag : "sokol", message_or_null ? message_or_null : "");}#else/* Native: SOKOL_GLCORE is defined via compiler flags. *//* Include sokol_app declarations WITHOUT implementation (implemented in sigil-app) */#include "sokol_app.h"/* Now define SOKOL_IMPL for the headers we implement */#define SOKOL_IMPL/* Bump sgp's uniform-block buffer to 64 floats (256 bytes) so custom * shaders have room for the auto-uniforms (u_time, u_resolution) plus * a reasonable budget of caller-set uniforms. The default 8 floats * (32 bytes) doesn't even fit the auto-uniforms plus a single vec4. */#define SGP_UNIFORM_CONTENT_SLOTS 64/* Order matters: gfx before glue, glue before gp */#include "sokol_gfx.h"#include "sokol_glue.h"/* slog_func is implemented in sigil-app's archive (sigil-app's * sokol-app.c picks up SOKOL_LOG_IMPL via SOKOL_IMPL). graphics.c * just declares it via sokol_log.h. */#endif