onejs-sl 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.9.0
4
+
5
+ A program can hold 64 uniforms and 8 textures, say how it samples a texture, and read a texture's size and its texels unfiltered. Every existing program keeps its hash and draws as it did; one that uses the new texture features is IR 6, which a host has to implement (below) to draw.
6
+
7
+ - 64 uniforms and 8 textures, where it was 16 and 4
8
+ - `[Wrap(Repeat)]`, `[Wrap(Mirror)]`, `[Wrap(Clamp)]` and `[Filter(Point)]`, `[Filter(Linear)]` on a `texture2D`; `sl.texture(name, { wrap, filter })`
9
+ - `textureSize(t)` and `tex2Dfetch(t, pixel)`; `t.size()` and `t.fetch(pixel)`
10
+ - IR 6: `TEXTURE_SIZE`, `SAMPLE_FETCH`, and `wrap` and `filter` on a `TextureDecl`, in the hash only when set
11
+ - `samplingOf`, `TEXTURE_WRAPS` and `TEXTURE_FILTERS` in `onejs-sl/core`; `TEXTURE_ATTRIBUTE_NAMES` and `TEXTURE_ATTRIBUTE_DOCS` in `onejs-sl/tables`
12
+ - `fromJSON` refuses a node that reads a texture slot the program does not declare
13
+ - `fromGLSL` turns `texelFetch` and `textureSize` into `tex2Dfetch` and `textureSize`
14
+ - `classifyLine` classifies a line at a time from the state the line before ended in, for an editor like Monaco
15
+ - `fromGLSL` declares a texture channel once when the shader declares it too
16
+ - The goldens anchor `wrap-repeat.sl`, `wrap-mirror.sl`, `filter-point.sl`, `fetch.sl` and `uniforms-64.sl` to arithmetic
17
+
18
+ ### What a host implements
19
+
20
+ A host that draws only programs it compiles from text (`compile`) gets all of this from the emitters. One with a frame of its own:
21
+
22
+ - **Caps.** 64 uniform slots of a float4 each, and texture slots 0 to 7. The web frame's uniform block stays 16 slots for a program with 16 uniforms or fewer, so an older WebGPU host's buffer still fits it; a web host fills all 64 either way. The web frame's previous frame moves with them, to WGSL bindings 17 and 18 (`1 + 2 * TEXTURE_SLOTS`), and a GLSL host should bind it on the unit after the eighth texture's.
23
+ - **`BodyTarget.sampleWith(slot, uv, lod, sampling)`**, for a texture whose program sets its sampler. `lod` is null for a plain sample and a level expression otherwise; `sampling` always has both halves, `wrap` one of `repeat`, `clamp`, `mirror` and `filter` one of `point`, `linear`. The sampler is the program's whatever the bound texture's settings: repeat and mirror wrap the filter's footprint too, point reads the nearest texel and level, linear blends four texels within the nearest level. Without it `emitBody` refuses such a program.
24
+ - **`BodyTarget.size(slot)`**, a float2 of the texture's full size in pixels, and **`BodyTarget.fetch(slot, pixel)`**, a float4 of one texel at full size, unfiltered, in the space `colour` names. `pixel` arrives floored and held inside the texture, so `fetch` only converts and loads (`t.Load(int3(pixel, 0))`, Metal's `t.read(uint2(pixel))`). `fetch` needs `size`. Without them `emitBody` refuses a program that uses them.
25
+ - **The web frame.** A slot the program samples with its own sampler ends its declaration with `// sampler <wrap> <filter>` (the `sl_samp<slot>` line in WGSL, the `sl_Tex<slot>` line in GLSL), which the host reads to build that slot's sampler. A WGSL slot that is only measured or fetched from declares its texture and no sampler, so the bind group leaves the sampler out.
26
+ - **JSON.** `fromJSON` reads `wrap` and `filter` on a texture; a reader before IR 6 refuses such a program by its version, rather than drawing it with the texture's own sampler.
27
+
28
+ `src/body.test.ts` spells all of this as Magerie's macros (`SL_SAMPLE_WITH`, `SL_SAMPLE_LEVEL_WITH`, `SL_SIZE`, `SL_FETCH`), and `src/metal.test.ts` compiles them with Apple's Metal compiler.
29
+
3
30
  ## 0.8.0
4
31
 
5
32
  A fractional `tex2Dlod` level now blends the two levels either side on every backend. No existing program's hash changes, but a host now gets two whole-level samples and a blend where it got one fractional sample, so a host that blended levels itself would blend twice, which makes this a minor.
package/README.md CHANGED
@@ -39,8 +39,8 @@ only what it calls.
39
39
 
40
40
  | Entry | Contents |
41
41
  |---|---|
42
- | `onejs-sl` | `parse` and `analyze`, `diagnose` (every error in a file, not just the first), `classify` (every token with its class, comments kept, never throws), `fromGLSL` (a pasted Shadertoy or WebGL shader as a `.sl` file, with notes on what did not carry over), the TypeScript form `sl`, the IR types, `SL_IR_VERSION`, `toJSON`/`fromJSON`, `SLParseError` (file, line, column, offset, length, the bare `text`, and a `fix` where one is certain) |
43
- | `onejs-sl/core` | the same without the parser: what a game needs at run time. Also the caps on one program, `UNIFORM_SLOTS` (16) and `TEXTURE_SLOTS` (4), which the parser and the builder enforce and a host can read |
42
+ | `onejs-sl` | `parse` and `analyze`, `diagnose` (every error in a file, not just the first), `classify` (every token with its class, comments kept, never throws) and `classifyLine` (the same a line at a time, for Monaco), `fromGLSL` (a pasted Shadertoy or WebGL shader as a `.sl` file, with notes on what did not carry over), the TypeScript form `sl`, the IR types, `SL_IR_VERSION`, `toJSON`/`fromJSON`, `SLParseError` (file, line, column, offset, length, the bare `text`, and a `fix` where one is certain) |
43
+ | `onejs-sl/core` | the same without the parser: what a game needs at run time. Also the caps on one program, `UNIFORM_SLOTS` (64) and `TEXTURE_SLOTS` (8), which the parser and the builder enforce and a host can read |
44
44
  | `onejs-sl/tables` | `BUILTINS`, `SL_HLSL`, `INPUTS`, `SL_SDF_SHAPES`, `SL_SDF_PARAMS`, `SL_KEYWORDS`, `SL_TYPES`, `TYPE_WIDTH`, `PRELUDE_NAMES`: what completion and highlighting read. `BUILTIN_PARAMS`, `SL_SDF_PARAM_NAMES` and `LIB_SIGNATURES` name every parameter, so an editor can show `lerp(x, y, s)`, and `BUILTIN_DOCS`, `INPUT_DOCS` and `PRELUDE_DOCS` give each a line for its tooltip |
45
45
  | `onejs-sl/compile` | `compile(program)`: what a host draws a program with. Its hash, its uniform and texture names in slot order, their defaults, and `hlsl`, `wgsl` and `glsl` as lazy getters. No budget |
46
46
  | `onejs-sl/emit/hlsl-body` | `emitBody`: a program as a function body for a host's own frame; `emitLibrary`: the library functions it calls |
@@ -75,7 +75,11 @@ fractional `tex2Dlod` level blends the two levels either side by the fraction,
75
75
  whatever the texture's filter mode, since the body asks for both whole levels
76
76
  and blends them itself. A level it can prove whole (a whole constant, a
77
77
  `floor`, an int) costs one sample, and a level past the smallest reads the
78
- smallest. OneJS's Unity shader is one frame over it (`hlsl.ts`); Magerie's compute kernel is another, and its
78
+ smallest. A texture whose program sets its own sampler (`[Wrap(Repeat)]`,
79
+ `[Filter(Point)]`) goes to `sampleWith` instead, with both halves filled in,
80
+ and `textureSize` and `tex2Dfetch` to `size` and `fetch`; each is optional,
81
+ and `emitBody` refuses a program that needs one a target lacks (CHANGELOG.md's
82
+ 0.9.0 entry says what a host implements). OneJS's Unity shader is one frame over it (`hlsl.ts`); Magerie's compute kernel is another, and its
79
83
  target is in `src/body.test.ts` so an opcode cannot change without the text
80
84
  Magerie compiles changing in front of a test.
81
85
 
@@ -153,12 +157,16 @@ what a WebGL player draws.
153
157
 
154
158
  `npm run goldens` draws it on WebGPU and WebGL2 in a Chrome with its own
155
159
  profile (set `CHROME` to choose one). The two backends must agree within 1/255
156
- over every pixel, and eight anchors must match arithmetic, not each other:
160
+ over every pixel, and the anchors must match arithmetic, not each other:
157
161
  `orient.sl` (orientation, and the linear to sRGB store), `hex.sl` (a hex colour
158
162
  stores as written), `texture.sl` (a texture's orientation and sRGB decode),
159
163
  `lod.sl` (each mip level `tex2Dlod` reads, the texture's smaller levels being
160
- solid colours) and `lod-frac.sl` (a fractional level blends the two levels
161
- either side, on a texture sampled nearest between levels). `sdf-values.sl`, `fbm-values.sl` and `ramp-values.sl` are black unless a
164
+ solid colours), `lod-frac.sl` (a fractional level blends the two levels
165
+ either side, on a texture sampled nearest between levels), `wrap-repeat.sl`
166
+ and `wrap-mirror.sl` (a program's own wrap over a texture the host binds
167
+ clamped, the filter's footprint wrapping with it), `filter-point.sl` (its own
168
+ point filter, to the byte, through `tex2D` and `tex2Dlod`) and `fetch.sl`
169
+ (`tex2Dfetch` held at the edges and `textureSize`, to the byte), and `uniforms-64.sl` (every uniform slot arrives). `sdf-values.sl`, `fbm-values.sl` and `ramp-values.sl` are black unless a
162
170
  shape, a noise or a ramp draws differently with its parameters as values than
163
171
  as constants.
164
172
  A fixture that reads the previous frame, `frame` or `deltaTime` is stepped
@@ -254,7 +262,7 @@ drew what had no shader yet; OneJS 3.8 deleted it.) `hlsl.ts` feeds OneJS's
254
262
  `Editor/SLShaderGenerator.cs`. Nobody writes a manifest for it: an editor that
255
263
  draws a program asks the compiled program for its
256
264
  `hlsl` (a lazy getter, never read in Play), records it into
257
- `Assets/OneJS/Recorded.sl.json`, generates the shader and
265
+ `Assets/OneJS.Recorded.sl.json`, generates the shader and
258
266
  moves the live material onto it. `manifest()`, in `onejs-unity/sl` and
259
267
  `onejs-unity/sl/compiler` rather than this package, is still there for an app
260
268
  that would rather write its programs out at build time.
@@ -269,8 +277,8 @@ printed at build time; a `compile()` result has them as lazy getters, like
269
277
  `hlsl`. The element draws nothing until the compiled
270
278
  program is ready, and nothing after a compile error, which the page reports.
271
279
  The host contract (the frame block, the
272
- 16 uniform slots, one binding pair per sampled texture) is written out at the
273
- top of `web.ts`.
280
+ uniform block, one binding pair per sampled texture, the note that names a
281
+ program's own sampler) is written out at the top of `web.ts`.
274
282
 
275
283
  The emitters match the HLSL emitter's semantics rather than each language's
276
284
  own: `%` truncates like `fmod`, `pow` takes `abs` of its base, `asin` and
@@ -326,7 +334,7 @@ at module load, not at draw time:
326
334
  | A program returning something other than a `vec4` | "a program must return a vec4. Wrap it: sl.vec4(value, 1)" |
327
335
  | `vec4` given the wrong number of parts | "vec4 needs 4 components, got 3" |
328
336
  | One uniform name at two widths | "declared as both a float and a vec4" |
329
- | More than 16 uniforms or 4 textures | "this program declares 5 textures and a program may sample 4", the parser's words |
337
+ | More than 64 uniforms or 8 textures | "this program declares 9 textures and a program may sample 8", the parser's words |
330
338
  | A value borrowed from another program | "a value from another program cannot be used in this one" |
331
339
 
332
340
  The caps are `UNIFORM_SLOTS` and `TEXTURE_SLOTS`: what OneJS binds to one
@@ -383,7 +391,10 @@ control flow (the `if` and `loop` nodes, a loop's `param`s and each result's
383
391
  none of them is still IR 3 and keeps its hash; one with an `if` statement is
384
392
  IR 4, since the statement is now a real branch rather than a select. IR 5 added
385
393
  the previous frame (`SAMPLE_PREVIOUS`) and the `frame` and `deltaTime` inputs;
386
- a program that reads none of them keeps the version and the hash it had.
394
+ a program that reads none of them keeps the version and the hash it had. IR 6
395
+ added `TEXTURE_SIZE` and `SAMPLE_FETCH`, and a texture's own sampler (`wrap`
396
+ and `filter` on its `TextureDecl`); the sampler is in the hash only when a
397
+ texture has one, so every other program keeps its hash.
387
398
 
388
399
  ## Control flow
389
400
 
@@ -491,6 +502,28 @@ control as `float`, with a matching Properties line (`[ToggleUI]`, since
491
502
  `[Toggle]` also defines a keyword; `[Enum]` as name, value pairs), and the bridge
492
503
  setting it with `SetFloat`. `Specs/SL_NEXT.md` 1 keeps that as a later change.
493
504
 
505
+ ## Textures
506
+
507
+ A program declares up to eight textures (`texture2D grain;`,
508
+ `sl.texture("grain")`), which a host binds by slot. `tex2D(t, uv)` samples one
509
+ as the bound texture is set, and `tex2Dlod(t, uv, lod)` at a mip level.
510
+
511
+ A program can set the sampler itself: `[Wrap(Repeat)]`, `[Wrap(Mirror)]` or
512
+ `[Wrap(Clamp)]`, and `[Filter(Point)]` or `[Filter(Linear)]`, before the
513
+ declaration, or `sl.texture("grain", { wrap: "repeat", filter: "point" })`.
514
+ Then every host samples it that way whatever the texture's own settings, and
515
+ the half left out is clamp or linear, since a Unity inline sampler state and a
516
+ WebGPU sampler each say both. A tiled noise texture no longer depends on
517
+ somebody remembering its import settings. Linear is bilinear within the
518
+ nearest mip level, as Unity's Bilinear is.
519
+
520
+ `textureSize(t)` is the texture's width and height in pixels (`t.size()`), and
521
+ `tex2Dfetch(t, pixel)` one texel, unfiltered and at full size (`t.fetch(pixel)`):
522
+ pixel (0, 0) is the texel `uv` (0, 0) samples, and a pixel is floored and held
523
+ inside the texture, so one past an edge reads the edge on every host rather
524
+ than what a host's load returns out of range. `tex2Dfetch(t, fragCoord)` on a
525
+ texture the size of the target reads it texel for texel.
526
+
494
527
  ## Colours
495
528
 
496
529
  A hex colour is sRGB as written, the way CSS reads it, and the target holds
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "generatedBy": "onejs-sl goldens/run.mjs",
3
- "package": "0.8.0",
4
- "ir": 5,
3
+ "package": "0.9.0",
4
+ "ir": 6,
5
5
  "target": "rgba8unorm-srgb: straight alpha, 8 bit, sRGB encoded, the stored bytes of a Linear OneJS game's element",
6
6
  "size": [
7
7
  64,
@@ -156,6 +156,24 @@
156
156
  "1.25": [0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255]
157
157
  }
158
158
  },
159
+ "fetch.sl": {
160
+ "hash": "5050430b",
161
+ "exact": true,
162
+ "source": "// An anchor for tex2Dfetch and textureSize. The left half fetches texels at\n// pixels from -1 to 9, which hold at the edge texels past 0 and 7. The right\n// half samples the same texture as it is set, at texel centres, so one texture\n// is read both ways and both are exact. Blue is the texture's width over 16,\n// which is 0.5.\ntexture2D t;\nfloat4 main() {\n float2 size = textureSize(t);\n float2 centre = (floor(uv * size) + 0.5) / size;\n float4 c = uv.x < 0.5 ? tex2Dfetch(t, uv * 10 - 1) : tex2D(t, centre);\n return float4(c.rg, size.x / 16, 1);\n}\n",
163
+ "samples": {
164
+ "0": [16,16,188,255,16,16,188,255,16,16,188,255,48,16,188,255,48,16,188,255,80,16,188,255,112,16,188,255,112,16,188,255,144,16,188,255,144,16,188,255,176,16,188,255,176,16,188,255,208,16,188,255,208,16,188,255,240,16,188,255,240,16,188,255,16,16,188,255,16,16,188,255,16,16,188,255,48,16,188,255,48,16,188,255,80,16,188,255,112,16,188,255,112,16,188,255,144,16,188,255,144,16,188,255,176,16,188,255,176,16,188,255,208,16,188,255,208,16,188,255,240,16,188,255,240,16,188,255,16,16,188,255,16,16,188,255,16,16,188,255,48,16,188,255,48,16,188,255,80,16,188,255,112,16,188,255,112,16,188,255,144,48,188,255,144,48,188,255,176,48,188,255,176,48,188,255,208,48,188,255,208,48,188,255,240,48,188,255,240,48,188,255,16,48,188,255,16,48,188,255,16,48,188,255,48,48,188,255,48,48,188,255,80,48,188,255,112,48,188,255,112,48,188,255,144,48,188,255,144,48,188,255,176,48,188,255,176,48,188,255,208,48,188,255,208,48,188,255,240,48,188,255,240,48,188,255,16,48,188,255,16,48,188,255,16,48,188,255,48,48,188,255,48,48,188,255,80,48,188,255,112,48,188,255,112,48,188,255,144,80,188,255,144,80,188,255,176,80,188,255,176,80,188,255,208,80,188,255,208,80,188,255,240,80,188,255,240,80,188,255,16,80,188,255,16,80,188,255,16,80,188,255,48,80,188,255,48,80,188,255,80,80,188,255,112,80,188,255,112,80,188,255,144,80,188,255,144,80,188,255,176,80,188,255,176,80,188,255,208,80,188,255,208,80,188,255,240,80,188,255,240,80,188,255,16,112,188,255,16,112,188,255,16,112,188,255,48,112,188,255,48,112,188,255,80,112,188,255,112,112,188,255,112,112,188,255,144,112,188,255,144,112,188,255,176,112,188,255,176,112,188,255,208,112,188,255,208,112,188,255,240,112,188,255,240,112,188,255,16,112,188,255,16,112,188,255,16,112,188,255,48,112,188,255,48,112,188,255,80,112,188,255,112,112,188,255,112,112,188,255,144,112,188,255,144,112,188,255,176,112,188,255,176,112,188,255,208,112,188,255,208,112,188,255,240,112,188,255,240,112,188,255,16,144,188,255,16,144,188,255,16,144,188,255,48,144,188,255,48,144,188,255,80,144,188,255,112,144,188,255,112,144,188,255,144,144,188,255,144,144,188,255,176,144,188,255,176,144,188,255,208,144,188,255,208,144,188,255,240,144,188,255,240,144,188,255,16,176,188,255,16,176,188,255,16,176,188,255,48,176,188,255,48,176,188,255,80,176,188,255,112,176,188,255,112,176,188,255,144,144,188,255,144,144,188,255,176,144,188,255,176,144,188,255,208,144,188,255,208,144,188,255,240,144,188,255,240,144,188,255,16,176,188,255,16,176,188,255,16,176,188,255,48,176,188,255,48,176,188,255,80,176,188,255,112,176,188,255,112,176,188,255,144,176,188,255,144,176,188,255,176,176,188,255,176,176,188,255,208,176,188,255,208,176,188,255,240,176,188,255,240,176,188,255,16,208,188,255,16,208,188,255,16,208,188,255,48,208,188,255,48,208,188,255,80,208,188,255,112,208,188,255,112,208,188,255,144,176,188,255,144,176,188,255,176,176,188,255,176,176,188,255,208,176,188,255,208,176,188,255,240,176,188,255,240,176,188,255,16,208,188,255,16,208,188,255,16,208,188,255,48,208,188,255,48,208,188,255,80,208,188,255,112,208,188,255,112,208,188,255,144,208,188,255,144,208,188,255,176,208,188,255,176,208,188,255,208,208,188,255,208,208,188,255,240,208,188,255,240,208,188,255,16,240,188,255,16,240,188,255,16,240,188,255,48,240,188,255,48,240,188,255,80,240,188,255,112,240,188,255,112,240,188,255,144,208,188,255,144,208,188,255,176,208,188,255,176,208,188,255,208,208,188,255,208,208,188,255,240,208,188,255,240,208,188,255,16,240,188,255,16,240,188,255,16,240,188,255,48,240,188,255,48,240,188,255,80,240,188,255,112,240,188,255,112,240,188,255,144,240,188,255,144,240,188,255,176,240,188,255,176,240,188,255,208,240,188,255,208,240,188,255,240,240,188,255,240,240,188,255,16,240,188,255,16,240,188,255,16,240,188,255,48,240,188,255,48,240,188,255,80,240,188,255,112,240,188,255,112,240,188,255,144,240,188,255,144,240,188,255,176,240,188,255,176,240,188,255,208,240,188,255,208,240,188,255,240,240,188,255,240,240,188,255],
165
+ "1.25": [16,16,188,255,16,16,188,255,16,16,188,255,48,16,188,255,48,16,188,255,80,16,188,255,112,16,188,255,112,16,188,255,144,16,188,255,144,16,188,255,176,16,188,255,176,16,188,255,208,16,188,255,208,16,188,255,240,16,188,255,240,16,188,255,16,16,188,255,16,16,188,255,16,16,188,255,48,16,188,255,48,16,188,255,80,16,188,255,112,16,188,255,112,16,188,255,144,16,188,255,144,16,188,255,176,16,188,255,176,16,188,255,208,16,188,255,208,16,188,255,240,16,188,255,240,16,188,255,16,16,188,255,16,16,188,255,16,16,188,255,48,16,188,255,48,16,188,255,80,16,188,255,112,16,188,255,112,16,188,255,144,48,188,255,144,48,188,255,176,48,188,255,176,48,188,255,208,48,188,255,208,48,188,255,240,48,188,255,240,48,188,255,16,48,188,255,16,48,188,255,16,48,188,255,48,48,188,255,48,48,188,255,80,48,188,255,112,48,188,255,112,48,188,255,144,48,188,255,144,48,188,255,176,48,188,255,176,48,188,255,208,48,188,255,208,48,188,255,240,48,188,255,240,48,188,255,16,48,188,255,16,48,188,255,16,48,188,255,48,48,188,255,48,48,188,255,80,48,188,255,112,48,188,255,112,48,188,255,144,80,188,255,144,80,188,255,176,80,188,255,176,80,188,255,208,80,188,255,208,80,188,255,240,80,188,255,240,80,188,255,16,80,188,255,16,80,188,255,16,80,188,255,48,80,188,255,48,80,188,255,80,80,188,255,112,80,188,255,112,80,188,255,144,80,188,255,144,80,188,255,176,80,188,255,176,80,188,255,208,80,188,255,208,80,188,255,240,80,188,255,240,80,188,255,16,112,188,255,16,112,188,255,16,112,188,255,48,112,188,255,48,112,188,255,80,112,188,255,112,112,188,255,112,112,188,255,144,112,188,255,144,112,188,255,176,112,188,255,176,112,188,255,208,112,188,255,208,112,188,255,240,112,188,255,240,112,188,255,16,112,188,255,16,112,188,255,16,112,188,255,48,112,188,255,48,112,188,255,80,112,188,255,112,112,188,255,112,112,188,255,144,112,188,255,144,112,188,255,176,112,188,255,176,112,188,255,208,112,188,255,208,112,188,255,240,112,188,255,240,112,188,255,16,144,188,255,16,144,188,255,16,144,188,255,48,144,188,255,48,144,188,255,80,144,188,255,112,144,188,255,112,144,188,255,144,144,188,255,144,144,188,255,176,144,188,255,176,144,188,255,208,144,188,255,208,144,188,255,240,144,188,255,240,144,188,255,16,176,188,255,16,176,188,255,16,176,188,255,48,176,188,255,48,176,188,255,80,176,188,255,112,176,188,255,112,176,188,255,144,144,188,255,144,144,188,255,176,144,188,255,176,144,188,255,208,144,188,255,208,144,188,255,240,144,188,255,240,144,188,255,16,176,188,255,16,176,188,255,16,176,188,255,48,176,188,255,48,176,188,255,80,176,188,255,112,176,188,255,112,176,188,255,144,176,188,255,144,176,188,255,176,176,188,255,176,176,188,255,208,176,188,255,208,176,188,255,240,176,188,255,240,176,188,255,16,208,188,255,16,208,188,255,16,208,188,255,48,208,188,255,48,208,188,255,80,208,188,255,112,208,188,255,112,208,188,255,144,176,188,255,144,176,188,255,176,176,188,255,176,176,188,255,208,176,188,255,208,176,188,255,240,176,188,255,240,176,188,255,16,208,188,255,16,208,188,255,16,208,188,255,48,208,188,255,48,208,188,255,80,208,188,255,112,208,188,255,112,208,188,255,144,208,188,255,144,208,188,255,176,208,188,255,176,208,188,255,208,208,188,255,208,208,188,255,240,208,188,255,240,208,188,255,16,240,188,255,16,240,188,255,16,240,188,255,48,240,188,255,48,240,188,255,80,240,188,255,112,240,188,255,112,240,188,255,144,208,188,255,144,208,188,255,176,208,188,255,176,208,188,255,208,208,188,255,208,208,188,255,240,208,188,255,240,208,188,255,16,240,188,255,16,240,188,255,16,240,188,255,48,240,188,255,48,240,188,255,80,240,188,255,112,240,188,255,112,240,188,255,144,240,188,255,144,240,188,255,176,240,188,255,176,240,188,255,208,240,188,255,208,240,188,255,240,240,188,255,240,240,188,255,16,240,188,255,16,240,188,255,16,240,188,255,48,240,188,255,48,240,188,255,80,240,188,255,112,240,188,255,112,240,188,255,144,240,188,255,144,240,188,255,176,240,188,255,176,240,188,255,208,240,188,255,208,240,188,255,240,240,188,255,240,240,188,255]
166
+ }
167
+ },
168
+ "filter-point.sl": {
169
+ "hash": "83692186",
170
+ "exact": true,
171
+ "source": "// An anchor for [Filter(Point)] with [Wrap(Repeat)]: the texture's eight by\n// eight texels as hard squares over two tiles, which the host binds linear and\n// clamped. The bottom half reads through tex2Dlod at level 0, so the program's\n// sampler reaches a sample at a level as well as a plain one.\n[Filter(Point)] [Wrap(Repeat)] texture2D t;\nfloat4 main() {\n float2 q = uv * 2 - 0.5;\n return uv.y > 0.5 ? tex2D(t, q) : tex2Dlod(t, q, 0);\n}\n",
172
+ "samples": {
173
+ "0": [144,144,200,255,176,144,40,255,208,144,200,255,240,144,40,255,16,144,200,255,48,144,40,255,80,144,200,255,112,144,40,255,144,144,200,255,176,144,40,255,208,144,200,255,240,144,40,255,16,144,200,255,48,144,40,255,80,144,200,255,112,144,40,255,144,176,40,255,176,176,200,255,208,176,40,255,240,176,200,255,16,176,40,255,48,176,200,255,80,176,40,255,112,176,200,255,144,176,40,255,176,176,200,255,208,176,40,255,240,176,200,255,16,176,40,255,48,176,200,255,80,176,40,255,112,176,200,255,144,208,200,255,176,208,40,255,208,208,200,255,240,208,40,255,16,208,200,255,48,208,40,255,80,208,200,255,112,208,40,255,144,208,200,255,176,208,40,255,208,208,200,255,240,208,40,255,16,208,200,255,48,208,40,255,80,208,200,255,112,208,40,255,144,240,40,255,176,240,200,255,208,240,40,255,240,240,200,255,16,240,40,255,48,240,200,255,80,240,40,255,112,240,200,255,144,240,40,255,176,240,200,255,208,240,40,255,240,240,200,255,16,240,40,255,48,240,200,255,80,240,40,255,112,240,200,255,144,16,200,255,176,16,40,255,208,16,200,255,240,16,40,255,16,16,200,255,48,16,40,255,80,16,200,255,112,16,40,255,144,16,200,255,176,16,40,255,208,16,200,255,240,16,40,255,16,16,200,255,48,16,40,255,80,16,200,255,112,16,40,255,144,48,40,255,176,48,200,255,208,48,40,255,240,48,200,255,16,48,40,255,48,48,200,255,80,48,40,255,112,48,200,255,144,48,40,255,176,48,200,255,208,48,40,255,240,48,200,255,16,48,40,255,48,48,200,255,80,48,40,255,112,48,200,255,144,80,200,255,176,80,40,255,208,80,200,255,240,80,40,255,16,80,200,255,48,80,40,255,80,80,200,255,112,80,40,255,144,80,200,255,176,80,40,255,208,80,200,255,240,80,40,255,16,80,200,255,48,80,40,255,80,80,200,255,112,80,40,255,144,112,40,255,176,112,200,255,208,112,40,255,240,112,200,255,16,112,40,255,48,112,200,255,80,112,40,255,112,112,200,255,144,112,40,255,176,112,200,255,208,112,40,255,240,112,200,255,16,112,40,255,48,112,200,255,80,112,40,255,112,112,200,255,144,144,200,255,176,144,40,255,208,144,200,255,240,144,40,255,16,144,200,255,48,144,40,255,80,144,200,255,112,144,40,255,144,144,200,255,176,144,40,255,208,144,200,255,240,144,40,255,16,144,200,255,48,144,40,255,80,144,200,255,112,144,40,255,144,176,40,255,176,176,200,255,208,176,40,255,240,176,200,255,16,176,40,255,48,176,200,255,80,176,40,255,112,176,200,255,144,176,40,255,176,176,200,255,208,176,40,255,240,176,200,255,16,176,40,255,48,176,200,255,80,176,40,255,112,176,200,255,144,208,200,255,176,208,40,255,208,208,200,255,240,208,40,255,16,208,200,255,48,208,40,255,80,208,200,255,112,208,40,255,144,208,200,255,176,208,40,255,208,208,200,255,240,208,40,255,16,208,200,255,48,208,40,255,80,208,200,255,112,208,40,255,144,240,40,255,176,240,200,255,208,240,40,255,240,240,200,255,16,240,40,255,48,240,200,255,80,240,40,255,112,240,200,255,144,240,40,255,176,240,200,255,208,240,40,255,240,240,200,255,16,240,40,255,48,240,200,255,80,240,40,255,112,240,200,255,144,16,200,255,176,16,40,255,208,16,200,255,240,16,40,255,16,16,200,255,48,16,40,255,80,16,200,255,112,16,40,255,144,16,200,255,176,16,40,255,208,16,200,255,240,16,40,255,16,16,200,255,48,16,40,255,80,16,200,255,112,16,40,255,144,48,40,255,176,48,200,255,208,48,40,255,240,48,200,255,16,48,40,255,48,48,200,255,80,48,40,255,112,48,200,255,144,48,40,255,176,48,200,255,208,48,40,255,240,48,200,255,16,48,40,255,48,48,200,255,80,48,40,255,112,48,200,255,144,80,200,255,176,80,40,255,208,80,200,255,240,80,40,255,16,80,200,255,48,80,40,255,80,80,200,255,112,80,40,255,144,80,200,255,176,80,40,255,208,80,200,255,240,80,40,255,16,80,200,255,48,80,40,255,80,80,200,255,112,80,40,255,144,112,40,255,176,112,200,255,208,112,40,255,240,112,200,255,16,112,40,255,48,112,200,255,80,112,40,255,112,112,200,255,144,112,40,255,176,112,200,255,208,112,40,255,240,112,200,255,16,112,40,255,48,112,200,255,80,112,40,255,112,112,200,255],
174
+ "1.25": [144,144,200,255,176,144,40,255,208,144,200,255,240,144,40,255,16,144,200,255,48,144,40,255,80,144,200,255,112,144,40,255,144,144,200,255,176,144,40,255,208,144,200,255,240,144,40,255,16,144,200,255,48,144,40,255,80,144,200,255,112,144,40,255,144,176,40,255,176,176,200,255,208,176,40,255,240,176,200,255,16,176,40,255,48,176,200,255,80,176,40,255,112,176,200,255,144,176,40,255,176,176,200,255,208,176,40,255,240,176,200,255,16,176,40,255,48,176,200,255,80,176,40,255,112,176,200,255,144,208,200,255,176,208,40,255,208,208,200,255,240,208,40,255,16,208,200,255,48,208,40,255,80,208,200,255,112,208,40,255,144,208,200,255,176,208,40,255,208,208,200,255,240,208,40,255,16,208,200,255,48,208,40,255,80,208,200,255,112,208,40,255,144,240,40,255,176,240,200,255,208,240,40,255,240,240,200,255,16,240,40,255,48,240,200,255,80,240,40,255,112,240,200,255,144,240,40,255,176,240,200,255,208,240,40,255,240,240,200,255,16,240,40,255,48,240,200,255,80,240,40,255,112,240,200,255,144,16,200,255,176,16,40,255,208,16,200,255,240,16,40,255,16,16,200,255,48,16,40,255,80,16,200,255,112,16,40,255,144,16,200,255,176,16,40,255,208,16,200,255,240,16,40,255,16,16,200,255,48,16,40,255,80,16,200,255,112,16,40,255,144,48,40,255,176,48,200,255,208,48,40,255,240,48,200,255,16,48,40,255,48,48,200,255,80,48,40,255,112,48,200,255,144,48,40,255,176,48,200,255,208,48,40,255,240,48,200,255,16,48,40,255,48,48,200,255,80,48,40,255,112,48,200,255,144,80,200,255,176,80,40,255,208,80,200,255,240,80,40,255,16,80,200,255,48,80,40,255,80,80,200,255,112,80,40,255,144,80,200,255,176,80,40,255,208,80,200,255,240,80,40,255,16,80,200,255,48,80,40,255,80,80,200,255,112,80,40,255,144,112,40,255,176,112,200,255,208,112,40,255,240,112,200,255,16,112,40,255,48,112,200,255,80,112,40,255,112,112,200,255,144,112,40,255,176,112,200,255,208,112,40,255,240,112,200,255,16,112,40,255,48,112,200,255,80,112,40,255,112,112,200,255,144,144,200,255,176,144,40,255,208,144,200,255,240,144,40,255,16,144,200,255,48,144,40,255,80,144,200,255,112,144,40,255,144,144,200,255,176,144,40,255,208,144,200,255,240,144,40,255,16,144,200,255,48,144,40,255,80,144,200,255,112,144,40,255,144,176,40,255,176,176,200,255,208,176,40,255,240,176,200,255,16,176,40,255,48,176,200,255,80,176,40,255,112,176,200,255,144,176,40,255,176,176,200,255,208,176,40,255,240,176,200,255,16,176,40,255,48,176,200,255,80,176,40,255,112,176,200,255,144,208,200,255,176,208,40,255,208,208,200,255,240,208,40,255,16,208,200,255,48,208,40,255,80,208,200,255,112,208,40,255,144,208,200,255,176,208,40,255,208,208,200,255,240,208,40,255,16,208,200,255,48,208,40,255,80,208,200,255,112,208,40,255,144,240,40,255,176,240,200,255,208,240,40,255,240,240,200,255,16,240,40,255,48,240,200,255,80,240,40,255,112,240,200,255,144,240,40,255,176,240,200,255,208,240,40,255,240,240,200,255,16,240,40,255,48,240,200,255,80,240,40,255,112,240,200,255,144,16,200,255,176,16,40,255,208,16,200,255,240,16,40,255,16,16,200,255,48,16,40,255,80,16,200,255,112,16,40,255,144,16,200,255,176,16,40,255,208,16,200,255,240,16,40,255,16,16,200,255,48,16,40,255,80,16,200,255,112,16,40,255,144,48,40,255,176,48,200,255,208,48,40,255,240,48,200,255,16,48,40,255,48,48,200,255,80,48,40,255,112,48,200,255,144,48,40,255,176,48,200,255,208,48,40,255,240,48,200,255,16,48,40,255,48,48,200,255,80,48,40,255,112,48,200,255,144,80,200,255,176,80,40,255,208,80,200,255,240,80,40,255,16,80,200,255,48,80,40,255,80,80,200,255,112,80,40,255,144,80,200,255,176,80,40,255,208,80,200,255,240,80,40,255,16,80,200,255,48,80,40,255,80,80,200,255,112,80,40,255,144,112,40,255,176,112,200,255,208,112,40,255,240,112,200,255,16,112,40,255,48,112,200,255,80,112,40,255,112,112,200,255,144,112,40,255,176,112,200,255,208,112,40,255,240,112,200,255,16,112,40,255,48,112,200,255,80,112,40,255,112,112,200,255]
175
+ }
176
+ },
159
177
  "frame-delta.sl": {
160
178
  "hash": "12de4ff1",
161
179
  "historyExact": true,
@@ -326,6 +344,31 @@
326
344
  "1.25": [118,155,220,255,111,160,209,255,104,162,197,255,100,161,189,255,98,161,186,255,100,161,189,255,103,161,194,255,105,162,199,255,107,161,201,255,106,161,199,255,103,162,195,255,100,161,189,255,98,160,185,255,98,160,186,255,102,161,192,255,108,161,204,255,122,149,229,255,118,155,221,255,114,159,214,255,111,160,209,255,111,160,208,255,112,159,211,255,114,158,215,255,116,157,217,255,115,158,216,255,112,159,211,255,108,161,203,255,103,162,195,255,100,161,189,255,100,161,190,255,105,162,197,255,112,160,211,255,124,146,232,255,121,150,227,255,119,154,223,255,118,154,222,255,119,153,224,255,122,150,228,255,124,147,231,255,124,146,232,255,123,148,229,255,119,154,222,255,113,159,212,255,106,161,200,255,102,161,192,255,101,161,191,255,105,162,198,255,113,159,212,255,122,149,228,255,120,152,225,255,119,153,224,255,120,152,226,255,123,148,230,255,127,141,236,255,129,134,241,255,130,132,242,255,128,137,239,255,123,148,230,255,116,157,218,255,108,161,203,255,101,161,191,255,99,161,187,255,102,161,192,255,110,161,207,255,116,157,217,255,114,158,214,255,115,158,215,255,117,156,220,255,122,150,228,255,127,140,237,255,132,131,244,255,139,132,246,255,131,130,243,255,125,144,234,255,117,156,219,255,107,161,202,255,98,161,186,255,93,158,177,255,95,159,180,255,103,161,194,255,106,162,199,255,104,162,196,255,105,162,198,255,109,161,205,255,116,157,217,255,123,149,229,255,128,137,239,255,133,131,244,255,130,132,242,255,125,144,233,255,116,157,218,255,105,162,198,255,94,159,178,255,86,153,164,255,85,153,163,255,92,158,175,255,93,158,177,255,90,156,171,255,91,157,173,255,97,160,183,255,105,162,199,255,115,158,216,255,123,148,229,255,127,139,237,255,127,139,238,255,123,148,230,255,114,158,214,255,102,161,193,255,89,155,169,255,78,145,150,255,74,141,143,255,79,147,152,255,82,149,157,255,75,143,145,255,75,142,145,255,82,149,157,255,93,158,177,255,105,162,198,255,115,157,216,255,122,150,228,255,124,146,232,255,121,152,226,255,113,159,211,255,100,161,190,255,86,153,164,255,73,139,141,255,71,137,137,255,71,137,137,255,75,142,145,255,71,137,137,255,71,137,137,255,71,137,137,255,81,149,155,255,96,160,181,255,108,161,204,255,117,156,219,255,121,151,226,255,119,154,223,255,112,159,211,255,101,161,191,255,87,154,167,255,73,140,142,255,71,137,137,255,71,137,137,255,77,145,148,255,71,137,137,255,71,137,137,255,71,137,137,255,73,140,141,255,89,156,170,255,103,162,195,255,114,159,213,255,119,154,223,255,119,153,223,255,114,158,215,255,105,162,198,255,93,158,177,255,81,148,155,255,71,138,138,255,71,137,137,255,87,154,166,255,72,139,140,255,71,137,137,255,71,137,137,255,73,140,141,255,88,155,167,255,102,161,192,255,113,159,212,255,119,153,224,255,121,151,227,255,118,155,221,255,111,160,209,255,102,161,192,255,92,157,175,255,84,152,161,255,81,149,156,255,100,161,189,255,87,154,165,255,76,143,146,255,73,140,141,255,79,147,152,255,91,157,173,255,103,162,195,255,114,158,214,255,121,151,227,255,124,146,231,255,122,149,229,255,118,155,220,255,111,160,208,255,103,162,195,255,98,160,186,255,96,160,182,255,113,159,211,255,101,161,190,255,90,157,172,255,86,153,164,255,88,155,168,255,97,160,183,255,107,161,201,255,116,157,218,255,123,148,230,255,126,142,235,255,126,143,235,255,123,149,229,255,118,155,221,255,113,159,212,255,110,161,207,255,109,161,205,255,122,149,229,255,112,160,210,255,102,161,193,255,97,160,184,255,97,160,184,255,103,161,194,255,110,160,208,255,118,155,221,255,124,147,231,255,127,141,237,255,127,140,237,255,125,145,233,255,122,150,228,255,119,154,223,255,117,155,220,255,118,155,221,255,128,138,238,255,119,154,222,255,110,160,207,255,105,162,198,255,104,162,196,255,107,161,201,255,112,159,211,255,118,155,222,255,123,149,229,255,125,145,233,255,125,145,233,255,123,148,230,255,121,151,227,255,120,153,224,255,120,152,225,255,122,149,229,255,128,136,239,255,121,151,226,255,114,159,213,255,108,161,204,255,107,161,202,255,109,161,205,255,113,159,212,255,117,156,219,255,119,153,224,255,120,152,225,255,119,153,223,255,117,155,220,255,116,157,217,255,116,157,217,255,118,155,221,255,122,150,228,255]
327
345
  }
328
346
  },
347
+ "uniforms-64.sl": {
348
+ "hash": "a71ac2c4",
349
+ "exact": true,
350
+ "source": "// An anchor: every one of the 64 uniform slots reaches the program with its\n// default (slot i holds i + 1), so a host that binds fewer draws green where\n// this draws red. Slots past 16 also widen the web frame's uniform block.\n\nuniform float u0 = 1;\nuniform float u1 = 2;\nuniform float u2 = 3;\nuniform float u3 = 4;\nuniform float u4 = 5;\nuniform float u5 = 6;\nuniform float u6 = 7;\nuniform float u7 = 8;\nuniform float u8 = 9;\nuniform float u9 = 10;\nuniform float u10 = 11;\nuniform float u11 = 12;\nuniform float u12 = 13;\nuniform float u13 = 14;\nuniform float u14 = 15;\nuniform float u15 = 16;\nuniform float u16 = 17;\nuniform float u17 = 18;\nuniform float u18 = 19;\nuniform float u19 = 20;\nuniform float u20 = 21;\nuniform float u21 = 22;\nuniform float u22 = 23;\nuniform float u23 = 24;\nuniform float u24 = 25;\nuniform float u25 = 26;\nuniform float u26 = 27;\nuniform float u27 = 28;\nuniform float u28 = 29;\nuniform float u29 = 30;\nuniform float u30 = 31;\nuniform float u31 = 32;\nuniform float u32 = 33;\nuniform float u33 = 34;\nuniform float u34 = 35;\nuniform float u35 = 36;\nuniform float u36 = 37;\nuniform float u37 = 38;\nuniform float u38 = 39;\nuniform float u39 = 40;\nuniform float u40 = 41;\nuniform float u41 = 42;\nuniform float u42 = 43;\nuniform float u43 = 44;\nuniform float u44 = 45;\nuniform float u45 = 46;\nuniform float u46 = 47;\nuniform float u47 = 48;\nuniform float u48 = 49;\nuniform float u49 = 50;\nuniform float u50 = 51;\nuniform float u51 = 52;\nuniform float u52 = 53;\nuniform float u53 = 54;\nuniform float u54 = 55;\nuniform float u55 = 56;\nuniform float u56 = 57;\nuniform float u57 = 58;\nuniform float u58 = 59;\nuniform float u59 = 60;\nuniform float u60 = 61;\nuniform float u61 = 62;\nuniform float u62 = 63;\nuniform float u63 = 64;\nfloat4 main() {\n float off = abs(u0 - 1) + abs(u1 - 2) + abs(u2 - 3) + abs(u3 - 4) + abs(u4 - 5) + abs(u5 - 6)\n + abs(u6 - 7) + abs(u7 - 8) + abs(u8 - 9) + abs(u9 - 10) + abs(u10 - 11) + abs(u11 - 12)\n + abs(u12 - 13) + abs(u13 - 14) + abs(u14 - 15) + abs(u15 - 16) + abs(u16 - 17) + abs(u17 - 18)\n + abs(u18 - 19) + abs(u19 - 20) + abs(u20 - 21) + abs(u21 - 22) + abs(u22 - 23) + abs(u23 - 24)\n + abs(u24 - 25) + abs(u25 - 26) + abs(u26 - 27) + abs(u27 - 28) + abs(u28 - 29) + abs(u29 - 30)\n + abs(u30 - 31) + abs(u31 - 32) + abs(u32 - 33) + abs(u33 - 34) + abs(u34 - 35) + abs(u35 - 36)\n + abs(u36 - 37) + abs(u37 - 38) + abs(u38 - 39) + abs(u39 - 40) + abs(u40 - 41) + abs(u41 - 42)\n + abs(u42 - 43) + abs(u43 - 44) + abs(u44 - 45) + abs(u45 - 46) + abs(u46 - 47) + abs(u47 - 48)\n + abs(u48 - 49) + abs(u49 - 50) + abs(u50 - 51) + abs(u51 - 52) + abs(u52 - 53) + abs(u53 - 54)\n + abs(u54 - 55) + abs(u55 - 56) + abs(u56 - 57) + abs(u57 - 58) + abs(u58 - 59) + abs(u59 - 60)\n + abs(u60 - 61) + abs(u61 - 62) + abs(u62 - 63) + abs(u63 - 64);\n return float4(1, off > 0.5 ? 1 : 0, 0, 1);\n}\n",
351
+ "samples": {
352
+ "0": [255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255],
353
+ "1.25": [255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255]
354
+ }
355
+ },
356
+ "wrap-mirror.sl": {
357
+ "hash": "31800abb",
358
+ "source": "// An anchor for [Wrap(Mirror)]: the goldens' texture over three tiles each way,\n// every other tile flipped, so the middle tile is the image as it is and the\n// tiles either side are its reflections.\n[Wrap(Mirror)] texture2D t;\nfloat4 main() { return tex2D(t, uv * 3 - 1); }\n",
359
+ "samples": {
360
+ "0": [227,227,150,255,178,227,155,255,131,227,148,255,83,227,142,255,37,227,150,255,16,227,141,255,64,227,150,255,110,227,155,255,159,227,148,255,206,227,142,255,240,227,156,255,210,227,142,255,163,227,150,255,114,227,155,255,68,227,148,255,19,227,142,255,227,178,155,255,178,178,190,255,131,178,142,255,83,178,83,255,37,178,155,255,16,178,67,255,64,178,155,255,110,178,190,255,159,178,142,255,206,178,83,255,240,178,195,255,210,178,83,255,163,178,155,255,114,178,190,255,68,178,142,255,19,178,83,255,227,131,148,255,178,131,142,255,131,131,150,255,83,131,155,255,37,131,148,255,16,131,156,255,64,131,148,255,110,131,142,255,159,131,150,255,206,131,155,255,240,131,141,255,210,131,155,255,163,131,148,255,114,131,142,255,68,131,150,255,19,131,155,255,227,83,142,255,178,83,83,255,131,83,155,255,83,83,190,255,37,83,142,255,16,83,195,255,64,83,142,255,110,83,83,255,159,83,155,255,206,83,190,255,240,83,67,255,210,83,190,255,163,83,142,255,114,83,83,255,68,83,155,255,19,83,190,255,227,37,150,255,178,37,155,255,131,37,148,255,83,37,142,255,37,37,150,255,16,37,141,255,64,37,150,255,110,37,155,255,159,37,148,255,206,37,142,255,240,37,156,255,210,37,142,255,163,37,150,255,114,37,155,255,68,37,148,255,19,37,142,255,227,16,141,255,178,16,67,255,131,16,156,255,83,16,195,255,37,16,141,255,16,16,200,255,64,16,141,255,110,16,67,255,159,16,156,255,206,16,195,255,240,16,40,255,210,16,195,255,163,16,141,255,114,16,67,255,68,16,156,255,19,16,195,255,227,64,150,255,178,64,155,255,131,64,148,255,83,64,142,255,37,64,150,255,16,64,141,255,64,64,150,255,110,64,155,255,159,64,148,255,206,64,142,255,240,64,156,255,210,64,142,255,163,64,150,255,114,64,155,255,68,64,148,255,19,64,142,255,227,110,155,255,178,110,190,255,131,110,142,255,83,110,83,255,37,110,155,255,16,110,67,255,64,110,155,255,110,110,190,255,159,110,142,255,206,110,83,255,240,110,195,255,210,110,83,255,163,110,155,255,114,110,190,255,68,110,142,255,19,110,83,255,227,159,148,255,178,159,142,255,131,159,150,255,83,159,155,255,37,159,148,255,16,159,156,255,64,159,148,255,110,159,142,255,159,159,150,255,206,159,155,255,240,159,141,255,210,159,155,255,163,159,148,255,114,159,142,255,68,159,150,255,19,159,155,255,227,206,142,255,178,206,83,255,131,206,155,255,83,206,190,255,37,206,142,255,16,206,195,255,64,206,142,255,110,206,83,255,159,206,155,255,206,206,190,255,240,206,67,255,210,206,190,255,163,206,142,255,114,206,83,255,68,206,155,255,19,206,190,255,227,240,156,255,178,240,195,255,131,240,141,255,83,240,67,255,37,240,156,255,16,240,40,255,64,240,156,255,110,240,195,255,159,240,141,255,206,240,67,255,240,240,200,255,210,240,67,255,163,240,156,255,114,240,195,255,68,240,141,255,19,240,67,255,227,210,142,255,178,210,83,255,131,210,155,255,83,210,190,255,37,210,142,255,16,210,195,255,64,210,142,255,110,210,83,255,159,210,155,255,206,210,190,255,240,210,67,255,210,210,190,255,163,210,142,255,114,210,83,255,68,210,155,255,19,210,190,255,227,163,150,255,178,163,155,255,131,163,148,255,83,163,142,255,37,163,150,255,16,163,141,255,64,163,150,255,110,163,155,255,159,163,148,255,206,163,142,255,240,163,156,255,210,163,142,255,163,163,150,255,114,163,155,255,68,163,148,255,19,163,142,255,227,114,155,255,178,114,190,255,131,114,142,255,83,114,83,255,37,114,155,255,16,114,67,255,64,114,155,255,110,114,190,255,159,114,142,255,206,114,83,255,240,114,195,255,210,114,83,255,163,114,155,255,114,114,190,255,68,114,142,255,19,114,83,255,227,68,148,255,178,68,142,255,131,68,150,255,83,68,155,255,37,68,148,255,16,68,156,255,64,68,148,255,110,68,142,255,159,68,150,255,206,68,155,255,240,68,141,255,210,68,155,255,163,68,148,255,114,68,142,255,68,68,150,255,19,68,155,255,227,19,142,255,178,19,83,255,131,19,155,255,83,19,190,255,37,19,142,255,16,19,195,255,64,19,142,255,110,19,83,255,159,19,155,255,206,19,190,255,240,19,67,255,210,19,190,255,163,19,142,255,114,19,83,255,68,19,155,255,19,19,190,255],
361
+ "1.25": [227,227,150,255,178,227,155,255,131,227,148,255,83,227,142,255,37,227,150,255,16,227,141,255,64,227,150,255,110,227,155,255,159,227,148,255,206,227,142,255,240,227,156,255,210,227,142,255,163,227,150,255,114,227,155,255,68,227,148,255,19,227,142,255,227,178,155,255,178,178,190,255,131,178,142,255,83,178,83,255,37,178,155,255,16,178,67,255,64,178,155,255,110,178,190,255,159,178,142,255,206,178,83,255,240,178,195,255,210,178,83,255,163,178,155,255,114,178,190,255,68,178,142,255,19,178,83,255,227,131,148,255,178,131,142,255,131,131,150,255,83,131,155,255,37,131,148,255,16,131,156,255,64,131,148,255,110,131,142,255,159,131,150,255,206,131,155,255,240,131,141,255,210,131,155,255,163,131,148,255,114,131,142,255,68,131,150,255,19,131,155,255,227,83,142,255,178,83,83,255,131,83,155,255,83,83,190,255,37,83,142,255,16,83,195,255,64,83,142,255,110,83,83,255,159,83,155,255,206,83,190,255,240,83,67,255,210,83,190,255,163,83,142,255,114,83,83,255,68,83,155,255,19,83,190,255,227,37,150,255,178,37,155,255,131,37,148,255,83,37,142,255,37,37,150,255,16,37,141,255,64,37,150,255,110,37,155,255,159,37,148,255,206,37,142,255,240,37,156,255,210,37,142,255,163,37,150,255,114,37,155,255,68,37,148,255,19,37,142,255,227,16,141,255,178,16,67,255,131,16,156,255,83,16,195,255,37,16,141,255,16,16,200,255,64,16,141,255,110,16,67,255,159,16,156,255,206,16,195,255,240,16,40,255,210,16,195,255,163,16,141,255,114,16,67,255,68,16,156,255,19,16,195,255,227,64,150,255,178,64,155,255,131,64,148,255,83,64,142,255,37,64,150,255,16,64,141,255,64,64,150,255,110,64,155,255,159,64,148,255,206,64,142,255,240,64,156,255,210,64,142,255,163,64,150,255,114,64,155,255,68,64,148,255,19,64,142,255,227,110,155,255,178,110,190,255,131,110,142,255,83,110,83,255,37,110,155,255,16,110,67,255,64,110,155,255,110,110,190,255,159,110,142,255,206,110,83,255,240,110,195,255,210,110,83,255,163,110,155,255,114,110,190,255,68,110,142,255,19,110,83,255,227,159,148,255,178,159,142,255,131,159,150,255,83,159,155,255,37,159,148,255,16,159,156,255,64,159,148,255,110,159,142,255,159,159,150,255,206,159,155,255,240,159,141,255,210,159,155,255,163,159,148,255,114,159,142,255,68,159,150,255,19,159,155,255,227,206,142,255,178,206,83,255,131,206,155,255,83,206,190,255,37,206,142,255,16,206,195,255,64,206,142,255,110,206,83,255,159,206,155,255,206,206,190,255,240,206,67,255,210,206,190,255,163,206,142,255,114,206,83,255,68,206,155,255,19,206,190,255,227,240,156,255,178,240,195,255,131,240,141,255,83,240,67,255,37,240,156,255,16,240,40,255,64,240,156,255,110,240,195,255,159,240,141,255,206,240,67,255,240,240,200,255,210,240,67,255,163,240,156,255,114,240,195,255,68,240,141,255,19,240,67,255,227,210,142,255,178,210,83,255,131,210,155,255,83,210,190,255,37,210,142,255,16,210,195,255,64,210,142,255,110,210,83,255,159,210,155,255,206,210,190,255,240,210,67,255,210,210,190,255,163,210,142,255,114,210,83,255,68,210,155,255,19,210,190,255,227,163,150,255,178,163,155,255,131,163,148,255,83,163,142,255,37,163,150,255,16,163,141,255,64,163,150,255,110,163,155,255,159,163,148,255,206,163,142,255,240,163,156,255,210,163,142,255,163,163,150,255,114,163,155,255,68,163,148,255,19,163,142,255,227,114,155,255,178,114,190,255,131,114,142,255,83,114,83,255,37,114,155,255,16,114,67,255,64,114,155,255,110,114,190,255,159,114,142,255,206,114,83,255,240,114,195,255,210,114,83,255,163,114,155,255,114,114,190,255,68,114,142,255,19,114,83,255,227,68,148,255,178,68,142,255,131,68,150,255,83,68,155,255,37,68,148,255,16,68,156,255,64,68,148,255,110,68,142,255,159,68,150,255,206,68,155,255,240,68,141,255,210,68,155,255,163,68,148,255,114,68,142,255,68,68,150,255,19,68,155,255,227,19,142,255,178,19,83,255,131,19,155,255,83,19,190,255,37,19,142,255,16,19,195,255,64,19,142,255,110,19,83,255,159,19,155,255,206,19,190,255,240,19,67,255,210,19,190,255,163,19,142,255,114,19,83,255,68,19,155,255,19,19,190,255]
362
+ }
363
+ },
364
+ "wrap-repeat.sl": {
365
+ "hash": "42fd2cf7",
366
+ "source": "// An anchor for [Wrap(Repeat)]: the goldens' texture tiled three times each\n// way, which the host binds clamped. A texture held at its edge shows as\n// stripes, and a seam at a tile edge as a hard line where the filter should\n// have blended the last column into the first.\n[Wrap(Repeat)] texture2D t;\nfloat4 main() { return tex2D(t, uv * 3 - 1); }\n",
367
+ "samples": {
368
+ "0": [34,34,150,255,78,34,155,255,127,34,148,255,174,34,142,255,223,34,150,255,69,34,155,255,64,34,148,255,110,34,142,255,159,34,150,255,206,34,155,255,186,34,148,255,47,34,142,255,96,34,150,255,142,34,155,255,191,34,148,255,238,34,142,255,34,78,155,255,78,78,190,255,127,78,142,255,174,78,83,255,223,78,155,255,69,78,190,255,64,78,142,255,110,78,83,255,159,78,155,255,206,78,190,255,186,78,142,255,47,78,83,255,96,78,155,255,142,78,190,255,191,78,142,255,238,78,83,255,34,127,148,255,78,127,142,255,127,127,150,255,174,127,155,255,223,127,148,255,69,127,142,255,64,127,150,255,110,127,155,255,159,127,148,255,206,127,142,255,186,127,150,255,47,127,155,255,96,127,148,255,142,127,142,255,191,127,150,255,238,127,155,255,34,174,142,255,78,174,83,255,127,174,155,255,174,174,190,255,223,174,142,255,69,174,83,255,64,174,155,255,110,174,190,255,159,174,142,255,206,174,83,255,186,174,155,255,47,174,190,255,96,174,142,255,142,174,83,255,191,174,155,255,238,174,190,255,34,223,150,255,78,223,155,255,127,223,148,255,174,223,142,255,223,223,150,255,69,223,155,255,64,223,148,255,110,223,142,255,159,223,150,255,206,223,155,255,186,223,148,255,47,223,142,255,96,223,150,255,142,223,155,255,191,223,148,255,238,223,142,255,34,69,155,255,78,69,190,255,127,69,142,255,174,69,83,255,223,69,155,255,69,69,190,255,64,69,142,255,110,69,83,255,159,69,155,255,206,69,190,255,186,69,142,255,47,69,83,255,96,69,155,255,142,69,190,255,191,69,142,255,238,69,83,255,34,64,148,255,78,64,142,255,127,64,150,255,174,64,155,255,223,64,148,255,69,64,142,255,64,64,150,255,110,64,155,255,159,64,148,255,206,64,142,255,186,64,150,255,47,64,155,255,96,64,148,255,142,64,142,255,191,64,150,255,238,64,155,255,34,110,142,255,78,110,83,255,127,110,155,255,174,110,190,255,223,110,142,255,69,110,83,255,64,110,155,255,110,110,190,255,159,110,142,255,206,110,83,255,186,110,155,255,47,110,190,255,96,110,142,255,142,110,83,255,191,110,155,255,238,110,190,255,34,159,150,255,78,159,155,255,127,159,148,255,174,159,142,255,223,159,150,255,69,159,155,255,64,159,148,255,110,159,142,255,159,159,150,255,206,159,155,255,186,159,148,255,47,159,142,255,96,159,150,255,142,159,155,255,191,159,148,255,238,159,142,255,34,206,155,255,78,206,190,255,127,206,142,255,174,206,83,255,223,206,155,255,69,206,190,255,64,206,142,255,110,206,83,255,159,206,155,255,206,206,190,255,186,206,142,255,47,206,83,255,96,206,155,255,142,206,190,255,191,206,142,255,238,206,83,255,34,186,148,255,78,186,142,255,127,186,150,255,174,186,155,255,223,186,148,255,69,186,142,255,64,186,150,255,110,186,155,255,159,186,148,255,206,186,142,255,186,186,150,255,47,186,155,255,96,186,148,255,142,186,142,255,191,186,150,255,238,186,155,255,34,47,142,255,78,47,83,255,127,47,155,255,174,47,190,255,223,47,142,255,69,47,83,255,64,47,155,255,110,47,190,255,159,47,142,255,206,47,83,255,186,47,155,255,47,47,190,255,96,47,142,255,142,47,83,255,191,47,155,255,238,47,190,255,34,96,150,255,78,96,155,255,127,96,148,255,174,96,142,255,223,96,150,255,69,96,155,255,64,96,148,255,110,96,142,255,159,96,150,255,206,96,155,255,186,96,148,255,47,96,142,255,96,96,150,255,142,96,155,255,191,96,148,255,238,96,142,255,34,142,155,255,78,142,190,255,127,142,142,255,174,142,83,255,223,142,155,255,69,142,190,255,64,142,142,255,110,142,83,255,159,142,155,255,206,142,190,255,186,142,142,255,47,142,83,255,96,142,155,255,142,142,190,255,191,142,142,255,238,142,83,255,34,191,148,255,78,191,142,255,127,191,150,255,174,191,155,255,223,191,148,255,69,191,142,255,64,191,150,255,110,191,155,255,159,191,148,255,206,191,142,255,186,191,150,255,47,191,155,255,96,191,148,255,142,191,142,255,191,191,150,255,238,191,155,255,34,238,142,255,78,238,83,255,127,238,155,255,174,238,190,255,223,238,142,255,69,238,83,255,64,238,155,255,110,238,190,255,159,238,142,255,206,238,83,255,186,238,155,255,47,238,190,255,96,238,142,255,142,238,83,255,191,238,155,255,238,238,190,255],
369
+ "1.25": [34,34,150,255,78,34,155,255,127,34,148,255,174,34,142,255,223,34,150,255,69,34,155,255,64,34,148,255,110,34,142,255,159,34,150,255,206,34,155,255,186,34,148,255,47,34,142,255,96,34,150,255,142,34,155,255,191,34,148,255,238,34,142,255,34,78,155,255,78,78,190,255,127,78,142,255,174,78,83,255,223,78,155,255,69,78,190,255,64,78,142,255,110,78,83,255,159,78,155,255,206,78,190,255,186,78,142,255,47,78,83,255,96,78,155,255,142,78,190,255,191,78,142,255,238,78,83,255,34,127,148,255,78,127,142,255,127,127,150,255,174,127,155,255,223,127,148,255,69,127,142,255,64,127,150,255,110,127,155,255,159,127,148,255,206,127,142,255,186,127,150,255,47,127,155,255,96,127,148,255,142,127,142,255,191,127,150,255,238,127,155,255,34,174,142,255,78,174,83,255,127,174,155,255,174,174,190,255,223,174,142,255,69,174,83,255,64,174,155,255,110,174,190,255,159,174,142,255,206,174,83,255,186,174,155,255,47,174,190,255,96,174,142,255,142,174,83,255,191,174,155,255,238,174,190,255,34,223,150,255,78,223,155,255,127,223,148,255,174,223,142,255,223,223,150,255,69,223,155,255,64,223,148,255,110,223,142,255,159,223,150,255,206,223,155,255,186,223,148,255,47,223,142,255,96,223,150,255,142,223,155,255,191,223,148,255,238,223,142,255,34,69,155,255,78,69,190,255,127,69,142,255,174,69,83,255,223,69,155,255,69,69,190,255,64,69,142,255,110,69,83,255,159,69,155,255,206,69,190,255,186,69,142,255,47,69,83,255,96,69,155,255,142,69,190,255,191,69,142,255,238,69,83,255,34,64,148,255,78,64,142,255,127,64,150,255,174,64,155,255,223,64,148,255,69,64,142,255,64,64,150,255,110,64,155,255,159,64,148,255,206,64,142,255,186,64,150,255,47,64,155,255,96,64,148,255,142,64,142,255,191,64,150,255,238,64,155,255,34,110,142,255,78,110,83,255,127,110,155,255,174,110,190,255,223,110,142,255,69,110,83,255,64,110,155,255,110,110,190,255,159,110,142,255,206,110,83,255,186,110,155,255,47,110,190,255,96,110,142,255,142,110,83,255,191,110,155,255,238,110,190,255,34,159,150,255,78,159,155,255,127,159,148,255,174,159,142,255,223,159,150,255,69,159,155,255,64,159,148,255,110,159,142,255,159,159,150,255,206,159,155,255,186,159,148,255,47,159,142,255,96,159,150,255,142,159,155,255,191,159,148,255,238,159,142,255,34,206,155,255,78,206,190,255,127,206,142,255,174,206,83,255,223,206,155,255,69,206,190,255,64,206,142,255,110,206,83,255,159,206,155,255,206,206,190,255,186,206,142,255,47,206,83,255,96,206,155,255,142,206,190,255,191,206,142,255,238,206,83,255,34,186,148,255,78,186,142,255,127,186,150,255,174,186,155,255,223,186,148,255,69,186,142,255,64,186,150,255,110,186,155,255,159,186,148,255,206,186,142,255,186,186,150,255,47,186,155,255,96,186,148,255,142,186,142,255,191,186,150,255,238,186,155,255,34,47,142,255,78,47,83,255,127,47,155,255,174,47,190,255,223,47,142,255,69,47,83,255,64,47,155,255,110,47,190,255,159,47,142,255,206,47,83,255,186,47,155,255,47,47,190,255,96,47,142,255,142,47,83,255,191,47,155,255,238,47,190,255,34,96,150,255,78,96,155,255,127,96,148,255,174,96,142,255,223,96,150,255,69,96,155,255,64,96,148,255,110,96,142,255,159,96,150,255,206,96,155,255,186,96,148,255,47,96,142,255,96,96,150,255,142,96,155,255,191,96,148,255,238,96,142,255,34,142,155,255,78,142,190,255,127,142,142,255,174,142,83,255,223,142,155,255,69,142,190,255,64,142,142,255,110,142,83,255,159,142,155,255,206,142,190,255,186,142,142,255,47,142,83,255,96,142,155,255,142,142,190,255,191,142,142,255,238,142,83,255,34,191,148,255,78,191,142,255,127,191,150,255,174,191,155,255,223,191,148,255,69,191,142,255,64,191,150,255,110,191,155,255,159,191,148,255,206,191,142,255,186,191,150,255,47,191,155,255,96,191,148,255,142,191,142,255,191,191,150,255,238,191,155,255,34,238,142,255,78,238,83,255,127,238,155,255,174,238,190,255,223,238,142,255,69,238,83,255,64,238,155,255,110,238,190,255,159,238,142,255,206,238,83,255,186,238,155,255,47,238,190,255,96,238,142,255,142,238,83,255,191,238,155,255,238,238,190,255]
370
+ }
371
+ },
329
372
  "sdf-circle.sl": {
330
373
  "hash": "0b0033fc",
331
374
  "source": "float4 main() {\n float2 p = (uv - 0.5) * 1.2;\n float d = sdf.circle(p, 0.35);\n return float4(0.5 + 0.5 * cos(d * 40.0), 0.5 + 0.5 * sin(d * 23.0), saturate(0.5 - d * 2.0), 1);\n}",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "onejs-sl",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "The OneJS shader language: a small typed language for per pixel programs, compiled to a portable IR and emitted as HLSL, WGSL or GLSL ES",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
package/src/body.ts CHANGED
@@ -21,7 +21,7 @@
21
21
  * gives common subexpression elimination for free.
22
22
  */
23
23
 
24
- import { INT_BOUNDS, SLError, TYPE, isWhole, valueAt, type InputName, type NodeRef, type StepInputName, type Program, type SLKind, type SLType, type ValueNode } from "./ir"
24
+ import { INT_BOUNDS, SLError, TYPE, isWhole, samplingOf, valueAt, type TextureSampling, type InputName, type NodeRef, type StepInputName, type Program, type SLKind, type SLType, type ValueNode } from "./ir"
25
25
  import { libClosure, LIB_FUNCTIONS } from "./lib"
26
26
  import { LIB_HLSL } from "./lib/hlsl"
27
27
  import { SLOP } from "./ops"
@@ -55,7 +55,8 @@ export interface BodyTarget {
55
55
  * - **Filtered and wrapped by the host.** The body does neither. OneJS's
56
56
  * hosts, the generated shader and the web backends alike, use the
57
57
  * bound texture's own filter and wrap modes, so a host that filters by
58
- * hand draws the same picture by following the texture's settings.
58
+ * hand draws the same picture by following the texture's settings. A
59
+ * texture whose program sets its sampler goes to `sampleWith` instead.
59
60
  *
60
61
  * What becomes of the result is the host's: OneJS writes it to the target
61
62
  * as it is, and a host that composites premultiplied multiplies on write.
@@ -72,6 +73,41 @@ export interface BodyTarget {
72
73
  * `tex2Dlod(s, float4(uv, 0, lod))` and Metal's `sample(s, uv, level(lod))`.
73
74
  */
74
75
  sampleLevel: (slot: number, uv: string, lod: string) => string
76
+ /**
77
+ * A float4 sample of a texture whose program sets its sampler
78
+ * (`[Wrap(Repeat)]`, `[Filter(Point)]`, IR 6), sampled that way whatever
79
+ * the bound texture's own settings: `sample` when `lod` is null, else
80
+ * `sampleLevel` at `lod`, with the same contract as those two in every
81
+ * other respect. `sampling` always has both halves (`samplingOf`):
82
+ *
83
+ * - `wrap`: `repeat` tiles, `mirror` tiles mirrored every other tile,
84
+ * `clamp` holds the edge texel. The filter's footprint wraps the same
85
+ * way, so a tiled texture has no seam.
86
+ * - `filter`: `point` reads the nearest texel and the nearest level,
87
+ * `linear` blends the four nearest texels within the nearest level, as
88
+ * Unity's Bilinear does.
89
+ *
90
+ * Optional, and `emitBody` refuses a program that samples such a texture
91
+ * when a target has none, rather than print one that samples as the
92
+ * bound texture is set. Unity's inline sampler states, a WebGPU sampler
93
+ * and a WebGL2 sampler object each say both halves.
94
+ */
95
+ sampleWith?: (slot: number, uv: string, lod: string | null, sampling: TextureSampling) => string
96
+ /**
97
+ * A float2 of the texture in `slot`'s width and height, in pixels, at full
98
+ * size (`textureSize(t)`, IR 6). Optional, as `previous` is.
99
+ */
100
+ size?: (slot: number) => string
101
+ /**
102
+ * A float4 of one texel of the texture in `slot`, unfiltered, at full size
103
+ * (`tex2Dfetch(t, pixel)`, IR 6). `pixel` is a float2 expression the body
104
+ * has already floored and held inside the texture with `size`, so a host
105
+ * converts it to an int2 and loads: HLSL's `t.Load(int3(pixel, 0))`,
106
+ * Metal's `t.read(uint2(pixel))`. Texel (0, 0) is the one `uv` (0, 0)
107
+ * samples. In the space `colour` names, as `sample` is, so an sRGB texture
108
+ * is decoded. Optional; needs `size` too.
109
+ */
110
+ fetch?: (slot: number, pixel: string) => string
75
111
  /**
76
112
  * A float4 of what this program drew the frame before, at `uv`, for a
77
113
  * host that keeps it (`tex2D(previous, uv)`, `Specs/SL_NEXT.md` 4).
@@ -113,7 +149,7 @@ export interface Body {
113
149
  uses: {
114
150
  /** Uniform slots the body reads, ascending. */
115
151
  uniforms: number[]
116
- /** Texture slots the body samples, ascending. */
152
+ /** Texture slots the body samples, measures or fetches from, ascending. */
117
153
  textures: number[]
118
154
  /** Library functions the body calls, sorted: `sl_fbm`, `sl_sdfDistance`, ... `emitLibrary` prints them. */
119
155
  helpers: string[]
@@ -168,6 +204,26 @@ export function emitBody(p: Program, target: BodyTarget): Body {
168
204
  const c = p.nodes[ref]!
169
205
  return c.k === "const" ? c.v : null
170
206
  }
207
+ /** A texture's sampler, when its program sets one, and the target that has to honour it. */
208
+ const sampling = (slot: number): TextureSampling | null => {
209
+ const s = samplingOf(p.textures[slot]!)
210
+ if (s !== null && target.sampleWith === undefined) {
211
+ throw new SLError(`this target cannot set a texture's sampler, and the program samples ${p.textures[slot]!.name} with ${s.wrap} and ${s.filter}`)
212
+ }
213
+ return s
214
+ }
215
+ const plain = (slot: number, uv: string) => {
216
+ const s = sampling(slot)
217
+ return s === null ? target.sample(slot, uv) : target.sampleWith!(slot, uv, null, s)
218
+ }
219
+ const level = (slot: number, uv: string, lod: string) => {
220
+ const s = sampling(slot)
221
+ return s === null ? target.sampleLevel(slot, uv, lod) : target.sampleWith!(slot, uv, lod, s)
222
+ }
223
+ const size = (slot: number) => {
224
+ if (target.size === undefined) throw new SLError(`this target cannot measure a texture, and the program measures ${p.textures[slot]!.name}`)
225
+ return target.size(slot)
226
+ }
171
227
  const splat = (ref: number, w: SLType) => (valueAt(p.nodes, ref).type === TYPE.FLOAT && w > 1 ? ctor(w, Array(w).fill(name(ref))) : name(ref))
172
228
 
173
229
  const expr = (ref: NodeRef): string => {
@@ -334,7 +390,7 @@ export function emitBody(p: Program, target: BodyTarget): Body {
334
390
  textures.add(slot)
335
391
  // Where pixels part ways there are no neighbours to take a mip
336
392
  // level from, so every backend samples level 0 there (`structure.ts`).
337
- return inVaryingFlow(shape, ref) ? target.sampleLevel(slot, a[0]!, "0.0") : target.sample(slot, a[0]!)
393
+ return inVaryingFlow(shape, ref) ? level(slot, a[0]!, "0.0") : plain(slot, a[0]!)
338
394
  }
339
395
  case SLOP.SAMPLE_LOD: {
340
396
  const slot = Math.round(imm[0] ?? 0)
@@ -343,9 +399,23 @@ export function emitBody(p: Program, target: BodyTarget): Body {
343
399
  // whatever the texture's filter between levels, as the web
344
400
  // emitters do (`isWhole`). Past the smallest level both read the
345
401
  // smallest, as a whole level past it does.
346
- if (isWhole(p.nodes, n.args[1]!)) return target.sampleLevel(slot, a[0]!, a[1]!)
402
+ if (isWhole(p.nodes, n.args[1]!)) return level(slot, a[0]!, a[1]!)
347
403
  const below = `floor(${a[1]})`
348
- return `lerp(${target.sampleLevel(slot, a[0]!, below)}, ${target.sampleLevel(slot, a[0]!, `${below} + 1.0`)}, frac(${a[1]}))`
404
+ return `lerp(${level(slot, a[0]!, below)}, ${level(slot, a[0]!, `${below} + 1.0`)}, frac(${a[1]}))`
405
+ }
406
+ case SLOP.TEXTURE_SIZE: {
407
+ const slot = Math.round(imm[0] ?? 0)
408
+ textures.add(slot)
409
+ return size(slot)
410
+ }
411
+ case SLOP.SAMPLE_FETCH: {
412
+ const slot = Math.round(imm[0] ?? 0)
413
+ textures.add(slot)
414
+ if (target.fetch === undefined) throw new SLError(`this target cannot fetch a texel, and the program reads ${p.textures[slot]!.name} with tex2Dfetch`)
415
+ // Floored and held inside, so a pixel past an edge reads the
416
+ // edge on every host rather than whatever a host's load returns
417
+ // out of range.
418
+ return target.fetch(slot, `clamp(floor(${a[0]}), float2(0.0, 0.0), ${size(slot)} - 1.0)`)
349
419
  }
350
420
  case SLOP.SAMPLE_PREVIOUS:
351
421
  if (target.previous === undefined) throw new SLError("this target keeps no previous frame, and the program samples it")
package/src/core.ts CHANGED
@@ -8,13 +8,14 @@
8
8
  * game never executes.
9
9
  */
10
10
  export * as sl from "./sl"
11
- export type { Float, Vec2, Vec3, Vec4, Num, ProgramInputs, PreviousFrame, Texture } from "./sl"
11
+ export type { Float, Vec2, Vec3, Vec4, Num, ProgramInputs, PreviousFrame, Texture, TextureSamplingOptions } from "./sl"
12
12
  export {
13
13
  TYPE, INPUTS, STEP_INPUTS, PREVIOUS, MAX_NODES, SLError, hashProgram, widthName, SL_IR_VERSION, SL_HASH_VERSION,
14
- inputsUsed, readsOf, CONTROL_FIELDS, controlProblem,
14
+ inputsUsed, readsOf, CONTROL_FIELDS, controlProblem, samplingOf, TEXTURE_WRAPS, TEXTURE_FILTERS,
15
15
  } from "./ir"
16
16
  export type {
17
17
  SLType, InputName, StepInputName, HostInputName, SLReads, NodeRef, SLNode, Program, UniformDecl, UniformControl, TextureDecl,
18
+ TextureSampling, TextureWrap, TextureFilter,
18
19
  } from "./ir"
19
20
  export { SLOP, SL_ARITY, SL_NAME, INPUT_ID, isSampling, UNIFORM_SLOTS, TEXTURE_SLOTS } from "./ops"
20
21
  export type { SLOpCode } from "./ops"
package/src/hlsl.ts CHANGED
@@ -15,8 +15,9 @@
15
15
  * next time it is generated.
16
16
  */
17
17
 
18
- import { SLError, SL_HASH_VERSION, readsOf, type Program } from "./ir"
18
+ import { SLError, SL_HASH_VERSION, readsOf, reachable, samplingOf, type Program, type TextureSampling } from "./ir"
19
19
  import { emitBody, lit, type BodyTarget } from "./body"
20
+ import { SLOP } from "./ops"
20
21
 
21
22
  /** The property name a uniform gets. Prefixed so it cannot collide with ours. */
22
23
  export function uniformProperty(name: string): string {
@@ -49,6 +50,7 @@ export function emitShader(p: Program, options: EmitOptions = {}): string {
49
50
  const include = options.include ?? "SLCommon.cginc"
50
51
  const body = emitFragmentBody(p)
51
52
  const reads = readsOf(p)
53
+ const use = textureUse(p)
52
54
 
53
55
  const props: string[] = [
54
56
  ` _Secs ("Seconds", Float) = 0`,
@@ -68,7 +70,22 @@ export function emitShader(p: Program, options: EmitOptions = {}): string {
68
70
  }
69
71
  for (const t of p.textures) {
70
72
  props.push(` _Tex${t.slot} ("${t.name}", 2D) = "white" {}`)
71
- decls.push(` sampler2D _Tex${t.slot};`)
73
+ // A texture sampled as it is set is the sampler2D it always was, so
74
+ // every program before IR 6 prints the shader it always did. One the
75
+ // program sets a sampler for, or fetches from, is a Texture2D: the
76
+ // inline sampler state or the Load needs the texture on its own.
77
+ if (!use.object.has(t.slot)) decls.push(` sampler2D _Tex${t.slot};`)
78
+ else {
79
+ decls.push(` Texture2D _Tex${t.slot};`)
80
+ // Its own settings, by Unity's naming rule, for a plain sample.
81
+ if (use.plain.has(t.slot)) decls.push(` SamplerState sampler_Tex${t.slot};`)
82
+ }
83
+ // Unity fills it from the bound texture: (1 / width, 1 / height, width, height).
84
+ if (use.sized.has(t.slot)) decls.push(` float4 _Tex${t.slot}_TexelSize;`)
85
+ }
86
+ // Unity's inline sampler states: the name says the filter and the wrap.
87
+ for (const name of [...new Set(p.textures.map(samplingOf).filter((s) => s !== null).map(inlineSampler))].sort()) {
88
+ decls.push(` SamplerState ${name};`)
72
89
  }
73
90
  // Only for a program that samples it, so every other program's shader is
74
91
  // the text it always was. Transparent black is the previous frame's clear
@@ -143,6 +160,7 @@ ${body}
143
160
  * shader compile, so this target always emits it.
144
161
  */
145
162
  function unityTarget(p: Program): BodyTarget {
163
+ const use = textureUse(p)
146
164
  return {
147
165
  // `_Res` is the TARGET's size, set by the host, not `_ScreenParams`.
148
166
  //
@@ -164,8 +182,15 @@ function unityTarget(p: Program): BodyTarget {
164
182
  deltaTime: "_Res.w",
165
183
  },
166
184
  uniform: (slot) => uniformProperty(p.uniforms[slot]!.name),
167
- sample: (slot, uv) => `tex2D(_Tex${slot}, ${uv})`,
168
- sampleLevel: (slot, uv, lod) => `tex2Dlod(_Tex${slot}, float4(${uv}, 0.0, ${lod}))`,
185
+ sample: (slot, uv) => use.object.has(slot) ? `_Tex${slot}.Sample(sampler_Tex${slot}, ${uv})` : `tex2D(_Tex${slot}, ${uv})`,
186
+ sampleLevel: (slot, uv, lod) => use.object.has(slot)
187
+ ? `_Tex${slot}.SampleLevel(sampler_Tex${slot}, ${uv}, ${lod})`
188
+ : `tex2Dlod(_Tex${slot}, float4(${uv}, 0.0, ${lod}))`,
189
+ sampleWith: (slot, uv, lod, s) => lod === null
190
+ ? `_Tex${slot}.Sample(${inlineSampler(s)}, ${uv})`
191
+ : `_Tex${slot}.SampleLevel(${inlineSampler(s)}, ${uv}, ${lod})`,
192
+ size: (slot) => `_Tex${slot}_TexelSize.zw`,
193
+ fetch: (slot, pixel) => `_Tex${slot}.Load(int3(${pixel}, 0))`,
169
194
  // Flipped as this frame flipped the uv it wrote at, so a read at a
170
195
  // pixel's own uv is that pixel whichever way the host's target runs.
171
196
  previous: (uv) => `tex2Dlod(_Prev, float4(${uv} * float2(1.0, 1.0 - 2.0 * _FlipY) + float2(0.0, _FlipY), 0.0, 0.0))`,
@@ -175,6 +200,36 @@ function unityTarget(p: Program): BodyTarget {
175
200
  }
176
201
  }
177
202
 
203
+ /**
204
+ * An inline sampler state's name. Unity reads the filter and the wrap from the
205
+ * name itself ("point" or "linear", "clamp", "repeat" or "mirror").
206
+ */
207
+ function inlineSampler(s: TextureSampling): string {
208
+ return `sl_sampler_${s.filter}_${s.wrap}`
209
+ }
210
+
211
+ /**
212
+ * How the program reaches each texture slot, which decides how the shader
213
+ * declares it. `object`: declared a Texture2D, because the program sets its
214
+ * sampler or fetches from it. `plain`: an object sampled with its own
215
+ * settings, which needs Unity's `sampler_` state. `sized`: reads `_TexelSize`,
216
+ * as `textureSize` and a fetch's bounds do.
217
+ */
218
+ function textureUse(p: Program): { object: Set<number>; plain: Set<number>; sized: Set<number> } {
219
+ const fetched = new Set<number>(), sampled = new Set<number>(), sized = new Set<number>()
220
+ for (const ref of reachable(p.nodes, p.result)) {
221
+ const n = p.nodes[ref]!
222
+ if (n.k !== "call") continue
223
+ const slot = Math.round(n.imm?.[0] ?? 0)
224
+ if (n.op === SLOP.SAMPLE || n.op === SLOP.SAMPLE_LOD) sampled.add(slot)
225
+ else if (n.op === SLOP.TEXTURE_SIZE) sized.add(slot)
226
+ else if (n.op === SLOP.SAMPLE_FETCH) { fetched.add(slot); sized.add(slot) }
227
+ }
228
+ const object = new Set(p.textures.filter((t) => samplingOf(t) !== null || fetched.has(t.slot)).map((t) => t.slot))
229
+ const plain = new Set([...sampled].filter((slot) => object.has(slot) && samplingOf(p.textures[slot]!) === null))
230
+ return { object, plain, sized }
231
+ }
232
+
178
233
  /** The straight line body: one local per reachable node, in order. */
179
234
  export function emitFragmentBody(p: Program): string {
180
235
  return emitBody(p, unityTarget(p)).body
package/src/index.ts CHANGED
@@ -18,10 +18,10 @@
18
18
  */
19
19
  export * from "./core"
20
20
  export {
21
- analyze, classify, diagnose, parse, parseUnit, preludeFunctions, tokenize, PRELUDE_SOURCE, SLParseError,
21
+ analyze, classify, classifyLine, diagnose, parse, parseUnit, preludeFunctions, tokenize, PRELUDE_SOURCE, SLParseError,
22
22
  } from "./lang"
23
23
  export type {
24
- Checked, Expr, FuncDecl, ParseOptions, Pos, SLClassifiedToken, SLFix, SLTokenClass, Stmt, Token, Unit,
24
+ Checked, Expr, FuncDecl, ParseOptions, Pos, SLClassifiedToken, SLFix, SLLineState, SLTokenClass, Stmt, Token, Unit,
25
25
  } from "./lang"
26
26
  export { fromGLSL } from "./lang/glsl"
27
27
  export type { FromGLSL } from "./lang/glsl"