@vibecook/ice 0.14.0 → 0.15.0-desk.2
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/{chunk-ZPUPBULB.js → chunk-52GMQ2BN.js} +1320 -450
- package/dist/chunk-52GMQ2BN.js.map +1 -0
- package/dist/{chunk-BA7XJC27.js → chunk-K4HUZAYJ.js} +49 -34
- package/dist/chunk-K4HUZAYJ.js.map +1 -0
- package/dist/{chunk-DYK6KNLG.js → chunk-PFJN3XN2.js} +39 -14
- package/dist/chunk-PFJN3XN2.js.map +1 -0
- package/dist/{chunk-IBWWLA6D.js → chunk-U4YMA4TJ.js} +6 -5
- package/dist/chunk-U4YMA4TJ.js.map +1 -0
- package/dist/desk-kit.js +2 -2
- package/dist/desk-objects.js +15 -9
- package/dist/desk-objects.js.map +1 -1
- package/dist/desk.js +31 -3
- package/dist/devtools.js +1 -1
- package/dist/dom.js +2 -2
- package/dist/index.js +1 -1
- package/dist/react.js +9 -7
- package/dist/react.js.map +1 -1
- package/dist/types/packages/core/src/index.d.ts +1 -1
- package/dist/types/packages/core/src/interaction/install.d.ts +7 -1
- package/dist/types/packages/core/src/systems/held.d.ts +3 -1
- package/dist/types/packages/core/src/systems/l1-pick.d.ts +16 -0
- package/dist/types/packages/core/src/systems/l2-recognize.d.ts +3 -1
- package/dist/types/packages/core/src/systems/press-button.d.ts +25 -0
- package/dist/types/packages/core/src/systems/tray.d.ts +3 -0
- package/dist/types/packages/desk/src/compose/builder.d.ts +22 -1
- package/dist/types/packages/desk/src/compose/marks.d.ts +7 -0
- package/dist/types/packages/desk/src/compose/pick.d.ts +1 -1
- package/dist/types/packages/desk/src/compose/reflector.d.ts +9 -0
- package/dist/types/packages/desk/src/engine/budget.d.ts +5 -0
- package/dist/types/packages/desk/src/faults.d.ts +38 -0
- package/dist/types/packages/desk/src/ground.d.ts +158 -9
- package/dist/types/packages/desk/src/hold/focus.d.ts +1 -1
- package/dist/types/packages/desk/src/hold/pose.d.ts +27 -7
- package/dist/types/packages/desk/src/host/index.d.ts +1 -1
- package/dist/types/packages/desk/src/host/layer.d.ts +110 -4
- package/dist/types/packages/desk/src/index.d.ts +5 -2
- package/dist/types/packages/desk/src/kind.d.ts +7 -5
- package/dist/types/packages/desk/src/kinds/world.d.ts +20 -2
- package/dist/types/packages/desk/src/kit/editor.d.ts +3 -1
- package/dist/types/packages/desk/src/kit/hold.d.ts +1 -1
- package/dist/types/packages/desk/src/missing/layout.d.ts +27 -0
- package/dist/types/packages/desk/src/missing/object.d.ts +6 -0
- package/dist/types/packages/desk/src/missing/pass.d.ts +39 -0
- package/dist/types/packages/desk/src/missing/shaders.d.ts +7 -0
- package/dist/types/packages/desk/src/missing/slots.d.ts +8 -0
- package/dist/types/packages/desk/src/shaders.gen.d.ts +5 -4
- package/dist/types/packages/desk/src/theme.d.ts +22 -0
- package/dist/types/packages/desk/src/tray/drawer.d.ts +16 -5
- package/dist/types/packages/desk/src/tray/flux.d.ts +4 -1
- package/dist/types/packages/desk/src/tray/index.d.ts +1 -1
- package/dist/types/packages/desk/src/tray/pass.d.ts +7 -2
- package/dist/types/packages/desk/src/tray/specimens.d.ts +21 -6
- package/dist/types/packages/dom/src/desk-host.d.ts +15 -2
- package/dist/types/packages/dom/src/pointer-adapter.d.ts +6 -0
- package/dist/types/packages/objects/src/board/layout.d.ts +1 -1
- package/dist/types/packages/objects/src/shaders.gen.d.ts +1 -1
- package/dist/types/packages/react/src/selection-menu.d.ts +5 -2
- package/package.json +1 -1
- package/dist/chunk-BA7XJC27.js.map +0 -1
- package/dist/chunk-DYK6KNLG.js.map +0 -1
- package/dist/chunk-IBWWLA6D.js.map +0 -1
- package/dist/chunk-ZPUPBULB.js.map +0 -1
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
LAYER_IDLE_MS,
|
|
20
20
|
MARKS,
|
|
21
21
|
MAT_GRID,
|
|
22
|
+
MISSING,
|
|
22
23
|
MatUniforms,
|
|
23
24
|
NOISE_SIZE,
|
|
24
25
|
NO_GLYPHS,
|
|
@@ -75,7 +76,7 @@ import {
|
|
|
75
76
|
solveFlightStart,
|
|
76
77
|
spring,
|
|
77
78
|
tilted
|
|
78
|
-
} from "./chunk-
|
|
79
|
+
} from "./chunk-K4HUZAYJ.js";
|
|
79
80
|
import {
|
|
80
81
|
BLEND_OVER,
|
|
81
82
|
bindGroup,
|
|
@@ -136,6 +137,7 @@ import {
|
|
|
136
137
|
defineQuery,
|
|
137
138
|
defineWidget,
|
|
138
139
|
departedCameraOf,
|
|
140
|
+
frameParent,
|
|
139
141
|
gateVerdict,
|
|
140
142
|
heldEntity,
|
|
141
143
|
menuActionsFor,
|
|
@@ -153,13 +155,435 @@ import {
|
|
|
153
155
|
trayTakeProps,
|
|
154
156
|
widgetSpawnInits,
|
|
155
157
|
widgetTypeFor
|
|
156
|
-
} from "./chunk-
|
|
158
|
+
} from "./chunk-PFJN3XN2.js";
|
|
157
159
|
import {
|
|
158
160
|
cubicBezierEase,
|
|
159
161
|
specimenFit,
|
|
160
162
|
trayScrollMax
|
|
161
163
|
} from "./chunk-JS6PG6YD.js";
|
|
162
164
|
|
|
165
|
+
// ../desk/src/faults.ts
|
|
166
|
+
var KIND_STRIKES = 3;
|
|
167
|
+
var KIND_MISSING = -1;
|
|
168
|
+
function faultText(err) {
|
|
169
|
+
const lines = (err instanceof Error ? err.message : typeof err === "object" && err !== null && "message" in err ? String(err.message) : String(err)).split("\n").map((l) => l.trim()).filter((l) => l.length > 0);
|
|
170
|
+
return (lines.length > 1 && lines[0]?.startsWith("WGSL ") ? `${lines[0]} ${lines[1]}` : lines[0]) ?? "refused";
|
|
171
|
+
}
|
|
172
|
+
function createKindFaults() {
|
|
173
|
+
const missing = /* @__PURE__ */ new Set();
|
|
174
|
+
const strikes = /* @__PURE__ */ new Map();
|
|
175
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
176
|
+
let list = [];
|
|
177
|
+
const go = (kind, reason) => {
|
|
178
|
+
missing.add(kind);
|
|
179
|
+
faults.size = missing.size;
|
|
180
|
+
const fault = { kind, reason };
|
|
181
|
+
list = [...list, fault];
|
|
182
|
+
console.error(`[ice] desk: the kind "${kind}" is MISSING \u2014 ${reason}. Its objects are drawn as missing and nothing of it is called again (petition I24).`);
|
|
183
|
+
for (const l of [...listeners]) l(fault);
|
|
184
|
+
};
|
|
185
|
+
const faults = {
|
|
186
|
+
size: 0,
|
|
187
|
+
missing: (kind) => missing.size > 0 && missing.has(kind),
|
|
188
|
+
refuse(kind, reason) {
|
|
189
|
+
if (missing.has(kind)) return;
|
|
190
|
+
go(kind, reason);
|
|
191
|
+
},
|
|
192
|
+
strike(kind, call, err, entity) {
|
|
193
|
+
if (missing.has(kind)) return false;
|
|
194
|
+
const n = (strikes.get(kind) ?? 0) + 1;
|
|
195
|
+
strikes.set(kind, n);
|
|
196
|
+
const on = entity === void 0 ? "" : ` on entity ${entity}`;
|
|
197
|
+
if (n < KIND_STRIKES) {
|
|
198
|
+
console.warn(`[ice] desk: the kind "${kind}" threw in its \`${call}\`${on} \u2014 strike ${n} of ${KIND_STRIKES}; the frame goes on without it`, err);
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
go(kind, `its \`${call}\` threw${on} (strike ${n} of ${KIND_STRIKES}): ${faultText(err)}`);
|
|
202
|
+
return true;
|
|
203
|
+
},
|
|
204
|
+
strikes: (kind) => strikes.get(kind) ?? 0,
|
|
205
|
+
list: () => list,
|
|
206
|
+
subscribe(listener) {
|
|
207
|
+
listeners.add(listener);
|
|
208
|
+
return () => {
|
|
209
|
+
listeners.delete(listener);
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
return faults;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// ../desk/src/missing/layout.ts
|
|
217
|
+
var MissingFace = defineStruct("MissingFace", [
|
|
218
|
+
["rect", "vec4f"],
|
|
219
|
+
// centre x, y; half extents x, y — world units
|
|
220
|
+
["ink", "vec4f"],
|
|
221
|
+
// the ink (rgb), the object's fade (w)
|
|
222
|
+
["mix", "vec4f"],
|
|
223
|
+
// the wash's, the hatching's and the edge's alpha
|
|
224
|
+
["shape", "vec4f"]
|
|
225
|
+
// the corner (world units); the hatching's pitch and weight, the edge's weight (CSS px)
|
|
226
|
+
]);
|
|
227
|
+
var isMissingRecord = (r) => typeof r === "object" && r !== null && r.missing === true;
|
|
228
|
+
var INKS = { light: rgb(MISSING.ink.light), dark: rgb(MISSING.ink.dark) };
|
|
229
|
+
function missingFace(rect, theme, fade = 1) {
|
|
230
|
+
return { missing: true, cx: rect.cx, cy: rect.cy, hx: Math.abs(rect.w) / 2, hy: Math.abs(rect.h) / 2, ink: INKS[theme.name] ?? INKS.light, fade };
|
|
231
|
+
}
|
|
232
|
+
var NONE = { rect: [0, 0, 0, 0], ink: [0, 0, 0, 0], mix: [0, 0, 0, 0], shape: [0, 0, 0, 0] };
|
|
233
|
+
function missingValues(r) {
|
|
234
|
+
if (!isMissingRecord(r)) return NONE;
|
|
235
|
+
return {
|
|
236
|
+
rect: [r.cx, r.cy, r.hx, r.hy],
|
|
237
|
+
ink: [r.ink[0], r.ink[1], r.ink[2], r.fade],
|
|
238
|
+
mix: [MISSING.wash, MISSING.hatch, MISSING.edge, 0],
|
|
239
|
+
shape: [MISSING.corner, MISSING.pitch, MISSING.weight, MISSING.edgeWeight]
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
function missingHit(g, wx, wy) {
|
|
243
|
+
return Math.abs(wx - g.cx) <= Math.abs(g.w) / 2 && Math.abs(wy - g.cy) <= Math.abs(g.h) / 2 ? "content" : null;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// ../desk/src/engine/records.ts
|
|
247
|
+
var DEFAULT_MAX = 65536;
|
|
248
|
+
var GAP = 4;
|
|
249
|
+
var NONE2 = { aux: 0, blockN: 0 };
|
|
250
|
+
function createRecordStore(opts) {
|
|
251
|
+
const { device, def, label, pack } = opts;
|
|
252
|
+
const max = opts.max ?? DEFAULT_MAX;
|
|
253
|
+
const blocksDef = opts.blocks;
|
|
254
|
+
const per = blocksDef?.per ?? 0;
|
|
255
|
+
let capacity = Math.max(1, Math.min(opts.capacity, max));
|
|
256
|
+
let cpu = def.alloc(capacity);
|
|
257
|
+
let gpu = storageBuffer(device, def.size * capacity, label);
|
|
258
|
+
let blockCpu = blocksDef ? blocksDef.def.alloc(capacity * per) : null;
|
|
259
|
+
let blockGpu = blocksDef ? storageBuffer(device, blocksDef.def.size * capacity * per, blocksDef.label) : null;
|
|
260
|
+
let orderCpu = new Uint32Array(capacity);
|
|
261
|
+
let orderGpu = storageBuffer(device, 4 * capacity, `${label} order`);
|
|
262
|
+
let version = 0;
|
|
263
|
+
let grown = 0;
|
|
264
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
265
|
+
let bySlot = new Array(capacity).fill(null);
|
|
266
|
+
const free = [];
|
|
267
|
+
let next = 0;
|
|
268
|
+
let gen = 0;
|
|
269
|
+
let lastKeys = null;
|
|
270
|
+
let prevOrder = [];
|
|
271
|
+
let count = 0;
|
|
272
|
+
const dirty = [];
|
|
273
|
+
let written = 0;
|
|
274
|
+
let bytes = 0;
|
|
275
|
+
let orderWrites = 0;
|
|
276
|
+
const grow = () => {
|
|
277
|
+
if (capacity >= max) throw new Error(`${label}: ${capacity} record slots is the most this store grows to`);
|
|
278
|
+
const was = capacity;
|
|
279
|
+
capacity = Math.min(capacity * 2, max);
|
|
280
|
+
const nextCpu = def.alloc(capacity);
|
|
281
|
+
new Uint8Array(nextCpu.bytes).set(new Uint8Array(cpu.bytes));
|
|
282
|
+
cpu = nextCpu;
|
|
283
|
+
gpu.destroy();
|
|
284
|
+
gpu = storageBuffer(device, def.size * capacity, label);
|
|
285
|
+
if (blocksDef && blockCpu && blockGpu) {
|
|
286
|
+
const nextBlocks = blocksDef.def.alloc(capacity * per);
|
|
287
|
+
new Uint8Array(nextBlocks.bytes).set(new Uint8Array(blockCpu.bytes));
|
|
288
|
+
blockCpu = nextBlocks;
|
|
289
|
+
blockGpu.destroy();
|
|
290
|
+
blockGpu = storageBuffer(device, blocksDef.def.size * capacity * per, blocksDef.label);
|
|
291
|
+
}
|
|
292
|
+
const nextOrder = new Uint32Array(capacity);
|
|
293
|
+
nextOrder.set(orderCpu);
|
|
294
|
+
orderCpu = nextOrder;
|
|
295
|
+
orderGpu.destroy();
|
|
296
|
+
orderGpu = storageBuffer(device, 4 * capacity, `${label} order`);
|
|
297
|
+
const nextBySlot = new Array(capacity).fill(null);
|
|
298
|
+
for (let i = 0; i < was; i++) nextBySlot[i] = bySlot[i] ?? null;
|
|
299
|
+
bySlot = nextBySlot;
|
|
300
|
+
version += 1;
|
|
301
|
+
grown += 1;
|
|
302
|
+
};
|
|
303
|
+
let grew = false;
|
|
304
|
+
const alloc = () => {
|
|
305
|
+
const reused = free.pop();
|
|
306
|
+
if (reused !== void 0) return reused;
|
|
307
|
+
if (next === capacity) {
|
|
308
|
+
grow();
|
|
309
|
+
grew = true;
|
|
310
|
+
}
|
|
311
|
+
return next++;
|
|
312
|
+
};
|
|
313
|
+
const release = (ent) => {
|
|
314
|
+
byKey.delete(ent.key);
|
|
315
|
+
bySlot[ent.slot] = null;
|
|
316
|
+
free.push(ent.slot);
|
|
317
|
+
};
|
|
318
|
+
const resetAll = () => {
|
|
319
|
+
bySlot.fill(null);
|
|
320
|
+
byKey.clear();
|
|
321
|
+
free.length = 0;
|
|
322
|
+
next = 0;
|
|
323
|
+
};
|
|
324
|
+
const packInto = (ent, record, aux) => {
|
|
325
|
+
ent.record = record;
|
|
326
|
+
ent.aux = aux;
|
|
327
|
+
ent.blockN = pack(record, aux, cpu, ent.slot, blockCpu, ent.slot * per);
|
|
328
|
+
dirty.push(ent.slot);
|
|
329
|
+
};
|
|
330
|
+
const runs = () => {
|
|
331
|
+
dirty.sort((a, b) => a - b);
|
|
332
|
+
const out = [];
|
|
333
|
+
for (const s of dirty) {
|
|
334
|
+
const last = out[out.length - 1];
|
|
335
|
+
if (last !== void 0 && s <= last[1] + 1 + GAP) {
|
|
336
|
+
if (s > last[1]) last[1] = s;
|
|
337
|
+
} else out.push([s, s]);
|
|
338
|
+
}
|
|
339
|
+
return out;
|
|
340
|
+
};
|
|
341
|
+
const upload = (n, orderMoved) => {
|
|
342
|
+
let rewriteOrder = orderMoved;
|
|
343
|
+
if (grew) {
|
|
344
|
+
grew = false;
|
|
345
|
+
if (next > 0) {
|
|
346
|
+
device.queue.writeBuffer(gpu, 0, cpu.bytes, 0, next * def.size);
|
|
347
|
+
bytes += next * def.size;
|
|
348
|
+
}
|
|
349
|
+
if (blocksDef && blockCpu && blockGpu && next > 0) {
|
|
350
|
+
device.queue.writeBuffer(blockGpu, 0, blockCpu.bytes, 0, next * per * blocksDef.def.size);
|
|
351
|
+
bytes += next * per * blocksDef.def.size;
|
|
352
|
+
}
|
|
353
|
+
written += dirty.length;
|
|
354
|
+
dirty.length = 0;
|
|
355
|
+
rewriteOrder = true;
|
|
356
|
+
} else if (dirty.length > 0) {
|
|
357
|
+
for (const [a, b] of runs()) {
|
|
358
|
+
const n0 = b - a + 1;
|
|
359
|
+
device.queue.writeBuffer(gpu, a * def.size, cpu.bytes, a * def.size, n0 * def.size);
|
|
360
|
+
bytes += n0 * def.size;
|
|
361
|
+
}
|
|
362
|
+
if (blocksDef && blockCpu && blockGpu) {
|
|
363
|
+
const bsize = blocksDef.def.size;
|
|
364
|
+
for (const s of dirty) {
|
|
365
|
+
const ent = bySlot[s];
|
|
366
|
+
if (!ent || ent.blockN === 0) continue;
|
|
367
|
+
device.queue.writeBuffer(blockGpu, s * per * bsize, blockCpu.bytes, s * per * bsize, ent.blockN * bsize);
|
|
368
|
+
bytes += ent.blockN * bsize;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
written += dirty.length;
|
|
372
|
+
dirty.length = 0;
|
|
373
|
+
}
|
|
374
|
+
if (rewriteOrder) {
|
|
375
|
+
if (n > 0) device.queue.writeBuffer(orderGpu, 0, orderCpu, 0, n);
|
|
376
|
+
orderWrites += 1;
|
|
377
|
+
prevOrder = Array.from(orderCpu.subarray(0, n));
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
return {
|
|
381
|
+
get records() {
|
|
382
|
+
return gpu;
|
|
383
|
+
},
|
|
384
|
+
get order() {
|
|
385
|
+
return orderGpu;
|
|
386
|
+
},
|
|
387
|
+
get blocks() {
|
|
388
|
+
return blockGpu;
|
|
389
|
+
},
|
|
390
|
+
get version() {
|
|
391
|
+
return version;
|
|
392
|
+
},
|
|
393
|
+
prepare(records, keys, aux) {
|
|
394
|
+
gen += 1;
|
|
395
|
+
const n = records.length;
|
|
396
|
+
let orderChanged = n !== prevOrder.length;
|
|
397
|
+
if (keys === void 0) {
|
|
398
|
+
resetAll();
|
|
399
|
+
lastKeys = null;
|
|
400
|
+
for (let i = 0; i < n; i++) {
|
|
401
|
+
const slot = alloc();
|
|
402
|
+
const ent = { key: -0.5 - i, slot, record: void 0, aux: 0, gen, blockN: 0 };
|
|
403
|
+
bySlot[slot] = ent;
|
|
404
|
+
packInto(ent, records[i], aux ? aux(i) : 0);
|
|
405
|
+
if (!orderChanged && prevOrder[i] !== slot) orderChanged = true;
|
|
406
|
+
orderCpu[i] = slot;
|
|
407
|
+
}
|
|
408
|
+
} else {
|
|
409
|
+
if (keys.length !== n) throw new Error(`${label}: ${keys.length} keys for ${n} records`);
|
|
410
|
+
if (lastKeys === null) resetAll();
|
|
411
|
+
const same = lastKeys !== null && lastKeys.length === n && lastKeys.every((k, i) => k === keys[i]);
|
|
412
|
+
for (let i = 0; i < n; i++) {
|
|
413
|
+
const key = keys[i];
|
|
414
|
+
let ent = byKey.get(key);
|
|
415
|
+
if (ent === void 0) {
|
|
416
|
+
const slot = alloc();
|
|
417
|
+
ent = { key, slot, record: void 0, aux: 0, gen, blockN: 0 };
|
|
418
|
+
byKey.set(key, ent);
|
|
419
|
+
bySlot[slot] = ent;
|
|
420
|
+
}
|
|
421
|
+
ent.gen = gen;
|
|
422
|
+
const a = aux ? aux(i) : 0;
|
|
423
|
+
if (ent.record !== records[i] || ent.aux !== a) packInto(ent, records[i], a);
|
|
424
|
+
if (!orderChanged && prevOrder[i] !== ent.slot) orderChanged = true;
|
|
425
|
+
orderCpu[i] = ent.slot;
|
|
426
|
+
}
|
|
427
|
+
if (!same) {
|
|
428
|
+
if (lastKeys !== null) for (const k of lastKeys) {
|
|
429
|
+
const ent = byKey.get(k);
|
|
430
|
+
if (ent !== void 0 && ent.gen !== gen) release(ent);
|
|
431
|
+
}
|
|
432
|
+
lastKeys = keys.slice();
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
upload(n, orderChanged);
|
|
436
|
+
count = n;
|
|
437
|
+
return n;
|
|
438
|
+
},
|
|
439
|
+
slotAt: (i) => i < count ? orderCpu[i] : -1,
|
|
440
|
+
entryAt(i) {
|
|
441
|
+
if (i >= count) return NONE2;
|
|
442
|
+
const ent = bySlot[orderCpu[i]];
|
|
443
|
+
return ent === null || ent === void 0 ? NONE2 : { aux: ent.aux, blockN: ent.blockN };
|
|
444
|
+
},
|
|
445
|
+
invalidate() {
|
|
446
|
+
for (const ent of byKey.values()) ent.record = void 0;
|
|
447
|
+
},
|
|
448
|
+
stats: () => ({ written, bytes, orderWrites, slots: next - free.length, capacity, grown }),
|
|
449
|
+
dispose() {
|
|
450
|
+
gpu.destroy();
|
|
451
|
+
orderGpu.destroy();
|
|
452
|
+
blockGpu?.destroy();
|
|
453
|
+
byKey.clear();
|
|
454
|
+
}
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// ../desk/src/missing/shaders.ts
|
|
459
|
+
var MISSING_SHADER_FILES = { entry: "missing/missing-pass.wgsl" };
|
|
460
|
+
function missingShaders(text2 = shaderText) {
|
|
461
|
+
return kitWgsl(["view", "portal", "sdf"], {
|
|
462
|
+
structs: [MissingFace],
|
|
463
|
+
entry: { label: MISSING_SHADER_FILES.entry, text: text2(MISSING_SHADER_FILES).entry }
|
|
464
|
+
}, text2);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// ../desk/src/missing/pass.ts
|
|
468
|
+
var BLEND_PREMUL = {
|
|
469
|
+
color: { srcFactor: "one", dstFactor: "one-minus-src-alpha", operation: "add" },
|
|
470
|
+
alpha: { srcFactor: "one", dstFactor: "one-minus-src-alpha", operation: "add" }
|
|
471
|
+
};
|
|
472
|
+
var MAX_FACES = 65536;
|
|
473
|
+
var NO_RECORDS = { written: 0, bytes: 0, orderWrites: 0, slots: 0, capacity: 0, grown: 0 };
|
|
474
|
+
var MissingPass = class _MissingPass {
|
|
475
|
+
name = "desk/missing";
|
|
476
|
+
store = null;
|
|
477
|
+
group = null;
|
|
478
|
+
boundStore = -1;
|
|
479
|
+
boundAssets = -1;
|
|
480
|
+
count = 0;
|
|
481
|
+
device;
|
|
482
|
+
shared;
|
|
483
|
+
mat;
|
|
484
|
+
constructor(device, shared, mat) {
|
|
485
|
+
this.device = device;
|
|
486
|
+
this.shared = shared;
|
|
487
|
+
this.mat = mat;
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* The root's pass on `mat`, made NOW (no await — a quarantine asks for it mid-frame): its layout and its one pipeline (it is lit by
|
|
491
|
+
* nothing — the same in every slot). The desk's own WGSL, composed from the host's text; WebGPU compiles it before its first draw.
|
|
492
|
+
*/
|
|
493
|
+
static make(device, format, mat, text2) {
|
|
494
|
+
const layout = bindLayout(device, [
|
|
495
|
+
{ binding: 0, stages: ["vertex", "fragment"], buffer: "uniform" },
|
|
496
|
+
{ binding: 1, stages: ["vertex", "fragment"], buffer: "read-only-storage" },
|
|
497
|
+
{ binding: 2, stages: ["vertex"], buffer: "read-only-storage" }
|
|
498
|
+
], "desk/missing");
|
|
499
|
+
const shader = compose(missingShaders(text2));
|
|
500
|
+
const module = device.createShaderModule({ code: shader.code, label: shader.label });
|
|
501
|
+
const pipeline = device.createRenderPipeline({
|
|
502
|
+
label: "desk/missing",
|
|
503
|
+
layout: device.createPipelineLayout({ bindGroupLayouts: [layout] }),
|
|
504
|
+
vertex: { module, entryPoint: "vs" },
|
|
505
|
+
fragment: { module, entryPoint: "fs", targets: [{ format, blend: BLEND_PREMUL }] },
|
|
506
|
+
primitive: { topology: "triangle-list" }
|
|
507
|
+
});
|
|
508
|
+
return new _MissingPass(device, { layout, pipeline }, mat);
|
|
509
|
+
}
|
|
510
|
+
/** A slot's own faces on the shared pipeline, through `mat`'s view block. */
|
|
511
|
+
spawn(mat) {
|
|
512
|
+
return new _MissingPass(this.device, this.shared, mat);
|
|
513
|
+
}
|
|
514
|
+
prepare(_encoder, _slot, records, extra) {
|
|
515
|
+
if (records.length === 0 && this.store === null) {
|
|
516
|
+
this.count = 0;
|
|
517
|
+
return 0;
|
|
518
|
+
}
|
|
519
|
+
this.store ??= createRecordStore({
|
|
520
|
+
device: this.device,
|
|
521
|
+
def: MissingFace,
|
|
522
|
+
capacity: 16,
|
|
523
|
+
max: MAX_FACES,
|
|
524
|
+
label: "desk/missing",
|
|
525
|
+
pack: (r, _aux, into, slot) => {
|
|
526
|
+
into.set(missingValues(r), slot);
|
|
527
|
+
return 0;
|
|
528
|
+
}
|
|
529
|
+
});
|
|
530
|
+
this.count = this.store.prepare(records.length > MAX_FACES ? records.slice(0, MAX_FACES) : records, extra?.keys !== void 0 && extra.keys.length > MAX_FACES ? extra.keys.slice(0, MAX_FACES) : extra?.keys);
|
|
531
|
+
this.rebind();
|
|
532
|
+
return this.count;
|
|
533
|
+
}
|
|
534
|
+
rebind() {
|
|
535
|
+
const store = this.store;
|
|
536
|
+
if (store === null || this.group !== null && this.boundStore === store.version && this.boundAssets === this.mat.assetVersion) return;
|
|
537
|
+
this.group = bindGroup(this.device, this.shared.layout, [this.mat.view, store.records, store.order], "desk/missing");
|
|
538
|
+
this.boundStore = store.version;
|
|
539
|
+
this.boundAssets = this.mat.assetVersion;
|
|
540
|
+
}
|
|
541
|
+
drawRange(pass, first, end) {
|
|
542
|
+
const hi = Math.min(end, this.count);
|
|
543
|
+
if (first >= hi || this.group === null) return;
|
|
544
|
+
pass.setPipeline(this.shared.pipeline);
|
|
545
|
+
pass.setBindGroup(0, this.group);
|
|
546
|
+
pass.draw(6, hi - first, 0, first);
|
|
547
|
+
}
|
|
548
|
+
/** The store's counters (a rig's witness) — nothing until the slot's first face. */
|
|
549
|
+
records() {
|
|
550
|
+
return this.store?.stats() ?? NO_RECORDS;
|
|
551
|
+
}
|
|
552
|
+
dispose() {
|
|
553
|
+
this.store?.dispose();
|
|
554
|
+
this.store = null;
|
|
555
|
+
this.group = null;
|
|
556
|
+
}
|
|
557
|
+
};
|
|
558
|
+
function missingFaces(device, format, mat, text2) {
|
|
559
|
+
let root = null;
|
|
560
|
+
return {
|
|
561
|
+
spawn: (m) => {
|
|
562
|
+
root ??= MissingPass.make(device, format, mat, text2);
|
|
563
|
+
return root.spawn(m);
|
|
564
|
+
},
|
|
565
|
+
get made() {
|
|
566
|
+
return root !== null;
|
|
567
|
+
},
|
|
568
|
+
dispose: () => {
|
|
569
|
+
root?.dispose();
|
|
570
|
+
root = null;
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// ../desk/src/missing/object.ts
|
|
576
|
+
var MISSING_KIND = "desk.missing";
|
|
577
|
+
var MISSING_OBJECT = {
|
|
578
|
+
name: MISSING_KIND,
|
|
579
|
+
stratum: "things",
|
|
580
|
+
reach: 0,
|
|
581
|
+
create: async (device, format, mat) => MissingPass.make(device, format, mat),
|
|
582
|
+
resolve: (ctx) => ctx.rect,
|
|
583
|
+
record: (g, ctx) => missingFace(g, ctx.theme, ctx.flux.fade),
|
|
584
|
+
hit: (g, wx, wy) => missingHit(g, wx, wy)
|
|
585
|
+
};
|
|
586
|
+
|
|
163
587
|
// ../desk/src/kind.ts
|
|
164
588
|
var STRATA = ["pads", "sheets", "things"];
|
|
165
589
|
|
|
@@ -231,9 +655,9 @@ function band(stretch) {
|
|
|
231
655
|
const a = Math.abs(stretch);
|
|
232
656
|
return Math.sign(stretch) * B * (1 - 1 / (1 + a * DRAWER.band.c / B));
|
|
233
657
|
}
|
|
234
|
-
function scrollRange(vw, vh, bottom) {
|
|
658
|
+
function scrollRange(vw, vh, bottom, foot = 0) {
|
|
235
659
|
const { h } = drawerSize(vw, vh);
|
|
236
|
-
return trayScrollMax(bottom, h, DRAWER.pitch);
|
|
660
|
+
return trayScrollMax(bottom, h - foot, DRAWER.pitch);
|
|
237
661
|
}
|
|
238
662
|
|
|
239
663
|
// ../desk/src/tray/lattice.ts
|
|
@@ -346,7 +770,7 @@ var TrayUniforms = defineStruct("TrayUniforms", [
|
|
|
346
770
|
["accessory", "vec4f"],
|
|
347
771
|
// K5a: the accessories' powder coat, linear, and their shadows' strength on the board
|
|
348
772
|
["fade", "vec4f"]
|
|
349
|
-
// the content's fade under the header (design-018 §4, R4): its band F, the clear header H above it, CSS px;
|
|
773
|
+
// the content's fade under the header (design-018 §4, R4): its band F, the clear header H above it, CSS px; a host's foot inset (I21; 0 none); —
|
|
350
774
|
]);
|
|
351
775
|
var TrayAccessoryStruct = defineStruct("TrayAccessory", [
|
|
352
776
|
["box", "vec4f"],
|
|
@@ -373,7 +797,7 @@ function trayShaders(text2) {
|
|
|
373
797
|
}
|
|
374
798
|
|
|
375
799
|
// ../desk/src/card/card.ts
|
|
376
|
-
var
|
|
800
|
+
var BLEND_PREMUL2 = {
|
|
377
801
|
color: { srcFactor: "one", dstFactor: "one-minus-src-alpha", operation: "add" },
|
|
378
802
|
alpha: { srcFactor: "one", dstFactor: "one-minus-src-alpha", operation: "add" }
|
|
379
803
|
};
|
|
@@ -541,8 +965,8 @@ async function buildCard(device, format, kinds) {
|
|
|
541
965
|
const module = await compile(device, compose(cardShaders(kinds)));
|
|
542
966
|
const pl = device.createPipelineLayout({ bindGroupLayouts: [layout] });
|
|
543
967
|
const [pipeline, litPipeline] = await Promise.all([
|
|
544
|
-
renderPipeline(device, { label: "card/flat", layout: pl, module, format, blend:
|
|
545
|
-
renderPipeline(device, { label: "card/flat, lit from elsewhere", layout: pl, module, format, blend:
|
|
968
|
+
renderPipeline(device, { label: "card/flat", layout: pl, module, format, blend: BLEND_PREMUL2 }),
|
|
969
|
+
renderPipeline(device, { label: "card/flat, lit from elsewhere", layout: pl, module, format, blend: BLEND_PREMUL2, constants: { LIT_ELSEWHERE: 1 } })
|
|
546
970
|
]);
|
|
547
971
|
return { ok: true, layout, pipeline, litPipeline };
|
|
548
972
|
} catch (e) {
|
|
@@ -709,13 +1133,21 @@ var CardPass = class _CardPass {
|
|
|
709
1133
|
}
|
|
710
1134
|
};
|
|
711
1135
|
|
|
1136
|
+
// ../desk/src/missing/slots.ts
|
|
1137
|
+
function swapToMissing(s, name, faces) {
|
|
1138
|
+
const k = s.kinds.get(name);
|
|
1139
|
+
if (k === void 0 || faces === void 0) return void 0;
|
|
1140
|
+
s.kinds.set(name, { name, stratum: k.stratum, pass: faces.spawn(s.mat) });
|
|
1141
|
+
return k.pass;
|
|
1142
|
+
}
|
|
1143
|
+
|
|
712
1144
|
// ../desk/src/hold/focus.ts
|
|
713
1145
|
var HoldUniformsStruct = defineStruct("HoldUniforms", [
|
|
714
1146
|
["texel", "vec4f"],
|
|
715
1147
|
["mix", "vec4f"]
|
|
716
1148
|
]);
|
|
717
1149
|
var KAWASE = { levels: 2, offsetPerTexel: 0.25 };
|
|
718
|
-
var
|
|
1150
|
+
var BLEND_PREMUL3 = {
|
|
719
1151
|
color: { srcFactor: "one", dstFactor: "one-minus-src-alpha", operation: "add" },
|
|
720
1152
|
alpha: { srcFactor: "one", dstFactor: "one-minus-src-alpha", operation: "add" }
|
|
721
1153
|
};
|
|
@@ -763,7 +1195,7 @@ var HoldPass = class _HoldPass {
|
|
|
763
1195
|
renderPipeline(device, { label: "hold/down", layout: pl, module, fragment: "fs_down", format }),
|
|
764
1196
|
renderPipeline(device, { label: "hold/up", layout: pl, module, fragment: "fs_up", format }),
|
|
765
1197
|
renderPipeline(device, { label: "hold/desk", layout: pl, module, fragment: "fs_desk", format }),
|
|
766
|
-
renderPipeline(device, { label: "hold/hand", layout: pl, module, fragment: "fs_hand", format, blend:
|
|
1198
|
+
renderPipeline(device, { label: "hold/hand", layout: pl, module, fragment: "fs_hand", format, blend: BLEND_PREMUL3 })
|
|
767
1199
|
]);
|
|
768
1200
|
return new _HoldPass(device, format, layout, pipes);
|
|
769
1201
|
}
|
|
@@ -1472,7 +1904,7 @@ function selectionBox(frames) {
|
|
|
1472
1904
|
}
|
|
1473
1905
|
|
|
1474
1906
|
// ../desk/src/marks/pass.ts
|
|
1475
|
-
var
|
|
1907
|
+
var BLEND_PREMUL4 = {
|
|
1476
1908
|
color: { srcFactor: "one", dstFactor: "one-minus-src-alpha", operation: "add" },
|
|
1477
1909
|
alpha: { srcFactor: "one", dstFactor: "one-minus-src-alpha", operation: "add" }
|
|
1478
1910
|
};
|
|
@@ -1512,7 +1944,7 @@ var MarksPass = class _MarksPass {
|
|
|
1512
1944
|
{ binding: 3, stages: ["fragment"], sampler: "filtering" }
|
|
1513
1945
|
], "marks");
|
|
1514
1946
|
const pl = device.createPipelineLayout({ label: "marks", bindGroupLayouts: [layout] });
|
|
1515
|
-
const pipeline = await renderPipeline(device, { label: "marks", layout: pl, module, format, blend:
|
|
1947
|
+
const pipeline = await renderPipeline(device, { label: "marks", layout: pl, module, format, blend: BLEND_PREMUL4 });
|
|
1516
1948
|
return new _MarksPass(device, mat, pipeline, layout);
|
|
1517
1949
|
}
|
|
1518
1950
|
/**
|
|
@@ -1791,12 +2223,22 @@ function carryView(pose, rect) {
|
|
|
1791
2223
|
}
|
|
1792
2224
|
|
|
1793
2225
|
// ../desk/src/tray/specimens.ts
|
|
1794
|
-
function
|
|
2226
|
+
function recordOf(kind, ctx, faults) {
|
|
2227
|
+
if (faults === void 0) return kind.record(kind.resolve(ctx), ctx);
|
|
2228
|
+
if (faults.missing(kind.name)) return missingFace(ctx.rect, ctx.theme, ctx.flux.fade);
|
|
2229
|
+
try {
|
|
2230
|
+
return kind.record(kind.resolve(ctx), ctx);
|
|
2231
|
+
} catch (err) {
|
|
2232
|
+
faults.strike(kind.name, "record", err, ctx.entity);
|
|
2233
|
+
return void 0;
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
function faceClip(rect, vh, foot = 0) {
|
|
1795
2237
|
const a = DRAWER.arris;
|
|
1796
2238
|
const x0 = rect.x + a;
|
|
1797
2239
|
const x1 = rect.x + rect.w - a;
|
|
1798
2240
|
const y0 = rect.y + a + DRAWER.header;
|
|
1799
|
-
const y1 = Math.max(vh, rect.y + rect.h) + DRAWER.radius;
|
|
2241
|
+
const y1 = foot > 0 ? rect.y + rect.h - foot : Math.max(vh, rect.y + rect.h) + DRAWER.radius;
|
|
1800
2242
|
return { cx: (x0 + x1) / 2, cy: (y0 + y1) / 2, hx: (x1 - x0) / 2, hy: (y1 - y0) / 2, r: DRAWER.radius - a };
|
|
1801
2243
|
}
|
|
1802
2244
|
function trayGrid(grid) {
|
|
@@ -1813,7 +2255,7 @@ function specimenFrames(specimens, drawn, env) {
|
|
|
1813
2255
|
const P = DRAWER.pitch;
|
|
1814
2256
|
const grid = trayGrid(env.grid);
|
|
1815
2257
|
const { width, height, dpr } = env.view;
|
|
1816
|
-
const face2 = faceClip(drawn.rect, height);
|
|
2258
|
+
const face2 = faceClip(drawn.rect, height, drawn.foot);
|
|
1817
2259
|
for (const s of specimens) {
|
|
1818
2260
|
const x0 = drawn.rect.x + s.rect.x;
|
|
1819
2261
|
const y0 = drawn.rect.y + s.rect.y - drawn.scroll;
|
|
@@ -1839,7 +2281,8 @@ function specimenFrames(specimens, drawn, env) {
|
|
|
1839
2281
|
...s.local !== void 0 ? { local: s.local } : {},
|
|
1840
2282
|
...s.asset !== void 0 ? { asset: s.asset } : {}
|
|
1841
2283
|
};
|
|
1842
|
-
const record =
|
|
2284
|
+
const record = recordOf(s.kind, ctx, env.faults);
|
|
2285
|
+
if (record === void 0) continue;
|
|
1843
2286
|
const hx = x0 + s.rect.w / 2;
|
|
1844
2287
|
const hy = s.accessory === "shelf" ? y0 + s.rect.h : y0;
|
|
1845
2288
|
out.push({
|
|
@@ -1917,7 +2360,8 @@ function carriedFrame(pose, src, env) {
|
|
|
1917
2360
|
dt: 0,
|
|
1918
2361
|
...src.local !== void 0 ? { local: src.local } : {}
|
|
1919
2362
|
};
|
|
1920
|
-
const record =
|
|
2363
|
+
const record = recordOf(src.kind, ctx, env.faults);
|
|
2364
|
+
if (record === void 0) return void 0;
|
|
1921
2365
|
const x0 = (r.x - v.camX) * v.zoom;
|
|
1922
2366
|
const y0 = (r.y - v.camY) * v.zoom;
|
|
1923
2367
|
return {
|
|
@@ -1934,7 +2378,7 @@ function carriedFrame(pose, src, env) {
|
|
|
1934
2378
|
};
|
|
1935
2379
|
}
|
|
1936
2380
|
function facePresent(drawn, vh) {
|
|
1937
|
-
return { opacity: 1, portal: faceClip(drawn.rect, vh) };
|
|
2381
|
+
return { opacity: 1, portal: faceClip(drawn.rect, vh, drawn.foot) };
|
|
1938
2382
|
}
|
|
1939
2383
|
var TraySlots = class {
|
|
1940
2384
|
device;
|
|
@@ -1972,7 +2416,7 @@ var TraySlots = class {
|
|
|
1972
2416
|
const mat = this.root.mat.spawn();
|
|
1973
2417
|
void program.create(this.device, this.format, mat).then((pass) => {
|
|
1974
2418
|
this.making.delete(type);
|
|
1975
|
-
if (this.disposed) {
|
|
2419
|
+
if (this.disposed || this.root.kinds.get(kind)?.pass !== own.pass) {
|
|
1976
2420
|
pass.dispose();
|
|
1977
2421
|
mat.dispose();
|
|
1978
2422
|
return;
|
|
@@ -2012,6 +2456,19 @@ var TraySlots = class {
|
|
|
2012
2456
|
for (const s of this.slots.values()) for (const k of s.kinds.values()) t = Math.min(t, k.pass.idleAt?.(ms) ?? Number.POSITIVE_INFINITY);
|
|
2013
2457
|
return t;
|
|
2014
2458
|
}
|
|
2459
|
+
/**
|
|
2460
|
+
* Kind `name` went MISSING (petition I24 — the ground's quarantine): its entry in every slot made so far becomes the desk's missing
|
|
2461
|
+
* faces on the slot's mat (a slot made from now on spawns the root's entry, which is already the face's). Returns the passes the
|
|
2462
|
+
* entries held; the ground lets them go.
|
|
2463
|
+
*/
|
|
2464
|
+
quarantine(name, faces) {
|
|
2465
|
+
const gone = [];
|
|
2466
|
+
for (const s of this.slots.values()) {
|
|
2467
|
+
const p = swapToMissing(s, name, faces);
|
|
2468
|
+
if (p !== void 0) gone.push(p);
|
|
2469
|
+
}
|
|
2470
|
+
return gone;
|
|
2471
|
+
}
|
|
2015
2472
|
/** The slots made so far (a rig's witness). */
|
|
2016
2473
|
get size() {
|
|
2017
2474
|
return this.slots.size;
|
|
@@ -2027,7 +2484,7 @@ var TraySlots = class {
|
|
|
2027
2484
|
};
|
|
2028
2485
|
|
|
2029
2486
|
// ../desk/src/tray/pass.ts
|
|
2030
|
-
var
|
|
2487
|
+
var BLEND_PREMUL5 = {
|
|
2031
2488
|
color: { srcFactor: "one", dstFactor: "one-minus-src-alpha", operation: "add" },
|
|
2032
2489
|
alpha: { srcFactor: "one", dstFactor: "one-minus-src-alpha", operation: "add" }
|
|
2033
2490
|
};
|
|
@@ -2082,6 +2539,8 @@ var TrayPass = class _TrayPass {
|
|
|
2082
2539
|
sent = false;
|
|
2083
2540
|
/** The quads the last prepare laid: 0 while the drawer is shut (p 0) — then it draws nothing. */
|
|
2084
2541
|
quads = 0;
|
|
2542
|
+
/** A host's foot inset this frame (I21): the veil lays a second quad, over the foot, in its one draw. */
|
|
2543
|
+
foot = 0;
|
|
2085
2544
|
group = null;
|
|
2086
2545
|
boundAssets = -1;
|
|
2087
2546
|
last = null;
|
|
@@ -2115,9 +2574,9 @@ var TrayPass = class _TrayPass {
|
|
|
2115
2574
|
], "tray/pegboard");
|
|
2116
2575
|
const pl = device.createPipelineLayout({ label: "tray/pegboard", bindGroupLayouts: [layout] });
|
|
2117
2576
|
const pipelines = await Promise.all([
|
|
2118
|
-
renderPipeline(device, { label: "tray/pegboard", layout: pl, module, format, blend:
|
|
2119
|
-
renderPipeline(device, { label: "tray/pegboard/accessories", layout: pl, module, format, blend:
|
|
2120
|
-
renderPipeline(device, { label: "tray/pegboard/veil", layout: pl, module, format, blend:
|
|
2577
|
+
renderPipeline(device, { label: "tray/pegboard", layout: pl, module, format, blend: BLEND_PREMUL5 }),
|
|
2578
|
+
renderPipeline(device, { label: "tray/pegboard/accessories", layout: pl, module, format, blend: BLEND_PREMUL5, fragment: "fs_accessory" }),
|
|
2579
|
+
renderPipeline(device, { label: "tray/pegboard/veil", layout: pl, module, format, blend: BLEND_PREMUL5, vertex: "vs_veil", fragment: "fs_veil" })
|
|
2121
2580
|
]);
|
|
2122
2581
|
return new _TrayPass(device, mat, pipelines, layout);
|
|
2123
2582
|
}
|
|
@@ -2131,8 +2590,10 @@ var TrayPass = class _TrayPass {
|
|
|
2131
2590
|
const p = Math.min(Math.max(inputs.p, 0), 1);
|
|
2132
2591
|
const rect = drawerRect(view.width, view.height, p);
|
|
2133
2592
|
const { rowBase, frac } = carry(inputs.scroll, P);
|
|
2593
|
+
const foot = inputs.foot !== void 0 && inputs.foot > 0 ? inputs.foot : 0;
|
|
2594
|
+
this.foot = foot;
|
|
2134
2595
|
if (p <= 0) {
|
|
2135
|
-
this.last = { rect, rowBase, frac, dim: 0, accessories: [] };
|
|
2596
|
+
this.last = { rect, rowBase, frac, dim: 0, accessories: [], ...foot > 0 ? { foot } : {} };
|
|
2136
2597
|
this.quads = 0;
|
|
2137
2598
|
return 0;
|
|
2138
2599
|
}
|
|
@@ -2165,7 +2626,7 @@ var TrayPass = class _TrayPass {
|
|
|
2165
2626
|
keepFine: [keep(fp, 210), keep(fp, 42), keep(fp, 105), 0],
|
|
2166
2627
|
keepEdge: [keep(fp, 9), keep(fp, 18), keep(fp, 36), 0],
|
|
2167
2628
|
accessory: [...T.accessory, T.accessoryShadow],
|
|
2168
|
-
fade: [DRAWER.fade, DRAWER.header,
|
|
2629
|
+
fade: [DRAWER.fade, DRAWER.header, foot, 0]
|
|
2169
2630
|
};
|
|
2170
2631
|
this.tray.set(values);
|
|
2171
2632
|
const gobo = grid.mat.gobo;
|
|
@@ -2182,7 +2643,7 @@ var TrayPass = class _TrayPass {
|
|
|
2182
2643
|
this.sent = true;
|
|
2183
2644
|
const accessories = (inputs.specimens ?? []).map(accessoryOf);
|
|
2184
2645
|
this.layAccessories(accessories);
|
|
2185
|
-
this.last = { rect, rowBase, frac, dim, accessories };
|
|
2646
|
+
this.last = { rect, rowBase, frac, dim, accessories, ...foot > 0 ? { foot } : {} };
|
|
2186
2647
|
this.quads = 1;
|
|
2187
2648
|
return 1;
|
|
2188
2649
|
}
|
|
@@ -2242,13 +2703,13 @@ var TrayPass = class _TrayPass {
|
|
|
2242
2703
|
/**
|
|
2243
2704
|
* THE VEIL (design-018 rev 5) — LAST, over everything the drawer holds (the caller left the scissor on the whole view): the plain board
|
|
2244
2705
|
* whole in the header and fading out over its ramp, so what hangs there and the holes behind it fade into the board together — a
|
|
2245
|
-
* specimen never turns see-through over a hole. One quad.
|
|
2706
|
+
* specimen never turns see-through over a hole. One quad — and with a host's foot (I21) a second, over the foot, in the same draw.
|
|
2246
2707
|
*/
|
|
2247
2708
|
drawVeil(pass) {
|
|
2248
2709
|
if (this.quads === 0) return;
|
|
2249
2710
|
pass.pushDebugGroup("tray/pegboard/veil");
|
|
2250
2711
|
this.bind(pass, this.veilPipeline);
|
|
2251
|
-
pass.draw(6, 1, 0, 0);
|
|
2712
|
+
pass.draw(this.foot > 0 ? 12 : 6, 1, 0, 0);
|
|
2252
2713
|
pass.popDebugGroup();
|
|
2253
2714
|
}
|
|
2254
2715
|
/** What the last prepare laid (a rig's witness). */
|
|
@@ -2265,26 +2726,127 @@ var TrayPass = class _TrayPass {
|
|
|
2265
2726
|
|
|
2266
2727
|
// ../desk/src/ground.ts
|
|
2267
2728
|
var visible = (p) => (p?.opacity ?? 1) > 0;
|
|
2268
|
-
|
|
2729
|
+
function checkPrograms(programs) {
|
|
2269
2730
|
const names = /* @__PURE__ */ new Set();
|
|
2270
2731
|
for (const p of programs) {
|
|
2271
2732
|
if (!p.name) throw new Error("ground: a kind needs a name \u2014 it is the kind's key in every slot");
|
|
2733
|
+
if (p.name === MISSING_KIND) throw new Error(`ground: the kind name "${MISSING_KIND}" is the desk's own \u2014 the missing face's (petition I24)`);
|
|
2272
2734
|
if (names.has(p.name)) throw new Error(`ground: two kinds are named "${p.name}" \u2014 a kind's name is its key in every slot`);
|
|
2273
2735
|
if (!STRATA.includes(p.stratum)) throw new Error(`ground: kind "${p.name}" lies in no stratum the ground draws ("${p.stratum}"; ${STRATA.join(", ")})`);
|
|
2274
2736
|
names.add(p.name);
|
|
2275
2737
|
}
|
|
2276
|
-
|
|
2738
|
+
}
|
|
2739
|
+
var SCOPES = ["validation", "out-of-memory", "internal"];
|
|
2740
|
+
var watched = (device) => typeof device.pushErrorScope === "function";
|
|
2741
|
+
var pushScopes = (device) => {
|
|
2742
|
+
if (watched(device)) for (const f of SCOPES) device.pushErrorScope(f);
|
|
2743
|
+
};
|
|
2744
|
+
function popScopes(device) {
|
|
2745
|
+
if (!watched(device)) return Promise.resolve(null);
|
|
2746
|
+
const popped = SCOPES.map(() => device.popErrorScope());
|
|
2747
|
+
return Promise.all(popped).then((errors) => errors.find((e) => e !== null) ?? null);
|
|
2748
|
+
}
|
|
2749
|
+
var settle = (p) => {
|
|
2750
|
+
try {
|
|
2751
|
+
return Promise.resolve(p()).then((value) => ({ value }), (error) => ({ error }));
|
|
2752
|
+
} catch (error) {
|
|
2753
|
+
return Promise.resolve({ error });
|
|
2754
|
+
}
|
|
2755
|
+
};
|
|
2756
|
+
function letGo(name, pass) {
|
|
2757
|
+
try {
|
|
2758
|
+
pass.dispose();
|
|
2759
|
+
} catch (err) {
|
|
2760
|
+
console.error(`desk: the kind "${name}"'s pass threw in its dispose`, err);
|
|
2761
|
+
}
|
|
2762
|
+
}
|
|
2763
|
+
async function createKindPasses(device, format, mat, programs, onError) {
|
|
2764
|
+
pushScopes(device);
|
|
2765
|
+
const made = programs.map((p) => {
|
|
2766
|
+
pushScopes(device);
|
|
2767
|
+
const created = settle(() => p.create(device, format, mat));
|
|
2768
|
+
return { created, own: popScopes(device) };
|
|
2769
|
+
});
|
|
2770
|
+
const first = await Promise.all(made.map(async (m) => ({ created: await m.created, own: await m.own })));
|
|
2771
|
+
const window2 = await popScopes(device);
|
|
2772
|
+
const passes = [];
|
|
2773
|
+
const faults = [];
|
|
2774
|
+
const refuse = (p, why) => {
|
|
2775
|
+
faults.push({ kind: p.name, reason: why });
|
|
2776
|
+
};
|
|
2777
|
+
const threw = (err) => `refused at create \u2014 ${faultText(err)}`;
|
|
2778
|
+
const raised = (err) => `refused at create \u2014 a GPU error while its pass was made: ${faultText(err)}`;
|
|
2779
|
+
first.forEach(({ created, own }, i) => {
|
|
2780
|
+
const p = programs[i];
|
|
2781
|
+
if ("error" in created) {
|
|
2782
|
+
passes.push(void 0);
|
|
2783
|
+
refuse(p, threw(created.error));
|
|
2784
|
+
return;
|
|
2785
|
+
}
|
|
2786
|
+
if (own !== null) {
|
|
2787
|
+
passes.push(void 0);
|
|
2788
|
+
letGo(p.name, created.value);
|
|
2789
|
+
refuse(p, raised(own));
|
|
2790
|
+
return;
|
|
2791
|
+
}
|
|
2792
|
+
passes.push(created.value);
|
|
2793
|
+
});
|
|
2794
|
+
if (window2 !== null) {
|
|
2795
|
+
let found = false;
|
|
2796
|
+
for (let i = 0; i < programs.length; i++) {
|
|
2797
|
+
const p = programs[i];
|
|
2798
|
+
const had = passes[i];
|
|
2799
|
+
if (had === void 0) continue;
|
|
2800
|
+
letGo(p.name, had);
|
|
2801
|
+
pushScopes(device);
|
|
2802
|
+
const again = await settle(() => p.create(device, format, mat));
|
|
2803
|
+
const own = await popScopes(device);
|
|
2804
|
+
if ("error" in again) {
|
|
2805
|
+
passes[i] = void 0;
|
|
2806
|
+
found = true;
|
|
2807
|
+
refuse(p, threw(again.error));
|
|
2808
|
+
continue;
|
|
2809
|
+
}
|
|
2810
|
+
if (own !== null) {
|
|
2811
|
+
passes[i] = void 0;
|
|
2812
|
+
found = true;
|
|
2813
|
+
letGo(p.name, again.value);
|
|
2814
|
+
refuse(p, raised(own));
|
|
2815
|
+
continue;
|
|
2816
|
+
}
|
|
2817
|
+
passes[i] = again.value;
|
|
2818
|
+
}
|
|
2819
|
+
if (!found) onError?.(window2);
|
|
2820
|
+
}
|
|
2821
|
+
faults.sort((a, b) => programs.findIndex((p) => p.name === a.kind) - programs.findIndex((p) => p.name === b.kind));
|
|
2822
|
+
return { passes, faults };
|
|
2823
|
+
}
|
|
2824
|
+
function slotSetOf(device, mat, programs, made, missing, cards) {
|
|
2277
2825
|
const kinds = /* @__PURE__ */ new Map();
|
|
2278
2826
|
for (let i = 0; i < programs.length; i++) {
|
|
2279
2827
|
const p = programs[i];
|
|
2280
|
-
|
|
2828
|
+
const pass = made.passes[i];
|
|
2829
|
+
kinds.set(p.name, pass === void 0 ? { name: p.name, stratum: p.stratum, pass: missing.spawn(mat) } : { name: p.name, stratum: p.stratum, pass, ...p.composite ? { composite: true } : {} });
|
|
2281
2830
|
}
|
|
2282
|
-
|
|
2831
|
+
const card = cards === null ? void 0 : new CardPass(device, cards, mat, kinds);
|
|
2832
|
+
return { mat, kinds, missing, ...card !== void 0 ? { card } : {}, ...made.faults.length > 0 ? { faults: made.faults } : {} };
|
|
2833
|
+
}
|
|
2834
|
+
var standing = (programs, made) => programs.filter((_, i) => made.passes[i] !== void 0);
|
|
2835
|
+
var unattributed = (e) => {
|
|
2836
|
+
console.error("desk: a GPU error while the kinds were made, no kind's alone \u2014", e.message);
|
|
2837
|
+
};
|
|
2838
|
+
async function createSlotSet(device, format, mat, programs, onError = unattributed) {
|
|
2839
|
+
checkPrograms(programs);
|
|
2840
|
+
const made = await createKindPasses(device, format, mat, programs, onError);
|
|
2841
|
+
const cards = await createCardShared(device, format, standing(programs, made));
|
|
2842
|
+
return slotSetOf(device, mat, programs, made, missingFaces(device, format, mat), cards);
|
|
2283
2843
|
}
|
|
2284
2844
|
var SlotPool = class {
|
|
2285
2845
|
slots = [];
|
|
2286
2846
|
used = 0;
|
|
2287
2847
|
root;
|
|
2848
|
+
/** False once a kind the card composes went missing (petition I24 — `Ground.quarantine`): every slot's card, spawned or yet to be, is off. */
|
|
2849
|
+
cardOn = true;
|
|
2288
2850
|
constructor(root) {
|
|
2289
2851
|
this.root = root;
|
|
2290
2852
|
}
|
|
@@ -2298,10 +2860,15 @@ var SlotPool = class {
|
|
|
2298
2860
|
const kinds = /* @__PURE__ */ new Map();
|
|
2299
2861
|
for (const k of this.root.kinds.values()) kinds.set(k.name, { name: k.name, stratum: k.stratum, pass: k.pass.spawn(mat), ...k.composite ? { composite: true } : {} });
|
|
2300
2862
|
const card = this.root.card?.spawn(mat, kinds);
|
|
2863
|
+
if (card !== void 0 && !this.cardOn) card.on = false;
|
|
2301
2864
|
this.slots.push(card === void 0 ? { mat, kinds } : { mat, kinds, card });
|
|
2302
2865
|
}
|
|
2303
2866
|
return this.slots[this.used++];
|
|
2304
2867
|
}
|
|
2868
|
+
/** Every slot spawned so far (a quarantine walks them). */
|
|
2869
|
+
each(fn) {
|
|
2870
|
+
for (const s of this.slots) fn(s);
|
|
2871
|
+
}
|
|
2305
2872
|
/** Slots spawned so far — the churn instrument. */
|
|
2306
2873
|
get size() {
|
|
2307
2874
|
return this.slots.length;
|
|
@@ -2421,7 +2988,13 @@ function prepareFrame(encoder, root, pool, inputs, grid = DEFAULT_GRID, target,
|
|
|
2421
2988
|
}
|
|
2422
2989
|
const indexOf = [];
|
|
2423
2990
|
for (const o of objects) {
|
|
2424
|
-
|
|
2991
|
+
let list = records.get(o.kind);
|
|
2992
|
+
if (!list && o.kind === MISSING_KIND && root.missing !== void 0) {
|
|
2993
|
+
s.kinds.set(MISSING_KIND, { name: MISSING_KIND, stratum: "things", pass: root.missing.spawn(s.mat) });
|
|
2994
|
+
list = [];
|
|
2995
|
+
records.set(MISSING_KIND, list);
|
|
2996
|
+
keys.set(MISSING_KIND, []);
|
|
2997
|
+
}
|
|
2425
2998
|
if (!list) throw new Error(`ground: no kind "${o.kind}" is registered (${[...s.kinds.keys()].join(", ") || "none"})`);
|
|
2426
2999
|
indexOf.push(list.length);
|
|
2427
3000
|
list.push(o.record);
|
|
@@ -2459,7 +3032,7 @@ function prepareFrame(encoder, root, pool, inputs, grid = DEFAULT_GRID, target,
|
|
|
2459
3032
|
for (const k of s.kinds.values()) {
|
|
2460
3033
|
const list = records.get(k.name) ?? [];
|
|
2461
3034
|
if (list.length === 0) {
|
|
2462
|
-
drawn.push([k.name, 0]);
|
|
3035
|
+
if (k.name !== MISSING_KIND) drawn.push([k.name, 0]);
|
|
2463
3036
|
continue;
|
|
2464
3037
|
}
|
|
2465
3038
|
const own = root.kinds.get(k.name);
|
|
@@ -2511,7 +3084,7 @@ function prepareFrame(encoder, root, pool, inputs, grid = DEFAULT_GRID, target,
|
|
|
2511
3084
|
const tray = [];
|
|
2512
3085
|
const specimens = inputs.tray?.specimens;
|
|
2513
3086
|
if (specimens !== void 0 && specimens.length > 0 && traySlots !== void 0 && inputs.tray !== void 0) {
|
|
2514
|
-
const present = facePresent({ rect: trayRectOf(inputs), scroll: inputs.tray.scroll }, inputs.view.height);
|
|
3087
|
+
const present = facePresent({ rect: trayRectOf(inputs), scroll: inputs.tray.scroll, ...inputs.tray.foot !== void 0 ? { foot: inputs.tray.foot } : {} }, inputs.view.height);
|
|
2515
3088
|
for (const f of specimens) {
|
|
2516
3089
|
const slot = traySlots.get(f.type, f.kind);
|
|
2517
3090
|
if (slot === void 0) continue;
|
|
@@ -2550,7 +3123,7 @@ function drawTray(pass, size, dpr, tray, slots, marks, carried) {
|
|
|
2550
3123
|
if (rect !== void 0) {
|
|
2551
3124
|
for (const s of slots ?? []) drawSlot(pass, size, dpr, { ...s, bare: true });
|
|
2552
3125
|
if (marks !== null && marks.tagCount > 0) {
|
|
2553
|
-
const [x, y, w, h] = scissorOf({ opacity: 1, portal: faceBox(rect, size.h / dpr) }, dpr, size);
|
|
3126
|
+
const [x, y, w, h] = scissorOf({ opacity: 1, portal: faceBox(rect, size.h / dpr, tray.laid?.foot ?? 0) }, dpr, size);
|
|
2554
3127
|
if (w > 0 && h > 0) {
|
|
2555
3128
|
pass.setScissorRect(x, y, w, h);
|
|
2556
3129
|
marks.drawTags(pass);
|
|
@@ -2564,13 +3137,27 @@ function drawTray(pass, size, dpr, tray, slots, marks, carried) {
|
|
|
2564
3137
|
pass.setScissorRect(0, 0, size.w, size.h);
|
|
2565
3138
|
}
|
|
2566
3139
|
}
|
|
2567
|
-
function faceBox(rect, vh) {
|
|
3140
|
+
function faceBox(rect, vh, foot) {
|
|
2568
3141
|
const x0 = rect.x + DRAWER.arris;
|
|
2569
3142
|
const x1 = rect.x + rect.w - DRAWER.arris;
|
|
2570
3143
|
const y0 = rect.y + DRAWER.arris + DRAWER.header;
|
|
2571
|
-
const y1 = Math.max(vh, rect.y + rect.h);
|
|
3144
|
+
const y1 = foot > 0 ? rect.y + rect.h - foot : Math.max(vh, rect.y + rect.h);
|
|
2572
3145
|
return { cx: (x0 + x1) / 2, cy: (y0 + y1) / 2, hx: (x1 - x0) / 2, hy: (y1 - y0) / 2, r: 0 };
|
|
2573
3146
|
}
|
|
3147
|
+
function encodeFrame(encoder, passes, inputs, into, target) {
|
|
3148
|
+
const { root, pool, grid, marks, tray, traySlots } = passes;
|
|
3149
|
+
const trayed = inputs.tray !== void 0 && tray !== null ? tray.prepare(inputs.view, inputs.theme, inputs.grid ?? grid, inputs.mat, inputs.tray) : 0;
|
|
3150
|
+
const prepared = prepareFrame(encoder, root, pool, inputs, grid, target, inputs.tray !== void 0 ? traySlots ?? void 0 : void 0);
|
|
3151
|
+
const marked = marks !== null ? marks.prepare(inputs.marks, trayed > 0 && tray !== null ? { view: inputs.view, tags: tagsOf(inputs.tray), night: inputs.theme.matLight.night } : void 0) : 0;
|
|
3152
|
+
const bg = inputs.theme.canvasBg;
|
|
3153
|
+
const size = into.size();
|
|
3154
|
+
const pass = beginPass(encoder, into.view(), [bg[0], bg[1], bg[2], 1], "ground");
|
|
3155
|
+
const drawn = drawFrame(pass, size, inputs.view.dpr, prepared.incoming, prepared.outgoing);
|
|
3156
|
+
if (marked > 0) marks?.draw(pass);
|
|
3157
|
+
if ((trayed > 0 || prepared.carried !== void 0) && tray !== null) drawTray(pass, size, inputs.view.dpr, tray, prepared.tray, marks, prepared.carried);
|
|
3158
|
+
pass.end();
|
|
3159
|
+
return { stats: { ...drawn.incoming, kinds: prepared.kinds, outgoing: drawn.outgoing, portals: prepared.portals, ...prepared.dropped ? { dropped: prepared.dropped } : {} }, prepared, marked };
|
|
3160
|
+
}
|
|
2574
3161
|
var Ground = class _Ground {
|
|
2575
3162
|
device;
|
|
2576
3163
|
surface;
|
|
@@ -2598,6 +3185,8 @@ var Ground = class _Ground {
|
|
|
2598
3185
|
}
|
|
2599
3186
|
/** The drops last said, by kind (D7). */
|
|
2600
3187
|
dropSaid = /* @__PURE__ */ new Map();
|
|
3188
|
+
/** The kinds MISSING on this ground (petition I24): refused at create, or quarantined since — their entries draw the missing face. */
|
|
3189
|
+
missing = /* @__PURE__ */ new Set();
|
|
2601
3190
|
constructor(device, surface2, root, marks, hold, tray, programs) {
|
|
2602
3191
|
this.device = device;
|
|
2603
3192
|
this.surface = surface2;
|
|
@@ -2608,21 +3197,68 @@ var Ground = class _Ground {
|
|
|
2608
3197
|
this.tray = tray;
|
|
2609
3198
|
this.pool = new SlotPool(root);
|
|
2610
3199
|
this.traySlots = tray === null ? null : new TraySlots(device, surface2.format, root, programs);
|
|
3200
|
+
for (const f of root.faults ?? []) this.missing.add(f.kind);
|
|
2611
3201
|
}
|
|
3202
|
+
/**
|
|
3203
|
+
* The mat first (every kind's pass is made on it), then every kind's pass in its own error scope (`createKindPasses` — a kind refused
|
|
3204
|
+
* there is MISSING from the start: `faults()`, petition I24), then — once the kinds' window has closed, so nothing of theirs is taken
|
|
3205
|
+
* for a kind's — the card over the kinds that stood, the marks, the hand and the tray, together. The missing faces are made only when
|
|
3206
|
+
* one is asked for (a kind refused here, a quarantine, an object with no kind).
|
|
3207
|
+
*/
|
|
2612
3208
|
static async create(opts) {
|
|
2613
3209
|
const surf = opts.surface;
|
|
2614
3210
|
const mat = await CuttingMat.create(opts.device, surf.format, opts.mat);
|
|
2615
|
-
|
|
2616
|
-
const
|
|
3211
|
+
checkPrograms(opts.kinds);
|
|
3212
|
+
const made = await createKindPasses(opts.device, surf.format, mat, opts.kinds, opts.onError ?? unattributed);
|
|
3213
|
+
const [cards, marks, hold, tray] = await Promise.all([
|
|
3214
|
+
createCardShared(opts.device, surf.format, standing(opts.kinds, made)),
|
|
2617
3215
|
opts.marks === void 0 ? null : MarksPass.create(opts.device, surf.format, opts.marks, mat),
|
|
2618
3216
|
opts.hold === void 0 ? null : HoldPass.create(opts.device, surf.format, opts.hold),
|
|
2619
3217
|
opts.tray === void 0 ? null : TrayPass.create(opts.device, surf.format, opts.tray, mat)
|
|
2620
3218
|
]);
|
|
2621
|
-
return new _Ground(opts.device, surf,
|
|
3219
|
+
return new _Ground(opts.device, surf, slotSetOf(opts.device, mat, opts.kinds, made, missingFaces(opts.device, surf.format, mat), cards), marks, hold, tray, opts.kinds);
|
|
2622
3220
|
}
|
|
2623
|
-
/**
|
|
3221
|
+
/**
|
|
3222
|
+
* The root's pass of the kind registered as `name` (undefined if none, or MISSING — petition I24: nothing of a missing kind is reached
|
|
3223
|
+
* again) — a host reaches its kind's own API through it: the note's ink pages, the whiteboard's rasters.
|
|
3224
|
+
*/
|
|
2624
3225
|
pass(name) {
|
|
2625
|
-
return this.root.kinds.get(name)?.pass;
|
|
3226
|
+
return this.missing.has(name) ? void 0 : this.root.kinds.get(name)?.pass;
|
|
3227
|
+
}
|
|
3228
|
+
/** The kinds REFUSED when this ground was made (petition I24): each its name and why. Quarantines since are the layer's word. */
|
|
3229
|
+
faults() {
|
|
3230
|
+
return this.root.faults ?? [];
|
|
3231
|
+
}
|
|
3232
|
+
/**
|
|
3233
|
+
* THE QUARANTINE (petition I24): kind `name` is MISSING from now on — its entry in every slot this ground holds (the root, the pool's,
|
|
3234
|
+
* the tray's) becomes a spawn of that slot's missing face, under its name and in its stratum, and the passes it had are disposed (the
|
|
3235
|
+
* pool's and the tray's first; the root's — whose shared resources go with it — last; a dispose that throws is said and passed). A
|
|
3236
|
+
* kind the flat card composes turns the card off in every slot, for good (K7b's own A/B door: each material kind then draws its own
|
|
3237
|
+
* runs — the card's pixels, more draws): its resources leave the card's bind group, and no draw may reach them. The next frame draws
|
|
3238
|
+
* the kind's objects in the missing face (the builder makes their records so); one already made for its own pass is drawn as nothing.
|
|
3239
|
+
* A kind already missing, or none of that name: nothing.
|
|
3240
|
+
*/
|
|
3241
|
+
quarantine(name) {
|
|
3242
|
+
if (this.missing.has(name) || !this.root.kinds.has(name)) return;
|
|
3243
|
+
this.missing.add(name);
|
|
3244
|
+
if (this.root.card?.materialOf(name) !== void 0) {
|
|
3245
|
+
this.root.card.on = false;
|
|
3246
|
+
this.pool.cardOn = false;
|
|
3247
|
+
this.pool.each((s) => {
|
|
3248
|
+
if (s.card !== void 0) s.card.on = false;
|
|
3249
|
+
});
|
|
3250
|
+
}
|
|
3251
|
+
const faces = this.root.missing;
|
|
3252
|
+
const gone = [];
|
|
3253
|
+
this.pool.each((s) => {
|
|
3254
|
+
const p = swapToMissing(s, name, faces);
|
|
3255
|
+
if (p !== void 0) gone.push(p);
|
|
3256
|
+
});
|
|
3257
|
+
gone.push(...this.traySlots?.quarantine(name, faces) ?? []);
|
|
3258
|
+
const root = swapToMissing(this.root, name, faces);
|
|
3259
|
+
if (root !== void 0) gone.push(root);
|
|
3260
|
+
for (const p of gone) letGo(name, p);
|
|
3261
|
+
if (this.heldCache.stamp !== null) this.heldCache.stamp = "";
|
|
2626
3262
|
}
|
|
2627
3263
|
/** Size the canvas to its CSS box; returns the CSS size and dpr the frame should use. (A host may size the canvas itself instead.) */
|
|
2628
3264
|
fit(maxDpr = 2) {
|
|
@@ -2637,17 +3273,18 @@ var Ground = class _Ground {
|
|
|
2637
3273
|
for (const k of this.root.kinds.values()) k.pass.endHold?.();
|
|
2638
3274
|
}
|
|
2639
3275
|
const encoder = this.device.createCommandEncoder({ label: "ground" });
|
|
2640
|
-
const
|
|
2641
|
-
const prepared = prepareFrame(encoder, this.root, this.pool, inputs, this.grid, void 0, inputs.tray !== void 0 ? this.traySlots ?? void 0 : void 0);
|
|
2642
|
-
const marked = this.marks !== null ? this.marks.prepare(inputs.marks, trayed > 0 && this.tray !== null ? { view: inputs.view, tags: tagsOf(inputs.tray), night: inputs.theme.matLight.night } : void 0) : 0;
|
|
2643
|
-
const bg = inputs.theme.canvasBg;
|
|
2644
|
-
const pass = beginPass(encoder, this.surface.view(), [bg[0], bg[1], bg[2], 1], "ground");
|
|
2645
|
-
const drawn = drawFrame(pass, this.surface.size(), inputs.view.dpr, prepared.incoming, prepared.outgoing);
|
|
2646
|
-
if (marked > 0) this.marks?.draw(pass);
|
|
2647
|
-
if ((trayed > 0 || prepared.carried !== void 0) && this.tray !== null) drawTray(pass, this.surface.size(), inputs.view.dpr, this.tray, prepared.tray, this.marks, prepared.carried);
|
|
2648
|
-
pass.end();
|
|
3276
|
+
const { stats } = encodeFrame(encoder, this, inputs, this.surface);
|
|
2649
3277
|
this.device.queue.submit([encoder.finish()]);
|
|
2650
|
-
return this.said(
|
|
3278
|
+
return this.said(stats);
|
|
3279
|
+
}
|
|
3280
|
+
/**
|
|
3281
|
+
* THE CAPTURE DOOR's GPU half (petition I23; `captureFrame`): `inputs` — the last frame's, as `render` took them — drawn once
|
|
3282
|
+
* more into a readable texture at the view's dpr × `scale`, `rect` (CSS px of the view) read back. The swap chain is not touched,
|
|
3283
|
+
* no frame is drawn, nothing is kept: the still and its readback buffer are made for the call and destroyed after it. Undefined
|
|
3284
|
+
* when the device is lost mid-copy, or the rect lies off the view.
|
|
3285
|
+
*/
|
|
3286
|
+
capture(inputs, opts = {}) {
|
|
3287
|
+
return captureFrame(this.device, this, this.surface.format, inputs, this.heldCache, opts);
|
|
2651
3288
|
}
|
|
2652
3289
|
/** A kind whose cap turns objects away is an ERROR on the host's console (D7): said when the drop begins and again if it grows. */
|
|
2653
3290
|
said(stats) {
|
|
@@ -2659,12 +3296,13 @@ var Ground = class _Ground {
|
|
|
2659
3296
|
for (const kind of [...this.dropSaid.keys()]) if (!(kind in now)) this.dropSaid.delete(kind);
|
|
2660
3297
|
return stats;
|
|
2661
3298
|
}
|
|
2662
|
-
/** The pool's slots, then the root's kinds in reverse registration order, then the mat. */
|
|
3299
|
+
/** The pool's slots, then the root's kinds in reverse registration order (a missing kind's face among them), its missing face, then the mat. */
|
|
2663
3300
|
dispose() {
|
|
2664
3301
|
this.pool.dispose();
|
|
2665
3302
|
this.traySlots?.dispose();
|
|
2666
3303
|
this.root.card?.dispose();
|
|
2667
3304
|
for (const k of [...this.root.kinds.values()].reverse()) k.pass.dispose();
|
|
3305
|
+
this.root.missing?.dispose();
|
|
2668
3306
|
this.marks?.dispose();
|
|
2669
3307
|
this.hold?.dispose();
|
|
2670
3308
|
this.tray?.dispose();
|
|
@@ -2687,7 +3325,7 @@ function tagsOf(tray) {
|
|
|
2687
3325
|
const P = DRAWER.pitch;
|
|
2688
3326
|
return (tray?.specimens ?? []).map((f) => ({ label: f.label, x: (f.screen.x0 + f.screen.x1) / 2, y: f.screen.y1 + (f.accessory === "shelf" ? 0.24 * P : 0) + 0.45 * P }));
|
|
2689
3327
|
}
|
|
2690
|
-
function renderHeldFrame(device, hold, root, pool, grid, into, inputs, held, cache) {
|
|
3328
|
+
function renderHeldFrame(device, hold, root, pool, grid, into, inputs, held, cache, label = "hold") {
|
|
2691
3329
|
const size = into.size();
|
|
2692
3330
|
const dpr = inputs.view.dpr;
|
|
2693
3331
|
const bg = inputs.theme.canvasBg;
|
|
@@ -2695,29 +3333,104 @@ function renderHeldFrame(device, hold, root, pool, grid, into, inputs, held, cac
|
|
|
2695
3333
|
if (remade || cache.stamp !== held.stamp) {
|
|
2696
3334
|
cache.stamp = held.stamp;
|
|
2697
3335
|
cache.copies += 1;
|
|
2698
|
-
const encoder2 = device.createCommandEncoder({ label:
|
|
3336
|
+
const encoder2 = device.createCommandEncoder({ label: `${label}/copy` });
|
|
2699
3337
|
const { held: _held, marks: _marks, ...rest } = inputs;
|
|
2700
3338
|
const copy = { ...rest, view: { ...inputs.view, dpr: dpr / 2 } };
|
|
2701
3339
|
const prepared = prepareFrame(encoder2, root, pool, copy, grid, "copy");
|
|
2702
|
-
const pass2 = beginPass(encoder2, hold.desk.view, [bg[0], bg[1], bg[2], 1],
|
|
3340
|
+
const pass2 = beginPass(encoder2, hold.desk.view, [bg[0], bg[1], bg[2], 1], `${label}/copy`);
|
|
2703
3341
|
const drawn = drawFrame(pass2, { w: hold.desk.width, h: hold.desk.height }, dpr / 2, prepared.incoming, prepared.outgoing);
|
|
2704
3342
|
pass2.end();
|
|
2705
3343
|
hold.blur(encoder2, held.blur * dpr / 2);
|
|
2706
3344
|
device.queue.submit([encoder2.finish()]);
|
|
2707
3345
|
cache.stats = { ...drawn.incoming, kinds: prepared.kinds, outgoing: drawn.outgoing, portals: prepared.portals, ...prepared.dropped ? { dropped: prepared.dropped } : {} };
|
|
2708
3346
|
}
|
|
2709
|
-
const encoder = device.createCommandEncoder({ label
|
|
3347
|
+
const encoder = device.createCommandEncoder({ label });
|
|
2710
3348
|
const handInputs = { view: held.view, grid: held.grid, objects: [held.object, ...held.riders ?? []], theme: { ...inputs.theme, matLight: held.light } };
|
|
2711
3349
|
const hand = prepareFrame(encoder, root, pool, handInputs, held.grid, "hand");
|
|
2712
|
-
const handPass = beginPass(encoder, hold.hand.view, [0, 0, 0, 0],
|
|
3350
|
+
const handPass = beginPass(encoder, hold.hand.view, [0, 0, 0, 0], `${label}/hand`);
|
|
2713
3351
|
drawSlot(handPass, size, dpr, { ...hand.incoming, bare: true });
|
|
2714
3352
|
handPass.end();
|
|
2715
|
-
const pass = beginPass(encoder, into.view(), [bg[0], bg[1], bg[2], 1],
|
|
3353
|
+
const pass = beginPass(encoder, into.view(), [bg[0], bg[1], bg[2], 1], label);
|
|
2716
3354
|
hold.composite(pass, { e: held.e, dim: held.dim, saturate: held.filter.saturate, brightness: held.filter.brightness });
|
|
2717
3355
|
pass.end();
|
|
2718
3356
|
device.queue.submit([encoder.finish()]);
|
|
2719
3357
|
return cache.stats ?? { k0: 0, fade: 0, wind: false, kinds: hand.kinds, outgoing: null, portals: 0 };
|
|
2720
3358
|
}
|
|
3359
|
+
var captureNumber = (what, v, positive) => {
|
|
3360
|
+
if (typeof v !== "number" || !Number.isFinite(v) || positive && v <= 0) throw new Error(`capture: ${what} must be a ${positive ? "positive " : ""}finite number (got ${String(v)})`);
|
|
3361
|
+
return v;
|
|
3362
|
+
};
|
|
3363
|
+
function checkCapture(opts) {
|
|
3364
|
+
captureNumber("scale", opts.scale ?? 1, true);
|
|
3365
|
+
const r = opts.rect;
|
|
3366
|
+
if (r === void 0) return;
|
|
3367
|
+
captureNumber("rect.x", r.x, false);
|
|
3368
|
+
captureNumber("rect.y", r.y, false);
|
|
3369
|
+
captureNumber("rect.width", r.width, false);
|
|
3370
|
+
captureNumber("rect.height", r.height, false);
|
|
3371
|
+
}
|
|
3372
|
+
function scaledInputs(inputs, scale) {
|
|
3373
|
+
if (scale === 1) return inputs;
|
|
3374
|
+
const dprOf = (v) => ({ ...v, dpr: v.dpr * scale });
|
|
3375
|
+
const slotOf = (s) => ({ ...s, view: dprOf(s.view), ...s.portals !== void 0 ? { portals: s.portals.map(slotOf) } : {} });
|
|
3376
|
+
const { outgoing, held, marks, tray } = inputs;
|
|
3377
|
+
return {
|
|
3378
|
+
...slotOf(inputs),
|
|
3379
|
+
...outgoing !== void 0 ? { outgoing: slotOf(outgoing) } : {},
|
|
3380
|
+
...held !== void 0 ? { held: { ...held, view: dprOf(held.view) } } : {},
|
|
3381
|
+
...marks !== void 0 ? { marks: { ...marks, view: dprOf(marks.view) } } : {},
|
|
3382
|
+
...tray !== void 0 ? { tray: { ...tray, ...tray.specimens !== void 0 ? { specimens: tray.specimens.map((f) => ({ ...f, view: dprOf(f.view) })) } : {}, ...tray.carried !== void 0 ? { carried: tray.carried.map((f) => ({ ...f, view: dprOf(f.view) })) } : {} } } : {}
|
|
3383
|
+
};
|
|
3384
|
+
}
|
|
3385
|
+
async function captureFrame(device, passes, format, inputs, cache, opts = {}) {
|
|
3386
|
+
checkCapture(opts);
|
|
3387
|
+
const frame = scaledInputs(inputs, opts.scale ?? 1);
|
|
3388
|
+
const dpr = frame.view.dpr;
|
|
3389
|
+
const size = { w: Math.max(1, Math.round(frame.view.width * dpr)), h: Math.max(1, Math.round(frame.view.height * dpr)) };
|
|
3390
|
+
let box2 = { x: 0, y: 0, w: size.w, h: size.h };
|
|
3391
|
+
const r = opts.rect;
|
|
3392
|
+
if (r !== void 0) {
|
|
3393
|
+
const x0 = Math.max(0, Math.round(r.x * dpr));
|
|
3394
|
+
const y0 = Math.max(0, Math.round(r.y * dpr));
|
|
3395
|
+
const x1 = Math.min(size.w, Math.round((r.x + r.width) * dpr));
|
|
3396
|
+
const y1 = Math.min(size.h, Math.round((r.y + r.height) * dpr));
|
|
3397
|
+
box2 = { x: x0, y: y0, w: x1 - x0, h: y1 - y0 };
|
|
3398
|
+
if (box2.w <= 0 || box2.h <= 0) return void 0;
|
|
3399
|
+
}
|
|
3400
|
+
const still = new Target(device, { format, label: "capture/still", readable: true }, size.w, size.h);
|
|
3401
|
+
const into = { view: () => still.view, size: () => size };
|
|
3402
|
+
const rowBytes = Math.ceil(box2.w * 4 / 256) * 256;
|
|
3403
|
+
const readback = device.createBuffer({ label: "capture/readback", size: rowBytes * box2.h, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ });
|
|
3404
|
+
try {
|
|
3405
|
+
const copy = (encoder) => {
|
|
3406
|
+
encoder.copyTextureToBuffer({ texture: still.texture, origin: [box2.x, box2.y] }, { buffer: readback, bytesPerRow: rowBytes }, [box2.w, box2.h]);
|
|
3407
|
+
};
|
|
3408
|
+
if (frame.held !== void 0 && frame.held.e > 0 && passes.hold !== null) {
|
|
3409
|
+
renderHeldFrame(device, passes.hold, passes.root, passes.pool, passes.grid, into, frame, frame.held, cache, "capture");
|
|
3410
|
+
const encoder = device.createCommandEncoder({ label: "capture/read" });
|
|
3411
|
+
copy(encoder);
|
|
3412
|
+
device.queue.submit([encoder.finish()]);
|
|
3413
|
+
} else {
|
|
3414
|
+
const encoder = device.createCommandEncoder({ label: "capture" });
|
|
3415
|
+
encodeFrame(encoder, passes, frame, into, "capture");
|
|
3416
|
+
copy(encoder);
|
|
3417
|
+
device.queue.submit([encoder.finish()]);
|
|
3418
|
+
}
|
|
3419
|
+
try {
|
|
3420
|
+
await readback.mapAsync(GPUMapMode.READ);
|
|
3421
|
+
} catch {
|
|
3422
|
+
return void 0;
|
|
3423
|
+
}
|
|
3424
|
+
const padded = new Uint8Array(readback.getMappedRange());
|
|
3425
|
+
const bytes = new Uint8Array(new ArrayBuffer(box2.w * box2.h * 4));
|
|
3426
|
+
for (let y = 0; y < box2.h; y++) bytes.set(padded.subarray(y * rowBytes, y * rowBytes + box2.w * 4), y * box2.w * 4);
|
|
3427
|
+
readback.unmap();
|
|
3428
|
+
return { width: box2.w, height: box2.h, format, bytes };
|
|
3429
|
+
} finally {
|
|
3430
|
+
readback.destroy();
|
|
3431
|
+
still.dispose();
|
|
3432
|
+
}
|
|
3433
|
+
}
|
|
2721
3434
|
|
|
2722
3435
|
// ../desk/src/mat/tilt.ts
|
|
2723
3436
|
function secondOrder(f = 1, z = 0.3, r = 2, value = [0, 0]) {
|
|
@@ -3303,12 +4016,38 @@ function createDeskBuilder(world, opts) {
|
|
|
3303
4016
|
const S = opts.springs ?? SPRINGS;
|
|
3304
4017
|
const rungCtx = { entity: NO_ENTITY, rect: { cx: 0, cy: 0, w: 0, h: 0 }, props: {}, zoom: 1, dpr: 1, local: void 0, px: 0 };
|
|
3305
4018
|
const locals = opts.locals;
|
|
4019
|
+
const faults = opts.faults;
|
|
3306
4020
|
const forget = (kind, e) => {
|
|
3307
4021
|
locals?.get(kind.name)?.forget?.(e);
|
|
3308
4022
|
};
|
|
4023
|
+
const drawerOf = (kind) => kind === MISSING_OBJECT || faults?.missing(kind.name) === true ? MISSING_OBJECT : kind;
|
|
4024
|
+
const fault = (kind, call, err, e) => {
|
|
4025
|
+
if (faults === void 0) throw err;
|
|
4026
|
+
faults.strike(kind.name, call, err, e);
|
|
4027
|
+
};
|
|
4028
|
+
const kindless = /* @__PURE__ */ new Set();
|
|
4029
|
+
const mounted = /* @__PURE__ */ new Set();
|
|
4030
|
+
for (const w of opts.objects) {
|
|
4031
|
+
const k = objectKindOf(w);
|
|
4032
|
+
if (k !== void 0) mounted.add(k.name);
|
|
4033
|
+
}
|
|
4034
|
+
const unmounted = /* @__PURE__ */ new Set();
|
|
4035
|
+
const veilers = [];
|
|
4036
|
+
const veilerNames = [];
|
|
4037
|
+
const liftedBy = (st, e) => {
|
|
4038
|
+
const local = locals?.get(st.kind.name);
|
|
4039
|
+
if (local?.lifted === void 0) return false;
|
|
4040
|
+
try {
|
|
4041
|
+
return local.lifted(e) === true;
|
|
4042
|
+
} catch (err) {
|
|
4043
|
+
fault(st.kind, "lifted", err, e);
|
|
4044
|
+
return false;
|
|
4045
|
+
}
|
|
4046
|
+
};
|
|
3309
4047
|
const ghostS = (opts.ghostMs ?? GHOST_MS) / 1e3;
|
|
3310
4048
|
const marginPx = opts.marginPx ?? MARGIN_PX;
|
|
3311
4049
|
const redressMs = opts.redressMs ?? REDRESS_MS;
|
|
4050
|
+
const reserves = opts.hold ?? HOLD;
|
|
3312
4051
|
const order = createSiblingOrderIndex(world);
|
|
3313
4052
|
const states = /* @__PURE__ */ new Map();
|
|
3314
4053
|
const ghosts = /* @__PURE__ */ new Map();
|
|
@@ -3418,7 +4157,7 @@ function createDeskBuilder(world, opts) {
|
|
|
3418
4157
|
const h = world.readField(e, Size, "h") ?? 0;
|
|
3419
4158
|
st.rect = rectOf({ x, y }, { w, h });
|
|
3420
4159
|
const props = {};
|
|
3421
|
-
for (const g of st.widget
|
|
4160
|
+
for (const g of st.widget?.groups ?? []) {
|
|
3422
4161
|
const v = world.get(e, g.component);
|
|
3423
4162
|
if (v !== void 0) for (const name of Object.keys(g.fields)) props[name] = v[name];
|
|
3424
4163
|
}
|
|
@@ -3443,13 +4182,28 @@ function createDeskBuilder(world, opts) {
|
|
|
3443
4182
|
const id3 = world.get(e, PrefabId)?.id;
|
|
3444
4183
|
if (typeof id3 !== "string") return void 0;
|
|
3445
4184
|
const widget = widgetTypeFor(world, id3);
|
|
3446
|
-
|
|
3447
|
-
if (
|
|
4185
|
+
let kind = objectKindOf(widget);
|
|
4186
|
+
if (kind !== void 0 && faults !== void 0 && !mounted.has(kind.name)) {
|
|
4187
|
+
if (!unmounted.has(id3)) {
|
|
4188
|
+
unmounted.add(id3);
|
|
4189
|
+
console.warn(`[ice] desk: the type "${id3}" has a kind ("${kind.name}") this desk was not mounted with \u2014 a desk's kinds are compiled at its mount, and a type registered after it adds none: its objects are drawn as missing; remount to draw it (petition I25)`);
|
|
4190
|
+
}
|
|
4191
|
+
kind = MISSING_OBJECT;
|
|
4192
|
+
}
|
|
4193
|
+
if (kind === void 0) {
|
|
4194
|
+
if (faults === void 0) return void 0;
|
|
4195
|
+
kind = MISSING_OBJECT;
|
|
4196
|
+
if (!kindless.has(id3)) {
|
|
4197
|
+
kindless.add(id3);
|
|
4198
|
+
console.warn(`[ice] desk: the type "${id3}" has no kind on this desk \u2014 its objects are drawn as missing (petition I24)`);
|
|
4199
|
+
}
|
|
4200
|
+
}
|
|
3448
4201
|
meet(kind);
|
|
3449
4202
|
const insert = world.has(e, InsertGhost);
|
|
3450
4203
|
const st = {
|
|
3451
4204
|
kind,
|
|
3452
4205
|
widget,
|
|
4206
|
+
face: false,
|
|
3453
4207
|
rect: { cx: 0, cy: 0, w: 0, h: 0 },
|
|
3454
4208
|
props: {},
|
|
3455
4209
|
selected: false,
|
|
@@ -3490,7 +4244,7 @@ function createDeskBuilder(world, opts) {
|
|
|
3490
4244
|
if (st === void 0) return void 0;
|
|
3491
4245
|
if (st.dirty) refresh(e, st);
|
|
3492
4246
|
if (had === void 0 && landing.length > 0 && !st.insert) {
|
|
3493
|
-
const i = landing.findIndex((l2) => l2.type === st.widget
|
|
4247
|
+
const i = landing.findIndex((l2) => l2.type === st.widget?.type && Math.abs(l2.rect.cx - st.rect.cx) < 0.5 && Math.abs(l2.rect.cy - st.rect.cy) < 0.5);
|
|
3494
4248
|
const l = landing[i];
|
|
3495
4249
|
if (l !== void 0) {
|
|
3496
4250
|
st.lift = l.lift;
|
|
@@ -3532,25 +4286,38 @@ function createDeskBuilder(world, opts) {
|
|
|
3532
4286
|
const frameGridOf = (frame, root, looks) => {
|
|
3533
4287
|
if (frame === void 0 || !world.isAlive(frame) || !world.hasTag(frame, Container)) return root;
|
|
3534
4288
|
const st = stateOf(frame);
|
|
3535
|
-
|
|
3536
|
-
|
|
4289
|
+
const kind = st === void 0 ? void 0 : drawerOf(st.kind);
|
|
4290
|
+
if (st === void 0 || kind?.insideGrid === void 0) return root;
|
|
4291
|
+
try {
|
|
4292
|
+
return kind.insideGrid({ props: st.props, look: looks.get(kind.name) }, root);
|
|
4293
|
+
} catch (err) {
|
|
4294
|
+
fault(kind, "insideGrid", err, frame);
|
|
4295
|
+
return root;
|
|
4296
|
+
}
|
|
3537
4297
|
};
|
|
3538
4298
|
const navFace = (container, cam) => {
|
|
3539
4299
|
const st = stateOf(container);
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
4300
|
+
const kind = st === void 0 ? void 0 : drawerOf(st.kind);
|
|
4301
|
+
if (st === void 0 || kind?.face === void 0) return void 0;
|
|
4302
|
+
let face2;
|
|
4303
|
+
try {
|
|
4304
|
+
let G;
|
|
4305
|
+
if (st.seen === seq && st.geometry !== null && st.slot === "root" && !st.face) G = st.geometry;
|
|
4306
|
+
else {
|
|
4307
|
+
const grid = lastGrid;
|
|
4308
|
+
const theme = lastTheme;
|
|
4309
|
+
if (grid === void 0 || theme === void 0) return void 0;
|
|
4310
|
+
const vp = world.getResource(Viewport);
|
|
4311
|
+
const view2 = { camX: cam.x, camY: cam.y, zoom: cam.zoom, width: vp?.w ?? 0, height: vp?.h ?? 0, dpr: vp?.dpr ?? 1 };
|
|
4312
|
+
const local = locals?.get(kind.name);
|
|
4313
|
+
const ctx = { entity: container, rect: st.rect, props: st.props, flux: FLUX_REST, look: lastLooks?.get(kind.name), theme, lamp: lampOf(grid.mat.plane), view: view2, grid, dt: 0, ...local !== void 0 ? { local } : {} };
|
|
4314
|
+
G = kind.resolve(ctx);
|
|
4315
|
+
}
|
|
4316
|
+
face2 = kind.face(G);
|
|
4317
|
+
} catch (err) {
|
|
4318
|
+
fault(kind, "face", err, container);
|
|
4319
|
+
return void 0;
|
|
3552
4320
|
}
|
|
3553
|
-
const face2 = st.kind.face(G);
|
|
3554
4321
|
if (face2 === void 0) return void 0;
|
|
3555
4322
|
const vpSize = viewportOf();
|
|
3556
4323
|
const view = insideViewOfFace(face2, st.kind.faceLaw?.radius ?? 0, contentOf(container), cam, vpSize, FIT, PORTAL_GATE);
|
|
@@ -3657,10 +4424,17 @@ function createDeskBuilder(world, opts) {
|
|
|
3657
4424
|
for (const c of childrenOf(e)) {
|
|
3658
4425
|
if (chips.length >= cap) break;
|
|
3659
4426
|
const cst = stateOf(c);
|
|
3660
|
-
|
|
4427
|
+
const ckind = cst === void 0 ? void 0 : drawerOf(cst.kind);
|
|
4428
|
+
if (cst === void 0 || ckind?.chip === void 0) continue;
|
|
3661
4429
|
const cctx = contextOf(c, cst, insideView, insideGrid, insideLamp, false);
|
|
3662
4430
|
work.resolved += 1;
|
|
3663
|
-
|
|
4431
|
+
let chip;
|
|
4432
|
+
try {
|
|
4433
|
+
chip = ckind.chip(ckind.resolve(cctx), cctx);
|
|
4434
|
+
} catch (err) {
|
|
4435
|
+
fault(ckind, "chip", err, c);
|
|
4436
|
+
continue;
|
|
4437
|
+
}
|
|
3664
4438
|
if (chip === null) continue;
|
|
3665
4439
|
const finish = finishOf(chip.finish, finishes);
|
|
3666
4440
|
if (finish === void 0) {
|
|
@@ -3671,28 +4445,32 @@ function createDeskBuilder(world, opts) {
|
|
|
3671
4445
|
}
|
|
3672
4446
|
return chips;
|
|
3673
4447
|
};
|
|
3674
|
-
const insideOf = (e, st, G, ctx, slotCam, slotGrid) => {
|
|
3675
|
-
const face2 =
|
|
4448
|
+
const insideOf = (e, st, kind, G, ctx, slotCam, slotGrid) => {
|
|
4449
|
+
const face2 = kind.face?.(G);
|
|
3676
4450
|
if (face2 === void 0) {
|
|
3677
4451
|
st.inside = null;
|
|
3678
4452
|
st.content = null;
|
|
3679
4453
|
return void 0;
|
|
3680
4454
|
}
|
|
3681
4455
|
const content = contentOf(e);
|
|
3682
|
-
const view = insideViewOfFace(face2,
|
|
4456
|
+
const view = insideViewOfFace(face2, kind.faceLaw?.radius ?? 0, content, slotCam, vpSize, FIT, PORTAL_GATE);
|
|
3683
4457
|
st.inside = view;
|
|
3684
4458
|
st.content = content;
|
|
3685
4459
|
return { content, view, chips: chipsOf(e, st, ctx, view, slotGrid) };
|
|
3686
4460
|
};
|
|
3687
|
-
const checkReuse = (e, st, view, slotGrid, slotLamp, springs, give, slotCam) => {
|
|
4461
|
+
const checkReuse = (e, st, kind, view, slotGrid, slotLamp, springs, give, slotCam) => {
|
|
3688
4462
|
const r = st.rect;
|
|
3689
4463
|
const drawn = give === 0 ? r : { ...r, cx: r.cx + give / slotCam.zoom };
|
|
3690
4464
|
const ctx = contextOf(e, st, view, slotGrid, slotLamp, springs, drawn);
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
4465
|
+
try {
|
|
4466
|
+
const G = kind.resolve(ctx);
|
|
4467
|
+
const face2 = kind.face?.(G);
|
|
4468
|
+
const inside = face2 === void 0 ? void 0 : { content: st.content, view: st.inside, chips: chipsOf(e, st, ctx, st.inside, slotGrid) };
|
|
4469
|
+
const R = kind.record(G, inside === void 0 ? ctx : { ...ctx, inside });
|
|
4470
|
+
if (!sameRecord(R, st.record)) mismatches += 1;
|
|
4471
|
+
} catch (err) {
|
|
4472
|
+
fault(kind, "record", err, e);
|
|
4473
|
+
}
|
|
3696
4474
|
};
|
|
3697
4475
|
const buildSlot = (members, slotCam, slotGrid, slot, depth, skip, redressOut2) => {
|
|
3698
4476
|
const slotLamp = lampOf(slotGrid.mat.plane);
|
|
@@ -3729,9 +4507,11 @@ function createDeskBuilder(world, opts) {
|
|
|
3729
4507
|
st.inside = null;
|
|
3730
4508
|
continue;
|
|
3731
4509
|
}
|
|
4510
|
+
const kind = (faults?.size ?? 0) === 0 ? st.kind : drawerOf(st.kind);
|
|
4511
|
+
const face2 = kind === MISSING_OBJECT;
|
|
3732
4512
|
const r = st.rect;
|
|
3733
|
-
const hx = r.w / 2 +
|
|
3734
|
-
const hy = r.h / 2 +
|
|
4513
|
+
const hx = r.w / 2 + kind.reach;
|
|
4514
|
+
const hy = r.h / 2 + kind.reach;
|
|
3735
4515
|
if (r.cx + hx < x0 || r.cx - hx > x1 || r.cy + hy < y0 || r.cy - hy > y1) {
|
|
3736
4516
|
st.geometry = null;
|
|
3737
4517
|
st.record = null;
|
|
@@ -3741,60 +4521,87 @@ function createDeskBuilder(world, opts) {
|
|
|
3741
4521
|
}
|
|
3742
4522
|
const give = slot === "root" ? marks.giveOf(e) : 0;
|
|
3743
4523
|
const fluxMoved = springs ? stepSprings(e, st) : false;
|
|
3744
|
-
const kind = st.kind;
|
|
3745
4524
|
const fresh = st.record === null || st.geometry === null;
|
|
3746
|
-
let remake = fresh || st.stale || remakeAll || fluxMoved || prevSlot !== slot || give !== st.give || kind.composite === true || restless?.has(kind.name) === true;
|
|
4525
|
+
let remake = fresh || st.stale || remakeAll || fluxMoved || prevSlot !== slot || give !== st.give || st.face !== face2 || kind.composite === true || restless?.has(kind.name) === true;
|
|
3747
4526
|
if (fresh) work.fresh += 1;
|
|
3748
4527
|
if (restless?.has(kind.name) === true) work.restless += 1;
|
|
3749
|
-
if (!remake && (redpr || slotCam.zoom !== st.zoom)) {
|
|
3750
|
-
if (kind.rung !== void 0) {
|
|
3751
|
-
if (rungOf(kind, e, st, slotCam) !== st.rung) {
|
|
3752
|
-
remake = true;
|
|
3753
|
-
work.rerung += 1;
|
|
3754
|
-
} else st.zoom = slotCam.zoom;
|
|
3755
|
-
} else if (kind.rezoom === true) {
|
|
3756
|
-
remake = true;
|
|
3757
|
-
work.rezoomed += 1;
|
|
3758
|
-
}
|
|
3759
|
-
}
|
|
3760
4528
|
let G;
|
|
3761
4529
|
let R;
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
4530
|
+
let call = "rung";
|
|
4531
|
+
try {
|
|
4532
|
+
if (!remake && (redpr || slotCam.zoom !== st.zoom)) {
|
|
4533
|
+
if (kind.rung !== void 0) {
|
|
4534
|
+
if (rungOf(kind, e, st, slotCam) !== st.rung) {
|
|
4535
|
+
remake = true;
|
|
4536
|
+
work.rerung += 1;
|
|
4537
|
+
} else st.zoom = slotCam.zoom;
|
|
4538
|
+
} else if (kind.rezoom === true) {
|
|
4539
|
+
remake = true;
|
|
4540
|
+
work.rezoomed += 1;
|
|
4541
|
+
}
|
|
3769
4542
|
}
|
|
3770
|
-
if (
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
4543
|
+
if (!remake) {
|
|
4544
|
+
G = st.geometry;
|
|
4545
|
+
R = st.record;
|
|
4546
|
+
work.reused += 1;
|
|
4547
|
+
if (kind.face !== void 0) {
|
|
4548
|
+
call = "face";
|
|
4549
|
+
const shown = kind.face(G);
|
|
4550
|
+
st.inside = shown === void 0 ? null : insideViewOfFace(shown, kind.faceLaw?.radius ?? 0, st.content, slotCam, vpSize, FIT, PORTAL_GATE);
|
|
4551
|
+
}
|
|
4552
|
+
if (verifying) checkReuse(e, st, kind, view, slotGrid, slotLamp, springs, give, slotCam);
|
|
4553
|
+
} else {
|
|
4554
|
+
const drawn = give === 0 ? r : { ...r, cx: r.cx + give / slotCam.zoom };
|
|
4555
|
+
const ctx = contextOf(e, st, view, slotGrid, slotLamp, springs, drawn);
|
|
4556
|
+
work.resolved += 1;
|
|
4557
|
+
call = "resolve";
|
|
4558
|
+
G = kind.resolve(ctx);
|
|
4559
|
+
call = "face";
|
|
4560
|
+
const inside = insideOf(e, st, kind, G, ctx, slotCam, slotGrid);
|
|
4561
|
+
work.recorded += 1;
|
|
4562
|
+
call = "record";
|
|
4563
|
+
R = kind.record(G, inside === void 0 ? ctx : { ...ctx, inside });
|
|
4564
|
+
call = "landed";
|
|
4565
|
+
const landed = face2 ? 0 : locals?.get(kind.name)?.landed?.(e) ?? 0;
|
|
4566
|
+
if (landed !== st.landed) {
|
|
4567
|
+
st.landed = landed;
|
|
4568
|
+
deskLanded = true;
|
|
4569
|
+
}
|
|
4570
|
+
call = "rung";
|
|
4571
|
+
const rung = kind.rung === void 0 ? 0 : rungOf(kind, e, st, slotCam);
|
|
4572
|
+
call = "frame";
|
|
4573
|
+
const markRow = slot === "root" ? { entity: e, frame: kind.frame?.(G) ?? rectFrame(drawn), rect: { x0: r.cx - r.w / 2, y0: r.cy - r.h / 2, x1: r.cx + r.w / 2, y1: r.cy + r.h / 2 }, selected: st.selected, locked: st.locked, grabbed: st.grabbed, resizable: st.resizable } : null;
|
|
4574
|
+
st.geometry = G;
|
|
4575
|
+
st.record = R;
|
|
4576
|
+
st.stale = false;
|
|
4577
|
+
st.give = give;
|
|
4578
|
+
st.zoom = slotCam.zoom;
|
|
4579
|
+
st.rung = rung;
|
|
4580
|
+
st.face = face2;
|
|
4581
|
+
st.markRow = markRow;
|
|
3783
4582
|
}
|
|
3784
|
-
|
|
3785
|
-
st.
|
|
3786
|
-
st.
|
|
3787
|
-
st.
|
|
3788
|
-
st.
|
|
3789
|
-
st.
|
|
3790
|
-
|
|
4583
|
+
} catch (err) {
|
|
4584
|
+
st.geometry = null;
|
|
4585
|
+
st.record = null;
|
|
4586
|
+
st.inside = null;
|
|
4587
|
+
st.markRow = null;
|
|
4588
|
+
st.stale = true;
|
|
4589
|
+
fault(kind, call, err, e);
|
|
4590
|
+
continue;
|
|
3791
4591
|
}
|
|
3792
4592
|
const at2 = rows2.length;
|
|
3793
|
-
rows2.push({ entity: e, kind: kind.name, record: R, band: st.band });
|
|
4593
|
+
rows2.push({ entity: e, kind: st.kind.name, record: R, band: st.band });
|
|
3794
4594
|
if (slot === "root" && st.markRow !== null) markRows.push(st.markRow);
|
|
3795
4595
|
const iv = st.inside;
|
|
3796
4596
|
if (iv !== null && portalsOn && depth < PORTAL_DEPTH && e !== skip && iv.presence > 0) {
|
|
3797
|
-
|
|
4597
|
+
let inner = slotGrid;
|
|
4598
|
+
try {
|
|
4599
|
+
inner = kind.insideGrid?.({ props: st.props, look: looks.get(kind.name) }, slotGrid) ?? slotGrid;
|
|
4600
|
+
} catch (err) {
|
|
4601
|
+
fault(kind, "insideGrid", err, e);
|
|
4602
|
+
continue;
|
|
4603
|
+
}
|
|
4604
|
+
cands.push({ at: at2, e, view: iv, grid: inner });
|
|
3798
4605
|
}
|
|
3799
4606
|
}
|
|
3800
4607
|
cands.sort((a, b) => b.view.clip.hx * b.view.clip.hy - a.view.clip.hx * a.view.clip.hy);
|
|
@@ -3833,14 +4640,30 @@ function createDeskBuilder(world, opts) {
|
|
|
3833
4640
|
else redressOut = { frame: redress.frame, from: redress.from, u };
|
|
3834
4641
|
}
|
|
3835
4642
|
}
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
4643
|
+
veilers.length = 0;
|
|
4644
|
+
veilerNames.length = 0;
|
|
4645
|
+
if (locals !== void 0) for (const name of locals.keys()) {
|
|
4646
|
+
const local = locals.get(name);
|
|
4647
|
+
if (local.veils !== void 0) {
|
|
4648
|
+
veilers.push(local);
|
|
4649
|
+
veilerNames.push(name);
|
|
4650
|
+
}
|
|
3839
4651
|
}
|
|
3840
|
-
const veiledNow = {
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
|
-
|
|
4652
|
+
const veiledNow = {
|
|
4653
|
+
has: (e) => {
|
|
4654
|
+
for (let i = 0; i < veilers.length; i++) {
|
|
4655
|
+
const name = veilerNames[i];
|
|
4656
|
+
if (faults?.missing(name) === true) continue;
|
|
4657
|
+
try {
|
|
4658
|
+
if (veilers[i].veils?.().has(e) === true) return true;
|
|
4659
|
+
} catch (err) {
|
|
4660
|
+
if (faults === void 0) throw err;
|
|
4661
|
+
faults.strike(name, "veils", err, e);
|
|
4662
|
+
}
|
|
4663
|
+
}
|
|
4664
|
+
return false;
|
|
4665
|
+
}
|
|
4666
|
+
};
|
|
3844
4667
|
const handRiders = /* @__PURE__ */ new Set();
|
|
3845
4668
|
const heldNow = heldEntity(world);
|
|
3846
4669
|
if (heldNow !== void 0) {
|
|
@@ -3859,7 +4682,7 @@ function createDeskBuilder(world, opts) {
|
|
|
3859
4682
|
let heldBuild;
|
|
3860
4683
|
if (hand !== null) {
|
|
3861
4684
|
const hst = world.isAlive(hand.entity) ? stateOf(hand.entity) : void 0;
|
|
3862
|
-
const binding = hst
|
|
4685
|
+
const binding = hst === void 0 || drawerOf(hst.kind) === MISSING_OBJECT ? void 0 : hst.kind.open;
|
|
3863
4686
|
if (hst === void 0 || binding === void 0) hand = null;
|
|
3864
4687
|
else {
|
|
3865
4688
|
const pin = bopts.hold;
|
|
@@ -3884,59 +4707,79 @@ function createDeskBuilder(world, opts) {
|
|
|
3884
4707
|
}
|
|
3885
4708
|
if (hand.dir < 0 && hand.p >= 1) hand = null;
|
|
3886
4709
|
else if (hand.e > 0) {
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
work.recorded += 1;
|
|
3907
|
-
const G = hst.kind.resolve(hctx);
|
|
3908
|
-
const R = hst.kind.record(G, hctx);
|
|
3909
|
-
hst.geometry = G;
|
|
3910
|
-
hst.record = R;
|
|
3911
|
-
hst.stale = true;
|
|
3912
|
-
hst.inside = null;
|
|
3913
|
-
hst.slot = "root";
|
|
3914
|
-
hst.seen = seq;
|
|
3915
|
-
const openness = binding.openness?.(hctx);
|
|
3916
|
-
hand.openness = openness ?? 0;
|
|
3917
|
-
const settledNow = pin !== void 0 ? hand.e >= 1 : hand.dir > 0 && hand.p >= 1;
|
|
3918
|
-
const coverMoving = openness !== void 0 && (openTarget ? openness < 1 - 1e-3 : openness > 1e-3);
|
|
3919
|
-
if (pin === void 0 && (hand.dir < 0 || hand.p < 1 || coverMoving)) live = true;
|
|
3920
|
-
const riders = [];
|
|
3921
|
-
const typeId = world.get(hand.entity, PrefabId)?.id;
|
|
3922
|
-
for (const rider of typeof typeId === "string" ? widgetTypeFor(world, typeId)?.riders?.(world, hand.entity) ?? [] : []) {
|
|
3923
|
-
const rst = veiledNow.has(rider) ? void 0 : stateOf(rider);
|
|
3924
|
-
if (rst === void 0) continue;
|
|
3925
|
-
const rctx = contextOf(rider, rst, heldView, heldGrid, lampOf(heldGrid.mat.plane), false);
|
|
4710
|
+
try {
|
|
4711
|
+
const extentLocal = binding.extent({ rect: hst.rect, props: hst.props });
|
|
4712
|
+
const angle = numberProp(hst.props, "angle", 0);
|
|
4713
|
+
const ox = extentLocal.cx - hst.rect.cx;
|
|
4714
|
+
const oy = extentLocal.cy - hst.rect.cy;
|
|
4715
|
+
const ca = Math.cos(angle);
|
|
4716
|
+
const sa = Math.sin(angle);
|
|
4717
|
+
const extentWorld = { cx: hst.rect.cx + ca * ox - sa * oy, cy: hst.rect.cy + sa * ox + ca * oy, w: extentLocal.w, h: extentLocal.h };
|
|
4718
|
+
const face2 = binding.spread === true ? binding.page?.({ entity: hand.entity, local: locals?.get(hst.kind.name) }) ?? 0 : 0;
|
|
4719
|
+
const target = readingTarget(extentLocal, vpSize, binding.spread === true, face2, reserves);
|
|
4720
|
+
const user = world.get(hand.entity, HeldView) ?? HELD_USER_REST;
|
|
4721
|
+
const pose = heldPose(homePose(extentWorld, angle, cam), target, user, hand.e);
|
|
4722
|
+
const { cam: heldCam, grow } = heldCamera(pose, hst.rect, extentLocal, cam.zoom, binding.pose === "eye", vpSize);
|
|
4723
|
+
const heldView = { camX: heldCam.x, camY: heldCam.y, zoom: heldCam.zoom, width: vp.width, height: vp.height, dpr: vp.dpr };
|
|
4724
|
+
const heldGrid = { ...frameGrid, mat: { ...frameGrid.mat, gobo: { ...frameGrid.mat.gobo, opacity: 0 } } };
|
|
4725
|
+
const base = contextOf(hand.entity, hst, heldView, heldGrid, lampOf(heldGrid.mat.plane), false);
|
|
4726
|
+
const props = typeof hst.props.angle === "number" ? { ...hst.props, angle: pose.angle } : hst.props;
|
|
4727
|
+
const snap = pin !== void 0 || bopts.freeze === true;
|
|
4728
|
+
const hctx = { ...base, props, held: { e: hand.e, open: openTarget, grow, snap } };
|
|
3926
4729
|
work.resolved += 1;
|
|
3927
4730
|
work.recorded += 1;
|
|
3928
|
-
|
|
3929
|
-
|
|
4731
|
+
const G = hst.kind.resolve(hctx);
|
|
4732
|
+
const R = hst.kind.record(G, hctx);
|
|
4733
|
+
hst.geometry = G;
|
|
4734
|
+
hst.record = R;
|
|
4735
|
+
hst.stale = true;
|
|
4736
|
+
hst.inside = null;
|
|
4737
|
+
hst.slot = "root";
|
|
4738
|
+
hst.seen = seq;
|
|
4739
|
+
const openness = binding.openness?.(hctx);
|
|
4740
|
+
hand.openness = openness ?? 0;
|
|
4741
|
+
const settledNow = pin !== void 0 ? hand.e >= 1 : hand.dir > 0 && hand.p >= 1;
|
|
4742
|
+
const coverMoving = openness !== void 0 && (openTarget ? openness < 1 - 1e-3 : openness > 1e-3);
|
|
4743
|
+
if (pin === void 0 && (hand.dir < 0 || hand.p < 1 || coverMoving)) live = true;
|
|
4744
|
+
const riders = [];
|
|
4745
|
+
const typeId = world.get(hand.entity, PrefabId)?.id;
|
|
4746
|
+
for (const rider of typeof typeId === "string" ? widgetTypeFor(world, typeId)?.riders?.(world, hand.entity) ?? [] : []) {
|
|
4747
|
+
const rst = veiledNow.has(rider) ? void 0 : stateOf(rider);
|
|
4748
|
+
if (rst === void 0) continue;
|
|
4749
|
+
const rkind = drawerOf(rst.kind);
|
|
4750
|
+
const rctx = contextOf(rider, rst, heldView, heldGrid, lampOf(heldGrid.mat.plane), false);
|
|
4751
|
+
work.resolved += 1;
|
|
4752
|
+
work.recorded += 1;
|
|
4753
|
+
let record;
|
|
4754
|
+
try {
|
|
4755
|
+
record = rkind.record(rkind.resolve(rctx), rctx);
|
|
4756
|
+
} catch (err) {
|
|
4757
|
+
fault(rkind, "record", err, rider);
|
|
4758
|
+
continue;
|
|
4759
|
+
}
|
|
4760
|
+
riders.push({ kind: rst.kind.name, record, key: rider });
|
|
4761
|
+
handRiders.add(rider);
|
|
4762
|
+
}
|
|
4763
|
+
heldBuild = {
|
|
4764
|
+
entity: hand.entity,
|
|
4765
|
+
e: hand.e,
|
|
4766
|
+
settled: settledNow,
|
|
4767
|
+
landing: hand.dir < 0,
|
|
4768
|
+
frame: { ...heldFrame(pose, extentLocal, target.single, face2), settled: settledNow },
|
|
4769
|
+
inputs: { object: { kind: hst.kind.name, record: R, key: hand.entity }, ...riders.length > 0 ? { riders } : {}, view: heldView, grid: heldGrid, e: hand.e, ...heldFocus(hand.e, vpSize, theme) },
|
|
4770
|
+
deskSeq
|
|
4771
|
+
};
|
|
4772
|
+
} catch (err) {
|
|
4773
|
+
const held = hand?.entity;
|
|
4774
|
+
hst.geometry = null;
|
|
4775
|
+
hst.record = null;
|
|
4776
|
+
hst.inside = null;
|
|
4777
|
+
hst.stale = true;
|
|
4778
|
+
hand = null;
|
|
4779
|
+
heldBuild = void 0;
|
|
4780
|
+
handRiders.clear();
|
|
4781
|
+
fault(hst.kind, "record", err, held);
|
|
3930
4782
|
}
|
|
3931
|
-
heldBuild = {
|
|
3932
|
-
entity: hand.entity,
|
|
3933
|
-
e: hand.e,
|
|
3934
|
-
settled: settledNow,
|
|
3935
|
-
landing: hand.dir < 0,
|
|
3936
|
-
frame: { ...heldFrame(pose, extentLocal, target.single, face2), settled: settledNow },
|
|
3937
|
-
inputs: { object: { kind: hst.kind.name, record: R, key: hand.entity }, ...riders.length > 0 ? { riders } : {}, view: heldView, grid: heldGrid, e: hand.e, ...heldFocus(hand.e, vpSize, theme) },
|
|
3938
|
-
deskSeq
|
|
3939
|
-
};
|
|
3940
4783
|
}
|
|
3941
4784
|
}
|
|
3942
4785
|
}
|
|
@@ -3947,7 +4790,7 @@ function createDeskBuilder(world, opts) {
|
|
|
3947
4790
|
dirtyStates.clear();
|
|
3948
4791
|
if (locals !== void 0) {
|
|
3949
4792
|
const check = (e, st) => {
|
|
3950
|
-
const v = !st.grabbed &&
|
|
4793
|
+
const v = !st.grabbed && liftedBy(st, e);
|
|
3951
4794
|
if (v !== st.lifted) {
|
|
3952
4795
|
st.lifted = v;
|
|
3953
4796
|
orderDirty = true;
|
|
@@ -3975,7 +4818,7 @@ function createDeskBuilder(world, opts) {
|
|
|
3975
4818
|
const st = stateOf(e);
|
|
3976
4819
|
if (st === void 0) continue;
|
|
3977
4820
|
st.active = true;
|
|
3978
|
-
st.lifted = !st.grabbed &&
|
|
4821
|
+
st.lifted = !st.grabbed && liftedBy(st, e);
|
|
3979
4822
|
(st.grabbed || st.lifted ? tiers[1] : tiers[0]).push(e);
|
|
3980
4823
|
}
|
|
3981
4824
|
});
|
|
@@ -4047,8 +4890,17 @@ function createDeskBuilder(world, opts) {
|
|
|
4047
4890
|
const ctx = { entity: e, rect: g.rect, props: g.props, flux: { ...g.flux, ring: 0, fade: 1 - g.del }, look: looks.get(g.kind.name), theme, lamp: rootLamp, view: rootView, grid: frameGrid, dt, ...g.asset !== void 0 ? { asset: g.asset } : {}, ...local !== void 0 ? { local } : {} };
|
|
4048
4891
|
work.resolved += 1;
|
|
4049
4892
|
work.recorded += 1;
|
|
4050
|
-
const
|
|
4051
|
-
|
|
4893
|
+
const gkind = drawerOf(g.kind);
|
|
4894
|
+
let record;
|
|
4895
|
+
try {
|
|
4896
|
+
record = gkind.record(gkind.resolve(ctx), ctx);
|
|
4897
|
+
} catch (err) {
|
|
4898
|
+
ghosts.delete(e);
|
|
4899
|
+
forget(g.kind, e);
|
|
4900
|
+
fault(gkind, "record", err, e);
|
|
4901
|
+
continue;
|
|
4902
|
+
}
|
|
4903
|
+
const row = { entity: void 0, kind: g.kind.name, record, band: g.band, ghostOf: e };
|
|
4052
4904
|
let at2 = g.next === void 0 ? -1 : rows.findIndex((q) => q.entity === g.next);
|
|
4053
4905
|
if (at2 < 0) {
|
|
4054
4906
|
at2 = rows.length;
|
|
@@ -4135,7 +4987,17 @@ function createDeskBuilder(world, opts) {
|
|
|
4135
4987
|
}
|
|
4136
4988
|
const objects = rows.map((r) => ({ kind: r.kind, record: r.record, key: r.entity !== void 0 ? r.entity : -r.ghostOf }));
|
|
4137
4989
|
const veiledSet = /* @__PURE__ */ new Set();
|
|
4138
|
-
for (
|
|
4990
|
+
for (let i = 0; i < veilers.length; i++) {
|
|
4991
|
+
const name = veilerNames[i];
|
|
4992
|
+
const local = veilers[i];
|
|
4993
|
+
if (locals?.get(name) !== local) continue;
|
|
4994
|
+
try {
|
|
4995
|
+
for (const e of local.veils?.() ?? []) veiledSet.add(e);
|
|
4996
|
+
} catch (err) {
|
|
4997
|
+
if (faults === void 0) throw err;
|
|
4998
|
+
faults.strike(name, "veils", err);
|
|
4999
|
+
}
|
|
5000
|
+
}
|
|
4139
5001
|
veiledList = veiledSet;
|
|
4140
5002
|
const ruler2 = frameGrid.mat.ruler;
|
|
4141
5003
|
const marked = marks.frame({ rows: markRows, cam, view: vp, dt, night: theme.name === "dark", rulers: ruler2.on ? { margin: ruler2.margin, band: ruler2.band } : null });
|
|
@@ -4225,7 +5087,7 @@ function createDeskBuilder(world, opts) {
|
|
|
4225
5087
|
const st = states.get(e);
|
|
4226
5088
|
if (st === void 0) continue;
|
|
4227
5089
|
if (st.insert) {
|
|
4228
|
-
landing.push({ type: st.widget
|
|
5090
|
+
landing.push({ type: st.widget?.type ?? "", rect: st.rect, lift: st.lift, liftV: st.liftV });
|
|
4229
5091
|
forget(st.kind, e);
|
|
4230
5092
|
} else {
|
|
4231
5093
|
ghostOf(e, st);
|
|
@@ -4332,8 +5194,25 @@ function createDeskBuilder(world, opts) {
|
|
|
4332
5194
|
heldPart(e, x, y) {
|
|
4333
5195
|
const w = heldToWorld(e, x, y);
|
|
4334
5196
|
const st = states.get(e);
|
|
4335
|
-
if (w === void 0 || st === void 0 || st.geometry === null) return null;
|
|
4336
|
-
|
|
5197
|
+
if (w === void 0 || st === void 0 || st.geometry === null || st.face) return null;
|
|
5198
|
+
try {
|
|
5199
|
+
return st.kind.hit(st.geometry, w[0], w[1]);
|
|
5200
|
+
} catch (err) {
|
|
5201
|
+
fault(st.kind, "hit", err, e);
|
|
5202
|
+
return null;
|
|
5203
|
+
}
|
|
5204
|
+
},
|
|
5205
|
+
hitAt(e, wx, wy) {
|
|
5206
|
+
const st = states.get(e);
|
|
5207
|
+
if (st === void 0 || st.geometry === null) return void 0;
|
|
5208
|
+
if (st.face) return MISSING_OBJECT.hit(st.geometry, wx, wy);
|
|
5209
|
+
if (drawerOf(st.kind) === MISSING_OBJECT) return void 0;
|
|
5210
|
+
try {
|
|
5211
|
+
return st.kind.hit(st.geometry, wx, wy);
|
|
5212
|
+
} catch (err) {
|
|
5213
|
+
fault(st.kind, "hit", err, e);
|
|
5214
|
+
return null;
|
|
5215
|
+
}
|
|
4337
5216
|
},
|
|
4338
5217
|
stats: () => stats,
|
|
4339
5218
|
dispose() {
|
|
@@ -4396,6 +5275,14 @@ function createRasterBudget(cap, floor = Math.floor(cap * BUDGET_FLOOR)) {
|
|
|
4396
5275
|
const ent = entries.get(k);
|
|
4397
5276
|
if (ent !== void 0) drop(k, ent);
|
|
4398
5277
|
},
|
|
5278
|
+
forget(owner) {
|
|
5279
|
+
let bytes = 0;
|
|
5280
|
+
for (const [k, ent] of [...entries]) if (ent.owner === owner) {
|
|
5281
|
+
drop(k, ent);
|
|
5282
|
+
bytes += ent.bytes;
|
|
5283
|
+
}
|
|
5284
|
+
return bytes;
|
|
5285
|
+
},
|
|
4399
5286
|
trim(keep2) {
|
|
4400
5287
|
const limit = room();
|
|
4401
5288
|
if (cached <= limit) return 0;
|
|
@@ -4551,6 +5438,10 @@ function createPickSource(builder, opts = {}) {
|
|
|
4551
5438
|
if (G === void 0 || kind === void 0) return void 0;
|
|
4552
5439
|
const hp = builder.heldPoint?.(e, wx, wy);
|
|
4553
5440
|
const [x, y] = hp ?? [wx, wy];
|
|
5441
|
+
if (builder.hitAt !== void 0) {
|
|
5442
|
+
const part = builder.hitAt(e, x, y);
|
|
5443
|
+
return part === void 0 ? void 0 : part ?? "outside";
|
|
5444
|
+
}
|
|
4554
5445
|
return kind.hit(G, x, y) ?? "outside";
|
|
4555
5446
|
},
|
|
4556
5447
|
live: () => builder.live() || opts.moving?.() === true
|
|
@@ -4559,7 +5450,8 @@ function createPickSource(builder, opts = {}) {
|
|
|
4559
5450
|
|
|
4560
5451
|
// ../desk/src/tray/flux.ts
|
|
4561
5452
|
var EPS2 = 1e-4;
|
|
4562
|
-
function createTrayFlux() {
|
|
5453
|
+
function createTrayFlux(opts = {}) {
|
|
5454
|
+
const foot = opts.foot ?? 0;
|
|
4563
5455
|
let facts = null;
|
|
4564
5456
|
let p = 0;
|
|
4565
5457
|
let from = 0;
|
|
@@ -4633,8 +5525,8 @@ function createTrayFlux() {
|
|
|
4633
5525
|
const pp = P?.p ?? p;
|
|
4634
5526
|
const pb = P?.band ?? shown;
|
|
4635
5527
|
const rect = drawerRect(vw, vh, pp);
|
|
4636
|
-
drawn = { x: rect.x, y: rect.y, w: rect.w, h: rect.h, p: pp, max: scrollRange(vw, vh, f.bottom ?? 0), pitch: DRAWER.pitch, scroll: f.scroll + pb, face: rect.h, head: DRAWER.arris + DRAWER.header };
|
|
4637
|
-
return { p: pp, scroll: f.scroll + pb };
|
|
5528
|
+
drawn = { x: rect.x, y: rect.y, w: rect.w, h: rect.h, p: pp, max: scrollRange(vw, vh, f.bottom ?? 0, foot), pitch: DRAWER.pitch, scroll: f.scroll + pb, face: rect.h, head: DRAWER.arris + DRAWER.header, ...foot > 0 ? { foot } : {} };
|
|
5529
|
+
return { p: pp, scroll: f.scroll + pb, ...foot > 0 ? { foot } : {} };
|
|
4638
5530
|
},
|
|
4639
5531
|
live: () => moving && pinned === null,
|
|
4640
5532
|
frame: () => drawn,
|
|
@@ -4652,12 +5544,15 @@ var localPointersQ2 = defineQuery([Pointer, LocalPointer, PointerScreen]);
|
|
|
4652
5544
|
var trayQ = defineQuery([Tray]);
|
|
4653
5545
|
var insertQ = defineQuery([InsertGhost, Position, Size]);
|
|
4654
5546
|
function createDeskReflector(opts) {
|
|
4655
|
-
const { world, builder, ambient } = opts;
|
|
5547
|
+
const { world, builder, ambient, faults } = opts;
|
|
4656
5548
|
const maxDpr = opts.maxDpr ?? 2;
|
|
4657
5549
|
let theme = opts.theme;
|
|
4658
5550
|
let palette = opts.palette;
|
|
4659
5551
|
let grid = opts.grid ?? DEFAULT_GRID;
|
|
4660
|
-
|
|
5552
|
+
const lookKinds = () => faults === void 0 || faults.size === 0 ? opts.kinds : opts.kinds.filter((k) => !faults.missing(k.name));
|
|
5553
|
+
const mountedKinds = new Set(opts.kinds.map((k) => k.name));
|
|
5554
|
+
const kindOn = (kind) => kind === void 0 || faults === void 0 || mountedKinds.has(kind.name) ? kind : void 0;
|
|
5555
|
+
let looks = looksOf(lookKinds(), palette, theme);
|
|
4661
5556
|
let dirty = true;
|
|
4662
5557
|
let disposed = false;
|
|
4663
5558
|
let redraws = 0;
|
|
@@ -4682,7 +5577,7 @@ function createDeskReflector(opts) {
|
|
|
4682
5577
|
let gridGen = 0;
|
|
4683
5578
|
let pinGen = 0;
|
|
4684
5579
|
const wakes = { world: 0, removed: 0, reset: 0, order: 0, hover: 0, marks: 0, camera: 0, viewport: 0, nav: 0, theme: 0, grid: 0, pin: 0, ambient: 0, live: 0, ink: 0, tray: 0 };
|
|
4685
|
-
const tray = createTrayFlux();
|
|
5580
|
+
const tray = createTrayFlux(opts.tray?.foot !== void 0 ? { foot: opts.tray.foot } : {});
|
|
4686
5581
|
let drawnSpecimens = [];
|
|
4687
5582
|
const carry2 = createTrayCarry();
|
|
4688
5583
|
let drawnCarried = [];
|
|
@@ -4810,11 +5705,11 @@ function createDeskReflector(opts) {
|
|
|
4810
5705
|
let trayed = tray.step(now, vp.w, vp.h);
|
|
4811
5706
|
drawnSpecimens = [];
|
|
4812
5707
|
if (trayed !== void 0 && trayed.p > 0 && tray.pinned()?.bare !== true) {
|
|
4813
|
-
const specimens = readSpecimens(w, te, opts.locals);
|
|
5708
|
+
const specimens = readSpecimens(w, te, opts.locals, kindOn);
|
|
4814
5709
|
if (specimens.length > 0) {
|
|
4815
5710
|
ground.warmTray(specimens.map((q) => [q.type, q.kind.name]), trayLanded);
|
|
4816
5711
|
for (const q of specimens) if (q.local !== void 0) faced.set(q.key, q.local);
|
|
4817
|
-
drawnSpecimens = specimenFrames(specimens, { rect: drawerRect(vp.w, vp.h, trayed.p), scroll: trayed.scroll }, { view: { width: vp.w, height: vp.h, dpr }, theme, grid, looks, lift: (t) => tray.lift(t) });
|
|
5712
|
+
drawnSpecimens = specimenFrames(specimens, { rect: drawerRect(vp.w, vp.h, trayed.p), scroll: trayed.scroll, ...trayed.foot !== void 0 ? { foot: trayed.foot } : {} }, { view: { width: vp.w, height: vp.h, dpr }, theme, grid, looks, lift: (t) => tray.lift(t), ...faults !== void 0 ? { faults } : {} });
|
|
4818
5713
|
trayed = { ...trayed, specimens: drawnSpecimens };
|
|
4819
5714
|
}
|
|
4820
5715
|
}
|
|
@@ -4846,11 +5741,11 @@ function createDeskReflector(opts) {
|
|
|
4846
5741
|
drawnCarried = [];
|
|
4847
5742
|
if (trayed !== void 0 && poses.length > 0) {
|
|
4848
5743
|
const L = lampOf(built.grid.mat.plane);
|
|
4849
|
-
const env = { view: { width: vp.w, height: vp.h, dpr }, theme, grid, looks };
|
|
5744
|
+
const env = { view: { width: vp.w, height: vp.h, dpr }, theme, grid, looks, ...faults !== void 0 ? { faults } : {} };
|
|
4850
5745
|
const made = [];
|
|
4851
5746
|
for (const pose of poses) {
|
|
4852
5747
|
const widget = widgetTypeFor(w, pose.type);
|
|
4853
|
-
const kind = objectKindOf(widget);
|
|
5748
|
+
const kind = kindOn(objectKindOf(widget));
|
|
4854
5749
|
if (widget === void 0 || kind === void 0) continue;
|
|
4855
5750
|
const local = opts.locals?.get(kind.name);
|
|
4856
5751
|
if (pose.ghost !== void 0) {
|
|
@@ -4859,7 +5754,8 @@ function createDeskReflector(opts) {
|
|
|
4859
5754
|
const size = w.get(g, Size);
|
|
4860
5755
|
if (at2 === void 0 || size === void 0) continue;
|
|
4861
5756
|
const r = rectOf(at2, size);
|
|
4862
|
-
|
|
5757
|
+
const frame2 = carriedFrame(pose, { kind, rect: { x: r.cx - r.w / 2, y: r.cy - r.h / 2, w: r.w, h: r.h }, props: propsOf(w, g, widget), key: g, lamp: L, ...local !== void 0 ? { local } : {} }, env);
|
|
5758
|
+
if (frame2 !== void 0) made.push(frame2);
|
|
4863
5759
|
continue;
|
|
4864
5760
|
}
|
|
4865
5761
|
const n = widget.defaultSize;
|
|
@@ -4868,10 +5764,11 @@ function createDeskReflector(opts) {
|
|
|
4868
5764
|
const cy = cam.y + pose.py / cam.zoom - (pose.v - 0.5) * n.h;
|
|
4869
5765
|
const key = -(1073741824 + pose.id);
|
|
4870
5766
|
if (copyLocal !== void 0) faced.set(key, copyLocal);
|
|
4871
|
-
|
|
5767
|
+
const frame = carriedFrame(pose, { kind, rect: { x: -n.w / 2, y: -n.h / 2, w: n.w, h: n.h }, props: takenProps(widget), key, lamp: { x: L.x - cx, y: L.y - cy, h: L.h }, ...copyLocal !== void 0 ? { local: copyLocal } : {} }, env);
|
|
5768
|
+
if (frame !== void 0) made.push(frame);
|
|
4872
5769
|
}
|
|
4873
5770
|
ground.warmTray(carry2.types().flatMap((t) => {
|
|
4874
|
-
const k = objectKindOf(widgetTypeFor(w, t));
|
|
5771
|
+
const k = kindOn(objectKindOf(widgetTypeFor(w, t)));
|
|
4875
5772
|
return k === void 0 ? [] : [[carrySlot(t), k.name]];
|
|
4876
5773
|
}), trayLanded);
|
|
4877
5774
|
drawnCarried = made;
|
|
@@ -4935,7 +5832,7 @@ function createDeskReflector(opts) {
|
|
|
4935
5832
|
setTheme(t, p) {
|
|
4936
5833
|
theme = t;
|
|
4937
5834
|
if (p !== void 0) palette = p;
|
|
4938
|
-
looks = looksOf(
|
|
5835
|
+
looks = looksOf(lookKinds(), palette, theme);
|
|
4939
5836
|
dirty = true;
|
|
4940
5837
|
wakes.theme += 1;
|
|
4941
5838
|
themeGen += 1;
|
|
@@ -4987,14 +5884,14 @@ function createDeskReflector(opts) {
|
|
|
4987
5884
|
}
|
|
4988
5885
|
};
|
|
4989
5886
|
}
|
|
4990
|
-
function readSpecimens(w, tray, locals) {
|
|
5887
|
+
function readSpecimens(w, tray, locals, on) {
|
|
4991
5888
|
if (tray === void 0) return [];
|
|
4992
5889
|
const out = [];
|
|
4993
5890
|
for (const e of specimensOf(w, tray)) {
|
|
4994
5891
|
const type = w.get(e, PrefabId)?.id;
|
|
4995
5892
|
if (typeof type !== "string") continue;
|
|
4996
5893
|
const widget = widgetTypeFor(w, type);
|
|
4997
|
-
const kind = objectKindOf(widget);
|
|
5894
|
+
const kind = on(objectKindOf(widget));
|
|
4998
5895
|
const entry = widget?.tray;
|
|
4999
5896
|
const at2 = w.get(e, Position);
|
|
5000
5897
|
const size = w.get(e, Size);
|
|
@@ -5323,6 +6220,7 @@ function createDeskEditor(opts) {
|
|
|
5323
6220
|
},
|
|
5324
6221
|
placement: () => placed,
|
|
5325
6222
|
dispose() {
|
|
6223
|
+
end();
|
|
5326
6224
|
if (idle !== void 0) clearTimeout(idle);
|
|
5327
6225
|
lent = void 0;
|
|
5328
6226
|
el.removeEventListener("input", onInput);
|
|
@@ -6282,20 +7180,56 @@ function kindsOf(types, extra) {
|
|
|
6282
7180
|
for (const k of extra) if (!byName.has(k.name)) byName.set(k.name, k);
|
|
6283
7181
|
return { kinds: [...byName.values()], objectKinds };
|
|
6284
7182
|
}
|
|
7183
|
+
function bitmapOf(c) {
|
|
7184
|
+
const n = c.width * c.height * 4;
|
|
7185
|
+
const rgba = new Uint8ClampedArray(n);
|
|
7186
|
+
const b = c.bytes;
|
|
7187
|
+
const bgra = c.format.startsWith("bgra");
|
|
7188
|
+
for (let i = 0; i < n; i += 4) {
|
|
7189
|
+
rgba[i] = b[bgra ? i + 2 : i];
|
|
7190
|
+
rgba[i + 1] = b[i + 1];
|
|
7191
|
+
rgba[i + 2] = b[bgra ? i : i + 2];
|
|
7192
|
+
rgba[i + 3] = 255;
|
|
7193
|
+
}
|
|
7194
|
+
return createImageBitmap(new ImageData(rgba, c.width, c.height), { premultiplyAlpha: "none", colorSpaceConversion: "none" });
|
|
7195
|
+
}
|
|
6285
7196
|
var toldAwake = /* @__PURE__ */ new Set();
|
|
6286
7197
|
function tellAwake(kind) {
|
|
6287
7198
|
if (toldAwake.has(kind)) return;
|
|
6288
7199
|
toldAwake.add(kind);
|
|
6289
7200
|
console.warn(`[ice] desk: the kind "${kind}" declares a local \`tick\` and no \`due\` \u2014 it is due every frame, so the desk never sleeps. Declare \`KindLocal.due(now)\`: now while it moves, a later time, or Infinity until a fact, an input or \`KindHost.wake\` moves it (design-016 K7a).`);
|
|
6290
7201
|
}
|
|
7202
|
+
var toldAnchor = /* @__PURE__ */ new Set();
|
|
7203
|
+
function tellAnchor(kind, call, err) {
|
|
7204
|
+
const key = `${call} ${kind}`;
|
|
7205
|
+
if (toldAnchor.has(key)) return;
|
|
7206
|
+
toldAnchor.add(key);
|
|
7207
|
+
const kept = call === "readout" ? "no word (petition I22)" : "no swatches (petition I24)";
|
|
7208
|
+
console.error(`[ice] desk: the kind "${kind}"'s \`open.${call}\` threw \u2014 the anchor carries its held tools and ${kept}; said once a page`, err);
|
|
7209
|
+
}
|
|
7210
|
+
function hostNumber(name, v) {
|
|
7211
|
+
if (v === void 0) return void 0;
|
|
7212
|
+
if (typeof v !== "number" || !Number.isFinite(v) || v < 0) throw new Error(`[ice] deskLayer: \`${name}\` is ${String(v)} \u2014 a finite number \u2265 0 (CSS px, or ms for a time)`);
|
|
7213
|
+
return v;
|
|
7214
|
+
}
|
|
7215
|
+
function holdOf(hold) {
|
|
7216
|
+
const top = hostNumber("hold.top", hold?.top);
|
|
7217
|
+
const band2 = hostNumber("hold.band", hold?.band);
|
|
7218
|
+
return { reserves: top === void 0 && band2 === void 0 ? void 0 : { top: top ?? HOLD.top, band: band2 ?? HOLD.band }, travelMs: hostNumber("hold.travelMs", hold?.travelMs) };
|
|
7219
|
+
}
|
|
6291
7220
|
function deskLayer(opts) {
|
|
6292
7221
|
return (ctx) => {
|
|
7222
|
+
const mountedAt = performance.now();
|
|
7223
|
+
const boot = {};
|
|
6293
7224
|
const { host, world } = ctx;
|
|
6294
7225
|
const doc = host.container.ownerDocument;
|
|
6295
7226
|
const view = doc.defaultView;
|
|
6296
7227
|
const types = /* @__PURE__ */ new Set([...(ctx.catalog?.widgetTypes() ?? []).filter((t) => t.object !== void 0), ...opts.objects ?? []]);
|
|
6297
7228
|
const { kinds, objectKinds } = kindsOf([...types], opts.kinds ?? []);
|
|
6298
7229
|
looksOf(objectKinds, opts.palette, opts.theme);
|
|
7230
|
+
const hold = holdOf(opts.hold);
|
|
7231
|
+
const foot = hostNumber("tray.foot", opts.tray?.foot);
|
|
7232
|
+
const cursors = opts.cursors !== false;
|
|
6299
7233
|
const canvas = doc.createElement("canvas");
|
|
6300
7234
|
canvas.style.position = "absolute";
|
|
6301
7235
|
canvas.style.left = "0";
|
|
@@ -6315,9 +7249,11 @@ function deskLayer(opts) {
|
|
|
6315
7249
|
let profiler;
|
|
6316
7250
|
let status = { state: "pending" };
|
|
6317
7251
|
const statusHeard = /* @__PURE__ */ new Set();
|
|
7252
|
+
const faults = createKindFaults();
|
|
6318
7253
|
const setStatus = (next) => {
|
|
6319
|
-
|
|
6320
|
-
|
|
7254
|
+
const { faults: _was, ...rest } = next;
|
|
7255
|
+
status = faults.size > 0 ? { ...rest, faults: faults.list() } : rest;
|
|
7256
|
+
for (const l of [...statusHeard]) l(status);
|
|
6321
7257
|
};
|
|
6322
7258
|
let disposed = false;
|
|
6323
7259
|
let ended = false;
|
|
@@ -6365,21 +7301,51 @@ function deskLayer(opts) {
|
|
|
6365
7301
|
}
|
|
6366
7302
|
const keeps = (owner, key) => locals.get(owner)?.keeps?.(key) ?? false;
|
|
6367
7303
|
const readMarquee = ctx.readMarquee;
|
|
6368
|
-
const builder = createDeskBuilder(world, { objects: [...types], locals, ...opts.springs !== void 0 ? { springs: opts.springs } : {}, ...readMarquee !== void 0 ? { marquee: readMarquee } : {}, ...ctx.spatial !== void 0 ? { spatial: ctx.spatial } : {} });
|
|
7304
|
+
const builder = createDeskBuilder(world, { objects: [...types], locals, faults, ...opts.springs !== void 0 ? { springs: opts.springs } : {}, ...readMarquee !== void 0 ? { marquee: readMarquee } : {}, ...ctx.spatial !== void 0 ? { spatial: ctx.spatial } : {}, ...hold.reserves !== void 0 ? { hold: hold.reserves } : {} });
|
|
6369
7305
|
const typeNamed = new Map([...types].map((t) => [t.type, t]));
|
|
6370
7306
|
const menuOf = (e) => {
|
|
6371
7307
|
const id3 = world.isAlive(e) ? world.get(e, PrefabId)?.id : void 0;
|
|
6372
7308
|
return typeof id3 === "string" ? typeNamed.get(id3)?.menu ?? [] : [];
|
|
6373
7309
|
};
|
|
7310
|
+
const propsOf2 = (e) => {
|
|
7311
|
+
const id3 = world.isAlive(e) ? world.get(e, PrefabId)?.id : void 0;
|
|
7312
|
+
const props = {};
|
|
7313
|
+
for (const g of (typeof id3 === "string" ? typeNamed.get(id3)?.groups : void 0) ?? []) Object.assign(props, world.get(e, g.component) ?? {});
|
|
7314
|
+
return props;
|
|
7315
|
+
};
|
|
7316
|
+
const readoutOf = (kind, e) => {
|
|
7317
|
+
const r = kind?.open?.readout;
|
|
7318
|
+
if (r === void 0 || kind === void 0) return void 0;
|
|
7319
|
+
let word = r;
|
|
7320
|
+
if (typeof r === "function") {
|
|
7321
|
+
try {
|
|
7322
|
+
word = r({ world, entity: e, props: () => propsOf2(e), local: locals.get(kind.name) });
|
|
7323
|
+
} catch (err) {
|
|
7324
|
+
tellAnchor(kind.name, "readout", err);
|
|
7325
|
+
return void 0;
|
|
7326
|
+
}
|
|
7327
|
+
}
|
|
7328
|
+
return typeof word === "string" && word.length > 0 ? word : void 0;
|
|
7329
|
+
};
|
|
7330
|
+
const swatchesOf = (kind) => {
|
|
7331
|
+
if (kind?.open?.swatches === void 0) return {};
|
|
7332
|
+
try {
|
|
7333
|
+
return kind.open.swatches(compose2.look(kind.name));
|
|
7334
|
+
} catch (err) {
|
|
7335
|
+
tellAnchor(kind.name, "swatches", err);
|
|
7336
|
+
return {};
|
|
7337
|
+
}
|
|
7338
|
+
};
|
|
6374
7339
|
const anchorOf = () => {
|
|
6375
7340
|
const a = builder.anchor();
|
|
6376
7341
|
if (trayOpen(world)) return { ...a, box: null, count: 0 };
|
|
6377
7342
|
const h = builder.hand();
|
|
6378
7343
|
if (h === void 0) return withKindActs(a, selectedEntities(world), menuOf);
|
|
6379
7344
|
const kind = builder.kindOf(h.entity);
|
|
6380
|
-
const swatches =
|
|
7345
|
+
const swatches = swatchesOf(kind);
|
|
6381
7346
|
const active = world.isAlive(h.entity) ? world.get(h.entity, HeldTool)?.id ?? "" : "";
|
|
6382
|
-
|
|
7347
|
+
const readout = readoutOf(kind, h.entity);
|
|
7348
|
+
return { ...a, held: { tools: heldSlots(kind?.open?.tools ?? [], swatches), active, landing: h.landing, settled: h.settled, ...hold.travelMs !== void 0 ? { travelMs: hold.travelMs } : {}, ...readout !== void 0 ? { readout } : {} } };
|
|
6383
7349
|
};
|
|
6384
7350
|
const listeners = /* @__PURE__ */ new Set();
|
|
6385
7351
|
let published = "";
|
|
@@ -6413,15 +7379,28 @@ function deskLayer(opts) {
|
|
|
6413
7379
|
trayPublished = key;
|
|
6414
7380
|
for (const l of [...trayListeners]) l();
|
|
6415
7381
|
};
|
|
7382
|
+
let presenting = false;
|
|
7383
|
+
const firstFrame = () => {
|
|
7384
|
+
if (presenting) return;
|
|
7385
|
+
presenting = true;
|
|
7386
|
+
const queue = drawDevice?.queue;
|
|
7387
|
+
if (typeof queue?.onSubmittedWorkDone !== "function") return;
|
|
7388
|
+
queue.onSubmittedWorkDone().then(() => {
|
|
7389
|
+
boot.presented ??= performance.now() - mountedAt;
|
|
7390
|
+
}, () => {
|
|
7391
|
+
});
|
|
7392
|
+
};
|
|
6416
7393
|
const compose2 = createDeskReflector({
|
|
6417
7394
|
onFrame: () => {
|
|
6418
7395
|
publish();
|
|
6419
7396
|
publishTray();
|
|
7397
|
+
firstFrame();
|
|
6420
7398
|
},
|
|
6421
7399
|
world,
|
|
6422
7400
|
builder,
|
|
6423
7401
|
kinds: objectKinds,
|
|
6424
7402
|
ambient,
|
|
7403
|
+
faults,
|
|
6425
7404
|
ground: () => ground,
|
|
6426
7405
|
attach: { resize: (w, h) => {
|
|
6427
7406
|
if (canvas.width !== w || canvas.height !== h) {
|
|
@@ -6434,6 +7413,7 @@ function deskLayer(opts) {
|
|
|
6434
7413
|
grid,
|
|
6435
7414
|
locals,
|
|
6436
7415
|
...opts.maxDpr !== void 0 ? { maxDpr: opts.maxDpr } : {},
|
|
7416
|
+
...foot !== void 0 ? { tray: { foot } } : {},
|
|
6437
7417
|
...opts.name !== void 0 ? { name: opts.name } : {},
|
|
6438
7418
|
// a frame asked for outside the flush — a pin, an ink landing, the ground arriving, a theme: a sleeping loop wakes (K7a)
|
|
6439
7419
|
onWake: (reason) => frame?.wake(`desk:${reason}`)
|
|
@@ -6441,6 +7421,8 @@ function deskLayer(opts) {
|
|
|
6441
7421
|
motionQuery?.addEventListener("change", syncMotion);
|
|
6442
7422
|
const docs = opts.docs ?? NO_DOCS;
|
|
6443
7423
|
const drivers = /* @__PURE__ */ new Map();
|
|
7424
|
+
const driverKinds = /* @__PURE__ */ new Map();
|
|
7425
|
+
const parked = [];
|
|
6444
7426
|
const ofKind = (e, name) => builder.kindOf(e)?.name === name && !world.has(e, InsertGhost);
|
|
6445
7427
|
const kindNamed = (name) => objectKinds.some((k) => k.name === name) ? (e) => ofKind(e, name) : void 0;
|
|
6446
7428
|
const providing = (key) => [...types].some((t) => t.provides.includes(key)) ? (e) => {
|
|
@@ -6465,7 +7447,10 @@ function deskLayer(opts) {
|
|
|
6465
7447
|
refused: (e) => builder.meetTape(e),
|
|
6466
7448
|
wake: () => compose2.wake("ink")
|
|
6467
7449
|
});
|
|
6468
|
-
if (d !== void 0)
|
|
7450
|
+
if (d !== void 0) {
|
|
7451
|
+
drivers.set(t.type, d);
|
|
7452
|
+
driverKinds.set(t.type, k.name);
|
|
7453
|
+
}
|
|
6469
7454
|
}
|
|
6470
7455
|
const driver = (type) => drivers.get(type);
|
|
6471
7456
|
const textParts = [];
|
|
@@ -6516,11 +7501,17 @@ function deskLayer(opts) {
|
|
|
6516
7501
|
restless.clear();
|
|
6517
7502
|
for (const [name, local] of locals) {
|
|
6518
7503
|
if (local.tick === void 0) continue;
|
|
6519
|
-
|
|
6520
|
-
|
|
6521
|
-
|
|
6522
|
-
|
|
6523
|
-
|
|
7504
|
+
let call = "due";
|
|
7505
|
+
try {
|
|
7506
|
+
if (timeAlone && !woken.has(name) && (local.due?.(now) ?? now) > now) continue;
|
|
7507
|
+
kindTicks[name] = (kindTicks[name] ?? 0) + 1;
|
|
7508
|
+
call = "tick";
|
|
7509
|
+
if (local.tick(now)) {
|
|
7510
|
+
want = true;
|
|
7511
|
+
restless.add(name);
|
|
7512
|
+
}
|
|
7513
|
+
} catch (err) {
|
|
7514
|
+
faults.strike(name, call, err);
|
|
6524
7515
|
}
|
|
6525
7516
|
}
|
|
6526
7517
|
woken.clear();
|
|
@@ -6545,11 +7536,22 @@ function deskLayer(opts) {
|
|
|
6545
7536
|
profiler?.flushed(spent);
|
|
6546
7537
|
}
|
|
6547
7538
|
};
|
|
7539
|
+
const dueOf = (local, now) => {
|
|
7540
|
+
try {
|
|
7541
|
+
return local.due?.(now) ?? now;
|
|
7542
|
+
} catch (err) {
|
|
7543
|
+
for (const [name, l] of locals) if (l === local) {
|
|
7544
|
+
faults.strike(name, "due", err);
|
|
7545
|
+
break;
|
|
7546
|
+
}
|
|
7547
|
+
return Number.POSITIVE_INFINITY;
|
|
7548
|
+
}
|
|
7549
|
+
};
|
|
6548
7550
|
const deskDue = (now) => {
|
|
6549
7551
|
let t = following || woken.size > 0 ? now : compose2.due(now);
|
|
6550
7552
|
for (const local of locals.values()) {
|
|
6551
7553
|
if (local.tick === void 0) continue;
|
|
6552
|
-
const d = local
|
|
7554
|
+
const d = dueOf(local, now);
|
|
6553
7555
|
if (d < t) t = d;
|
|
6554
7556
|
}
|
|
6555
7557
|
const tray = ground?.trayIdleAt() ?? Number.POSITIVE_INFINITY;
|
|
@@ -6559,6 +7561,31 @@ function deskLayer(opts) {
|
|
|
6559
7561
|
};
|
|
6560
7562
|
const stopWake = frame?.wakeWhen("desk", deskDue);
|
|
6561
7563
|
const stopText = opts.text?.onVersion?.(() => frame?.wake("desk:text"));
|
|
7564
|
+
const retire = (name) => {
|
|
7565
|
+
const local = locals.get(name);
|
|
7566
|
+
locals.delete(name);
|
|
7567
|
+
woken.delete(name);
|
|
7568
|
+
for (const [type, kind] of driverKinds) {
|
|
7569
|
+
const d = drivers.get(type);
|
|
7570
|
+
if (kind === name && d !== void 0) {
|
|
7571
|
+
drivers.delete(type);
|
|
7572
|
+
parked.push(d);
|
|
7573
|
+
}
|
|
7574
|
+
}
|
|
7575
|
+
rasters.clear(name);
|
|
7576
|
+
budget.forget(name);
|
|
7577
|
+
try {
|
|
7578
|
+
local?.dispose?.();
|
|
7579
|
+
} catch (err) {
|
|
7580
|
+
console.error(`[ice] desk: the missing kind "${name}"'s desk state threw in its dispose`, err);
|
|
7581
|
+
}
|
|
7582
|
+
ground?.quarantine(name);
|
|
7583
|
+
compose2.wake("ink");
|
|
7584
|
+
};
|
|
7585
|
+
faults.subscribe((f) => {
|
|
7586
|
+
retire(f.kind);
|
|
7587
|
+
if (status.state !== "pending") setStatus(status);
|
|
7588
|
+
});
|
|
6562
7589
|
const pick = createPickSource(builder, { moving: () => moving });
|
|
6563
7590
|
const framePick = ctx.framePick;
|
|
6564
7591
|
if (framePick !== void 0) framePick.current = pick;
|
|
@@ -6605,27 +7632,31 @@ function deskLayer(opts) {
|
|
|
6605
7632
|
};
|
|
6606
7633
|
const shared = ctx.gpu;
|
|
6607
7634
|
const device = shared !== void 0 ? Promise.resolve(adopt(shared.adapter, shared.device, events)) : gpu === void 0 ? Promise.reject(new Error("WebGPU is unavailable here (no navigator.gpu)")) : acquire({ gpu, label: "desk", ...events });
|
|
6608
|
-
const
|
|
7635
|
+
const booted = device.then(async (g) => {
|
|
6609
7636
|
if (disposed) {
|
|
6610
7637
|
if (shared === void 0) g.device.destroy();
|
|
6611
7638
|
throw new Error("disposed before the device arrived");
|
|
6612
7639
|
}
|
|
7640
|
+
boot.device = performance.now() - mountedAt;
|
|
6613
7641
|
drawDevice = g.device;
|
|
6614
7642
|
if (shared === void 0) ownDevice = g.device;
|
|
6615
7643
|
if (opts.gpuLedger === true) ledger = instrumentMemory(g.device);
|
|
6616
7644
|
opts.onDevice?.(g.device);
|
|
6617
|
-
const made = await Ground.create({ device: g.device, surface: surface(g.device, canvas), mat: matShaders(shaderText(MAT_SHADER_FILES)), kinds, marks: marksShaders(shaderText(MARKS_SHADER_FILES)), hold: holdShaders(shaderText(HOLD_SHADER_FILES)), tray: trayShaders(shaderText) });
|
|
7645
|
+
const made = await Ground.create({ device: g.device, surface: surface(g.device, canvas), mat: matShaders(shaderText(MAT_SHADER_FILES)), kinds, marks: marksShaders(shaderText(MARKS_SHADER_FILES)), hold: holdShaders(shaderText(HOLD_SHADER_FILES)), tray: trayShaders(shaderText), ...events.onError !== void 0 ? { onError: events.onError } : {} });
|
|
6618
7646
|
if (disposed || ended) {
|
|
6619
7647
|
made.dispose();
|
|
6620
7648
|
return;
|
|
6621
7649
|
}
|
|
7650
|
+
boot.compiled = performance.now() - mountedAt;
|
|
6622
7651
|
made.mat.setNoise(blueNoise());
|
|
6623
7652
|
made.grid = grid;
|
|
7653
|
+
for (const f of made.faults()) faults.refuse(f.kind, f.reason);
|
|
7654
|
+
for (const f of faults.list()) made.quarantine(f.kind);
|
|
6624
7655
|
ground = made;
|
|
6625
7656
|
if (status.state === "pending") setStatus({ state: "ready" });
|
|
6626
7657
|
compose2.ready();
|
|
6627
7658
|
});
|
|
6628
|
-
|
|
7659
|
+
booted.catch((e) => {
|
|
6629
7660
|
if (!disposed) fail("no desk \u2014 the adapter, the device or the pipelines were refused", e);
|
|
6630
7661
|
});
|
|
6631
7662
|
const setGrid = (next) => {
|
|
@@ -6633,8 +7664,42 @@ function deskLayer(opts) {
|
|
|
6633
7664
|
if (ground !== null) ground.grid = next;
|
|
6634
7665
|
compose2.configureGrid(next);
|
|
6635
7666
|
};
|
|
7667
|
+
let capturing = null;
|
|
7668
|
+
let captures = Promise.resolve();
|
|
7669
|
+
const captureKey = (o) => JSON.stringify([o.scale ?? 1, o.rect === void 0 ? null : [o.rect.x, o.rect.y, o.rect.width, o.rect.height]]);
|
|
7670
|
+
const capture = (opts2 = {}) => {
|
|
7671
|
+
checkCapture(opts2);
|
|
7672
|
+
const key = captureKey(opts2);
|
|
7673
|
+
const asked2 = compose2.lastInputs();
|
|
7674
|
+
const same = capturing;
|
|
7675
|
+
if (same !== null && same.key === key && same.inputs === asked2) return same.promise;
|
|
7676
|
+
const run = captures.then(async () => {
|
|
7677
|
+
const g = ground;
|
|
7678
|
+
const inputs = compose2.lastInputs();
|
|
7679
|
+
if (disposed || ended || g === null || status.state !== "ready" || inputs === null) return void 0;
|
|
7680
|
+
const bytes = await g.capture(inputs, opts2);
|
|
7681
|
+
return bytes === void 0 ? void 0 : await bitmapOf(bytes);
|
|
7682
|
+
}).finally(() => {
|
|
7683
|
+
if (capturing?.promise === run) capturing = null;
|
|
7684
|
+
});
|
|
7685
|
+
capturing = { key, inputs: asked2, promise: run };
|
|
7686
|
+
captures = run.catch(() => void 0);
|
|
7687
|
+
return run;
|
|
7688
|
+
};
|
|
7689
|
+
const pickAt = ctx.pickAt;
|
|
7690
|
+
const pickPoint = (point) => {
|
|
7691
|
+
if (typeof point?.x !== "number" || typeof point.y !== "number" || !Number.isFinite(point.x) || !Number.isFinite(point.y)) {
|
|
7692
|
+
throw new Error(`[ice] desk: pick \u2014 the point is ${JSON.stringify(point) ?? String(point)}: { x, y } in CSS px of the view, two finite numbers`);
|
|
7693
|
+
}
|
|
7694
|
+
if (pickAt === void 0 || ground === null || compose2.lastInputs() === null || heldEntity(world) !== void 0) return null;
|
|
7695
|
+
const hit = pickAt(point.x, point.y);
|
|
7696
|
+
const type = hit === void 0 ? void 0 : world.get(hit.entity, PrefabId)?.id;
|
|
7697
|
+
if (hit === void 0 || typeof type !== "string") return null;
|
|
7698
|
+
return { entity: hit.entity, type, canvas: frameParent(world) ?? NO_ENTITY, part: hit.part };
|
|
7699
|
+
};
|
|
6636
7700
|
return {
|
|
6637
7701
|
reflector,
|
|
7702
|
+
cursors,
|
|
6638
7703
|
canvas,
|
|
6639
7704
|
available: () => ground !== null && (status.state === "ready" || status.state === "degraded"),
|
|
6640
7705
|
status: () => status,
|
|
@@ -6647,6 +7712,8 @@ function deskLayer(opts) {
|
|
|
6647
7712
|
device: () => drawDevice ?? void 0,
|
|
6648
7713
|
ground: () => ground,
|
|
6649
7714
|
setTheme: (t, p) => compose2.setTheme(t, p),
|
|
7715
|
+
capture,
|
|
7716
|
+
pick: pickPoint,
|
|
6650
7717
|
configureMat: (mat) => setGrid({ ...grid, mat: { ...grid.mat, ...mat, ...mat.gobo !== void 0 ? { gobo: { ...grid.mat.gobo, ...mat.gobo } } : {}, ...mat.ruler !== void 0 ? { ruler: { ...grid.mat.ruler, ...mat.ruler } } : {} } }),
|
|
6651
7718
|
configureFadeIn: (fadeIn) => setGrid({ ...grid, fadeIn }),
|
|
6652
7719
|
setPlate(name, bytes) {
|
|
@@ -6690,6 +7757,7 @@ function deskLayer(opts) {
|
|
|
6690
7757
|
hand: () => builder.hand(),
|
|
6691
7758
|
setPortals: (on) => compose2.pinBuild({ portals: on }),
|
|
6692
7759
|
tuneLaw(kind, law) {
|
|
7760
|
+
if (faults.missing(kind)) return;
|
|
6693
7761
|
for (const t of types) {
|
|
6694
7762
|
const k = objectKindOf(t);
|
|
6695
7763
|
if (k?.name === kind) k.tune?.(law);
|
|
@@ -6751,7 +7819,7 @@ function deskLayer(opts) {
|
|
|
6751
7819
|
}
|
|
6752
7820
|
return profiler;
|
|
6753
7821
|
},
|
|
6754
|
-
perf: () => ({ ...perf, kindTicks: { ...kindTicks } }),
|
|
7822
|
+
perf: () => ({ ...perf, kindTicks: { ...kindTicks }, boot: { ...boot } }),
|
|
6755
7823
|
memory: () => budget.stats(),
|
|
6756
7824
|
rasters: () => rasters.stats(),
|
|
6757
7825
|
gpuMemory: () => ledger,
|
|
@@ -6768,7 +7836,8 @@ function deskLayer(opts) {
|
|
|
6768
7836
|
wakes: () => compose2.wakes(),
|
|
6769
7837
|
due: (now) => {
|
|
6770
7838
|
const kinds2 = {};
|
|
6771
|
-
for (const [name, local] of locals) if (local.tick !== void 0) kinds2[name] = local
|
|
7839
|
+
for (const [name, local] of locals) if (local.tick !== void 0) kinds2[name] = dueOf(local, now);
|
|
7840
|
+
for (const f of faults.list()) kinds2[f.kind] = KIND_MISSING;
|
|
6772
7841
|
const busy = [];
|
|
6773
7842
|
for (const [type, d] of drivers) if (d.idle?.() !== true) busy.push(type);
|
|
6774
7843
|
return { at: deskDue(now), reflector: compose2.due(now), drivers: following ? now : Number.POSITIVE_INFINITY, following: busy, woken: [...woken], kinds: kinds2, tray: ground?.trayIdleAt() ?? Number.POSITIVE_INFINITY, rasters: rasters.size > 0 ? now : Number.POSITIVE_INFINITY };
|
|
@@ -6780,7 +7849,7 @@ function deskLayer(opts) {
|
|
|
6780
7849
|
dirty: () => {
|
|
6781
7850
|
if (compose2.dirty() || woken.size > 0) return true;
|
|
6782
7851
|
const now = performance.now();
|
|
6783
|
-
for (const local of locals.values()) if (local.tick !== void 0 && (local
|
|
7852
|
+
for (const local of locals.values()) if (local.tick !== void 0 && dueOf(local, now) <= now) return true;
|
|
6784
7853
|
return false;
|
|
6785
7854
|
},
|
|
6786
7855
|
builder,
|
|
@@ -6843,7 +7912,7 @@ function deskLayer(opts) {
|
|
|
6843
7912
|
listeners.clear();
|
|
6844
7913
|
trayListeners.clear();
|
|
6845
7914
|
statusHeard.clear();
|
|
6846
|
-
for (const d of drivers.values()) d.dispose?.();
|
|
7915
|
+
for (const d of [...drivers.values(), ...parked]) d.dispose?.();
|
|
6847
7916
|
editor.dispose();
|
|
6848
7917
|
for (const local of locals.values()) local.dispose?.();
|
|
6849
7918
|
motionQuery?.removeEventListener("change", syncMotion);
|
|
@@ -7097,219 +8166,16 @@ async function ablateKinds(a, opts = {}) {
|
|
|
7097
8166
|
return { frames, rounds, base: baseS, control: sampled(c), aa: median(c) - baseS.median, noise, kinds: out, samples: Object.fromEntries(ms) };
|
|
7098
8167
|
}
|
|
7099
8168
|
|
|
7100
|
-
// ../desk/src/engine/records.ts
|
|
7101
|
-
var DEFAULT_MAX = 65536;
|
|
7102
|
-
var GAP = 4;
|
|
7103
|
-
var NONE = { aux: 0, blockN: 0 };
|
|
7104
|
-
function createRecordStore(opts) {
|
|
7105
|
-
const { device, def, label, pack } = opts;
|
|
7106
|
-
const max = opts.max ?? DEFAULT_MAX;
|
|
7107
|
-
const blocksDef = opts.blocks;
|
|
7108
|
-
const per = blocksDef?.per ?? 0;
|
|
7109
|
-
let capacity = Math.max(1, Math.min(opts.capacity, max));
|
|
7110
|
-
let cpu = def.alloc(capacity);
|
|
7111
|
-
let gpu = storageBuffer(device, def.size * capacity, label);
|
|
7112
|
-
let blockCpu = blocksDef ? blocksDef.def.alloc(capacity * per) : null;
|
|
7113
|
-
let blockGpu = blocksDef ? storageBuffer(device, blocksDef.def.size * capacity * per, blocksDef.label) : null;
|
|
7114
|
-
let orderCpu = new Uint32Array(capacity);
|
|
7115
|
-
let orderGpu = storageBuffer(device, 4 * capacity, `${label} order`);
|
|
7116
|
-
let version = 0;
|
|
7117
|
-
let grown = 0;
|
|
7118
|
-
const byKey = /* @__PURE__ */ new Map();
|
|
7119
|
-
let bySlot = new Array(capacity).fill(null);
|
|
7120
|
-
const free = [];
|
|
7121
|
-
let next = 0;
|
|
7122
|
-
let gen = 0;
|
|
7123
|
-
let lastKeys = null;
|
|
7124
|
-
let prevOrder = [];
|
|
7125
|
-
let count = 0;
|
|
7126
|
-
const dirty = [];
|
|
7127
|
-
let written = 0;
|
|
7128
|
-
let bytes = 0;
|
|
7129
|
-
let orderWrites = 0;
|
|
7130
|
-
const grow = () => {
|
|
7131
|
-
if (capacity >= max) throw new Error(`${label}: ${capacity} record slots is the most this store grows to`);
|
|
7132
|
-
const was = capacity;
|
|
7133
|
-
capacity = Math.min(capacity * 2, max);
|
|
7134
|
-
const nextCpu = def.alloc(capacity);
|
|
7135
|
-
new Uint8Array(nextCpu.bytes).set(new Uint8Array(cpu.bytes));
|
|
7136
|
-
cpu = nextCpu;
|
|
7137
|
-
gpu.destroy();
|
|
7138
|
-
gpu = storageBuffer(device, def.size * capacity, label);
|
|
7139
|
-
if (blocksDef && blockCpu && blockGpu) {
|
|
7140
|
-
const nextBlocks = blocksDef.def.alloc(capacity * per);
|
|
7141
|
-
new Uint8Array(nextBlocks.bytes).set(new Uint8Array(blockCpu.bytes));
|
|
7142
|
-
blockCpu = nextBlocks;
|
|
7143
|
-
blockGpu.destroy();
|
|
7144
|
-
blockGpu = storageBuffer(device, blocksDef.def.size * capacity * per, blocksDef.label);
|
|
7145
|
-
}
|
|
7146
|
-
const nextOrder = new Uint32Array(capacity);
|
|
7147
|
-
nextOrder.set(orderCpu);
|
|
7148
|
-
orderCpu = nextOrder;
|
|
7149
|
-
orderGpu.destroy();
|
|
7150
|
-
orderGpu = storageBuffer(device, 4 * capacity, `${label} order`);
|
|
7151
|
-
const nextBySlot = new Array(capacity).fill(null);
|
|
7152
|
-
for (let i = 0; i < was; i++) nextBySlot[i] = bySlot[i] ?? null;
|
|
7153
|
-
bySlot = nextBySlot;
|
|
7154
|
-
version += 1;
|
|
7155
|
-
grown += 1;
|
|
7156
|
-
};
|
|
7157
|
-
let grew = false;
|
|
7158
|
-
const alloc = () => {
|
|
7159
|
-
const reused = free.pop();
|
|
7160
|
-
if (reused !== void 0) return reused;
|
|
7161
|
-
if (next === capacity) {
|
|
7162
|
-
grow();
|
|
7163
|
-
grew = true;
|
|
7164
|
-
}
|
|
7165
|
-
return next++;
|
|
7166
|
-
};
|
|
7167
|
-
const release = (ent) => {
|
|
7168
|
-
byKey.delete(ent.key);
|
|
7169
|
-
bySlot[ent.slot] = null;
|
|
7170
|
-
free.push(ent.slot);
|
|
7171
|
-
};
|
|
7172
|
-
const resetAll = () => {
|
|
7173
|
-
bySlot.fill(null);
|
|
7174
|
-
byKey.clear();
|
|
7175
|
-
free.length = 0;
|
|
7176
|
-
next = 0;
|
|
7177
|
-
};
|
|
7178
|
-
const packInto = (ent, record, aux) => {
|
|
7179
|
-
ent.record = record;
|
|
7180
|
-
ent.aux = aux;
|
|
7181
|
-
ent.blockN = pack(record, aux, cpu, ent.slot, blockCpu, ent.slot * per);
|
|
7182
|
-
dirty.push(ent.slot);
|
|
7183
|
-
};
|
|
7184
|
-
const runs = () => {
|
|
7185
|
-
dirty.sort((a, b) => a - b);
|
|
7186
|
-
const out = [];
|
|
7187
|
-
for (const s of dirty) {
|
|
7188
|
-
const last = out[out.length - 1];
|
|
7189
|
-
if (last !== void 0 && s <= last[1] + 1 + GAP) {
|
|
7190
|
-
if (s > last[1]) last[1] = s;
|
|
7191
|
-
} else out.push([s, s]);
|
|
7192
|
-
}
|
|
7193
|
-
return out;
|
|
7194
|
-
};
|
|
7195
|
-
const upload = (n, orderMoved) => {
|
|
7196
|
-
let rewriteOrder = orderMoved;
|
|
7197
|
-
if (grew) {
|
|
7198
|
-
grew = false;
|
|
7199
|
-
if (next > 0) {
|
|
7200
|
-
device.queue.writeBuffer(gpu, 0, cpu.bytes, 0, next * def.size);
|
|
7201
|
-
bytes += next * def.size;
|
|
7202
|
-
}
|
|
7203
|
-
if (blocksDef && blockCpu && blockGpu && next > 0) {
|
|
7204
|
-
device.queue.writeBuffer(blockGpu, 0, blockCpu.bytes, 0, next * per * blocksDef.def.size);
|
|
7205
|
-
bytes += next * per * blocksDef.def.size;
|
|
7206
|
-
}
|
|
7207
|
-
written += dirty.length;
|
|
7208
|
-
dirty.length = 0;
|
|
7209
|
-
rewriteOrder = true;
|
|
7210
|
-
} else if (dirty.length > 0) {
|
|
7211
|
-
for (const [a, b] of runs()) {
|
|
7212
|
-
const n0 = b - a + 1;
|
|
7213
|
-
device.queue.writeBuffer(gpu, a * def.size, cpu.bytes, a * def.size, n0 * def.size);
|
|
7214
|
-
bytes += n0 * def.size;
|
|
7215
|
-
}
|
|
7216
|
-
if (blocksDef && blockCpu && blockGpu) {
|
|
7217
|
-
const bsize = blocksDef.def.size;
|
|
7218
|
-
for (const s of dirty) {
|
|
7219
|
-
const ent = bySlot[s];
|
|
7220
|
-
if (!ent || ent.blockN === 0) continue;
|
|
7221
|
-
device.queue.writeBuffer(blockGpu, s * per * bsize, blockCpu.bytes, s * per * bsize, ent.blockN * bsize);
|
|
7222
|
-
bytes += ent.blockN * bsize;
|
|
7223
|
-
}
|
|
7224
|
-
}
|
|
7225
|
-
written += dirty.length;
|
|
7226
|
-
dirty.length = 0;
|
|
7227
|
-
}
|
|
7228
|
-
if (rewriteOrder) {
|
|
7229
|
-
if (n > 0) device.queue.writeBuffer(orderGpu, 0, orderCpu, 0, n);
|
|
7230
|
-
orderWrites += 1;
|
|
7231
|
-
prevOrder = Array.from(orderCpu.subarray(0, n));
|
|
7232
|
-
}
|
|
7233
|
-
};
|
|
7234
|
-
return {
|
|
7235
|
-
get records() {
|
|
7236
|
-
return gpu;
|
|
7237
|
-
},
|
|
7238
|
-
get order() {
|
|
7239
|
-
return orderGpu;
|
|
7240
|
-
},
|
|
7241
|
-
get blocks() {
|
|
7242
|
-
return blockGpu;
|
|
7243
|
-
},
|
|
7244
|
-
get version() {
|
|
7245
|
-
return version;
|
|
7246
|
-
},
|
|
7247
|
-
prepare(records, keys, aux) {
|
|
7248
|
-
gen += 1;
|
|
7249
|
-
const n = records.length;
|
|
7250
|
-
let orderChanged = n !== prevOrder.length;
|
|
7251
|
-
if (keys === void 0) {
|
|
7252
|
-
resetAll();
|
|
7253
|
-
lastKeys = null;
|
|
7254
|
-
for (let i = 0; i < n; i++) {
|
|
7255
|
-
const slot = alloc();
|
|
7256
|
-
const ent = { key: -0.5 - i, slot, record: void 0, aux: 0, gen, blockN: 0 };
|
|
7257
|
-
bySlot[slot] = ent;
|
|
7258
|
-
packInto(ent, records[i], aux ? aux(i) : 0);
|
|
7259
|
-
if (!orderChanged && prevOrder[i] !== slot) orderChanged = true;
|
|
7260
|
-
orderCpu[i] = slot;
|
|
7261
|
-
}
|
|
7262
|
-
} else {
|
|
7263
|
-
if (keys.length !== n) throw new Error(`${label}: ${keys.length} keys for ${n} records`);
|
|
7264
|
-
if (lastKeys === null) resetAll();
|
|
7265
|
-
const same = lastKeys !== null && lastKeys.length === n && lastKeys.every((k, i) => k === keys[i]);
|
|
7266
|
-
for (let i = 0; i < n; i++) {
|
|
7267
|
-
const key = keys[i];
|
|
7268
|
-
let ent = byKey.get(key);
|
|
7269
|
-
if (ent === void 0) {
|
|
7270
|
-
const slot = alloc();
|
|
7271
|
-
ent = { key, slot, record: void 0, aux: 0, gen, blockN: 0 };
|
|
7272
|
-
byKey.set(key, ent);
|
|
7273
|
-
bySlot[slot] = ent;
|
|
7274
|
-
}
|
|
7275
|
-
ent.gen = gen;
|
|
7276
|
-
const a = aux ? aux(i) : 0;
|
|
7277
|
-
if (ent.record !== records[i] || ent.aux !== a) packInto(ent, records[i], a);
|
|
7278
|
-
if (!orderChanged && prevOrder[i] !== ent.slot) orderChanged = true;
|
|
7279
|
-
orderCpu[i] = ent.slot;
|
|
7280
|
-
}
|
|
7281
|
-
if (!same) {
|
|
7282
|
-
if (lastKeys !== null) for (const k of lastKeys) {
|
|
7283
|
-
const ent = byKey.get(k);
|
|
7284
|
-
if (ent !== void 0 && ent.gen !== gen) release(ent);
|
|
7285
|
-
}
|
|
7286
|
-
lastKeys = keys.slice();
|
|
7287
|
-
}
|
|
7288
|
-
}
|
|
7289
|
-
upload(n, orderChanged);
|
|
7290
|
-
count = n;
|
|
7291
|
-
return n;
|
|
7292
|
-
},
|
|
7293
|
-
slotAt: (i) => i < count ? orderCpu[i] : -1,
|
|
7294
|
-
entryAt(i) {
|
|
7295
|
-
if (i >= count) return NONE;
|
|
7296
|
-
const ent = bySlot[orderCpu[i]];
|
|
7297
|
-
return ent === null || ent === void 0 ? NONE : { aux: ent.aux, blockN: ent.blockN };
|
|
7298
|
-
},
|
|
7299
|
-
invalidate() {
|
|
7300
|
-
for (const ent of byKey.values()) ent.record = void 0;
|
|
7301
|
-
},
|
|
7302
|
-
stats: () => ({ written, bytes, orderWrites, slots: next - free.length, capacity, grown }),
|
|
7303
|
-
dispose() {
|
|
7304
|
-
gpu.destroy();
|
|
7305
|
-
orderGpu.destroy();
|
|
7306
|
-
blockGpu?.destroy();
|
|
7307
|
-
byKey.clear();
|
|
7308
|
-
}
|
|
7309
|
-
};
|
|
7310
|
-
}
|
|
7311
|
-
|
|
7312
8169
|
export {
|
|
8170
|
+
KIND_STRIKES,
|
|
8171
|
+
KIND_MISSING,
|
|
8172
|
+
faultText,
|
|
8173
|
+
createKindFaults,
|
|
8174
|
+
isMissingRecord,
|
|
8175
|
+
missingFace,
|
|
8176
|
+
createRecordStore,
|
|
8177
|
+
MISSING_KIND,
|
|
8178
|
+
MISSING_OBJECT,
|
|
7313
8179
|
STRATA,
|
|
7314
8180
|
DRAWER,
|
|
7315
8181
|
drawerSize,
|
|
@@ -7329,15 +8195,20 @@ export {
|
|
|
7329
8195
|
TRAY_SHADER_FILES,
|
|
7330
8196
|
trayShaders,
|
|
7331
8197
|
visible,
|
|
8198
|
+
createKindPasses,
|
|
7332
8199
|
createSlotSet,
|
|
7333
8200
|
SlotPool,
|
|
7334
8201
|
drawSlot,
|
|
7335
8202
|
drawFrame,
|
|
7336
8203
|
prepareFrame,
|
|
7337
8204
|
drawTray,
|
|
8205
|
+
encodeFrame,
|
|
7338
8206
|
Ground,
|
|
7339
8207
|
tagsOf,
|
|
7340
8208
|
renderHeldFrame,
|
|
8209
|
+
checkCapture,
|
|
8210
|
+
scaledInputs,
|
|
8211
|
+
captureFrame,
|
|
7341
8212
|
AMBIENT_DEFAULTS,
|
|
7342
8213
|
createAmbient,
|
|
7343
8214
|
rectOf,
|
|
@@ -7393,7 +8264,6 @@ export {
|
|
|
7393
8264
|
inkRaster,
|
|
7394
8265
|
kindsIn,
|
|
7395
8266
|
withoutKind,
|
|
7396
|
-
ablateKinds
|
|
7397
|
-
createRecordStore
|
|
8267
|
+
ablateKinds
|
|
7398
8268
|
};
|
|
7399
|
-
//# sourceMappingURL=chunk-
|
|
8269
|
+
//# sourceMappingURL=chunk-52GMQ2BN.js.map
|