AtlatestRepositorysigil-graphics
1# sigil-graphics
2
32D graphics, image loading, and font rendering for [Sigil](https://codeberg.org/sigil/sigil).
4
5Provides 2D rendering capabilities via sokol_gfx and sokol_gp, image loading (stb_image), and font rendering (stb_truetype).
6
7## Modules
8
9| Module | Purpose |
10|--------|---------|
11| `(sigil graphics)` | Core 2D rendering (shapes, transforms, textures) |
12| `(sigil graphics image)` | CPU-side image loading |
13| `(sigil graphics font)` | Font loading and text rendering |
15## System Prerequisites
17- No GL headers: the GL entry points sokol_gfx calls are loaded at run
18 time through sigil-desktop (`src/c/gl_native_loader.h`, generated from the
19 vendored `sokol_gfx.h` by `scripts/gen-gl-loader.sh`), and nothing links
20 libGL. Building sigil-desktop needs the X11 and Wayland headers listed in
21 `manifest.scm`.
23## Dependencies
25- sigil-stdlib
26- sigil-desktop (the window, GL context and input; GLFW. Named sigil-app
27 through 0.9.x, pinned here as `name: "sigil-desktop"` at the old URL until
28 the Codeberg repository is renamed)
30## Build
32```sh
33sigil deps install
34sigil build
35```
37## Render targets and custom shaders
39Offscreen rendering and custom fragment shaders (since v0.10.0) build a
40post-processing or simulation pipeline out of three pieces:
42```scheme
43(define rt (make-render-target 256 256)) ; 'linear sampling (default)
44(define grid (make-render-target 64 64 'nearest)) ; texel-exact when drawn
46(with-render-target rt
47 (draw-filled-rect 0.0 0.0 256.0 256.0)) ; draws land in rt
49(define fx (load-shader VERT-SOURCE FRAG-SOURCE)) ; GLSL strings; optional 3rd arg
50 ; 'normal (default) | 'additive | 'none
51(with-shader fx
52 (draw-render-target rt 0.0 0.0 256.0 256.0)) ; rt is channel 0
53```
55The fragment shader samples channel 0 as `iTexChannel0_iSmpChannel0` (sokol_gp's
56name) and receives `texUV` and `iColor` from the vertex stage; the vertex shader is
57the sgp passthrough with `coord` at location 0 and `color` at location 1 (see
58`test/test-shader`). Natively the sources are `#version 410`; on the `web` config
59they are `#version 300 es` with precision qualifiers, so a package that builds for
60both prefixes the version line under `cond-expand`.
62### Uniforms and uniform arrays
64`load-shader` scans the fragment source for `uniform` declarations of `float`,
65`vec2`, `vec3`, `vec4` and `mat4`, scalar or array (`uniform vec4 palette[8];`, a
66literal count; a `lowp`/`mediump`/`highp` qualifier is fine). `sampler2D` is not a
67uniform-block entry. Up to 16 declarations (an array is one) and 512 bytes in total,
68both checked by `load-shader` (the error names the limit); a GLSL compile error
69is an error too, with sokol's log line before it. Entries are
70packed in declaration order.
72```scheme
73(set-shader-uniform fx 'u_radius 2.5) ; float
74(set-shader-uniform fx 'u_tint '(1.0 0.8 0.6 1.0)) ; vec4, list or vector
75(set-shader-uniform fx 'palette '((1 0 0 1) (0 1 0 1) ...)) ; vec4 palette[8]: nested,
76(set-shader-uniform fx 'levels #(0.0 0.25 0.5 1.0)) ; or flat, per element
77```
79The float count must match the declaration exactly; a mismatch is an error, not a
80partial write. Two uniforms are filled in for you on every `with-shader` entry:
81`u_time` (float, seconds since `gfx-setup`) and `u_resolution` (vec2: the virtual
82viewport, or the render target's size when the shader is bound inside
83`with-render-target`).
85### Textures from pixels
87```scheme
88(define tex (make-texture-from-pixels 4 4 bytes 'nearest)) ; RGBA8 bytevector,
89(update-texture tex other-bytes) ; top row first
90```
92`bytes` is exactly `width * height * 4` bytes (a size mismatch is an error). The
93texture draws with `draw-texture` / `draw-texture-region` like one from
94`load-texture`. sokol_gfx allows one upload per texture per frame (a frame ends at
95`end-frame`), and creating the texture is that frame's upload, so make the texture
96one frame before the first `update-texture`; a second upload in a frame is refused
97with an error that says so.
99### GPU simulations by ping-pong
101`with-shader` composes inside `with-render-target`: a step shader bound in a pass on
102target B can read target A through `draw-render-target`, and swapping the two each
103frame runs a cellular automaton with no cell state on the CPU. Load the step shader
104with `'none` blending so it overwrites the target (alpha blending would scale data
105channels), and read neighbours with
106`texelFetch(iTexChannel0_iSmpChannel0, ivec2(gl_FragCoord.xy) + offset, 0)` (the
107sampler's filter does not apply) and wrap on `u_resolution`. `test/test-shader-limits`
108is the worked example, verified pixel-for-pixel on native and in the browser; its
109README has the commands.
111Render targets on the `web` config work as of v0.11.3 (earlier releases refused
112every offscreen pass there, see the tag notes).
115## License
117BSD-3-Clause