@pixerate/editor 0.271.0 → 0.272.1
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/agent/index.cjs +34 -32
- package/dist/agent/index.js +10 -8
- package/dist/animation-editor/index.cjs +60 -60
- package/dist/animation-editor/index.js +4 -4
- package/dist/brushes/index.cjs +69 -66
- package/dist/brushes/index.js +6 -3
- package/dist/brushes/patch.d.cts +1 -1
- package/dist/brushes/patch.d.ts +1 -1
- package/dist/brushes/schema.d.cts +1 -0
- package/dist/brushes/schema.d.ts +1 -0
- package/dist/brushes/types.d.cts +8 -0
- package/dist/brushes/types.d.ts +8 -0
- package/dist/{brushstrokeRender-WR2N5HHY.cjs → brushstrokeRender-5YBCLFDQ.cjs} +15 -15
- package/dist/{brushstrokeRender-A727TTNQ.js → brushstrokeRender-DZGFU3J4.js} +3 -3
- package/dist/canvas/index.cjs +13 -13
- package/dist/canvas/index.js +1 -1
- package/dist/chart/contract.d.cts +95 -0
- package/dist/chart/contract.d.ts +95 -0
- package/dist/chart/controller.d.cts +4 -0
- package/dist/chart/controller.d.ts +4 -0
- package/dist/chart/index.cjs +492 -26
- package/dist/chart/index.d.cts +1 -0
- package/dist/chart/index.d.ts +1 -0
- package/dist/chart/index.js +476 -10
- package/dist/chart/tools.d.cts +3 -0
- package/dist/chart/tools.d.ts +3 -0
- package/dist/chart-maps/index.cjs +4 -64
- package/dist/chart-maps/index.js +3 -63
- package/dist/{chunk-YNFSH72F.js → chunk-2F3YDXCN.js} +1 -1
- package/dist/{chunk-QYXUE37Q.js → chunk-2XDNF73E.js} +1 -1
- package/dist/{chunk-3KNQ2W6X.cjs → chunk-3JKCREEU.cjs} +59 -53
- package/dist/{chunk-NMZQMPFZ.js → chunk-4LZQO5Y7.js} +2 -0
- package/dist/{chunk-B5W677L7.js → chunk-5HP2VSAS.js} +1 -1
- package/dist/chunk-5UGRMVNE.js +328 -0
- package/dist/{chunk-X4FTNFIA.js → chunk-7MGPW2OV.js} +1 -1
- package/dist/{chunk-BPJSI4NT.cjs → chunk-7W2EQQBP.cjs} +2 -2
- package/dist/{chunk-DGITFN73.cjs → chunk-BWJBZAUE.cjs} +8 -8
- package/dist/chunk-CHZYVNXZ.js +336 -0
- package/dist/{chunk-LETF75CA.js → chunk-CLB2I2FU.js} +1 -1
- package/dist/chunk-DRMZ5R3S.cjs +67 -0
- package/dist/{chunk-BAZMCFVL.js → chunk-DZVRH63Y.js} +1 -1
- package/dist/chunk-EI5GFTKG.js +67 -0
- package/dist/{chunk-U2ASNGO6.cjs → chunk-FXVCB6YG.cjs} +35 -35
- package/dist/{chunk-EU2ZZA6L.cjs → chunk-GHGBIAWQ.cjs} +126 -39
- package/dist/chunk-JV7DKLMX.js +1073 -0
- package/dist/{chunk-2WOGXEDX.cjs → chunk-M3RZOF3G.cjs} +1 -1
- package/dist/chunk-MFBUQC67.cjs +328 -0
- package/dist/{chunk-GSTSZPSR.js → chunk-N3SKPQEH.js} +225 -18
- package/dist/{chunk-J5VQYK7T.cjs → chunk-N5IMDAHM.cjs} +251 -44
- package/dist/{chunk-ININNHLM.js → chunk-NAHJV3O6.js} +11 -5
- package/dist/{chunk-IBXEQOGI.js → chunk-PYHB2EHE.js} +2 -324
- package/dist/chunk-QEUI6OGE.cjs +336 -0
- package/dist/{chunk-6ZSFRRJI.js → chunk-RSF6BT34.js} +1 -1
- package/dist/{chunk-JJ2H25JG.cjs → chunk-SNAFFCAX.cjs} +200 -174
- package/dist/chunk-T2HUQBRC.cjs +1073 -0
- package/dist/{chunk-M2ZVPU7L.cjs → chunk-TNLKFW7D.cjs} +23 -23
- package/dist/{chunk-KZI3YWKW.js → chunk-UXYCY3HP.js} +93 -6
- package/dist/{chunk-GSLOH2IN.cjs → chunk-VF6ODSYX.cjs} +2 -0
- package/dist/{chunk-NQUKTRKN.cjs → chunk-WZLNNGG3.cjs} +45 -45
- package/dist/{chunk-NRBGAEFI.cjs → chunk-Y3RUYOOW.cjs} +8 -330
- package/dist/{chunk-DDL3ZBHK.cjs → chunk-YJANF2BL.cjs} +86 -86
- package/dist/{chunk-TNHDCP4R.js → chunk-ZEI7ZEA4.js} +31 -5
- package/dist/commands/index.cjs +7 -323
- package/dist/commands/index.js +5 -321
- package/dist/extensions/index.cjs +4 -4
- package/dist/extensions/index.js +3 -3
- package/dist/image-editor/index.cjs +789 -789
- package/dist/image-editor/index.js +5 -5
- package/dist/index.cjs +9 -9
- package/dist/index.js +3 -3
- package/dist/paint/index.cjs +2 -2
- package/dist/paint/index.js +1 -1
- package/dist/paint/wet/world.d.cts +37 -1
- package/dist/paint/wet/world.d.ts +37 -1
- package/dist/paint-editor/brush-controls.d.cts +2 -0
- package/dist/paint-editor/brush-controls.d.ts +2 -0
- package/dist/paint-editor/brush-model.d.cts +14 -1
- package/dist/paint-editor/brush-model.d.ts +14 -1
- package/dist/paint-editor/index.cjs +343 -306
- package/dist/paint-editor/index.js +48 -11
- package/dist/paint-editor/ui.d.cts +1 -1
- package/dist/paint-editor/ui.d.ts +1 -1
- package/dist/paint-editor/wet.d.cts +8 -1
- package/dist/paint-editor/wet.d.ts +8 -1
- package/dist/persistence/index.cjs +24 -1042
- package/dist/persistence/index.js +22 -1040
- package/dist/tools/index.cjs +5 -3
- package/dist/tools/index.js +8 -6
- package/dist/vector/index.cjs +999 -999
- package/dist/vector/index.js +5 -5
- package/package.json +1 -1
- package/skills/pixerate-brushes/SKILL.md +1 -0
- package/skills/pixerate-paint-editor/SKILL.md +4 -11
- package/skills/pixerate-paint-editor/references/brush-facets.md +1 -0
- package/skills/pixerate-paint-editor/references/ghost.md +47 -0
- package/skills/pixerate-paint-watercolour/SKILL.md +1 -0
|
@@ -849,9 +849,13 @@ var SLOT_FLOATS = SLOT_PLANES * PLANE;
|
|
|
849
849
|
var S2 = SLOT_SIDE;
|
|
850
850
|
var SNAP_PLANES = SET_PLANES + MASS_CHANNELS;
|
|
851
851
|
var noLight = () => new (0, _chunk474IQG74cjs.TiledSurface)(1, /* @__PURE__ */ new Map(), 0);
|
|
852
|
-
function
|
|
852
|
+
function cloneGhost(g) {
|
|
853
|
+
return g ? { pigment: [...g.pigment], remaining: g.remaining, total: g.total, linger: g.linger } : null;
|
|
854
|
+
}
|
|
855
|
+
function newLane(id, index, params, flow, flowStrength, base, light, ghost) {
|
|
853
856
|
const l = _nullishCoalesce(light, () => ( noLight()));
|
|
854
|
-
|
|
857
|
+
const g = cloneGhost(ghost);
|
|
858
|
+
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: !g && l.tiles.size > 0, ghost: g, lightShaded: /* @__PURE__ */ new Map(), lightDisplay: null, lightKey: "" };
|
|
855
859
|
}
|
|
856
860
|
var WetWorldError = class extends Error {
|
|
857
861
|
constructor(message) {
|
|
@@ -1012,11 +1016,12 @@ var WetWorld = (_class = class {
|
|
|
1012
1016
|
if (options.params) this.setParams(id, options.params);
|
|
1013
1017
|
if (options.base) this.setBase(id, options.base);
|
|
1014
1018
|
if (options.light) this.setLight(id, options.light);
|
|
1019
|
+
if (options.ghost !== void 0) this.setGhost(id, options.ghost);
|
|
1015
1020
|
return;
|
|
1016
1021
|
}
|
|
1017
1022
|
const index = this.lanes.indexOf(null);
|
|
1018
1023
|
if (index < 0) throw new WetWorldError(`At most ${MAX_WET_LANES} layers can hold wet paint at once; dry one (dry_paint) first.`);
|
|
1019
|
-
this.lanes[index] = newLane(id, index, normalizeWetParams(_nullishCoalesce(options.params, () => ( {})), DEFAULT_WET_PARAMS), _nullishCoalesce(options.flow, () => ( null)), options.flow ? _nullishCoalesce(options.flowStrength, () => ( 1)) : 0, _nullishCoalesce(options.base, () => ( new (0, _chunk474IQG74cjs.TiledSurface)(4, /* @__PURE__ */ new Map(), 0))), options.light);
|
|
1024
|
+
this.lanes[index] = newLane(id, index, normalizeWetParams(_nullishCoalesce(options.params, () => ( {})), DEFAULT_WET_PARAMS), _nullishCoalesce(options.flow, () => ( null)), options.flow ? _nullishCoalesce(options.flowStrength, () => ( 1)) : 0, _nullishCoalesce(options.base, () => ( new (0, _chunk474IQG74cjs.TiledSurface)(4, /* @__PURE__ */ new Map(), 0))), options.light, options.ghost);
|
|
1020
1025
|
this.pack(this.lanes[index]);
|
|
1021
1026
|
}
|
|
1022
1027
|
/** Drops a wet layer and its wet paint (nothing is baked). */
|
|
@@ -1089,17 +1094,46 @@ var WetWorld = (_class = class {
|
|
|
1089
1094
|
}
|
|
1090
1095
|
/** Whether a layer has light paint, under its wet paint or in it. */
|
|
1091
1096
|
isLit(id) {
|
|
1092
|
-
|
|
1097
|
+
const l = this.laneOf(id);
|
|
1098
|
+
return l.lit && !l.ghost;
|
|
1093
1099
|
}
|
|
1094
1100
|
/** Replaces the light paint under a layer's wet paint. */
|
|
1095
1101
|
setLight(id, light) {
|
|
1096
1102
|
const lane = this.laneOf(id);
|
|
1097
1103
|
if (light === lane.light) return;
|
|
1098
1104
|
lane.light = light;
|
|
1099
|
-
if (light.tiles.size) lane.lit = true;
|
|
1105
|
+
if (light.tiles.size && !lane.ghost) lane.lit = true;
|
|
1100
1106
|
lane.lightShaded.clear();
|
|
1101
1107
|
lane.stamp++;
|
|
1102
1108
|
}
|
|
1109
|
+
/** Active ghost paint state on the layer, or `null`. */
|
|
1110
|
+
getGhost(id) {
|
|
1111
|
+
return cloneGhost(this.laneOf(id).ghost);
|
|
1112
|
+
}
|
|
1113
|
+
/** Sets or clears a layer's active ghost paint state. */
|
|
1114
|
+
setGhost(id, ghost) {
|
|
1115
|
+
this.requireIdle();
|
|
1116
|
+
const lane = this.laneOf(id);
|
|
1117
|
+
lane.ghost = cloneGhost(ghost);
|
|
1118
|
+
if (lane.ghost) lane.lit = false;
|
|
1119
|
+
}
|
|
1120
|
+
/**
|
|
1121
|
+
* Starts a ghost paint fade on `id` with `pigment` per unit tracer and `linger` seconds. If an
|
|
1122
|
+
* earlier ghost of a different colour is still fading on the layer, it finishes at once first.
|
|
1123
|
+
*/
|
|
1124
|
+
startGhost(id, pigment, linger, stepsPerSecond = 120) {
|
|
1125
|
+
this.requireIdle();
|
|
1126
|
+
const lane = this.laneOf(id);
|
|
1127
|
+
const p = [Math.fround(pigment[0]), Math.fround(pigment[1]), Math.fround(pigment[2]), Math.fround(pigment[3])];
|
|
1128
|
+
if (lane.ghost) {
|
|
1129
|
+
const g = lane.ghost.pigment;
|
|
1130
|
+
const same = Math.abs(g[0] - p[0]) <= 1e-6 && Math.abs(g[1] - p[1]) <= 1e-6 && Math.abs(g[2] - p[2]) <= 1e-6 && Math.abs(g[3] - p[3]) <= 1e-6;
|
|
1131
|
+
if (!same) this.fadeGhost(id, 1);
|
|
1132
|
+
}
|
|
1133
|
+
const total = Math.max(1, Math.round(linger * stepsPerSecond / FREE_INTERVAL));
|
|
1134
|
+
lane.ghost = { pigment: p, remaining: total, total, linger };
|
|
1135
|
+
lane.lit = false;
|
|
1136
|
+
}
|
|
1103
1137
|
pack(lane) {
|
|
1104
1138
|
packWetParams(lane.params, _nullishCoalesce(this.paper, () => ( DEFAULT_WET_PAPER)), this.tilt, lane.flowStrength, this.prm);
|
|
1105
1139
|
this.f32.set(this.prm, this.layout.params + lane.index * PARAM_FLOATS * 4 >> 2);
|
|
@@ -1332,6 +1366,13 @@ var WetWorld = (_class = class {
|
|
|
1332
1366
|
let woke = false;
|
|
1333
1367
|
for (const key of wakeups) woke = this.activate(key) || woke;
|
|
1334
1368
|
if (this.clock % FREE_INTERVAL === 0) {
|
|
1369
|
+
for (const lane of this.lanes) {
|
|
1370
|
+
if (!_optionalChain([lane, 'optionalAccess', _19 => _19.ghost])) continue;
|
|
1371
|
+
const g = lane.ghost;
|
|
1372
|
+
const amount = g.remaining <= 1 ? 1 : 1 / g.remaining;
|
|
1373
|
+
g.remaining = Math.max(0, g.remaining - 1);
|
|
1374
|
+
this.fadeGhost(lane.id, amount);
|
|
1375
|
+
}
|
|
1335
1376
|
const dead = this.active.filter((key) => {
|
|
1336
1377
|
if (this.u32[lastBase + key] & FLAG_ALIVE) return false;
|
|
1337
1378
|
const laneBase = this.laneIndexOf(key) * perLane;
|
|
@@ -1531,7 +1572,10 @@ var WetWorld = (_class = class {
|
|
|
1531
1572
|
paint(id, rect, cov, water, pigment, field = null, light = 0) {
|
|
1532
1573
|
if (!(water >= 0)) throw new WetWorldError(`water ${water} must be 0 or more.`);
|
|
1533
1574
|
if (!(light >= 0)) throw new WetWorldError(`light ${light} must be 0 or more.`);
|
|
1534
|
-
if (light > 0)
|
|
1575
|
+
if (light > 0) {
|
|
1576
|
+
const l = this.laneOf(id);
|
|
1577
|
+
if (!l.ghost) l.lit = true;
|
|
1578
|
+
}
|
|
1535
1579
|
this.footprint(id, rect, cov, (c, w, x, y) => {
|
|
1536
1580
|
const dw = Math.fround(water * w);
|
|
1537
1581
|
if (dw > 0) this.addWaterAt(c, dw);
|
|
@@ -1683,12 +1727,12 @@ var WetWorld = (_class = class {
|
|
|
1683
1727
|
* the paper as settled pigment, so water can move it again, and the same share of its light
|
|
1684
1728
|
* paint (`light`) as settled light. Only where there is surface water.
|
|
1685
1729
|
*/
|
|
1686
|
-
rewet(id, rect, cov, amount, paper) {
|
|
1730
|
+
rewet(id, rect, cov, amount, paper, suspend = false) {
|
|
1687
1731
|
const lane = this.laneOf(id);
|
|
1688
1732
|
const pig = [0, 0, 0, 0];
|
|
1689
1733
|
const tiles = new Map(lane.base.tiles);
|
|
1690
1734
|
const written = /* @__PURE__ */ new Set();
|
|
1691
|
-
const lightTiles = lane.lit ? new Map(lane.light.tiles) : null;
|
|
1735
|
+
const lightTiles = lane.lit && !lane.ghost ? new Map(lane.light.tiles) : null;
|
|
1692
1736
|
const lightWritten = /* @__PURE__ */ new Set();
|
|
1693
1737
|
const scratch2 = new Uint8ClampedArray(4);
|
|
1694
1738
|
this.footprint(
|
|
@@ -1701,7 +1745,7 @@ var WetWorld = (_class = class {
|
|
|
1701
1745
|
if (!(a > 0)) return;
|
|
1702
1746
|
const key = _chunk474IQG74cjs.tileKey.call(void 0, x >> 8, y >> 8);
|
|
1703
1747
|
const li = (y & 255) * _chunk474IQG74cjs.TILE + (x & 255);
|
|
1704
|
-
let lt = _optionalChain([lightTiles, 'optionalAccess',
|
|
1748
|
+
let lt = _optionalChain([lightTiles, 'optionalAccess', _20 => _20.get, 'call', _21 => _21(key)]);
|
|
1705
1749
|
if (lt && (_nullishCoalesce(lt.uniform, () => ( 1))) !== 0) {
|
|
1706
1750
|
if (!lightWritten.has(key)) {
|
|
1707
1751
|
const data = lt.data.length ? new Uint8ClampedArray(lt.data) : new Uint8ClampedArray(_chunk474IQG74cjs.TILE * _chunk474IQG74cjs.TILE).fill(_nullishCoalesce(lt.uniform, () => ( 0)));
|
|
@@ -1730,8 +1774,8 @@ var WetWorld = (_class = class {
|
|
|
1730
1774
|
const clear = new Uint8ClampedArray([0, 0, 0, 0]);
|
|
1731
1775
|
filmPixel(pig[0] * (1 - a), pig[1] * (1 - a), pig[2] * (1 - a), 0, clear, 0, paper, 0, scratch2, 0);
|
|
1732
1776
|
tile.data.set(scratch2, i);
|
|
1733
|
-
const
|
|
1734
|
-
for (let q = 0; q < 3; q++) this.f32[
|
|
1777
|
+
const into = suspend ? c + P_P0 * PLANE : this.single(c) + P_D0 * PLANE;
|
|
1778
|
+
for (let q = 0; q < 3; q++) this.f32[into + q * PLANE] += Math.fround(pig[q] * a);
|
|
1735
1779
|
},
|
|
1736
1780
|
false
|
|
1737
1781
|
);
|
|
@@ -1752,6 +1796,114 @@ var WetWorld = (_class = class {
|
|
|
1752
1796
|
this.setLight(id, new (0, _chunk474IQG74cjs.TiledSurface)(1, lightTiles, 0));
|
|
1753
1797
|
}
|
|
1754
1798
|
}
|
|
1799
|
+
/**
|
|
1800
|
+
* Subtracts `amount` (0..1) of a ghost lane's remaining tracer (`P_L`, `P_DL`) and proportional
|
|
1801
|
+
* ghost pigment (`lane.ghost.pigment`) across all live tiles of `id`. Speeds up in cells that
|
|
1802
|
+
* are nearly dry so drying paint never pops. Clears the lane's `ghost` state once no tracer remains.
|
|
1803
|
+
*/
|
|
1804
|
+
fadeGhost(id, amount) {
|
|
1805
|
+
this.requireIdle();
|
|
1806
|
+
const lane = this.laneOf(id);
|
|
1807
|
+
if (!lane.ghost) return;
|
|
1808
|
+
const keys = this.active.filter((k) => this.laneIndexOf(k) === lane.index);
|
|
1809
|
+
let anyRemaining = false;
|
|
1810
|
+
for (const key of keys) {
|
|
1811
|
+
if (this.fadeGhostKey(key, lane, amount)) anyRemaining = true;
|
|
1812
|
+
}
|
|
1813
|
+
if (!anyRemaining || amount >= 1 - 1e-6) lane.ghost = null;
|
|
1814
|
+
this.refreshHalos();
|
|
1815
|
+
}
|
|
1816
|
+
/** Whether any live tile of `lane` still holds ghost tracer (`P_L > 0` or `P_DL > 0`). */
|
|
1817
|
+
hasGhostTracer(lane) {
|
|
1818
|
+
const f = this.f32;
|
|
1819
|
+
for (const key of this.active) {
|
|
1820
|
+
if (this.laneIndexOf(key) !== lane.index) continue;
|
|
1821
|
+
const b = this.slotBase(this.slotOf(key));
|
|
1822
|
+
const cur = b + this.parity * SET_PLANES * PLANE;
|
|
1823
|
+
for (let y = 1; y <= WET_TILE; y++) {
|
|
1824
|
+
for (let x = 1; x <= WET_TILE; x++) {
|
|
1825
|
+
const c = y * S2 + x;
|
|
1826
|
+
if (f[cur + P_L * PLANE + c] > 0 || f[b + P_DL * PLANE + c] > 0) return true;
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
return false;
|
|
1831
|
+
}
|
|
1832
|
+
/**
|
|
1833
|
+
* Fades ghost tracer and pigment in one slot by `amount` (0..1). Returns whether any tracer
|
|
1834
|
+
* remains in the slot.
|
|
1835
|
+
*/
|
|
1836
|
+
fadeGhostKey(key, lane, amount) {
|
|
1837
|
+
if (!lane.ghost) return false;
|
|
1838
|
+
const pig = lane.ghost.pigment;
|
|
1839
|
+
const slot = this.slotOf(key);
|
|
1840
|
+
if (slot < 0) return false;
|
|
1841
|
+
const b = this.slotBase(slot);
|
|
1842
|
+
const cur = b + this.parity * SET_PLANES * PLANE;
|
|
1843
|
+
const f = this.f32;
|
|
1844
|
+
const baseAmt = Math.min(1, Math.max(0, amount));
|
|
1845
|
+
let remainingTracer = false;
|
|
1846
|
+
let yMin = WET_TILE + 1;
|
|
1847
|
+
let yMax = 0;
|
|
1848
|
+
for (let y = 1; y <= WET_TILE; y++) {
|
|
1849
|
+
for (let x = 1; x <= WET_TILE; x++) {
|
|
1850
|
+
const c = y * S2 + x;
|
|
1851
|
+
const tl = f[cur + P_L * PLANE + c];
|
|
1852
|
+
const dl = f[b + P_DL * PLANE + c];
|
|
1853
|
+
if (!(tl > 0 || dl > 0)) continue;
|
|
1854
|
+
const water = f[cur + P_RHO * PLANE + c] + f[cur + P_SW * PLANE + c];
|
|
1855
|
+
const dryFade = water <= DRY_EPS ? 1 : water < 0.02 ? (1 - water / 0.02) * 0.5 : 0;
|
|
1856
|
+
const a = baseAmt >= 1 - 1e-6 ? 1 : Math.min(1, Math.max(baseAmt, dryFade));
|
|
1857
|
+
if (!(a > 0)) {
|
|
1858
|
+
remainingTracer = true;
|
|
1859
|
+
continue;
|
|
1860
|
+
}
|
|
1861
|
+
if (y < yMin) yMin = y;
|
|
1862
|
+
if (y > yMax) yMax = y;
|
|
1863
|
+
if (tl > 0) {
|
|
1864
|
+
const done = a >= 1 || tl * (1 - a) <= 1e-7;
|
|
1865
|
+
const dt = done ? tl : Math.fround(tl * a);
|
|
1866
|
+
const tNew = done ? 0 : Math.fround(tl - dt);
|
|
1867
|
+
f[cur + P_L * PLANE + c] = tNew;
|
|
1868
|
+
for (let q = 0; q < 4; q++) {
|
|
1869
|
+
const idx = cur + (P_P0 + q) * PLANE + c;
|
|
1870
|
+
const eps = Math.max(1e-3, pig[q] * 2e-4);
|
|
1871
|
+
const v = Math.max(0, Math.fround(f[idx] - Math.fround(dt * pig[q])));
|
|
1872
|
+
f[idx] = tNew === 0 && v <= eps ? 0 : v;
|
|
1873
|
+
}
|
|
1874
|
+
if (tNew > 0) remainingTracer = true;
|
|
1875
|
+
}
|
|
1876
|
+
if (dl > 0) {
|
|
1877
|
+
const done = a >= 1 || dl * (1 - a) <= 1e-7;
|
|
1878
|
+
const dd = done ? dl : Math.fround(dl * a);
|
|
1879
|
+
const dNew = done ? 0 : Math.fround(dl - dd);
|
|
1880
|
+
f[b + P_DL * PLANE + c] = dNew;
|
|
1881
|
+
for (let q = 0; q < 4; q++) {
|
|
1882
|
+
const idx = b + (P_D0 + q) * PLANE + c;
|
|
1883
|
+
const eps = Math.max(1e-3, pig[q] * 2e-4);
|
|
1884
|
+
const v = Math.max(0, Math.fround(f[idx] - Math.fround(dd * pig[q])));
|
|
1885
|
+
f[idx] = dNew === 0 && v <= eps ? 0 : v;
|
|
1886
|
+
}
|
|
1887
|
+
if (dNew > 0) remainingTracer = true;
|
|
1888
|
+
}
|
|
1889
|
+
if (f[cur + P_L * PLANE + c] === 0 && f[b + P_DL * PLANE + c] === 0) {
|
|
1890
|
+
for (let q = 0; q < 4; q++) {
|
|
1891
|
+
const eps = Math.max(1e-3, pig[q] * 2e-4);
|
|
1892
|
+
const pi = cur + (P_P0 + q) * PLANE + c;
|
|
1893
|
+
if (f[pi] <= eps) f[pi] = 0;
|
|
1894
|
+
const di = b + (P_D0 + q) * PLANE + c;
|
|
1895
|
+
if (f[di] <= eps) f[di] = 0;
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
if (yMax >= yMin) {
|
|
1901
|
+
lane.urgent.add(this.tileKeyOf(key));
|
|
1902
|
+
this.gpuDirtySlot(slot, yMin, yMax);
|
|
1903
|
+
lane.stamp++;
|
|
1904
|
+
}
|
|
1905
|
+
return remainingTracer;
|
|
1906
|
+
}
|
|
1755
1907
|
/**
|
|
1756
1908
|
* Dries wet paint at once (everything settles where it is, the water goes): in `rect`, or the
|
|
1757
1909
|
* whole layer. Whole tiles that end up dry are baked into the base and freed. Returns the
|
|
@@ -1779,10 +1931,28 @@ var WetWorld = (_class = class {
|
|
|
1779
1931
|
continue;
|
|
1780
1932
|
}
|
|
1781
1933
|
const f = this.f32;
|
|
1934
|
+
const pig = _nullishCoalesce(_optionalChain([lane, 'access', _22 => _22.ghost, 'optionalAccess', _23 => _23.pigment]), () => ( null));
|
|
1782
1935
|
for (let y = y0; y < y1; y++) {
|
|
1783
1936
|
for (let x = x0; x < x1; x++) {
|
|
1784
1937
|
const c = this.cell(lane, x, y);
|
|
1785
1938
|
const d = this.single(c) + P_D0 * PLANE;
|
|
1939
|
+
if (pig) {
|
|
1940
|
+
const tl = f[c + P_L * PLANE];
|
|
1941
|
+
const dl = f[d + 4 * PLANE];
|
|
1942
|
+
if (tl > 0 || dl > 0) {
|
|
1943
|
+
f[c + P_L * PLANE] = 0;
|
|
1944
|
+
f[d + 4 * PLANE] = 0;
|
|
1945
|
+
for (let q = 0; q < 4; q++) {
|
|
1946
|
+
const eps = Math.max(1e-3, pig[q] * 2e-4);
|
|
1947
|
+
const pi = c + (P_P0 + q) * PLANE;
|
|
1948
|
+
const pv = Math.max(0, Math.fround(f[pi] - Math.fround(tl * pig[q])));
|
|
1949
|
+
f[pi] = pv <= eps ? 0 : pv;
|
|
1950
|
+
const di = d + q * PLANE;
|
|
1951
|
+
const dv = Math.max(0, Math.fround(f[di] - Math.fround(dl * pig[q])));
|
|
1952
|
+
f[di] = dv <= eps ? 0 : dv;
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1786
1956
|
for (let q = 0; q < MASS_CHANNELS; q++) {
|
|
1787
1957
|
f[d + q * PLANE] += f[c + (P_P0 + q) * PLANE];
|
|
1788
1958
|
f[c + (P_P0 + q) * PLANE] = 0;
|
|
@@ -1797,6 +1967,7 @@ var WetWorld = (_class = class {
|
|
|
1797
1967
|
bounds = unionRect(bounds, { x: x0, y: y0, width: x1 - x0, height: y1 - y0 });
|
|
1798
1968
|
this.markEdited(lane, x0, y0, x1, y1);
|
|
1799
1969
|
}
|
|
1970
|
+
if (lane.ghost && !this.hasGhostTracer(lane)) lane.ghost = null;
|
|
1800
1971
|
this.syncList();
|
|
1801
1972
|
this.refreshHalos();
|
|
1802
1973
|
lane.stamp++;
|
|
@@ -1808,10 +1979,14 @@ var WetWorld = (_class = class {
|
|
|
1808
1979
|
*/
|
|
1809
1980
|
bakeKey(key, all) {
|
|
1810
1981
|
const lane = this.lanes[this.laneIndexOf(key)];
|
|
1982
|
+
if (lane.ghost) {
|
|
1983
|
+
this.fadeGhostKey(key, lane, 1);
|
|
1984
|
+
if (!this.hasGhostTracer(lane)) lane.ghost = null;
|
|
1985
|
+
}
|
|
1811
1986
|
const [tx, ty] = this.tileXY(key);
|
|
1812
1987
|
const tk = _chunk474IQG74cjs.tileKey.call(void 0, tx, ty);
|
|
1813
1988
|
let lightChanged = false;
|
|
1814
|
-
if (lane.lit) {
|
|
1989
|
+
if (lane.lit && !lane.ghost) {
|
|
1815
1990
|
const lout = this.shadeLightSlot(key, _nullishCoalesce(lane.light.tiles.get(tk), () => ( null)), all ? "bake-all" : "bake");
|
|
1816
1991
|
if (lout) {
|
|
1817
1992
|
const tiles2 = new Map(lane.light.tiles);
|
|
@@ -1822,7 +1997,7 @@ var WetWorld = (_class = class {
|
|
|
1822
1997
|
lightChanged = true;
|
|
1823
1998
|
}
|
|
1824
1999
|
}
|
|
1825
|
-
const src = _nullishCoalesce(_optionalChain([lane, 'access',
|
|
2000
|
+
const src = _nullishCoalesce(_optionalChain([lane, 'access', _24 => _24.base, 'access', _25 => _25.tiles, 'access', _26 => _26.get, 'call', _27 => _27(tk), 'optionalAccess', _28 => _28.data]), () => ( null));
|
|
1826
2001
|
const out = this.shadeSlot(key, src, all ? "bake-all" : "bake");
|
|
1827
2002
|
if (!out) return lightChanged;
|
|
1828
2003
|
const tiles = new Map(lane.base.tiles);
|
|
@@ -1857,7 +2032,8 @@ var WetWorld = (_class = class {
|
|
|
1857
2032
|
const out = src ? new Uint8ClampedArray(src) : new Uint8ClampedArray(_chunk474IQG74cjs.TILE * _chunk474IQG74cjs.TILE * 4);
|
|
1858
2033
|
const w = Math.min(WET_TILE, this.width - tx * WET_TILE);
|
|
1859
2034
|
const h = Math.min(WET_TILE, this.height - ty * WET_TILE);
|
|
1860
|
-
const
|
|
2035
|
+
const lane = this.lanes[this.laneIndexOf(key)];
|
|
2036
|
+
const lit = lane.lit && !lane.ghost;
|
|
1861
2037
|
const changed = shadeTile(
|
|
1862
2038
|
this.f32,
|
|
1863
2039
|
PLANE,
|
|
@@ -1885,7 +2061,38 @@ var WetWorld = (_class = class {
|
|
|
1885
2061
|
for (const key of this.active) {
|
|
1886
2062
|
if (this.laneIndexOf(key) !== lane.index) continue;
|
|
1887
2063
|
const tk = this.tileKeyOf(key);
|
|
1888
|
-
|
|
2064
|
+
let out;
|
|
2065
|
+
if (lane.ghost) {
|
|
2066
|
+
const b = this.slotBase(this.slotOf(key));
|
|
2067
|
+
const cur = b + this.parity * SET_PLANES * PLANE;
|
|
2068
|
+
const savedP = this.f32.slice(cur + P_P0 * PLANE, cur + (P_P0 + MASS_CHANNELS) * PLANE);
|
|
2069
|
+
const savedD = this.f32.slice(b + P_D0 * PLANE, b + (P_D0 + MASS_CHANNELS) * PLANE);
|
|
2070
|
+
const pig = lane.ghost.pigment;
|
|
2071
|
+
for (let y = 1; y <= WET_TILE; y++) {
|
|
2072
|
+
for (let x = 1; x <= WET_TILE; x++) {
|
|
2073
|
+
const c = y * S2 + x;
|
|
2074
|
+
const tl = this.f32[cur + P_L * PLANE + c];
|
|
2075
|
+
const dl = this.f32[b + P_DL * PLANE + c];
|
|
2076
|
+
if (!(tl > 0 || dl > 0)) continue;
|
|
2077
|
+
this.f32[cur + P_L * PLANE + c] = 0;
|
|
2078
|
+
this.f32[b + P_DL * PLANE + c] = 0;
|
|
2079
|
+
for (let q = 0; q < 4; q++) {
|
|
2080
|
+
const eps = Math.max(1e-3, pig[q] * 2e-4);
|
|
2081
|
+
const pi = cur + (P_P0 + q) * PLANE + c;
|
|
2082
|
+
const pv = Math.max(0, Math.fround(this.f32[pi] - Math.fround(tl * pig[q])));
|
|
2083
|
+
this.f32[pi] = pv <= eps ? 0 : pv;
|
|
2084
|
+
const di = b + (P_D0 + q) * PLANE + c;
|
|
2085
|
+
const dv = Math.max(0, Math.fround(this.f32[di] - Math.fround(dl * pig[q])));
|
|
2086
|
+
this.f32[di] = dv <= eps ? 0 : dv;
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
out = this.shadeSlot(key, _nullishCoalesce(_optionalChain([lane, 'access', _29 => _29.base, 'access', _30 => _30.tiles, 'access', _31 => _31.get, 'call', _32 => _32(tk), 'optionalAccess', _33 => _33.data]), () => ( null)), "bake-all");
|
|
2091
|
+
this.f32.set(savedP, cur + P_P0 * PLANE);
|
|
2092
|
+
this.f32.set(savedD, b + P_D0 * PLANE);
|
|
2093
|
+
} else {
|
|
2094
|
+
out = this.shadeSlot(key, _nullishCoalesce(_optionalChain([lane, 'access', _34 => _34.base, 'access', _35 => _35.tiles, 'access', _36 => _36.get, 'call', _37 => _37(tk), 'optionalAccess', _38 => _38.data]), () => ( null)), "bake-all");
|
|
2095
|
+
}
|
|
1889
2096
|
if (!out) continue;
|
|
1890
2097
|
const t = _chunk474IQG74cjs.finishTile.call(void 0, out, 4, 0);
|
|
1891
2098
|
if (t) tiles.set(tk, t);
|
|
@@ -1897,7 +2104,7 @@ var WetWorld = (_class = class {
|
|
|
1897
2104
|
bakedLight(id) {
|
|
1898
2105
|
this.requireIdle();
|
|
1899
2106
|
const lane = this.laneOf(id);
|
|
1900
|
-
if (!lane.lit) return lane.light;
|
|
2107
|
+
if (!lane.lit || lane.ghost) return lane.light;
|
|
1901
2108
|
const tiles = new Map(lane.light.tiles);
|
|
1902
2109
|
for (const key of this.active) {
|
|
1903
2110
|
if (this.laneIndexOf(key) !== lane.index) continue;
|
|
@@ -2008,14 +2215,14 @@ var WetWorld = (_class = class {
|
|
|
2008
2215
|
display(id, maxTiles = Infinity) {
|
|
2009
2216
|
const lane = this.laneOf(id);
|
|
2010
2217
|
const keys = this.active.filter((k) => this.laneIndexOf(k) === lane.index);
|
|
2011
|
-
const stale = keys.filter((k) => _optionalChain([lane, 'access',
|
|
2012
|
-
stale.sort((a, b) => Number(lane.urgent.has(this.tileKeyOf(b))) - Number(lane.urgent.has(this.tileKeyOf(a))) || (_nullishCoalesce(_optionalChain([lane, 'access',
|
|
2218
|
+
const stale = keys.filter((k) => _optionalChain([lane, 'access', _39 => _39.shaded, 'access', _40 => _40.get, 'call', _41 => _41(this.tileKeyOf(k)), 'optionalAccess', _42 => _42.stamp]) !== lane.stamp);
|
|
2219
|
+
stale.sort((a, b) => Number(lane.urgent.has(this.tileKeyOf(b))) - Number(lane.urgent.has(this.tileKeyOf(a))) || (_nullishCoalesce(_optionalChain([lane, 'access', _43 => _43.shaded, 'access', _44 => _44.get, 'call', _45 => _45(this.tileKeyOf(a)), 'optionalAccess', _46 => _46.stamp]), () => ( 0))) - (_nullishCoalesce(_optionalChain([lane, 'access', _47 => _47.shaded, 'access', _48 => _48.get, 'call', _49 => _49(this.tileKeyOf(b)), 'optionalAccess', _50 => _50.stamp]), () => ( 0))));
|
|
2013
2220
|
const changed = [];
|
|
2014
2221
|
let done = 0;
|
|
2015
2222
|
for (const key of stale) {
|
|
2016
2223
|
if (done >= maxTiles) break;
|
|
2017
2224
|
const tk = this.tileKeyOf(key);
|
|
2018
|
-
const src = _nullishCoalesce(_optionalChain([lane, 'access',
|
|
2225
|
+
const src = _nullishCoalesce(_optionalChain([lane, 'access', _51 => _51.base, 'access', _52 => _52.tiles, 'access', _53 => _53.get, 'call', _54 => _54(tk), 'optionalAccess', _55 => _55.data]), () => ( null));
|
|
2019
2226
|
const out = this.shadeSlot(key, src, "display");
|
|
2020
2227
|
const tile = out ? _chunk474IQG74cjs.finishTile.call(void 0, out, 4, 0) : _nullishCoalesce(lane.base.tiles.get(tk), () => ( null));
|
|
2021
2228
|
lane.shaded.set(tk, { stamp: lane.stamp, tile: _nullishCoalesce(tile, () => ( { data: new Uint8ClampedArray(0), uniform: 0 })) });
|
|
@@ -2045,14 +2252,14 @@ var WetWorld = (_class = class {
|
|
|
2045
2252
|
*/
|
|
2046
2253
|
lightDisplay(id) {
|
|
2047
2254
|
const lane = this.laneOf(id);
|
|
2048
|
-
if (!lane.lit) return null;
|
|
2255
|
+
if (!lane.lit || lane.ghost) return null;
|
|
2049
2256
|
const keys = this.active.filter((k) => this.laneIndexOf(k) === lane.index);
|
|
2050
2257
|
let changed = false;
|
|
2051
2258
|
const live = /* @__PURE__ */ new Set();
|
|
2052
2259
|
for (const key2 of keys) {
|
|
2053
2260
|
const tk = this.tileKeyOf(key2);
|
|
2054
2261
|
live.add(tk);
|
|
2055
|
-
if (_optionalChain([lane, 'access',
|
|
2262
|
+
if (_optionalChain([lane, 'access', _56 => _56.lightShaded, 'access', _57 => _57.get, 'call', _58 => _58(tk), 'optionalAccess', _59 => _59.stamp]) === lane.stamp) continue;
|
|
2056
2263
|
const src = _nullishCoalesce(lane.light.tiles.get(tk), () => ( null));
|
|
2057
2264
|
const out = this.shadeLightSlot(key2, src, "display");
|
|
2058
2265
|
lane.lightShaded.set(tk, { stamp: lane.stamp, tile: out ? _chunk474IQG74cjs.finishTile.call(void 0, out, 1, 0) : src });
|
|
@@ -2250,7 +2457,7 @@ var WetWorld = (_class = class {
|
|
|
2250
2457
|
if (!this.gpu || this.busyFlag && !plan || !plan && !this.gpuDecide()) return { ...this.display(id, maxCpuTiles), gpu: false };
|
|
2251
2458
|
const lane = this.laneOf(id);
|
|
2252
2459
|
const keys = this.active.filter((k) => this.laneIndexOf(k) === lane.index);
|
|
2253
|
-
const stale = plan ? keys : keys.filter((k) => _optionalChain([lane, 'access',
|
|
2460
|
+
const stale = plan ? keys : keys.filter((k) => _optionalChain([lane, 'access', _60 => _60.shaded, 'access', _61 => _61.get, 'call', _62 => _62(this.tileKeyOf(k)), 'optionalAccess', _63 => _63.stamp]) !== lane.stamp);
|
|
2254
2461
|
if (!stale.length) return { ...this.display(id, 0), gpu: true };
|
|
2255
2462
|
let tiles;
|
|
2256
2463
|
const stamp = lane.stamp;
|
|
@@ -2258,7 +2465,7 @@ var WetWorld = (_class = class {
|
|
|
2258
2465
|
try {
|
|
2259
2466
|
if (!plan) this.gpuSync();
|
|
2260
2467
|
const parity = plan ? plan.parity + plan.done & 1 : this.parity;
|
|
2261
|
-
tiles = await this.gpu.shade(this.gpuJobs(stale), parity, stale.map((k) => _nullishCoalesce(_optionalChain([base, 'access',
|
|
2468
|
+
tiles = await this.gpu.shade(this.gpuJobs(stale), parity, stale.map((k) => _nullishCoalesce(_optionalChain([base, 'access', _64 => _64.tiles, 'access', _65 => _65.get, 'call', _66 => _66(this.tileKeyOf(k)), 'optionalAccess', _67 => _67.data]), () => ( null))), [this.paperBytes[0], this.paperBytes[1], this.paperBytes[2]]);
|
|
2262
2469
|
} catch (e) {
|
|
2263
2470
|
this.gpuStop(`Wet paint stopped using the GPU (${e.message}).`);
|
|
2264
2471
|
return { ...this.display(id, maxCpuTiles), gpu: false };
|
|
@@ -2291,7 +2498,7 @@ var WetWorld = (_class = class {
|
|
|
2291
2498
|
slots.set(key, { planes, last: this.u32[(this.layout.last >> 2) + key] });
|
|
2292
2499
|
bytes += planes.byteLength;
|
|
2293
2500
|
}
|
|
2294
|
-
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 }));
|
|
2501
|
+
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, ghost: cloneGhost(l.ghost) }));
|
|
2295
2502
|
return { clock: this.clock, tilt: { ...this.tilt }, lanes, slots, bytes };
|
|
2296
2503
|
}
|
|
2297
2504
|
/** Puts a snapshot back exactly (the simulation then continues as it would have). */
|
|
@@ -2301,8 +2508,8 @@ var WetWorld = (_class = class {
|
|
|
2301
2508
|
this.lanes.fill(null);
|
|
2302
2509
|
this.tilt = { ...snap.tilt };
|
|
2303
2510
|
for (const l of snap.lanes) {
|
|
2304
|
-
const lane = newLane(l.id, l.index, { ...l.params }, l.flow, l.flowStrength, l.base, l.light);
|
|
2305
|
-
lane.lit = lane.lit || Boolean(l.lit);
|
|
2511
|
+
const lane = newLane(l.id, l.index, { ...l.params }, l.flow, l.flowStrength, l.base, l.light, l.ghost);
|
|
2512
|
+
lane.lit = !lane.ghost && (lane.lit || Boolean(l.lit));
|
|
2306
2513
|
this.lanes[l.index] = lane;
|
|
2307
2514
|
this.pack(this.lanes[l.index]);
|
|
2308
2515
|
}
|
|
@@ -2437,8 +2644,8 @@ function normalizeFlow(raw = {}, base = DEFAULT_FLOW) {
|
|
|
2437
2644
|
}
|
|
2438
2645
|
function flowField(spec, width, height) {
|
|
2439
2646
|
const k = FLOW_ACCEL;
|
|
2440
|
-
const cx = _nullishCoalesce(_optionalChain([spec, 'access',
|
|
2441
|
-
const cy = _nullishCoalesce(_optionalChain([spec, 'access',
|
|
2647
|
+
const cx = _nullishCoalesce(_optionalChain([spec, 'access', _68 => _68.center, 'optionalAccess', _69 => _69.x]), () => ( width / 2));
|
|
2648
|
+
const cy = _nullishCoalesce(_optionalChain([spec, 'access', _70 => _70.center, 'optionalAccess', _71 => _71.y]), () => ( height / 2));
|
|
2442
2649
|
const r0 = Math.max(width, height) / 2;
|
|
2443
2650
|
switch (spec.kind) {
|
|
2444
2651
|
case "none":
|
|
@@ -2901,7 +3108,7 @@ var UNIFORM = 64;
|
|
|
2901
3108
|
var STORAGE = 128;
|
|
2902
3109
|
function findWebGpu() {
|
|
2903
3110
|
const nav = globalThis.navigator;
|
|
2904
|
-
return _nullishCoalesce(_optionalChain([nav, 'optionalAccess',
|
|
3111
|
+
return _nullishCoalesce(_optionalChain([nav, 'optionalAccess', _72 => _72.gpu]), () => ( null));
|
|
2905
3112
|
}
|
|
2906
3113
|
async function createWetGpuEngine(gpu = findWebGpu()) {
|
|
2907
3114
|
const no = (reason, adapter2 = null) => ({ engine: null, support: { supported: false, reason, adapter: adapter2, maxSlots: 0 } });
|
|
@@ -2913,7 +3120,7 @@ async function createWetGpuEngine(gpu = findWebGpu()) {
|
|
|
2913
3120
|
return no(`WebGPU gave no adapter (${e.message}); wet paint runs on the CPU.`);
|
|
2914
3121
|
}
|
|
2915
3122
|
if (!adapter) return no("WebGPU gave no adapter (the GPU may be blocklisted); wet paint runs on the CPU.");
|
|
2916
|
-
const name = [_optionalChain([adapter, 'access',
|
|
3123
|
+
const name = [_optionalChain([adapter, 'access', _73 => _73.info, 'optionalAccess', _74 => _74.vendor]), _optionalChain([adapter, 'access', _75 => _75.info, 'optionalAccess', _76 => _76.architecture])].filter(Boolean).join(" ") || null;
|
|
2917
3124
|
const binding = Math.min(_nullishCoalesce(adapter.limits.maxStorageBufferBindingSize, () => ( 0)), _nullishCoalesce(adapter.limits.maxBufferSize, () => ( 0)));
|
|
2918
3125
|
const maxSlots = Math.min(MAX_WET_SLOTS, Math.floor(binding / SLOT_BYTES));
|
|
2919
3126
|
if (maxSlots < 4) return no(`The GPU's storage buffers hold ${Math.max(0, maxSlots)} wet tiles; at least 4 are needed. Wet paint runs on the CPU.`, name);
|
|
@@ -2933,27 +3140,27 @@ async function createWetGpuEngine(gpu = findWebGpu()) {
|
|
|
2933
3140
|
const engine = await WetGpuEngine.start(device, maxSlots, name);
|
|
2934
3141
|
return { engine, support: { supported: true, reason: null, adapter: name, maxSlots } };
|
|
2935
3142
|
} catch (e) {
|
|
2936
|
-
_optionalChain([device, 'access',
|
|
3143
|
+
_optionalChain([device, 'access', _77 => _77.destroy, 'optionalCall', _78 => _78()]);
|
|
2937
3144
|
return no(`The wet-media shaders did not compile on this GPU (${e.message}); wet paint runs on the CPU.`, name);
|
|
2938
3145
|
}
|
|
2939
3146
|
}
|
|
2940
3147
|
async function wetGpuSupport(gpu = findWebGpu()) {
|
|
2941
3148
|
const { engine, support } = await createWetGpuEngine(gpu);
|
|
2942
|
-
_optionalChain([engine, 'optionalAccess',
|
|
3149
|
+
_optionalChain([engine, 'optionalAccess', _79 => _79.destroy, 'call', _80 => _80()]);
|
|
2943
3150
|
return support;
|
|
2944
3151
|
}
|
|
2945
3152
|
async function pipeline(device, code, label) {
|
|
2946
|
-
_optionalChain([device, 'access',
|
|
3153
|
+
_optionalChain([device, 'access', _81 => _81.pushErrorScope, 'optionalCall', _82 => _82("validation")]);
|
|
2947
3154
|
const module = device.createShaderModule({ code, label });
|
|
2948
|
-
const info = await _optionalChain([module, 'access',
|
|
2949
|
-
const errors = _nullishCoalesce(_optionalChain([info, 'optionalAccess',
|
|
3155
|
+
const info = await _optionalChain([module, 'access', _83 => _83.getCompilationInfo, 'optionalCall', _84 => _84()]);
|
|
3156
|
+
const errors = _nullishCoalesce(_optionalChain([info, 'optionalAccess', _85 => _85.messages, 'access', _86 => _86.filter, 'call', _87 => _87((m) => m.type === "error")]), () => ( []));
|
|
2950
3157
|
if (errors.length) {
|
|
2951
|
-
await _optionalChain([device, 'access',
|
|
3158
|
+
await _optionalChain([device, 'access', _88 => _88.popErrorScope, 'optionalCall', _89 => _89()]);
|
|
2952
3159
|
throw new Error(`${label}: ${errors.map((m) => `line ${m.lineNum}: ${m.message}`).join("; ")}`);
|
|
2953
3160
|
}
|
|
2954
3161
|
const desc = { layout: "auto", compute: { module, entryPoint: "main" }, label };
|
|
2955
3162
|
const p = device.createComputePipelineAsync ? await device.createComputePipelineAsync(desc) : device.createComputePipeline(desc);
|
|
2956
|
-
const err = await _optionalChain([device, 'access',
|
|
3163
|
+
const err = await _optionalChain([device, 'access', _90 => _90.popErrorScope, 'optionalCall', _91 => _91()]);
|
|
2957
3164
|
if (err) throw new Error(`${label}: ${err.message}`);
|
|
2958
3165
|
return p;
|
|
2959
3166
|
}
|
|
@@ -2979,8 +3186,8 @@ var WetGpuEngine = (_class3 = class _WetGpuEngine {
|
|
|
2979
3186
|
return b;
|
|
2980
3187
|
});
|
|
2981
3188
|
this.shadeUni = d.createBuffer({ size: 16, usage: UNIFORM | COPY_DST, label: "wet shade" });
|
|
2982
|
-
void _optionalChain([device, 'access',
|
|
2983
|
-
this.lostReason = _optionalChain([info, 'optionalAccess',
|
|
3189
|
+
void _optionalChain([device, 'access', _92 => _92.lost, 'optionalAccess', _93 => _93.then, 'call', _94 => _94((info) => {
|
|
3190
|
+
this.lostReason = _optionalChain([info, 'optionalAccess', _95 => _95.message]) || _optionalChain([info, 'optionalAccess', _96 => _96.reason]) || "the GPU device was lost";
|
|
2984
3191
|
})]);
|
|
2985
3192
|
}
|
|
2986
3193
|
|
|
@@ -3014,7 +3221,7 @@ var WetGpuEngine = (_class3 = class _WetGpuEngine {
|
|
|
3014
3221
|
}
|
|
3015
3222
|
/** Bytes of GPU memory in use. */
|
|
3016
3223
|
memoryBytes() {
|
|
3017
|
-
return this.state.size + this.jobs.size + (_nullishCoalesce(_optionalChain([this, 'access',
|
|
3224
|
+
return this.state.size + this.jobs.size + (_nullishCoalesce(_optionalChain([this, 'access', _97 => _97.srcTiles, 'optionalAccess', _98 => _98.size]), () => ( 0))) + (_nullishCoalesce(_optionalChain([this, 'access', _99 => _99.outTiles, 'optionalAccess', _100 => _100.size]), () => ( 0))) * 2;
|
|
3018
3225
|
}
|
|
3019
3226
|
/** Slots the state buffer holds now. */
|
|
3020
3227
|
get capacity() {
|
|
@@ -3163,9 +3370,9 @@ var WetGpuEngine = (_class3 = class _WetGpuEngine {
|
|
|
3163
3370
|
const d = this.device;
|
|
3164
3371
|
const tileBytes = TILE_WORDS * 4;
|
|
3165
3372
|
if (n > this.tileCap || !this.outTiles || !this.outRead || !this.srcTiles) {
|
|
3166
|
-
_optionalChain([this, 'access',
|
|
3167
|
-
_optionalChain([this, 'access',
|
|
3168
|
-
_optionalChain([this, 'access',
|
|
3373
|
+
_optionalChain([this, 'access', _101 => _101.srcTiles, 'optionalAccess', _102 => _102.destroy, 'call', _103 => _103()]);
|
|
3374
|
+
_optionalChain([this, 'access', _104 => _104.outTiles, 'optionalAccess', _105 => _105.destroy, 'call', _106 => _106()]);
|
|
3375
|
+
_optionalChain([this, 'access', _107 => _107.outRead, 'optionalAccess', _108 => _108.destroy, 'call', _109 => _109()]);
|
|
3169
3376
|
this.tileCap = Math.max(n, this.tileCap * 2, 4);
|
|
3170
3377
|
this.srcTiles = d.createBuffer({ size: this.tileCap * tileBytes, usage: STORAGE | COPY_DST, label: "wet base tiles" });
|
|
3171
3378
|
this.outTiles = d.createBuffer({ size: this.tileCap * tileBytes, usage: STORAGE | COPY_SRC, label: "wet shaded tiles" });
|
|
@@ -3219,7 +3426,7 @@ var WetGpuEngine = (_class3 = class _WetGpuEngine {
|
|
|
3219
3426
|
return this.device.queue.onSubmittedWorkDone();
|
|
3220
3427
|
}
|
|
3221
3428
|
destroy() {
|
|
3222
|
-
for (const b of [this.state, this.params, this.jobs, this.flags, this.flagsRead, ...this.uni, this.shadeUni, this.srcTiles, this.outTiles, this.outRead]) _optionalChain([b, 'optionalAccess',
|
|
3429
|
+
for (const b of [this.state, this.params, this.jobs, this.flags, this.flagsRead, ...this.uni, this.shadeUni, this.srcTiles, this.outTiles, this.outRead]) _optionalChain([b, 'optionalAccess', _110 => _110.destroy, 'call', _111 => _111()]);
|
|
3223
3430
|
this.device.destroy();
|
|
3224
3431
|
}
|
|
3225
3432
|
}, _class3);
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
resolveEngine,
|
|
28
28
|
summarizeBrushSource,
|
|
29
29
|
withKeptIssues
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-UXYCY3HP.js";
|
|
31
31
|
import {
|
|
32
32
|
base64ToBytes
|
|
33
33
|
} from "./chunk-OTTT5N3K.js";
|
|
@@ -44,7 +44,7 @@ var BRUSH_PATCH_PROPERTIES = (() => {
|
|
|
44
44
|
const { required: _r, ...tip } = rest.tip;
|
|
45
45
|
return { ...rest, tip: { ...tip, description: `${tip.description} In a patch, shape may be left out to keep it.` } };
|
|
46
46
|
})();
|
|
47
|
-
var UNSETTABLE_BRUSH_FACETS = ["description", "tags", "medium", "variety", "marks", "dynamics", "behaviour", "light", "motion", "colour"];
|
|
47
|
+
var UNSETTABLE_BRUSH_FACETS = ["description", "tags", "medium", "variety", "marks", "dynamics", "behaviour", "light", "ghost", "motion", "colour"];
|
|
48
48
|
var BRUSH_UNSET_PROPERTY = {
|
|
49
49
|
type: "array",
|
|
50
50
|
minItems: 1,
|
|
@@ -1117,9 +1117,13 @@ var PICKUP_SLIDERS = [
|
|
|
1117
1117
|
{ path: "behavior.pickup", label: "Pick-up", min: 0, max: 1, step: 0.01 },
|
|
1118
1118
|
{ path: "behavior.mix", label: "Mix", min: 0, max: 1, step: 0.01 }
|
|
1119
1119
|
];
|
|
1120
|
+
var GHOST_SLIDERS = [
|
|
1121
|
+
{ path: "ghost.linger", label: "Linger", min: 0.5, max: 60, step: 0.5 },
|
|
1122
|
+
{ path: "ghost.smear", label: "Smear", min: 0, max: 1, step: 0.01 }
|
|
1123
|
+
];
|
|
1120
1124
|
function brushEngineControls(brush) {
|
|
1121
1125
|
const c = engineControls(brush);
|
|
1122
|
-
const wetPaint = brush.engine === "wet" && brush.wet?.tool === "paint";
|
|
1126
|
+
const wetPaint = brush.engine === "wet" && brush.wet?.tool === "paint" && !brush.ghost;
|
|
1123
1127
|
if (!c || !(wetPaint || ["dab", "mixer", "particle", "bristle", "impasto"].includes(brush.engine))) return c;
|
|
1124
1128
|
const extra = brush.engine === "impasto" ? [{ path: "impasto.rim", label: "Rim", min: 0, max: 1, step: 0.01 }, { path: "impasto.clarity", label: "Clarity", min: 0, max: 1, step: 0.01 }] : [];
|
|
1125
1129
|
return { ...c, sliders: [...c.sliders, LIGHT_SLIDER, ...extra], light: true };
|
|
@@ -1203,6 +1207,7 @@ function engineControls(brush) {
|
|
|
1203
1207
|
};
|
|
1204
1208
|
case "wet": {
|
|
1205
1209
|
const tool = brush.wet?.tool ?? "paint";
|
|
1210
|
+
const ghost = tool === "paint" && Boolean(brush.ghost);
|
|
1206
1211
|
const sliders = tool === "paint" ? [
|
|
1207
1212
|
{ path: "wet.water", label: "Water", min: 0, max: 1, step: 0.01 },
|
|
1208
1213
|
{ path: "wet.pigment", label: "Pigment", min: 0, max: 1, step: 0.01 },
|
|
@@ -1210,12 +1215,12 @@ function engineControls(brush) {
|
|
|
1210
1215
|
{ path: "wet.rewet", label: "Re-wet", min: 0, max: 1, step: 0.01 },
|
|
1211
1216
|
{ path: "wet.load", label: "Load", min: 0, max: 1, step: 0.01 },
|
|
1212
1217
|
{ path: "wet.thinner", label: "Thinner", min: 0, max: 1, step: 0.01 },
|
|
1213
|
-
...PICKUP_SLIDERS
|
|
1218
|
+
...ghost ? GHOST_SLIDERS : PICKUP_SLIDERS
|
|
1214
1219
|
] : tool === "water" ? [
|
|
1215
1220
|
{ path: "wet.water", label: "Water", min: 0, max: 1, step: 0.01 },
|
|
1216
1221
|
{ path: "wet.rewet", label: "Re-wet", min: 0, max: 1, step: 0.01 }
|
|
1217
1222
|
] : [{ path: "wet.strength", label: "Strength", min: 0, max: 1, step: 0.01 }];
|
|
1218
|
-
return { title: "Wet brush", sliders, mixingPath: tool === "paint" ? "behavior.mixing" : null, dirty: tool === "paint", multicolor: false, load: tool === "paint", wetTool: true };
|
|
1223
|
+
return { title: "Wet brush", sliders, mixingPath: tool === "paint" ? "behavior.mixing" : null, dirty: tool === "paint" && !ghost, multicolor: false, load: tool === "paint" && !ghost, wetTool: true };
|
|
1219
1224
|
}
|
|
1220
1225
|
case "blender":
|
|
1221
1226
|
return {
|
|
@@ -1284,6 +1289,7 @@ export {
|
|
|
1284
1289
|
createBrushLibraryTools,
|
|
1285
1290
|
createBrushLibraryToolProvider,
|
|
1286
1291
|
BRUSH_SLIDERS,
|
|
1292
|
+
GHOST_SLIDERS,
|
|
1287
1293
|
brushEngineControls,
|
|
1288
1294
|
multiColorSliders,
|
|
1289
1295
|
patchBrushValue
|