onejs-sl 0.6.0 → 0.7.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/src/web.ts CHANGED
@@ -12,13 +12,22 @@
12
12
  * named `n<index>`. What differs is the contract with the host, which is fixed
13
13
  * and the same for both languages:
14
14
  *
15
- * sl_Res (target width, target height, seconds, 0)
16
- * sl_Opt (1 in a Linear colour space project else 0, 1 to flip uv.y, 0, 0)
15
+ * sl_Res (target width, target height, seconds, frame)
16
+ * sl_Opt (1 in a Linear colour space project else 0, 1 to flip uv.y, deltaTime, 0)
17
17
  * sl_U[16] uniform slots, each a vec4, in the program's slot order
18
18
  * textures by slot: GLSL `sl_Tex<slot>`; WGSL `sl_tex<slot>` at binding
19
19
  * 2 + 2 * slot with its own sampler `sl_samp<slot>` at 1 + 2 * slot,
20
20
  * all in group 0 beside the frame block at binding 0. Only the
21
21
  * slots the program samples are declared.
22
+ * the previous frame, only for a program that samples it: GLSL `sl_Prev`;
23
+ * WGSL `sl_prev` with its sampler `sl_prevSamp`, at the two
24
+ * bindings after the last texture slot's, whatever the program
25
+ * declares. Read at level 0 (`body.ts`, `BodyTarget.previous`),
26
+ * its y flipped when `sl_Opt.y` flips uv, so the texture the host
27
+ * drew last frame reads back the way it was written.
28
+ *
29
+ * `frame` and `deltaTime` ride in components that were 0, and a host sets
30
+ * them only for a program that reads them (`readsOf`).
22
31
  *
23
32
  * WGSL also carries its vertex stage (`sl_vs`, a full-target triangle from the
24
33
  * vertex index) so one module is one pipeline; the GLSL host supplies its own.
@@ -30,7 +39,7 @@ import { inVaryingFlow, local, printBody, structure, type Syntax } from "./struc
30
39
  import { libClosure, libIndex, LIB_FUNCTIONS, SDF_CALLS } from "./lib"
31
40
  import { LIB_GLSL } from "./lib/glsl"
32
41
  import { LIB_WGSL } from "./lib/wgsl"
33
- import { INPUT_ID, SLOP, UNIFORM_SLOTS } from "./ops"
42
+ import { INPUT_ID, SLOP, TEXTURE_SLOTS, UNIFORM_SLOTS } from "./ops"
34
43
 
35
44
  export type WebLanguage = "glsl" | "wgsl"
36
45
 
@@ -50,6 +59,8 @@ function emitWeb(p: Program, lang: WebLanguage): string {
50
59
  const need = new Set<number>()
51
60
  const smoothsteps = new Set<SLType>()
52
61
  const sampled = new Set<number>()
62
+ /** Whether the body samples the previous frame, which declares its binding. */
63
+ let previous = false
53
64
  const shape = structure(p)
54
65
  const T = (t: SLType) => (W ? (t === 1 ? "f32" : `vec${t}f`) : t === 1 ? "float" : `vec${t}`)
55
66
  /** A value's type in this language, its kind included. */
@@ -90,7 +101,10 @@ function emitWeb(p: Program, lang: WebLanguage): string {
90
101
  case 1: return `(sl_uv * ${res}.xy)`
91
102
  case 2: return `${res}.xy`
92
103
  case 3: return `${res}.z`
93
- default: return `(${res}.x / max(${res}.y, 1.0))`
104
+ case 4: return `(${res}.x / max(${res}.y, 1.0))`
105
+ case 5: return `${res}.w`
106
+ case 6: return W ? "sl.opt.z" : "sl_Opt.z"
107
+ default: throw new Error(`no web mapping for the input "${n.name}"`)
94
108
  }
95
109
  }
96
110
  case "uniform": {
@@ -251,6 +265,13 @@ function emitWeb(p: Program, lang: WebLanguage): string {
251
265
  ? `textureSampleLevel(sl_tex${slot}, sl_samp${slot}, ${a[0]}, ${a[1]})`
252
266
  : `textureLod(sl_Tex${slot}, ${a[0]}, ${a[1]})`
253
267
  }
268
+ case SLOP.SAMPLE_PREVIOUS:
269
+ previous = true
270
+ // Flipped as this frame flipped the uv it wrote at, so a read at
271
+ // a pixel's own uv is that pixel on either backend.
272
+ return W
273
+ ? `textureSampleLevel(sl_prev, sl_prevSamp, ${a[0]} * vec2f(1.0, 1.0 - 2.0 * sl.opt.y) + vec2f(0.0, sl.opt.y), 0.0)`
274
+ : `textureLod(sl_Prev, ${a[0]} * vec2(1.0, 1.0 - 2.0 * sl_Opt.y) + vec2(0.0, sl_Opt.y), 0.0)`
254
275
  default:
255
276
  throw new SLError(
256
277
  `the ${lang.toUpperCase()} emitter has no case for opcode ${n.op}. A program using it would ` +
@@ -342,9 +363,12 @@ function emitWeb(p: Program, lang: WebLanguage): string {
342
363
  const textures = p.textures.filter((t) => sampled.has(t.slot))
343
364
 
344
365
  if (W) {
345
- const bindings = textures.map((t) =>
366
+ const bindings = [...textures.map((t) =>
346
367
  `@group(0) @binding(${1 + 2 * t.slot}) var sl_samp${t.slot}: sampler;\n` +
347
- `@group(0) @binding(${2 + 2 * t.slot}) var sl_tex${t.slot}: texture_2d<f32>;`).join("\n")
368
+ `@group(0) @binding(${2 + 2 * t.slot}) var sl_tex${t.slot}: texture_2d<f32>;`),
369
+ ...previous ? [
370
+ `@group(0) @binding(${1 + 2 * TEXTURE_SLOTS}) var sl_prevSamp: sampler;\n` +
371
+ `@group(0) @binding(${2 + 2 * TEXTURE_SLOTS}) var sl_prev: texture_2d<f32>;`] : []].join("\n")
348
372
  return `${header}
349
373
  struct SLFrame { res: vec4f, opt: vec4f, u: array<vec4f, ${WEB_UNIFORM_SLOTS}> }
350
374
  @group(0) @binding(0) var<uniform> sl: SLFrame;
@@ -362,7 +386,7 @@ ${body}
362
386
  }
363
387
  `
364
388
  }
365
- const samplers = textures.map((t) => `uniform sampler2D sl_Tex${t.slot};`).join("\n")
389
+ const samplers = [...textures.map((t) => `uniform sampler2D sl_Tex${t.slot};`), ...previous ? ["uniform sampler2D sl_Prev;"] : []].join("\n")
366
390
  return `#version 300 es
367
391
  ${header}
368
392
  precision highp float;