| static const char *demo_shader_wgsl = |
| "/*\n" |
| " * Copyright 2026 Behdad Esfahbod. All Rights Reserved.\n" |
| " */\n" |
| "\n" |
| "struct Uniforms {\n" |
| " mvp: mat4x4f,\n" |
| " viewport: vec2f,\n" |
| " gamma: f32,\n" |
| " stem_darkening: f32,\n" |
| " foreground: vec4f,\n" |
| " debug: f32,\n" |
| "};\n" |
| "\n" |
| "@group(0) @binding(0) var<uniform> u: Uniforms;\n" |
| "@group(0) @binding(1) var<storage, read> hb_gpu_atlas: array<vec4<i32>>;\n" |
| "\n" |
| "struct VertexInput {\n" |
| " @location(0) position: vec2f,\n" |
| " @location(1) texcoord: vec2f,\n" |
| " @location(2) normal: vec2f,\n" |
| " @location(3) emPerPos: f32,\n" |
| " @location(4) glyphLoc: u32,\n" |
| "};\n" |
| "\n" |
| "struct VertexOutput {\n" |
| " @builtin(position) clip_position: vec4f,\n" |
| " @location(0) texcoord: vec2f,\n" |
| " @location(1) @interpolate(flat) glyphLoc: u32,\n" |
| "};\n" |
| "\n" |
| "@vertex fn vs_main (in: VertexInput) -> VertexOutput {\n" |
| " var pos = in.position;\n" |
| " var tc = in.texcoord;\n" |
| " let jac = vec4f (in.emPerPos, 0.0, 0.0, -in.emPerPos);\n" |
| " let result = hb_gpu_dilate (pos, tc, in.normal, jac, u.mvp, u.viewport);\n" |
| " pos = result[0];\n" |
| " tc = result[1];\n" |
| "\n" |
| " var out: VertexOutput;\n" |
| " out.clip_position = u.mvp * vec4f (pos, 0.0, 1.0);\n" |
| " out.texcoord = tc;\n" |
| " out.glyphLoc = in.glyphLoc;\n" |
| " return out;\n" |
| "}\n" |
| "\n" |
| "@fragment fn fs_main (in: VertexOutput) -> @location(0) vec4f {\n" |
| " /* Compute ppem up front so fwidth is called at uniform control\n" |
| " * flow, before the non-uniform branches below. */\n" |
| " let fw = fwidth (in.texcoord);\n" |
| " let ppem = 1.0 / max (fw.x, fw.y);\n" |
| "\n" |
| " var cov: f32;\n" |
| " var c = hb_gpu_paint (in.texcoord, in.glyphLoc, u.foreground,\n" |
| " &hb_gpu_atlas, &cov);\n" |
| "\n" |
| " if (cov > 0.0 && cov < 1.0) {\n" |
| " var adj = cov;\n" |
| " if (u.stem_darkening > 0.0) {\n" |
| " let brightness = select (0.0,\n" |
| " dot (c.rgb, vec3f (1.0 / 3.0)) / c.a, c.a > 0.0);\n" |
| " adj = hb_gpu_stem_darken (adj, brightness, ppem);\n" |
| " }\n" |
| " if (u.gamma != 1.0) {\n" |
| " adj = pow (adj, u.gamma);\n" |
| " }\n" |
| " c = c * (adj / cov);\n" |
| " }\n" |
| "\n" |
| " if (u.debug > 0.0) {\n" |
| " let counts = _hb_gpu_curve_counts (in.texcoord, in.glyphLoc, &hb_gpu_atlas);\n" |
| " let r = clamp (f32 (counts.x) / 8.0, 0.0, 1.0);\n" |
| " let g = clamp (f32 (counts.y) / 8.0, 0.0, 1.0);\n" |
| " return vec4f (r, g, c.a, max (max (r, g), c.a));\n" |
| " }\n" |
| "\n" |
| " return c;\n" |
| "}\n" |
| ; |