@pixerate/editor 0.242.0 → 0.244.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/dist/animation-editor/index.cjs +59 -59
- package/dist/animation-editor/index.js +3 -3
- package/dist/{brushstrokeRender-MOYGEXOC.js → brushstrokeRender-4542T5HP.js} +3 -3
- package/dist/{brushstrokeRender-UKADOV5D.cjs → brushstrokeRender-QA5WVIDT.cjs} +5 -5
- package/dist/canvas/index.cjs +8 -8
- package/dist/canvas/index.js +1 -1
- package/dist/{chunk-ILM6GYAX.js → chunk-4EQY4TZJ.js} +1 -1
- package/dist/{chunk-5BR7LC24.cjs → chunk-4T47Z4J3.cjs} +68 -6
- package/dist/{chunk-ZDPLZDTT.js → chunk-5RFENYO5.js} +1 -1
- package/dist/{chunk-NE6OOKWJ.js → chunk-7YQNKSQ7.js} +1 -1
- package/dist/{chunk-AFLMXITL.cjs → chunk-BDIH4DYR.cjs} +23 -23
- package/dist/{chunk-HGGJ36HR.cjs → chunk-HZ547SGQ.cjs} +1 -1
- package/dist/{chunk-KCMV2534.cjs → chunk-IZL5V5RK.cjs} +2 -2
- package/dist/{chunk-QP2B3MID.js → chunk-L5PB7EG3.js} +1 -1
- package/dist/{chunk-HW72ABGR.cjs → chunk-M6JORA5Z.cjs} +86 -86
- package/dist/{chunk-UDBDYZET.js → chunk-OSTKS3YN.js} +1 -1
- package/dist/{chunk-HLBTRSQJ.js → chunk-P3NIPIKS.js} +263 -63
- package/dist/{chunk-7F4G74UQ.cjs → chunk-SD23XMVJ.cjs} +35 -35
- package/dist/{chunk-XBZK47LV.js → chunk-TBJEMELS.js} +67 -5
- package/dist/{chunk-XFYLA3ZO.cjs → chunk-VMROIWLL.cjs} +290 -90
- package/dist/image-editor/index.cjs +785 -777
- package/dist/image-editor/index.js +13 -5
- package/dist/kernel-wasm-4KVONDAU.js +9 -0
- package/dist/kernel-wasm-TTYRBGAK.cjs +9 -0
- package/dist/paint/index.cjs +10 -2
- package/dist/paint/index.js +9 -1
- package/dist/paint/wet/film.d.cts +19 -1
- package/dist/paint/wet/film.d.ts +19 -1
- package/dist/paint/wet/gpu-kernels.d.cts +2 -2
- package/dist/paint/wet/gpu-kernels.d.ts +2 -2
- package/dist/paint/wet/kernel-wasm.d.cts +5 -5
- package/dist/paint/wet/kernel-wasm.d.ts +5 -5
- package/dist/paint/wet/kernel.d.cts +1 -1
- package/dist/paint/wet/kernel.d.ts +1 -1
- package/dist/paint/wet/medium.d.cts +3 -1
- package/dist/paint/wet/medium.d.ts +3 -1
- package/dist/paint/wet/model.d.cts +19 -4
- package/dist/paint/wet/model.d.ts +19 -4
- package/dist/paint/wet/world.d.cts +34 -8
- package/dist/paint/wet/world.d.ts +34 -8
- package/dist/paint-editor/backlight.d.cts +77 -0
- package/dist/paint-editor/backlight.d.ts +77 -0
- package/dist/paint-editor/brushes.d.cts +18 -2
- package/dist/paint-editor/brushes.d.ts +18 -2
- package/dist/paint-editor/controller.d.cts +39 -0
- package/dist/paint-editor/controller.d.ts +39 -0
- package/dist/paint-editor/document.d.cts +3 -0
- package/dist/paint-editor/document.d.ts +3 -0
- package/dist/paint-editor/index.cjs +1335 -529
- package/dist/paint-editor/index.d.cts +1 -0
- package/dist/paint-editor/index.d.ts +1 -0
- package/dist/paint-editor/index.js +856 -50
- package/dist/paint-editor/light.d.cts +74 -0
- package/dist/paint-editor/light.d.ts +74 -0
- package/dist/paint-editor/paper.d.cts +7 -0
- package/dist/paint-editor/paper.d.ts +7 -0
- package/dist/paint-editor/stroke.d.cts +14 -0
- package/dist/paint-editor/stroke.d.ts +14 -0
- package/dist/paint-editor/thick-tools.d.cts +2 -2
- package/dist/paint-editor/thick-tools.d.ts +2 -2
- package/dist/paint-editor/thick.d.cts +5 -1
- package/dist/paint-editor/thick.d.ts +5 -1
- package/dist/paint-editor/ui.d.cts +2 -0
- package/dist/paint-editor/ui.d.ts +2 -0
- package/dist/paint-editor/wet.d.cts +9 -0
- package/dist/paint-editor/wet.d.ts +9 -0
- package/dist/vector/index.cjs +962 -962
- package/dist/vector/index.js +4 -4
- package/package.json +1 -1
- package/skills/pixerate-paint-editor/SKILL.md +11 -11
- package/skills/pixerate-paint-editor/references/canvas-hosted.md +8 -0
- package/skills/pixerate-paint-editor/references/light-paint.md +48 -0
- package/skills/pixerate-paint-oil-impasto/SKILL.md +1 -0
- package/skills/pixerate-paint-watercolour/SKILL.md +10 -1
- package/skills/pixerate-paint-watercolour/evals/glowing-wash.json +22 -0
- package/skills/pixerate-paint-watercolour/evals/stained-glass.json +16 -0
- package/dist/kernel-wasm-6FPOLVUZ.cjs +0 -9
- package/dist/kernel-wasm-WIMMJUF2.js +0 -9
|
@@ -85,20 +85,23 @@ var WET_TILE = 256;
|
|
|
85
85
|
var SLOT_SIDE = 258;
|
|
86
86
|
var PLANE = SLOT_SIDE * SLOT_SIDE;
|
|
87
87
|
var PLANE_BYTES = PLANE * 4;
|
|
88
|
-
var SET_PLANES =
|
|
88
|
+
var SET_PLANES = 19;
|
|
89
89
|
var P_RHO = 9;
|
|
90
90
|
var P_UX = 10;
|
|
91
91
|
var P_UY = 11;
|
|
92
92
|
var P_SW = 12;
|
|
93
93
|
var P_P0 = 13;
|
|
94
|
-
var
|
|
94
|
+
var P_L = P_P0 + 4;
|
|
95
|
+
var P_EDGE = 18;
|
|
95
96
|
var P_D0 = 2 * SET_PLANES;
|
|
96
|
-
var
|
|
97
|
+
var P_DL = P_D0 + 4;
|
|
98
|
+
var P_H = P_D0 + 5;
|
|
97
99
|
var P_FX = P_H + 1;
|
|
98
100
|
var P_FY = P_H + 2;
|
|
99
101
|
var SLOT_PLANES = P_FY + 1;
|
|
100
102
|
var SLOT_BYTES = SLOT_PLANES * PLANE_BYTES;
|
|
101
103
|
var PIGMENT_CHANNELS = 4;
|
|
104
|
+
var MASS_CHANNELS = 5;
|
|
102
105
|
var EX = [0, 1, 0, -1, 0, 1, -1, -1, 1];
|
|
103
106
|
var EY = [0, 0, 1, 0, -1, 1, 1, -1, -1];
|
|
104
107
|
var OPP = [0, 3, 4, 1, 2, 7, 8, 5, 6];
|
|
@@ -358,10 +361,9 @@ function filmPixel(k0, k1, k2, s, px, i, paper, wet, out, o) {
|
|
|
358
361
|
const e0 = linearToSrgb8(scratch[0] * dark);
|
|
359
362
|
const e1 = linearToSrgb8(scratch[1] * dark);
|
|
360
363
|
const e2 = linearToSrgb8(scratch[2] * dark);
|
|
361
|
-
let alpha =
|
|
362
|
-
alpha
|
|
363
|
-
|
|
364
|
-
alpha = needAlpha(e2, p2, alpha);
|
|
364
|
+
let alpha = needAlpha(e2, p2, needAlpha(e1, p1, needAlpha(e0, p0, 0)));
|
|
365
|
+
if (s > 0 && alpha < 1) alpha += (1 - expNeg(HIDE * s)) * (1 - alpha);
|
|
366
|
+
if (a > alpha) alpha = a;
|
|
365
367
|
if (alpha <= 0) {
|
|
366
368
|
out[o] = px[i];
|
|
367
369
|
out[o + 1] = px[i + 1];
|
|
@@ -392,7 +394,7 @@ function pixelPigment(px, i, paper, out) {
|
|
|
392
394
|
}
|
|
393
395
|
out[3] = 0;
|
|
394
396
|
}
|
|
395
|
-
function shadeTile(f, plane, side, d, p, rho, sw, src, out, w, h, paper) {
|
|
397
|
+
function shadeTile(f, plane, side, d, p, rho, sw, src, out, w, h, paper, dl = -1, pl = -1) {
|
|
396
398
|
const p0 = paper[0];
|
|
397
399
|
const p1 = paper[1];
|
|
398
400
|
const p2 = paper[2];
|
|
@@ -445,14 +447,31 @@ function shadeTile(f, plane, side, d, p, rho, sw, src, out, w, h, paper) {
|
|
|
445
447
|
r1 += hide * rinf(k1 * inv);
|
|
446
448
|
r2 += hide * rinf(k2 * inv);
|
|
447
449
|
}
|
|
450
|
+
if (dl >= 0) {
|
|
451
|
+
let l = f[dl + c];
|
|
452
|
+
if (pl >= 0) l += f[pl + c];
|
|
453
|
+
if (l > 1e-7) {
|
|
454
|
+
if (l > 1) l = 1;
|
|
455
|
+
let w0 = keep * expT(tab, 2 * k0);
|
|
456
|
+
let w1 = keep * expT(tab, 2 * k1);
|
|
457
|
+
let w2 = keep * expT(tab, 2 * k2);
|
|
458
|
+
if (hide > 0) {
|
|
459
|
+
w0 += hide * rinf(k0 * inv);
|
|
460
|
+
w1 += hide * rinf(k1 * inv);
|
|
461
|
+
w2 += hide * rinf(k2 * inv);
|
|
462
|
+
}
|
|
463
|
+
r0 += l * (w0 - r0);
|
|
464
|
+
r1 += l * (w1 - r1);
|
|
465
|
+
r2 += l * (w2 - r2);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
448
468
|
const dark = 1 - 0.07 * wet;
|
|
449
469
|
const e0 = encode(enc, r0 * dark);
|
|
450
470
|
const e1 = encode(enc, r1 * dark);
|
|
451
471
|
const e2 = encode(enc, r2 * dark);
|
|
452
|
-
let alpha =
|
|
453
|
-
alpha
|
|
454
|
-
|
|
455
|
-
alpha = needAlpha(e2, p2, alpha);
|
|
472
|
+
let alpha = needAlpha(e2, p2, needAlpha(e1, p1, needAlpha(e0, p0, 0)));
|
|
473
|
+
if (hide > 0 && alpha < 1) alpha += hide * (1 - alpha);
|
|
474
|
+
if (a > alpha) alpha = a;
|
|
456
475
|
if (alpha <= 0) {
|
|
457
476
|
out[i + 3] = 0;
|
|
458
477
|
continue;
|
|
@@ -483,6 +502,42 @@ function encode(enc, v) {
|
|
|
483
502
|
if (v >= 1) return 255;
|
|
484
503
|
return enc[Math.round(v * ENC_STEPS)];
|
|
485
504
|
}
|
|
505
|
+
function shadeLightTile(f, plane, side, d, p, dl, pl, src, out, w, h) {
|
|
506
|
+
const tab = EXP_TABLE;
|
|
507
|
+
let any = false;
|
|
508
|
+
for (let y = 0; y < h; y++) {
|
|
509
|
+
for (let x = 0; x < w; x++) {
|
|
510
|
+
const c = (y + 1) * side + x + 1;
|
|
511
|
+
let l = f[dl + c];
|
|
512
|
+
if (pl >= 0) l += f[pl + c];
|
|
513
|
+
const i = y * 256 + x;
|
|
514
|
+
const old = src ? src[i] : 0;
|
|
515
|
+
if (!(l > 1e-7) && old === 0) continue;
|
|
516
|
+
let keep = 1;
|
|
517
|
+
if (old > 0) {
|
|
518
|
+
let k0 = f[d + c];
|
|
519
|
+
let k1 = f[d + plane + c];
|
|
520
|
+
let k2 = f[d + 2 * plane + c];
|
|
521
|
+
let s = f[d + 3 * plane + c];
|
|
522
|
+
if (p >= 0) {
|
|
523
|
+
k0 += f[p + c];
|
|
524
|
+
k1 += f[p + plane + c];
|
|
525
|
+
k2 += f[p + 2 * plane + c];
|
|
526
|
+
s += f[p + 3 * plane + c];
|
|
527
|
+
}
|
|
528
|
+
if (k0 > 1e-7 || k1 > 1e-7 || k2 > 1e-7 || s > 1e-7) {
|
|
529
|
+
const hide = s > 0 ? 1 - expT(tab, HIDE * s) : 0;
|
|
530
|
+
keep = (1 - hide) * (expT(tab, 2 * k0) + expT(tab, 2 * k1) + expT(tab, 2 * k2)) / 3;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
const v = Math.round(Math.min(255, 255 * Math.min(1, l > 0 ? l : 0) + old * keep));
|
|
534
|
+
if (v === old) continue;
|
|
535
|
+
out[i] = v;
|
|
536
|
+
any = true;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
return any;
|
|
540
|
+
}
|
|
486
541
|
|
|
487
542
|
// src/paint/wet/kernel.ts
|
|
488
543
|
var F = Math.fround;
|
|
@@ -498,7 +553,7 @@ var DECAY = F(0.99);
|
|
|
498
553
|
var NB = [0, -1, -S, 1, S, -S - 1, -S + 1, S + 1, S - 1];
|
|
499
554
|
var OPP2 = [0, 3, 4, 1, 2, 7, 8, 5, 6];
|
|
500
555
|
var fin = new Float32Array(9);
|
|
501
|
-
var pNew = new Float32Array(
|
|
556
|
+
var pNew = new Float32Array(MASS_CHANNELS);
|
|
502
557
|
function stepSlotTs(f, base, parity, prm) {
|
|
503
558
|
const src = base + parity * SET_PLANES * PLANE;
|
|
504
559
|
const dst = base + (1 - parity) * SET_PLANES * PLANE;
|
|
@@ -632,13 +687,13 @@ function stepSlotTs(f, base, parity, prm) {
|
|
|
632
687
|
const rxWet = !rxDry;
|
|
633
688
|
const uxc = f[uxS + c];
|
|
634
689
|
const uyc = f[uyS + c];
|
|
635
|
-
for (let q = 0; q <
|
|
690
|
+
for (let q = 0; q < MASS_CHANNELS; q++) pNew[q] = f[pS + q * PLANE + c];
|
|
636
691
|
for (let face = 0; face < 4; face++) {
|
|
637
692
|
const nb = c + (face === 0 ? 1 : face === 1 ? -1 : face === 2 ? S : -S);
|
|
638
693
|
const open = rxWet && f[rhoS + nb] >= EPS;
|
|
639
694
|
const uf = face === 0 ? F(mobility * F(uxc + f[uxS + nb])) : face === 1 ? F(mobility * F(f[uxS + nb] + uxc)) : face === 2 ? F(mobility * F(uyc + f[uyS + nb])) : F(mobility * F(f[uyS + nb] + uyc));
|
|
640
695
|
const out = face === 0 || face === 2;
|
|
641
|
-
for (let q = 0; q <
|
|
696
|
+
for (let q = 0; q < MASS_CHANNELS; q++) {
|
|
642
697
|
const pc = f[pS + q * PLANE + c];
|
|
643
698
|
const pn = f[pS + q * PLANE + nb];
|
|
644
699
|
const flux = out ? uf > 0 ? F(uf * pc) : F(uf * pn) : uf > 0 ? F(uf * pn) : F(uf * pc);
|
|
@@ -650,7 +705,7 @@ function stepSlotTs(f, base, parity, prm) {
|
|
|
650
705
|
const dryNow = rhoNew < EPS;
|
|
651
706
|
const rate = F(F(depRate * F(1 + F(gran * F(1 - hx)))) * F(1 + F(edgeDep * ex)));
|
|
652
707
|
const lift = dryNow ? 0 : F(F(pickup * Math.min(rhoNew, 1)) * F(1 + F(bloom * Math.max(0, F(rhoNew - rx)))));
|
|
653
|
-
for (let q = 0; q <
|
|
708
|
+
for (let q = 0; q < MASS_CHANNELS; q++) {
|
|
654
709
|
const pq = Math.max(0, pNew[q]);
|
|
655
710
|
const dq = f[dP + q * PLANE + c];
|
|
656
711
|
const dep = dryNow ? pq : Math.min(pq, F(pq * rate));
|
|
@@ -686,7 +741,7 @@ function loadWetKernel(shared) {
|
|
|
686
741
|
const key = shared ? "shared" : "single";
|
|
687
742
|
let p = modules[key];
|
|
688
743
|
if (!p) {
|
|
689
|
-
p = import("./kernel-wasm-
|
|
744
|
+
p = import("./kernel-wasm-4KVONDAU.js").then((m) => WebAssembly.compile(decode(shared ? m.WET_KERNEL_SHARED : m.WET_KERNEL_SINGLE)));
|
|
690
745
|
p.catch(() => {
|
|
691
746
|
modules = { ...modules, [key]: void 0 };
|
|
692
747
|
});
|
|
@@ -864,10 +919,15 @@ var WetWorkerPool = class _WetWorkerPool {
|
|
|
864
919
|
|
|
865
920
|
// src/paint/wet/world.ts
|
|
866
921
|
var MAX_WET_LANES = 8;
|
|
867
|
-
var MAX_WET_SLOTS =
|
|
922
|
+
var MAX_WET_SLOTS = 328;
|
|
868
923
|
var SLOT_FLOATS = SLOT_PLANES * PLANE;
|
|
869
924
|
var S2 = SLOT_SIDE;
|
|
870
|
-
var SNAP_PLANES = SET_PLANES +
|
|
925
|
+
var SNAP_PLANES = SET_PLANES + MASS_CHANNELS;
|
|
926
|
+
var noLight = () => new TiledSurface(1, /* @__PURE__ */ new Map(), 0);
|
|
927
|
+
function newLane(id, index, params, flow, flowStrength, base, light) {
|
|
928
|
+
const l = light ?? noLight();
|
|
929
|
+
return { id, index, params, flow, flowStrength, base, shaded: /* @__PURE__ */ new Map(), urgent: /* @__PURE__ */ new Set(), stamp: 1, display: null, shadedVersion: 0, displayKey: "", light: l, lit: l.tiles.size > 0, lightShaded: /* @__PURE__ */ new Map(), lightDisplay: null, lightKey: "" };
|
|
930
|
+
}
|
|
871
931
|
var WetWorldError = class extends Error {
|
|
872
932
|
constructor(message) {
|
|
873
933
|
super(message);
|
|
@@ -1026,24 +1086,12 @@ var WetWorld = class {
|
|
|
1026
1086
|
if (existing) {
|
|
1027
1087
|
if (options.params) this.setParams(id, options.params);
|
|
1028
1088
|
if (options.base) this.setBase(id, options.base);
|
|
1089
|
+
if (options.light) this.setLight(id, options.light);
|
|
1029
1090
|
return;
|
|
1030
1091
|
}
|
|
1031
1092
|
const index = this.lanes.indexOf(null);
|
|
1032
1093
|
if (index < 0) throw new WetWorldError(`At most ${MAX_WET_LANES} layers can hold wet paint at once; dry one (dry_paint) first.`);
|
|
1033
|
-
this.lanes[index] = {
|
|
1034
|
-
id,
|
|
1035
|
-
index,
|
|
1036
|
-
params: normalizeWetParams(options.params ?? {}, DEFAULT_WET_PARAMS),
|
|
1037
|
-
flow: options.flow ?? null,
|
|
1038
|
-
flowStrength: options.flow ? options.flowStrength ?? 1 : 0,
|
|
1039
|
-
base: options.base ?? new TiledSurface(4, /* @__PURE__ */ new Map(), 0),
|
|
1040
|
-
shaded: /* @__PURE__ */ new Map(),
|
|
1041
|
-
urgent: /* @__PURE__ */ new Set(),
|
|
1042
|
-
stamp: 1,
|
|
1043
|
-
display: null,
|
|
1044
|
-
shadedVersion: 0,
|
|
1045
|
-
displayKey: ""
|
|
1046
|
-
};
|
|
1094
|
+
this.lanes[index] = newLane(id, index, normalizeWetParams(options.params ?? {}, DEFAULT_WET_PARAMS), options.flow ?? null, options.flow ? options.flowStrength ?? 1 : 0, options.base ?? new TiledSurface(4, /* @__PURE__ */ new Map(), 0), options.light);
|
|
1047
1095
|
this.pack(this.lanes[index]);
|
|
1048
1096
|
}
|
|
1049
1097
|
/** Drops a wet layer and its wet paint (nothing is baked). */
|
|
@@ -1110,6 +1158,23 @@ var WetWorld = class {
|
|
|
1110
1158
|
lane.shadedVersion++;
|
|
1111
1159
|
lane.stamp++;
|
|
1112
1160
|
}
|
|
1161
|
+
/** The light paint under a layer's wet paint (one channel). */
|
|
1162
|
+
getLight(id) {
|
|
1163
|
+
return this.laneOf(id).light;
|
|
1164
|
+
}
|
|
1165
|
+
/** Whether a layer has light paint, under its wet paint or in it. */
|
|
1166
|
+
isLit(id) {
|
|
1167
|
+
return this.laneOf(id).lit;
|
|
1168
|
+
}
|
|
1169
|
+
/** Replaces the light paint under a layer's wet paint. */
|
|
1170
|
+
setLight(id, light) {
|
|
1171
|
+
const lane = this.laneOf(id);
|
|
1172
|
+
if (light === lane.light) return;
|
|
1173
|
+
lane.light = light;
|
|
1174
|
+
if (light.tiles.size) lane.lit = true;
|
|
1175
|
+
lane.lightShaded.clear();
|
|
1176
|
+
lane.stamp++;
|
|
1177
|
+
}
|
|
1113
1178
|
pack(lane) {
|
|
1114
1179
|
packWetParams(lane.params, this.paper ?? DEFAULT_WET_PAPER, this.tilt, lane.flowStrength, this.prm);
|
|
1115
1180
|
this.f32.set(this.prm, this.layout.params + lane.index * PARAM_FLOATS * 4 >> 2);
|
|
@@ -1535,11 +1600,13 @@ var WetWorld = class {
|
|
|
1535
1600
|
}
|
|
1536
1601
|
/**
|
|
1537
1602
|
* Lays paint: `water` depth and pigment mass `pigment` (K r, g, b, S) per unit of coverage, or
|
|
1538
|
-
* per pixel from `field` (4 values per pixel of `rect`)
|
|
1539
|
-
* the paper (settled).
|
|
1603
|
+
* per pixel from `field` (4 values per pixel of `rect`), and `light` (light paint mass) per unit
|
|
1604
|
+
* of coverage. Pigment and light without water land straight in the paper (settled).
|
|
1540
1605
|
*/
|
|
1541
|
-
paint(id, rect, cov, water, pigment, field = null) {
|
|
1606
|
+
paint(id, rect, cov, water, pigment, field = null, light = 0) {
|
|
1542
1607
|
if (!(water >= 0)) throw new WetWorldError(`water ${water} must be 0 or more.`);
|
|
1608
|
+
if (!(light >= 0)) throw new WetWorldError(`light ${light} must be 0 or more.`);
|
|
1609
|
+
if (light > 0) this.laneOf(id).lit = true;
|
|
1543
1610
|
this.footprint(id, rect, cov, (c, w, x, y) => {
|
|
1544
1611
|
const dw = Math.fround(water * w);
|
|
1545
1612
|
if (dw > 0) this.addWaterAt(c, dw);
|
|
@@ -1548,6 +1615,7 @@ var WetWorld = class {
|
|
|
1548
1615
|
const o = ((y - rect.y) * rect.width + (x - rect.x)) * 4;
|
|
1549
1616
|
for (let q = 0; q < 4; q++) this.f32[into + q * PLANE] += field[o + q] * w;
|
|
1550
1617
|
} else if (pigment) for (let q = 0; q < 4; q++) this.f32[into + q * PLANE] += pigment[q] * w;
|
|
1618
|
+
if (light > 0) this.f32[into + 4 * PLANE] += light * w;
|
|
1551
1619
|
});
|
|
1552
1620
|
}
|
|
1553
1621
|
/** Damp paper: fills the paper's water towards its capacity by `amount` (0..1) × coverage, plus a thin film of surface water. */
|
|
@@ -1581,10 +1649,10 @@ var WetWorld = class {
|
|
|
1581
1649
|
f[c + P_RHO * PLANE] *= kw;
|
|
1582
1650
|
}
|
|
1583
1651
|
if (ks < 1) f[c + P_SW * PLANE] *= ks;
|
|
1584
|
-
if (kp < 1) for (let q = 0; q <
|
|
1652
|
+
if (kp < 1) for (let q = 0; q < MASS_CHANNELS; q++) f[c + (P_P0 + q) * PLANE] *= kp;
|
|
1585
1653
|
if (kd < 1) {
|
|
1586
1654
|
const d = this.single(c) + P_D0 * PLANE;
|
|
1587
|
-
for (let q = 0; q <
|
|
1655
|
+
for (let q = 0; q < MASS_CHANNELS; q++) f[d + q * PLANE] *= kd;
|
|
1588
1656
|
}
|
|
1589
1657
|
},
|
|
1590
1658
|
false
|
|
@@ -1614,10 +1682,10 @@ var WetWorld = class {
|
|
|
1614
1682
|
false
|
|
1615
1683
|
);
|
|
1616
1684
|
}
|
|
1617
|
-
/** Blends wet paint: each wet cell's suspended pigment moves `strength` × coverage towards the footprint's mean. */
|
|
1685
|
+
/** Blends wet paint: each wet cell's suspended pigment (and light) moves `strength` × coverage towards the footprint's mean. */
|
|
1618
1686
|
blend(id, rect, cov, strength) {
|
|
1619
1687
|
const lane = this.laneOf(id);
|
|
1620
|
-
const sums = [0, 0, 0, 0];
|
|
1688
|
+
const sums = [0, 0, 0, 0, 0];
|
|
1621
1689
|
let wsum = 0;
|
|
1622
1690
|
const cells = [];
|
|
1623
1691
|
this.footprint(
|
|
@@ -1628,13 +1696,13 @@ var WetWorld = class {
|
|
|
1628
1696
|
if (!(this.f32[c + P_RHO * PLANE] >= DRY_EPS)) return;
|
|
1629
1697
|
cells.push([c, w]);
|
|
1630
1698
|
wsum += w;
|
|
1631
|
-
for (let q = 0; q <
|
|
1699
|
+
for (let q = 0; q < MASS_CHANNELS; q++) sums[q] += this.f32[c + (P_P0 + q) * PLANE] * w;
|
|
1632
1700
|
},
|
|
1633
1701
|
false
|
|
1634
1702
|
);
|
|
1635
1703
|
if (!(wsum > 0)) return;
|
|
1636
1704
|
const k = Math.min(1, Math.max(0, strength));
|
|
1637
|
-
for (const [c, w] of cells) for (let q = 0; q <
|
|
1705
|
+
for (const [c, w] of cells) for (let q = 0; q < MASS_CHANNELS; q++) {
|
|
1638
1706
|
const i = c + (P_P0 + q) * PLANE;
|
|
1639
1707
|
this.f32[i] += k * w * (sums[q] / wsum - this.f32[i]);
|
|
1640
1708
|
}
|
|
@@ -1643,7 +1711,7 @@ var WetWorld = class {
|
|
|
1643
1711
|
}
|
|
1644
1712
|
/**
|
|
1645
1713
|
* Drags wet paint by (`dx`, `dy`) cells: each footprint cell takes `strength` × coverage of the
|
|
1646
|
-
* water and suspended pigment of the cell it came from (a smudge through wet paint).
|
|
1714
|
+
* water and suspended pigment (and light) of the cell it came from (a smudge through wet paint).
|
|
1647
1715
|
*/
|
|
1648
1716
|
drag(id, rect, cov, dx, dy, strength) {
|
|
1649
1717
|
const lane = this.laneOf(id);
|
|
@@ -1664,14 +1732,14 @@ var WetWorld = class {
|
|
|
1664
1732
|
);
|
|
1665
1733
|
const f = this.f32;
|
|
1666
1734
|
const taken = moves.map(([from, , a]) => {
|
|
1667
|
-
const t = new Float32Array(
|
|
1735
|
+
const t = new Float32Array(10 + MASS_CHANNELS);
|
|
1668
1736
|
for (let k = 0; k < 9; k++) {
|
|
1669
1737
|
t[k] = f[from + k * PLANE] * a;
|
|
1670
1738
|
f[from + k * PLANE] -= t[k];
|
|
1671
1739
|
}
|
|
1672
1740
|
t[9] = f[from + P_RHO * PLANE] * a;
|
|
1673
1741
|
f[from + P_RHO * PLANE] -= t[9];
|
|
1674
|
-
for (let q = 0; q <
|
|
1742
|
+
for (let q = 0; q < MASS_CHANNELS; q++) {
|
|
1675
1743
|
t[10 + q] = f[from + (P_P0 + q) * PLANE] * a;
|
|
1676
1744
|
f[from + (P_P0 + q) * PLANE] -= t[10 + q];
|
|
1677
1745
|
}
|
|
@@ -1681,19 +1749,22 @@ var WetWorld = class {
|
|
|
1681
1749
|
const t = taken[i];
|
|
1682
1750
|
for (let k = 0; k < 9; k++) f[to + k * PLANE] += t[k];
|
|
1683
1751
|
f[to + P_RHO * PLANE] += t[9];
|
|
1684
|
-
for (let q = 0; q <
|
|
1752
|
+
for (let q = 0; q < MASS_CHANNELS; q++) f[to + (P_P0 + q) * PLANE] += t[10 + q];
|
|
1685
1753
|
});
|
|
1686
1754
|
this.refreshHalos();
|
|
1687
1755
|
}
|
|
1688
1756
|
/**
|
|
1689
1757
|
* Re-wetting: lifts `amount` × coverage of the dried paint in the layer's pixels (`base`) back into
|
|
1690
|
-
* the paper as settled pigment, so water can move it again
|
|
1758
|
+
* the paper as settled pigment, so water can move it again, and the same share of its light
|
|
1759
|
+
* paint (`light`) as settled light. Only where there is surface water.
|
|
1691
1760
|
*/
|
|
1692
1761
|
rewet(id, rect, cov, amount, paper) {
|
|
1693
1762
|
const lane = this.laneOf(id);
|
|
1694
1763
|
const pig = [0, 0, 0, 0];
|
|
1695
1764
|
const tiles = new Map(lane.base.tiles);
|
|
1696
1765
|
const written = /* @__PURE__ */ new Set();
|
|
1766
|
+
const lightTiles = lane.lit ? new Map(lane.light.tiles) : null;
|
|
1767
|
+
const lightWritten = /* @__PURE__ */ new Set();
|
|
1697
1768
|
const scratch2 = new Uint8ClampedArray(4);
|
|
1698
1769
|
this.footprint(
|
|
1699
1770
|
id,
|
|
@@ -1704,6 +1775,22 @@ var WetWorld = class {
|
|
|
1704
1775
|
const a = Math.min(1, Math.max(0, amount * w));
|
|
1705
1776
|
if (!(a > 0)) return;
|
|
1706
1777
|
const key = tileKey(x >> 8, y >> 8);
|
|
1778
|
+
const li = (y & 255) * TILE + (x & 255);
|
|
1779
|
+
let lt = lightTiles?.get(key);
|
|
1780
|
+
if (lt && (lt.uniform ?? 1) !== 0) {
|
|
1781
|
+
if (!lightWritten.has(key)) {
|
|
1782
|
+
const data = lt.data.length ? new Uint8ClampedArray(lt.data) : new Uint8ClampedArray(TILE * TILE).fill(lt.uniform ?? 0);
|
|
1783
|
+
lt = { data, uniform: null };
|
|
1784
|
+
lightTiles.set(key, lt);
|
|
1785
|
+
lightWritten.add(key);
|
|
1786
|
+
}
|
|
1787
|
+
const lv = lt.data[li];
|
|
1788
|
+
if (lv > 0) {
|
|
1789
|
+
const lifted = Math.round(lv * a);
|
|
1790
|
+
lt.data[li] = lv - lifted;
|
|
1791
|
+
this.f32[this.single(c) + P_DL * PLANE] += Math.fround(lifted / 255);
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1707
1794
|
let tile = tiles.get(key);
|
|
1708
1795
|
if (!tile) return;
|
|
1709
1796
|
if (!written.has(key)) {
|
|
@@ -1731,6 +1818,14 @@ var WetWorld = class {
|
|
|
1731
1818
|
}
|
|
1732
1819
|
this.setBase(id, new TiledSurface(4, tiles, 0));
|
|
1733
1820
|
}
|
|
1821
|
+
if (lightWritten.size) {
|
|
1822
|
+
for (const key of lightWritten) {
|
|
1823
|
+
const t = finishTile(lightTiles.get(key).data, 1, 0);
|
|
1824
|
+
if (t) lightTiles.set(key, t);
|
|
1825
|
+
else lightTiles.delete(key);
|
|
1826
|
+
}
|
|
1827
|
+
this.setLight(id, new TiledSurface(1, lightTiles, 0));
|
|
1828
|
+
}
|
|
1734
1829
|
}
|
|
1735
1830
|
/**
|
|
1736
1831
|
* Dries wet paint at once (everything settles where it is, the water goes): in `rect`, or the
|
|
@@ -1763,7 +1858,7 @@ var WetWorld = class {
|
|
|
1763
1858
|
for (let x = x0; x < x1; x++) {
|
|
1764
1859
|
const c = this.cell(lane, x, y);
|
|
1765
1860
|
const d = this.single(c) + P_D0 * PLANE;
|
|
1766
|
-
for (let q = 0; q <
|
|
1861
|
+
for (let q = 0; q < MASS_CHANNELS; q++) {
|
|
1767
1862
|
f[d + q * PLANE] += f[c + (P_P0 + q) * PLANE];
|
|
1768
1863
|
f[c + (P_P0 + q) * PLANE] = 0;
|
|
1769
1864
|
}
|
|
@@ -1790,9 +1885,21 @@ var WetWorld = class {
|
|
|
1790
1885
|
const lane = this.lanes[this.laneIndexOf(key)];
|
|
1791
1886
|
const [tx, ty] = this.tileXY(key);
|
|
1792
1887
|
const tk = tileKey(tx, ty);
|
|
1888
|
+
let lightChanged = false;
|
|
1889
|
+
if (lane.lit) {
|
|
1890
|
+
const lout = this.shadeLightSlot(key, lane.light.tiles.get(tk) ?? null, all ? "bake-all" : "bake");
|
|
1891
|
+
if (lout) {
|
|
1892
|
+
const tiles2 = new Map(lane.light.tiles);
|
|
1893
|
+
const t2 = finishTile(lout, 1, 0);
|
|
1894
|
+
if (t2) tiles2.set(tk, t2);
|
|
1895
|
+
else tiles2.delete(tk);
|
|
1896
|
+
this.setLight(lane.id, new TiledSurface(1, tiles2, 0));
|
|
1897
|
+
lightChanged = true;
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1793
1900
|
const src = lane.base.tiles.get(tk)?.data ?? null;
|
|
1794
1901
|
const out = this.shadeSlot(key, src, all ? "bake-all" : "bake");
|
|
1795
|
-
if (!out) return
|
|
1902
|
+
if (!out) return lightChanged;
|
|
1796
1903
|
const tiles = new Map(lane.base.tiles);
|
|
1797
1904
|
const t = finishTile(out, 4, 0);
|
|
1798
1905
|
if (t) tiles.set(tk, t);
|
|
@@ -1800,6 +1907,19 @@ var WetWorld = class {
|
|
|
1800
1907
|
this.setBase(lane.id, new TiledSurface(4, tiles, 0));
|
|
1801
1908
|
return true;
|
|
1802
1909
|
}
|
|
1910
|
+
/** `shadeSlot` for light paint: one channel over a light tile (see `shadeLightTile`); `null` when nothing would change. */
|
|
1911
|
+
shadeLightSlot(key, src, mode) {
|
|
1912
|
+
const [tx, ty] = this.tileXY(key);
|
|
1913
|
+
const b = this.slotBase(this.slotOf(key));
|
|
1914
|
+
const cur = b + this.parity * SET_PLANES * PLANE;
|
|
1915
|
+
const full = src ? src.data.length ? src.data : new Uint8ClampedArray(TILE * TILE).fill(src.uniform ?? 0) : null;
|
|
1916
|
+
const out = full ? new Uint8ClampedArray(full) : new Uint8ClampedArray(TILE * TILE);
|
|
1917
|
+
const w = Math.min(WET_TILE, this.width - tx * WET_TILE);
|
|
1918
|
+
const h = Math.min(WET_TILE, this.height - ty * WET_TILE);
|
|
1919
|
+
const live = mode !== "bake";
|
|
1920
|
+
const changed = shadeLightTile(this.f32, PLANE, S2, b + P_D0 * PLANE, live ? cur + P_P0 * PLANE : -1, b + P_DL * PLANE, live ? cur + P_L * PLANE : -1, full, out, w, h);
|
|
1921
|
+
return changed ? out : null;
|
|
1922
|
+
}
|
|
1803
1923
|
/**
|
|
1804
1924
|
* Shades one slot over a base tile. `display`: the wet look (suspended + settled, wet paper a
|
|
1805
1925
|
* little darker); `bake`: settled pigment only; `bake-all`: suspended and settled (dry now).
|
|
@@ -1812,6 +1932,7 @@ var WetWorld = class {
|
|
|
1812
1932
|
const out = src ? new Uint8ClampedArray(src) : new Uint8ClampedArray(TILE * TILE * 4);
|
|
1813
1933
|
const w = Math.min(WET_TILE, this.width - tx * WET_TILE);
|
|
1814
1934
|
const h = Math.min(WET_TILE, this.height - ty * WET_TILE);
|
|
1935
|
+
const lit = this.lanes[this.laneIndexOf(key)].lit;
|
|
1815
1936
|
const changed = shadeTile(
|
|
1816
1937
|
this.f32,
|
|
1817
1938
|
PLANE,
|
|
@@ -1824,7 +1945,10 @@ var WetWorld = class {
|
|
|
1824
1945
|
out,
|
|
1825
1946
|
w,
|
|
1826
1947
|
h,
|
|
1827
|
-
this.paperBytes
|
|
1948
|
+
this.paperBytes,
|
|
1949
|
+
// Glowing paint shows its own hue (see shadeTile).
|
|
1950
|
+
lit ? b + P_DL * PLANE : -1,
|
|
1951
|
+
lit && mode !== "bake" ? cur + P_L * PLANE : -1
|
|
1828
1952
|
);
|
|
1829
1953
|
return changed ? out : null;
|
|
1830
1954
|
}
|
|
@@ -1844,6 +1968,23 @@ var WetWorld = class {
|
|
|
1844
1968
|
}
|
|
1845
1969
|
return new TiledSurface(4, tiles, 0);
|
|
1846
1970
|
}
|
|
1971
|
+
/** The layer's light paint with all its wet paint dried where it is (`bakedSurface` for light); changes nothing. */
|
|
1972
|
+
bakedLight(id) {
|
|
1973
|
+
this.requireIdle();
|
|
1974
|
+
const lane = this.laneOf(id);
|
|
1975
|
+
if (!lane.lit) return lane.light;
|
|
1976
|
+
const tiles = new Map(lane.light.tiles);
|
|
1977
|
+
for (const key of this.active) {
|
|
1978
|
+
if (this.laneIndexOf(key) !== lane.index) continue;
|
|
1979
|
+
const tk = this.tileKeyOf(key);
|
|
1980
|
+
const out = this.shadeLightSlot(key, lane.light.tiles.get(tk) ?? null, "bake-all");
|
|
1981
|
+
if (!out) continue;
|
|
1982
|
+
const t = finishTile(out, 1, 0);
|
|
1983
|
+
if (t) tiles.set(tk, t);
|
|
1984
|
+
else tiles.delete(tk);
|
|
1985
|
+
}
|
|
1986
|
+
return new TiledSurface(1, tiles, 0);
|
|
1987
|
+
}
|
|
1847
1988
|
// --- Reading -------------------------------------------------------------------
|
|
1848
1989
|
/**
|
|
1849
1990
|
* Sums over a footprint of a lane, weighted by coverage: `weight` (coverage), `water` (surface
|
|
@@ -1972,6 +2113,38 @@ var WetWorld = class {
|
|
|
1972
2113
|
lane.displayKey = displayKey;
|
|
1973
2114
|
return { surface: lane.display, changed, pending: stale.length - done };
|
|
1974
2115
|
}
|
|
2116
|
+
/**
|
|
2117
|
+
* The layer's light paint with its live light shaded in (`null` when the layer has none): the
|
|
2118
|
+
* light under the wet paint with each live tile's light over it. Like `display`, every stale
|
|
2119
|
+
* tile is reshaded (light tiles are cheap: one channel, no colour maths).
|
|
2120
|
+
*/
|
|
2121
|
+
lightDisplay(id) {
|
|
2122
|
+
const lane = this.laneOf(id);
|
|
2123
|
+
if (!lane.lit) return null;
|
|
2124
|
+
const keys = this.active.filter((k) => this.laneIndexOf(k) === lane.index);
|
|
2125
|
+
let changed = false;
|
|
2126
|
+
const live = /* @__PURE__ */ new Set();
|
|
2127
|
+
for (const key2 of keys) {
|
|
2128
|
+
const tk = this.tileKeyOf(key2);
|
|
2129
|
+
live.add(tk);
|
|
2130
|
+
if (lane.lightShaded.get(tk)?.stamp === lane.stamp) continue;
|
|
2131
|
+
const src = lane.light.tiles.get(tk) ?? null;
|
|
2132
|
+
const out = this.shadeLightSlot(key2, src, "display");
|
|
2133
|
+
lane.lightShaded.set(tk, { stamp: lane.stamp, tile: out ? finishTile(out, 1, 0) : src });
|
|
2134
|
+
changed = true;
|
|
2135
|
+
}
|
|
2136
|
+
for (const tk of [...lane.lightShaded.keys()]) if (!live.has(tk) && lane.lightShaded.delete(tk)) changed = true;
|
|
2137
|
+
const key = `${lane.light.id}`;
|
|
2138
|
+
if (!changed && lane.lightDisplay && lane.lightKey === key) return lane.lightDisplay;
|
|
2139
|
+
const tiles = new Map(lane.light.tiles);
|
|
2140
|
+
for (const [tk, { tile }] of lane.lightShaded) {
|
|
2141
|
+
if (tile) tiles.set(tk, tile);
|
|
2142
|
+
else tiles.delete(tk);
|
|
2143
|
+
}
|
|
2144
|
+
lane.lightDisplay = new TiledSurface(1, tiles, 0);
|
|
2145
|
+
lane.lightKey = key;
|
|
2146
|
+
return lane.lightDisplay;
|
|
2147
|
+
}
|
|
1975
2148
|
/**
|
|
1976
2149
|
* The water as an overlay tile (RGBA, blue, alpha from surface depth and damp paper) for a
|
|
1977
2150
|
* document tile, or `null` where nothing is wet.
|
|
@@ -2104,7 +2277,7 @@ var WetWorld = class {
|
|
|
2104
2277
|
}
|
|
2105
2278
|
const from = y0 * SLOT_SIDE;
|
|
2106
2279
|
const to = (y1 + 1) * SLOT_SIDE;
|
|
2107
|
-
const planes = [...Array(SET_PLANES).keys()].map((k) => this.parity * SET_PLANES + k).concat([
|
|
2280
|
+
const planes = [...Array(SET_PLANES).keys()].map((k) => this.parity * SET_PLANES + k).concat([...Array(MASS_CHANNELS).keys()].map((q) => P_D0 + q));
|
|
2108
2281
|
for (const plane of planes) gpu.writeSlot(slot, plane * PLANE + from, this.f32.subarray(b + plane * PLANE + from, b + plane * PLANE + to));
|
|
2109
2282
|
}
|
|
2110
2283
|
this.gpuDirty.clear();
|
|
@@ -2189,11 +2362,11 @@ var WetWorld = class {
|
|
|
2189
2362
|
const b = this.slotBase(this.slotOf(key));
|
|
2190
2363
|
const planes = new Float32Array(SNAP_PLANES * PLANE);
|
|
2191
2364
|
planes.set(this.f32.subarray(b + this.parity * SET_PLANES * PLANE, b + (this.parity + 1) * SET_PLANES * PLANE), 0);
|
|
2192
|
-
planes.set(this.f32.subarray(b + P_D0 * PLANE, b + (P_D0 +
|
|
2365
|
+
planes.set(this.f32.subarray(b + P_D0 * PLANE, b + (P_D0 + MASS_CHANNELS) * PLANE), SET_PLANES * PLANE);
|
|
2193
2366
|
slots.set(key, { planes, last: this.u32[(this.layout.last >> 2) + key] });
|
|
2194
2367
|
bytes += planes.byteLength;
|
|
2195
2368
|
}
|
|
2196
|
-
const lanes = this.lanes.filter((l) => Boolean(l)).map((l) => ({ id: l.id, index: l.index, params: { ...l.params }, flow: l.flow, flowStrength: l.flowStrength, base: l.base }));
|
|
2369
|
+
const lanes = this.lanes.filter((l) => Boolean(l)).map((l) => ({ id: l.id, index: l.index, params: { ...l.params }, flow: l.flow, flowStrength: l.flowStrength, base: l.base, light: l.light, lit: l.lit }));
|
|
2197
2370
|
return { clock: this.clock, tilt: { ...this.tilt }, lanes, slots, bytes };
|
|
2198
2371
|
}
|
|
2199
2372
|
/** Puts a snapshot back exactly (the simulation then continues as it would have). */
|
|
@@ -2203,7 +2376,9 @@ var WetWorld = class {
|
|
|
2203
2376
|
this.lanes.fill(null);
|
|
2204
2377
|
this.tilt = { ...snap.tilt };
|
|
2205
2378
|
for (const l of snap.lanes) {
|
|
2206
|
-
|
|
2379
|
+
const lane = newLane(l.id, l.index, { ...l.params }, l.flow, l.flowStrength, l.base, l.light);
|
|
2380
|
+
lane.lit = lane.lit || Boolean(l.lit);
|
|
2381
|
+
this.lanes[l.index] = lane;
|
|
2207
2382
|
this.pack(this.lanes[l.index]);
|
|
2208
2383
|
}
|
|
2209
2384
|
for (const [key, { planes, last }] of snap.slots) {
|
|
@@ -2260,7 +2435,7 @@ function moveWetSnapshot(snap, from, to, dx, dy, lane = () => ({})) {
|
|
|
2260
2435
|
}
|
|
2261
2436
|
const lanes = snap.lanes.map((l) => {
|
|
2262
2437
|
const moved = lane(l);
|
|
2263
|
-
return { ...l, base: moved.base ?? l.base, flow: moved.flow === void 0 ? l.flow : moved.flow };
|
|
2438
|
+
return { ...l, base: moved.base ?? l.base, light: moved.light ?? l.light, flow: moved.flow === void 0 ? l.flow : moved.flow };
|
|
2264
2439
|
});
|
|
2265
2440
|
return { clock: snap.clock, tilt: { ...snap.tilt }, lanes, slots, bytes };
|
|
2266
2441
|
}
|
|
@@ -2396,6 +2571,7 @@ var WetMedium = class {
|
|
|
2396
2571
|
}
|
|
2397
2572
|
deposit(rect, cov, dep, paint, _pigment, field = null) {
|
|
2398
2573
|
const { water, mass, body } = this.options;
|
|
2574
|
+
const light = (this.options.light ?? 0) * dep;
|
|
2399
2575
|
if (field) {
|
|
2400
2576
|
const n = rect.width * rect.height;
|
|
2401
2577
|
const out = new Float32Array(n * 4);
|
|
@@ -2404,12 +2580,12 @@ var WetMedium = class {
|
|
|
2404
2580
|
pigmentOf([field[p * 3], field[p * 3 + 1], field[p * 3 + 2]], body, one);
|
|
2405
2581
|
for (let q = 0; q < 4; q++) out[p * 4 + q] = one[q] * mass * dep;
|
|
2406
2582
|
}
|
|
2407
|
-
this.world.paint(this.laneId, rect, cov, water * dep, null, out);
|
|
2583
|
+
this.world.paint(this.laneId, rect, cov, water * dep, null, out, light);
|
|
2408
2584
|
return;
|
|
2409
2585
|
}
|
|
2410
2586
|
pigmentOf(paint, body, this.pig);
|
|
2411
2587
|
const pig = [0, 1, 2, 3].map((q) => this.pig[q] * mass * dep);
|
|
2412
|
-
this.world.paint(this.laneId, rect, cov, water * dep, mass > 0 ? pig : null);
|
|
2588
|
+
this.world.paint(this.laneId, rect, cov, water * dep, mass > 0 ? pig : null, null, light);
|
|
2413
2589
|
}
|
|
2414
2590
|
};
|
|
2415
2591
|
|
|
@@ -2482,7 +2658,10 @@ function faces() {
|
|
|
2482
2658
|
let pn = vec4<f32>(st[pS + nb], st[pS + PL + nb], st[pS + 2u * PL + nb], st[pS + 3u * PL + nb]);
|
|
2483
2659
|
let flux = ${outF ? "select(uf * pn, uf * pc, uf > 0.0)" : "select(uf * pc, uf * pn, uf > 0.0)"};
|
|
2484
2660
|
let v = pNew ${outF ? "-" : "+"} flux + bleed * (pn - pc);
|
|
2485
|
-
|
|
2661
|
+
let ln = st[pS + 4u * PL + nb];
|
|
2662
|
+
let fluxL = ${outF ? "select(uf * ln, uf * lc, uf > 0.0)" : "select(uf * lc, uf * ln, uf > 0.0)"};
|
|
2663
|
+
let vL = lNew ${outF ? "-" : "+"} fluxL + bleed * (ln - lc);
|
|
2664
|
+
if (rxWet && st[rhoS + nb] >= EPS) { pNew = v; lNew = vL; }
|
|
2486
2665
|
}`;
|
|
2487
2666
|
});
|
|
2488
2667
|
return out;
|
|
@@ -2605,12 +2784,14 @@ ${stream()}
|
|
|
2605
2784
|
st[dst + c] = (f0 + omega * (wr0 * (1.0 - usq) - f0)) * scale;
|
|
2606
2785
|
${collide()}
|
|
2607
2786
|
|
|
2608
|
-
// 5. pigment: upwind advection with the last step's velocities, plus bleed
|
|
2787
|
+
// 5. pigment and light: upwind advection with the last step's velocities, plus bleed
|
|
2609
2788
|
let rxWet = !rxDry;
|
|
2610
2789
|
let uxc = st[uxS + c];
|
|
2611
2790
|
let uyc = st[uyS + c];
|
|
2612
2791
|
var pNew = vec4<f32>(st[pS + c], st[pS + PL + c], st[pS + 2u * PL + c], st[pS + 3u * PL + c]);
|
|
2613
2792
|
let pc = pNew;
|
|
2793
|
+
var lNew = st[pS + 4u * PL + c];
|
|
2794
|
+
let lc = lNew;
|
|
2614
2795
|
${faces()}
|
|
2615
2796
|
|
|
2616
2797
|
// 6. deposition and pickup
|
|
@@ -2627,6 +2808,15 @@ ${faces()}
|
|
|
2627
2808
|
st[dst + (${P_P0}u + q) * PL + c] = pq - dep + lq;
|
|
2628
2809
|
st[dP + q * PL + c] = dq + dep - lq;
|
|
2629
2810
|
}
|
|
2811
|
+
{
|
|
2812
|
+
let pq = max(0.0, lNew);
|
|
2813
|
+
let dq = st[dP + 4u * PL + c];
|
|
2814
|
+
var dep = min(pq, pq * rate);
|
|
2815
|
+
if (dryNow) { dep = pq; }
|
|
2816
|
+
let lq = dq * lift;
|
|
2817
|
+
st[dst + ${P_P0 + 4}u * PL + c] = pq - dep + lq;
|
|
2818
|
+
st[dP + 4u * PL + c] = dq + dep - lq;
|
|
2819
|
+
}
|
|
2630
2820
|
let mean4 = (st[eS + c + 1u] + st[eS + c - 1u] + st[eS + c + S] + st[eS + c - S]) * 0.25;
|
|
2631
2821
|
let eNew = min(1.0, max(min(1.0, dryNb * 0.25), DECAY * mean4));
|
|
2632
2822
|
st[dst + ${P_EDGE}u * PL + c] = select(eNew, 0.0, dryNow);
|
|
@@ -2754,12 +2944,18 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
2754
2944
|
if (s > 1e-9) { inv = 1.0 / s; }
|
|
2755
2945
|
var film = keep * exp(-2.0 * k.xyz) * below;
|
|
2756
2946
|
if (hide > 0.0) { film = film + hide * vec3<f32>(rinf(k.x * inv), rinf(k.y * inv), rinf(k.z * inv)); }
|
|
2947
|
+
// Light paint: glowing paint shows its own hue (the film over white), as shadeTile does.
|
|
2948
|
+
let l = min(1.0, st[d + 4u * PL + c] + st[p + 4u * PL + c]);
|
|
2949
|
+
if (l > 1e-7) {
|
|
2950
|
+
var w = keep * exp(-2.0 * k.xyz);
|
|
2951
|
+
if (hide > 0.0) { w = w + hide * vec3<f32>(rinf(k.x * inv), rinf(k.y * inv), rinf(k.z * inv)); }
|
|
2952
|
+
film = film + l * (w - film);
|
|
2953
|
+
}
|
|
2757
2954
|
let dark = 1.0 - 0.07 * wet;
|
|
2758
2955
|
let e = vec3<f32>(toByte(film.x * dark), toByte(film.y * dark), toByte(film.z * dark));
|
|
2759
|
-
var alpha =
|
|
2760
|
-
alpha =
|
|
2761
|
-
alpha =
|
|
2762
|
-
alpha = needAlpha(e.z, paper.z, alpha);
|
|
2956
|
+
var alpha = needAlpha(e.z, paper.z, needAlpha(e.y, paper.y, needAlpha(e.x, paper.x, 0.0)));
|
|
2957
|
+
if (hide > 0.0 && alpha < 1.0) { alpha = alpha + hide * (1.0 - alpha); }
|
|
2958
|
+
alpha = max(alpha, a);
|
|
2763
2959
|
if (alpha <= 0.0) { outTiles[o] = px & 0x00ffffffu; return; }
|
|
2764
2960
|
let a8 = max(round(min(1.0, alpha) * 255.0), pr.w);
|
|
2765
2961
|
let al = a8 / 255.0;
|
|
@@ -3140,14 +3336,17 @@ export {
|
|
|
3140
3336
|
P_UY,
|
|
3141
3337
|
P_SW,
|
|
3142
3338
|
P_P0,
|
|
3339
|
+
P_L,
|
|
3143
3340
|
P_EDGE,
|
|
3144
3341
|
P_D0,
|
|
3342
|
+
P_DL,
|
|
3145
3343
|
P_H,
|
|
3146
3344
|
P_FX,
|
|
3147
3345
|
P_FY,
|
|
3148
3346
|
SLOT_PLANES,
|
|
3149
3347
|
SLOT_BYTES,
|
|
3150
3348
|
PIGMENT_CHANNELS,
|
|
3349
|
+
MASS_CHANNELS,
|
|
3151
3350
|
EX,
|
|
3152
3351
|
EY,
|
|
3153
3352
|
OPP,
|
|
@@ -3192,6 +3391,7 @@ export {
|
|
|
3192
3391
|
filmPixel,
|
|
3193
3392
|
pixelPigment,
|
|
3194
3393
|
shadeTile,
|
|
3394
|
+
shadeLightTile,
|
|
3195
3395
|
stepSlotTs,
|
|
3196
3396
|
loadWetKernel,
|
|
3197
3397
|
canShareMemory,
|