@moku-labs/game 0.15.19 → 0.15.22
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/app/page.d.mts +1 -1
- package/dist/app/page.mjs +1 -1
- package/dist/app/system.d.mts +3 -3
- package/dist/app.d.mts +3 -3
- package/dist/app.mjs +1 -1
- package/dist/assets.d.mts +1 -1
- package/dist/{capture-D7XvoHdH.mjs → capture-PTJXDpxK.mjs} +117 -16
- package/dist/{commands-G9maNqTK.d.mts → commands-BvNp27KS.d.mts} +5 -5
- package/dist/control.d.mts +4 -4
- package/dist/control.mjs +1 -1
- package/dist/{define-BAuGN0UM.d.mts → define-DAVDb7dr.d.mts} +2 -2
- package/dist/{headless-uUUH54Ij.d.mts → headless-BCwsb1wR.d.mts} +1 -1
- package/dist/{headless-BA6ffzqD.mjs → headless-Bxxl_mQX.mjs} +1 -1
- package/dist/{index-Cku9aRz_.d.mts → index-CKXNW8_t.d.mts} +26 -4
- package/dist/index.d.mts +5 -5
- package/dist/index.mjs +3 -3
- package/dist/inspect.d.mts +6 -6
- package/dist/inspect.mjs +1 -1
- package/dist/jsx-dev-runtime.d.mts +1 -1
- package/dist/jsx-runtime.d.mts +1 -1
- package/dist/{run-BqYmcNo7.mjs → run-DRcc2SKF.mjs} +2 -2
- package/dist/{runtime-CuMDZhii.d.mts → runtime-Dt7VdhqR.d.mts} +1 -1
- package/dist/{sources-BYKXYPhd.mjs → sources-Dpc4NXvG.mjs} +1 -1
- package/dist/{src-CXfBuKpl.mjs → src-BcfQy5vB.mjs} +1293 -277
- package/dist/testing.d.mts +4 -4
- package/dist/testing.mjs +2 -2
- package/dist/{types-4T4QTU48.d.mts → types-B02c7d6g.d.mts} +19 -4
- package/dist/{types-bwefoJES.d.mts → types-BFGyVykz.d.mts} +213 -19
- package/dist/{types-DMsvVZZT.d.mts → types-C8JK9u1Y.d.mts} +2 -2
- package/dist/{types-rr56N0Ab.d.mts → types-COWBfy2L.d.mts} +8 -5
- package/dist/{types-DQtBMqRE.d.mts → types-YxQts-fd.d.mts} +4 -4
- package/dist/{visual-B-c5OIFB.d.mts → visual-Dv67ITPu.d.mts} +6 -6
- package/dist/{visual-DNM5oFYx.mjs → visual-kEC9nb-o.mjs} +20 -2
- package/dist/visual.d.mts +1 -1
- package/dist/visual.mjs +2 -2
- package/llms.txt +2 -2
- package/package.json +1 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.mjs";
|
|
2
2
|
import { r as systemSource, t as memory } from "./memory-CWlqhS7l.mjs";
|
|
3
3
|
import { a as finishDrafts, i as enableDraftPatches, n as deepFreeze$1, o as openDrafts, r as dropDrafts } from "./drafts-BawpSaVp.mjs";
|
|
4
|
-
import { d as
|
|
5
|
-
import { $ as component, A as localPoseOf, B as OverlayLevel, C as builtInStyles, D as textFor, E as readStyle, F as rootPoseOf, G as arcDefaults, H as Shape, I as Display, J as Exiting, K as componentsFor, L as HudPart, M as poseUnder, N as rootPointOf, O as applyPose, P as rootPoseInto, Q as Tree, R as NineSlice, U as Sprite, V as Parent, W as Transform, X as Now, Y as Layer, Z as Order, _ as uiFor, a as visualOf$1, b as Countdown, c as Covered, d as LocalWrite, f as Scroll, h as UiCounters, i as samePose, it as tag, j as parentOf$1, k as isLeaving, l as DebugTrigger, m as UI_OWNER, n as drawnRect, nt as system, o as visualRectOf, p as ScrollState, r as fitScaleOf, rt as systemsFor, s as Box, t as CONTENT$1, tt as resource, u as Escapable, x as Text, z as Overlay } from "./visual-
|
|
4
|
+
import { _ as pushEntry, c as collectFlows, d as findNode, f as framePath, g as compact, h as slotNames, i as servePaused, l as describeGraph, m as isRestCheckpoint, n as captureFrame, o as epochOf, p as graphHash, r as serveCaptures, s as pageNow$1, t as cancelCaptures } from "./capture-PTJXDpxK.mjs";
|
|
5
|
+
import { $ as component, A as localPoseOf, B as OverlayLevel, C as builtInStyles, D as textFor, E as readStyle, F as rootPoseOf, G as arcDefaults, H as Shape, I as Display, J as Exiting, K as componentsFor, L as HudPart, M as poseUnder, N as rootPointOf, O as applyPose, P as rootPoseInto, Q as Tree, R as NineSlice, U as Sprite, V as Parent, W as Transform, X as Now, Y as Layer, Z as Order, _ as uiFor, a as visualOf$1, b as Countdown, c as Covered, d as LocalWrite, f as Scroll, h as UiCounters, i as samePose, it as tag, j as parentOf$1, k as isLeaving, l as DebugTrigger, m as UI_OWNER, n as drawnRect, nt as system, o as visualRectOf, p as ScrollState, r as fitScaleOf, rt as systemsFor, s as Box, t as CONTENT$1, tt as resource, u as Escapable, x as Text, z as Overlay } from "./visual-kEC9nb-o.mjs";
|
|
6
6
|
import { a as isDev } from "./dev-BNndV-hU.mjs";
|
|
7
7
|
import { n as isComponentDefinition } from "./component-DGg5DqKK.mjs";
|
|
8
8
|
import { n as flatten } from "./flatten-nUX9PpGo.mjs";
|
|
@@ -252,7 +252,7 @@ function createMeasureState() {
|
|
|
252
252
|
*
|
|
253
253
|
* @returns The page clock, ms.
|
|
254
254
|
*/
|
|
255
|
-
function pageNow
|
|
255
|
+
function pageNow() {
|
|
256
256
|
return globalThis.performance.now();
|
|
257
257
|
}
|
|
258
258
|
/**
|
|
@@ -277,7 +277,7 @@ function timePhase(ctx, record, callbacks, phase, start) {
|
|
|
277
277
|
error
|
|
278
278
|
});
|
|
279
279
|
}
|
|
280
|
-
const end = pageNow
|
|
280
|
+
const end = pageNow();
|
|
281
281
|
record.phaseMs[phase] = end - start;
|
|
282
282
|
return end;
|
|
283
283
|
}
|
|
@@ -294,7 +294,7 @@ function timePhase(ctx, record, callbacks, phase, start) {
|
|
|
294
294
|
function runMeasuredFrame(ctx, measure, at, stepped) {
|
|
295
295
|
const { record } = measure;
|
|
296
296
|
const phases = capturePhases(ctx);
|
|
297
|
-
let mark = pageNow
|
|
297
|
+
let mark = pageNow();
|
|
298
298
|
record.startMs = stepped ? 0 : mark - at;
|
|
299
299
|
mark = timePhase(ctx, record, phases[0], 0, mark);
|
|
300
300
|
mark = timePhase(ctx, record, phases[1], 1, mark);
|
|
@@ -324,7 +324,7 @@ function runMeasuredFrame(ctx, measure, at, stepped) {
|
|
|
324
324
|
} catch (error) {
|
|
325
325
|
ctx.log.error("time: measure listener failed", { error });
|
|
326
326
|
}
|
|
327
|
-
measure.listenersMs = pageNow
|
|
327
|
+
measure.listenersMs = pageNow() - mark;
|
|
328
328
|
measure.lastAt = at;
|
|
329
329
|
measure.skipped = 0;
|
|
330
330
|
}
|
|
@@ -977,7 +977,7 @@ function createRateState(config) {
|
|
|
977
977
|
* @returns The page clock, ms.
|
|
978
978
|
*/
|
|
979
979
|
function nowOf() {
|
|
980
|
-
return typeof globalThis.performance === "undefined" ? 0 : pageNow
|
|
980
|
+
return typeof globalThis.performance === "undefined" ? 0 : pageNow();
|
|
981
981
|
}
|
|
982
982
|
/**
|
|
983
983
|
* Empties both windows: evidence of one rate never judges another, and a resume is a new situation.
|
|
@@ -1650,12 +1650,12 @@ function runFrameWork(ctx, at) {
|
|
|
1650
1650
|
if (typeof __MOKU_GAME_AGENT__ !== "undefined" && __MOKU_GAME_AGENT__) {
|
|
1651
1651
|
const { measure } = ctx.state;
|
|
1652
1652
|
if (measure !== void 0 && measure.listeners.length > 0) {
|
|
1653
|
-
runMeasuredFrame(ctx, measure, at ?? pageNow
|
|
1653
|
+
runMeasuredFrame(ctx, measure, at ?? pageNow(), at === void 0);
|
|
1654
1654
|
return measure.record.workMs;
|
|
1655
1655
|
}
|
|
1656
1656
|
}
|
|
1657
1657
|
runPhases(ctx);
|
|
1658
|
-
return at !== void 0 && ctx.state.rate.governor !== void 0 ? pageNow
|
|
1658
|
+
return at !== void 0 && ctx.state.rate.governor !== void 0 ? pageNow() - at : 0;
|
|
1659
1659
|
}
|
|
1660
1660
|
/**
|
|
1661
1661
|
* Runs exactly one frame: advances `Time` by the scaled delta, then calls the six phases.
|
|
@@ -1849,7 +1849,7 @@ function createTimeApi(ctx) {
|
|
|
1849
1849
|
}
|
|
1850
1850
|
return noMeasure;
|
|
1851
1851
|
},
|
|
1852
|
-
agentClock: () => typeof __MOKU_GAME_AGENT__ !== "undefined" && __MOKU_GAME_AGENT__ ? pageNow
|
|
1852
|
+
agentClock: () => typeof __MOKU_GAME_AGENT__ !== "undefined" && __MOKU_GAME_AGENT__ ? pageNow : void 0,
|
|
1853
1853
|
chargeAgent: (ms) => {
|
|
1854
1854
|
if (typeof __MOKU_GAME_AGENT__ !== "undefined" && __MOKU_GAME_AGENT__) {
|
|
1855
1855
|
const { measure } = ctx.state;
|
|
@@ -3050,7 +3050,7 @@ async function effectValue(state, log, descriptor, signal) {
|
|
|
3050
3050
|
* @param work - The promise of the running effect.
|
|
3051
3051
|
* @returns A promise that settles in the next `signals` phase after `work` settled.
|
|
3052
3052
|
*/
|
|
3053
|
-
function enqueue$
|
|
3053
|
+
function enqueue$2(state, work) {
|
|
3054
3054
|
return new Promise((resolve, reject) => {
|
|
3055
3055
|
const pending = {
|
|
3056
3056
|
ready: false,
|
|
@@ -3191,7 +3191,7 @@ function createFxApi(ctx, deps) {
|
|
|
3191
3191
|
const shown = descriptor.kind === "guide" ? beginGuide(state, signal) : signal;
|
|
3192
3192
|
const work = effectValue(state, ctx.log, descriptor, shown);
|
|
3193
3193
|
if (state.mode === "fast" || !ctx.deps.time.isRunning()) return work;
|
|
3194
|
-
return enqueue$
|
|
3194
|
+
return enqueue$2(state, work);
|
|
3195
3195
|
},
|
|
3196
3196
|
buffer: (item) => {
|
|
3197
3197
|
if (state.mode === "fast") return;
|
|
@@ -5507,7 +5507,7 @@ function startDeadline(timeoutMs) {
|
|
|
5507
5507
|
* @param running - The promise of `run()`.
|
|
5508
5508
|
* @returns `true` when the loop settled, `false` when the deadline won and the loop still runs.
|
|
5509
5509
|
*/
|
|
5510
|
-
async function settle$
|
|
5510
|
+
async function settle$3(ctx, running) {
|
|
5511
5511
|
const quiet = running.then(noop, noop);
|
|
5512
5512
|
const deadline = startDeadline(ctx.config.settleTimeoutMs);
|
|
5513
5513
|
try {
|
|
@@ -5536,7 +5536,7 @@ async function stopRunner(ctx) {
|
|
|
5536
5536
|
stop.abort("stop");
|
|
5537
5537
|
state.abort = stop;
|
|
5538
5538
|
}
|
|
5539
|
-
const settled = running === void 0 || await settle$
|
|
5539
|
+
const settled = running === void 0 || await settle$3(ctx, running);
|
|
5540
5540
|
state.running = void 0;
|
|
5541
5541
|
ctx.state.gate.held = void 0;
|
|
5542
5542
|
if (settled) state.abort = void 0;
|
|
@@ -14939,6 +14939,11 @@ function createHostApi(ctx, deps) {
|
|
|
14939
14939
|
});
|
|
14940
14940
|
return true;
|
|
14941
14941
|
},
|
|
14942
|
+
initSource: (source) => {
|
|
14943
|
+
const app = state.app;
|
|
14944
|
+
if (!state.ready || app === void 0) return;
|
|
14945
|
+
app.renderer.texture.initSource(source);
|
|
14946
|
+
},
|
|
14942
14947
|
clearsCanvas: () => state.ready && state.app?.renderer.background.clearBeforeRender === true,
|
|
14943
14948
|
setResolution: (value, reason) => askResolution(state, value, reason),
|
|
14944
14949
|
overrideResolution: (value) => {
|
|
@@ -15058,7 +15063,10 @@ const KEY = {
|
|
|
15058
15063
|
qc: 25,
|
|
15059
15064
|
qd: 26,
|
|
15060
15065
|
qtx: 27,
|
|
15061
|
-
qty: 28
|
|
15066
|
+
qty: 28,
|
|
15067
|
+
/** The canvas size at the take, CSS px: a picture cut to it is taken again when it changes (F53). */
|
|
15068
|
+
sw: 29,
|
|
15069
|
+
sh: 30
|
|
15062
15070
|
};
|
|
15063
15071
|
/** A whole number of texels within this much (P2.5). */
|
|
15064
15072
|
const ON_GRID = 1 / 64;
|
|
@@ -15123,6 +15131,27 @@ function gridSpan(start, end, resolution) {
|
|
|
15123
15131
|
};
|
|
15124
15132
|
}
|
|
15125
15133
|
/**
|
|
15134
|
+
* A span on the canvas cut to the canvas and the padding around it (F53). Pixi's live filter pass cuts its target to
|
|
15135
|
+
* the viewport and pads it after, so it draws what lies within the padding of the canvas too: a glow just off the
|
|
15136
|
+
* screen still reaches in. A span wholly outside comes back empty: its end is not after its start.
|
|
15137
|
+
*
|
|
15138
|
+
* @param start - The span's start on the canvas, CSS px.
|
|
15139
|
+
* @param end - Its end.
|
|
15140
|
+
* @param size - The canvas size on that axis, CSS px.
|
|
15141
|
+
* @param padding - The padding of the filters, CSS px.
|
|
15142
|
+
* @returns The part of the span kept.
|
|
15143
|
+
* @example
|
|
15144
|
+
* ```ts
|
|
15145
|
+
* cutSpan(-40, 120, 100, 10); // { start: -10, end: 110 }
|
|
15146
|
+
* ```
|
|
15147
|
+
*/
|
|
15148
|
+
function cutSpan(start, end, size, padding) {
|
|
15149
|
+
return {
|
|
15150
|
+
start: Math.max(start, -padding),
|
|
15151
|
+
end: Math.min(end, size + padding)
|
|
15152
|
+
};
|
|
15153
|
+
}
|
|
15154
|
+
/**
|
|
15126
15155
|
* The padding of a stack on the grid of its resolution: what stage 3 adds on each side of the subtree picture, so the
|
|
15127
15156
|
* picture's bounds stay on that grid inside the output texture.
|
|
15128
15157
|
*
|
|
@@ -15925,6 +15954,123 @@ function flushRanges(kctx) {
|
|
|
15925
15954
|
}
|
|
15926
15955
|
}
|
|
15927
15956
|
//#endregion
|
|
15957
|
+
//#region src/plugins/renderer/kept/drawn-bounds.ts
|
|
15958
|
+
/** Every flag of a node's display status: visible, renderable, not culled (Pixi's `localDisplayStatus`). */
|
|
15959
|
+
const SHOWN = 7;
|
|
15960
|
+
/** The effects of a node that holds none. */
|
|
15961
|
+
const NO_EFFECTS = [];
|
|
15962
|
+
/** The matrix of each depth of the walk, from the top's space to the node's. Grown once, then reused. */
|
|
15963
|
+
const MATRICES = [];
|
|
15964
|
+
/** The bounds a masked node's subtree is gathered in, one per depth. Grown once, then reused. */
|
|
15965
|
+
const MASKED = [];
|
|
15966
|
+
/** The bounds the last walk answered, made once. */
|
|
15967
|
+
const RESULT = [];
|
|
15968
|
+
/**
|
|
15969
|
+
* The matrix of a depth, made the first time the walk reaches it.
|
|
15970
|
+
*
|
|
15971
|
+
* @param pixi - The module that draws.
|
|
15972
|
+
* @param depth - The depth under the top.
|
|
15973
|
+
* @returns The matrix.
|
|
15974
|
+
*/
|
|
15975
|
+
function matrixAt(pixi, depth) {
|
|
15976
|
+
const known = MATRICES[depth];
|
|
15977
|
+
if (known !== void 0) return known;
|
|
15978
|
+
const made = new pixi.Matrix();
|
|
15979
|
+
MATRICES[depth] = made;
|
|
15980
|
+
return made;
|
|
15981
|
+
}
|
|
15982
|
+
/**
|
|
15983
|
+
* The bounds a masked node of a depth gathers its subtree in, made the first time the walk needs it.
|
|
15984
|
+
*
|
|
15985
|
+
* @param pixi - The module that draws.
|
|
15986
|
+
* @param depth - The depth under the top.
|
|
15987
|
+
* @returns The bounds, cleared.
|
|
15988
|
+
*/
|
|
15989
|
+
function maskedAt(pixi, depth) {
|
|
15990
|
+
const known = MASKED[depth];
|
|
15991
|
+
if (known !== void 0) return known.clear();
|
|
15992
|
+
const made = new pixi.Bounds();
|
|
15993
|
+
MASKED[depth] = made;
|
|
15994
|
+
return made;
|
|
15995
|
+
}
|
|
15996
|
+
/**
|
|
15997
|
+
* Tells whether Pixi skips a node and its subtree: hidden, not renderable, culled, or not measured (a mask).
|
|
15998
|
+
*
|
|
15999
|
+
* @param node - A node under the top.
|
|
16000
|
+
* @returns True when it adds nothing.
|
|
16001
|
+
*/
|
|
16002
|
+
function skipped(node) {
|
|
16003
|
+
return node.localDisplayStatus !== SHOWN || !node.measurable;
|
|
16004
|
+
}
|
|
16005
|
+
/**
|
|
16006
|
+
* Adds what a node draws itself and what its children draw to the bounds, under the node's matrix.
|
|
16007
|
+
*
|
|
16008
|
+
* @param pixi - The module that draws.
|
|
16009
|
+
* @param node - The node, shown.
|
|
16010
|
+
* @param into - The bounds so far.
|
|
16011
|
+
* @param depth - Its depth under the top.
|
|
16012
|
+
* @param top - The top.
|
|
16013
|
+
*/
|
|
16014
|
+
function addContent(pixi, node, into, depth, top) {
|
|
16015
|
+
const matrix = matrixAt(pixi, depth);
|
|
16016
|
+
if (node.boundsArea) {
|
|
16017
|
+
into.addRect(node.boundsArea, matrix);
|
|
16018
|
+
return;
|
|
16019
|
+
}
|
|
16020
|
+
if (node.renderPipeId !== void 0) {
|
|
16021
|
+
const own = node.bounds;
|
|
16022
|
+
into.addFrame(own.minX, own.minY, own.maxX, own.maxY, matrix);
|
|
16023
|
+
}
|
|
16024
|
+
const children = node.children;
|
|
16025
|
+
for (let index = 0; index < children.length; index += 1) {
|
|
16026
|
+
const child = children[index];
|
|
16027
|
+
if (child !== void 0) addDrawn$1(pixi, child, into, depth + 1, top);
|
|
16028
|
+
}
|
|
16029
|
+
}
|
|
16030
|
+
/**
|
|
16031
|
+
* Adds what one node and its subtree draw to the bounds, in the top's space. The top itself is never skipped: it is
|
|
16032
|
+
* the root of the picture's render, drawn whatever its own flags say. A masked node gathers its subtree apart, then
|
|
16033
|
+
* the mask cuts it.
|
|
16034
|
+
*
|
|
16035
|
+
* @param pixi - The module that draws.
|
|
16036
|
+
* @param node - The node.
|
|
16037
|
+
* @param into - The bounds so far.
|
|
16038
|
+
* @param depth - Its depth under the top, 0 for the top.
|
|
16039
|
+
* @param top - The top: the space of the bounds, and the root a mask is measured from.
|
|
16040
|
+
*/
|
|
16041
|
+
function addDrawn$1(pixi, node, into, depth, top) {
|
|
16042
|
+
if (depth > 0 && skipped(node)) return;
|
|
16043
|
+
const matrix = matrixAt(pixi, depth);
|
|
16044
|
+
if (depth === 0) matrix.identity();
|
|
16045
|
+
else {
|
|
16046
|
+
node.updateLocalTransform();
|
|
16047
|
+
matrix.appendFrom(node.localTransform, matrixAt(pixi, depth - 1));
|
|
16048
|
+
}
|
|
16049
|
+
const effects = node.effects ?? NO_EFFECTS;
|
|
16050
|
+
if (effects.length === 0) {
|
|
16051
|
+
addContent(pixi, node, into, depth, top);
|
|
16052
|
+
return;
|
|
16053
|
+
}
|
|
16054
|
+
const masked = maskedAt(pixi, depth);
|
|
16055
|
+
addContent(pixi, node, masked, depth, top);
|
|
16056
|
+
for (const effect of effects) effect.addLocalBounds?.(masked, top);
|
|
16057
|
+
if (masked.isValid) into.addFrame(masked.minX, masked.minY, masked.maxX, masked.maxY);
|
|
16058
|
+
}
|
|
16059
|
+
/**
|
|
16060
|
+
* The bounds of what a subtree draws, in its top's own space: no node Pixi skips, masks applied.
|
|
16061
|
+
*
|
|
16062
|
+
* @param pixi - The module that draws.
|
|
16063
|
+
* @param top - The top of the subtree.
|
|
16064
|
+
* @returns The bounds, one object the next walk writes again; empty (`isValid` false) when nothing is drawn.
|
|
16065
|
+
*/
|
|
16066
|
+
function drawnBounds(pixi, top) {
|
|
16067
|
+
const into = RESULT[0] ?? new pixi.Bounds();
|
|
16068
|
+
RESULT[0] = into;
|
|
16069
|
+
into.clear();
|
|
16070
|
+
addDrawn$1(pixi, top, into, 0, top);
|
|
16071
|
+
return into;
|
|
16072
|
+
}
|
|
16073
|
+
//#endregion
|
|
15928
16074
|
//#region src/plugins/renderer/kept/state.ts
|
|
15929
16075
|
/**
|
|
15930
16076
|
* @file renderer/kept — the state of the kept-picture cache, and its stop from state alone.
|
|
@@ -16081,6 +16227,7 @@ const NOW = {
|
|
|
16081
16227
|
enabled: 0,
|
|
16082
16228
|
rs: 1,
|
|
16083
16229
|
P: 0,
|
|
16230
|
+
alpha: NaN,
|
|
16084
16231
|
r: 1,
|
|
16085
16232
|
a: 1,
|
|
16086
16233
|
b: 0,
|
|
@@ -16109,27 +16256,42 @@ function resolutionOf$1(filter, resolution) {
|
|
|
16109
16256
|
return own === "inherit" ? resolution : own;
|
|
16110
16257
|
}
|
|
16111
16258
|
/**
|
|
16112
|
-
* Reads what the enabled filters of a stack draw with: how many, the smallest resolution,
|
|
16113
|
-
* pads by (whole pixels)
|
|
16259
|
+
* Reads what the enabled filters of a stack draw with: how many, the smallest resolution, the padding sum Pixi
|
|
16260
|
+
* pads by (whole pixels), and the alpha they multiply by while every one is an `AlphaFilter`.
|
|
16114
16261
|
*
|
|
16115
16262
|
* @param slots - The record's slots.
|
|
16116
16263
|
* @param resolution - The renderer resolution.
|
|
16264
|
+
* @param alphaFilter - Pixi's `AlphaFilter` class.
|
|
16117
16265
|
* @param into - Where the numbers go.
|
|
16118
16266
|
*/
|
|
16119
|
-
function readStack(slots, resolution, into) {
|
|
16267
|
+
function readStack(slots, resolution, alphaFilter, into) {
|
|
16120
16268
|
let enabled = 0;
|
|
16121
16269
|
let rs = Number.POSITIVE_INFINITY;
|
|
16122
16270
|
let padding = 0;
|
|
16271
|
+
let alpha = 1;
|
|
16123
16272
|
for (let index = 0; index < slots.length; index += 1) {
|
|
16124
16273
|
const filter = slots[index]?.filter;
|
|
16125
16274
|
if (filter === void 0 || !filter.enabled) continue;
|
|
16126
16275
|
enabled += 1;
|
|
16127
16276
|
rs = Math.min(rs, resolutionOf$1(filter, resolution));
|
|
16128
16277
|
padding += filter.padding;
|
|
16278
|
+
alpha *= filter instanceof alphaFilter ? filter.alpha : NaN;
|
|
16129
16279
|
}
|
|
16130
16280
|
into.enabled = enabled;
|
|
16131
16281
|
into.rs = enabled === 0 ? resolution : rs;
|
|
16132
16282
|
into.P = Math.trunc(padding);
|
|
16283
|
+
into.alpha = alpha;
|
|
16284
|
+
}
|
|
16285
|
+
/**
|
|
16286
|
+
* Tells whether a stack draws as its subtree picture at an alpha (F54): every enabled filter an `AlphaFilter`, no
|
|
16287
|
+
* padding, at the renderer resolution. The quad then draws the picture itself at that alpha, as Pixi's alpha pass
|
|
16288
|
+
* draws its input: no stage 3, no pass when the alpha changes.
|
|
16289
|
+
*
|
|
16290
|
+
* @param now - This frame's numbers.
|
|
16291
|
+
* @returns True when it does.
|
|
16292
|
+
*/
|
|
16293
|
+
function drawsDirect(now) {
|
|
16294
|
+
return !Number.isNaN(now.alpha) && now.P === 0 && now.rs === now.r;
|
|
16133
16295
|
}
|
|
16134
16296
|
/**
|
|
16135
16297
|
* Tells whether a blend mode draws over what is under it as a picture does.
|
|
@@ -16283,7 +16445,7 @@ function holdsDisplay(kctx, top) {
|
|
|
16283
16445
|
*/
|
|
16284
16446
|
function createRecord$1(kctx, pixi, entity, view, slots, category) {
|
|
16285
16447
|
const top = view.wrapper ?? view.object;
|
|
16286
|
-
const key = (/* @__PURE__ */ new Float64Array(
|
|
16448
|
+
const key = (/* @__PURE__ */ new Float64Array(31)).fill(NaN);
|
|
16287
16449
|
const record = {
|
|
16288
16450
|
entity,
|
|
16289
16451
|
top,
|
|
@@ -16316,6 +16478,8 @@ function createRecord$1(kctx, pixi, entity, view, slots, category) {
|
|
|
16316
16478
|
bytes: 0,
|
|
16317
16479
|
settle: false,
|
|
16318
16480
|
refused: 0,
|
|
16481
|
+
cut: false,
|
|
16482
|
+
direct: false,
|
|
16319
16483
|
displays: void 0
|
|
16320
16484
|
};
|
|
16321
16485
|
const { state } = kctx;
|
|
@@ -16441,7 +16605,8 @@ function linearDiffers(key, now, base, rsAt) {
|
|
|
16441
16605
|
*/
|
|
16442
16606
|
function neededBytes(record, now, box) {
|
|
16443
16607
|
const { w1, h1, Ps } = box;
|
|
16444
|
-
let bytes = textureBytes(w1, h1, now.rs)
|
|
16608
|
+
let bytes = textureBytes(w1, h1, now.rs);
|
|
16609
|
+
if (!drawsDirect(now)) bytes += textureBytes(w1 + 2 * Ps, h1 + 2 * Ps, now.r);
|
|
16445
16610
|
const first = firstInputs(record.slots);
|
|
16446
16611
|
if (first !== void 0) for (let index = 0; index < first.inputs.count; index += 1) {
|
|
16447
16612
|
const scale = first.inputs.scaleOf(index) ?? 0;
|
|
@@ -16508,14 +16673,22 @@ function writeTakeKeys(record, now, box) {
|
|
|
16508
16673
|
function takePicture(kctx, pixi, matrices, record, view, now) {
|
|
16509
16674
|
const { top } = record;
|
|
16510
16675
|
if (!kctx.ctx.config.onDemand && holdsDisplay(kctx, top)) return false;
|
|
16511
|
-
const
|
|
16676
|
+
const drawn = drawnBounds(pixi, top);
|
|
16677
|
+
if (!drawn.isValid) return false;
|
|
16678
|
+
const local = clippedToArea(drawn, top.filterArea);
|
|
16512
16679
|
if (isEmptyBounds(local)) return false;
|
|
16513
16680
|
const box = linearBounds(now.a, now.b, now.c, now.d, local);
|
|
16514
|
-
const
|
|
16515
|
-
const
|
|
16681
|
+
const screen = kctx.host.screen();
|
|
16682
|
+
const width = screen?.width ?? Number.POSITIVE_INFINITY;
|
|
16683
|
+
const height = screen?.height ?? Number.POSITIVE_INFINITY;
|
|
16684
|
+
const Ps = paddingOnGrid(now.P, now.rs);
|
|
16685
|
+
const across = cutSpan(now.tx + box.x0, now.tx + box.x1, width, Ps);
|
|
16686
|
+
const down = cutSpan(now.ty + box.y0, now.ty + box.y1, height, Ps);
|
|
16687
|
+
if (isEmptySpan(across) || isEmptySpan(down)) return false;
|
|
16688
|
+
const x = gridSpan(across.start, across.end, now.rs);
|
|
16689
|
+
const y = gridSpan(down.start, down.end, now.rs);
|
|
16516
16690
|
const w1 = x.texels / now.rs;
|
|
16517
16691
|
const h1 = y.texels / now.rs;
|
|
16518
|
-
const Ps = paddingOnGrid(now.P, now.rs);
|
|
16519
16692
|
if (!fitsTexture(w1, h1, now.rs) || !fitsTexture(w1 + 2 * Ps, h1 + 2 * Ps, now.r)) return false;
|
|
16520
16693
|
const needed = neededBytes(record, now, {
|
|
16521
16694
|
w1,
|
|
@@ -16528,6 +16701,11 @@ function takePicture(kctx, pixi, matrices, record, view, now) {
|
|
|
16528
16701
|
return false;
|
|
16529
16702
|
}
|
|
16530
16703
|
record.refused = 0;
|
|
16704
|
+
const cutAcross = across.start > now.tx + box.x0 || across.end < now.tx + box.x1;
|
|
16705
|
+
const cutDown = down.start > now.ty + box.y0 || down.end < now.ty + box.y1;
|
|
16706
|
+
record.cut = cutAcross || cutDown;
|
|
16707
|
+
record.key[KEY.sw] = width;
|
|
16708
|
+
record.key[KEY.sh] = height;
|
|
16531
16709
|
writeTakeKeys(record, now, {
|
|
16532
16710
|
x,
|
|
16533
16711
|
y,
|
|
@@ -16540,6 +16718,21 @@ function takePicture(kctx, pixi, matrices, record, view, now) {
|
|
|
16540
16718
|
return ok;
|
|
16541
16719
|
}
|
|
16542
16720
|
/**
|
|
16721
|
+
* Tells whether a span holds nothing: its end is not after its start. Pure.
|
|
16722
|
+
*
|
|
16723
|
+
* @param span - The span.
|
|
16724
|
+
* @param span.start - Its start.
|
|
16725
|
+
* @param span.end - Its end.
|
|
16726
|
+
* @returns True when it is empty.
|
|
16727
|
+
* @example
|
|
16728
|
+
* ```ts
|
|
16729
|
+
* isEmptySpan({ start: -10, end: -10 }); // true
|
|
16730
|
+
* ```
|
|
16731
|
+
*/
|
|
16732
|
+
function isEmptySpan(span) {
|
|
16733
|
+
return span.end <= span.start;
|
|
16734
|
+
}
|
|
16735
|
+
/**
|
|
16543
16736
|
* The local bounds of a top cut to its filter area, both in the top's own units: its filters draw nothing outside
|
|
16544
16737
|
* the area. With no area the bounds are returned as they are. Pure.
|
|
16545
16738
|
*
|
|
@@ -16591,6 +16784,13 @@ function renderStages(kctx, pixi, matrices, record, view, now) {
|
|
|
16591
16784
|
if (live) handFilters(kctx, pixi, record, view);
|
|
16592
16785
|
const first = firstInputs(record.slots);
|
|
16593
16786
|
let ok = renderStage1(kctx, pixi, matrices, record);
|
|
16787
|
+
if (drawsDirect(now)) {
|
|
16788
|
+
goDirect(kctx, record);
|
|
16789
|
+
account(kctx, record);
|
|
16790
|
+
if (!ok && live) putFiltersBack(kctx, record, view);
|
|
16791
|
+
return ok;
|
|
16792
|
+
}
|
|
16793
|
+
record.direct = false;
|
|
16594
16794
|
if (ok && first !== void 0) renderStage2(kctx, pixi, matrices, record, {
|
|
16595
16795
|
inputs: first.inputs,
|
|
16596
16796
|
resolution: now.r,
|
|
@@ -16599,13 +16799,36 @@ function renderStages(kctx, pixi, matrices, record, view, now) {
|
|
|
16599
16799
|
else if (record.s2Of !== void 0) releaseInputs(kctx, record);
|
|
16600
16800
|
ok = ok && renderStage3(kctx, pixi, matrices, record, now);
|
|
16601
16801
|
account(kctx, record);
|
|
16602
|
-
if (!ok && live)
|
|
16603
|
-
if (record.standIn !== void 0) record.standIn.filters = null;
|
|
16604
|
-
kctx.sync.applyFilters(view, filtersOf$1(kctx.ctx.state.sync, record.entity), noMark$1, record.top);
|
|
16605
|
-
}
|
|
16802
|
+
if (!ok && live) putFiltersBack(kctx, record, view);
|
|
16606
16803
|
return ok;
|
|
16607
16804
|
}
|
|
16608
16805
|
/**
|
|
16806
|
+
* Puts the filters of a live record whose take failed back on its top: it draws live again.
|
|
16807
|
+
*
|
|
16808
|
+
* @param kctx - The kept context.
|
|
16809
|
+
* @param record - The record.
|
|
16810
|
+
* @param view - Its view.
|
|
16811
|
+
*/
|
|
16812
|
+
function putFiltersBack(kctx, record, view) {
|
|
16813
|
+
if (record.standIn !== void 0) record.standIn.filters = null;
|
|
16814
|
+
kctx.sync.applyFilters(view, filtersOf$1(kctx.ctx.state.sync, record.entity), noMark$1, record.top);
|
|
16815
|
+
}
|
|
16816
|
+
/**
|
|
16817
|
+
* Lets a record draw its subtree picture itself (F54): the pre-pass results and the filter output go, and the quad
|
|
16818
|
+
* shows the picture at the stack's alpha from now on.
|
|
16819
|
+
*
|
|
16820
|
+
* @param kctx - The kept context.
|
|
16821
|
+
* @param record - The record.
|
|
16822
|
+
*/
|
|
16823
|
+
function goDirect(kctx, record) {
|
|
16824
|
+
if (record.s2Of !== void 0) releaseInputs(kctx, record);
|
|
16825
|
+
if (record.s3 !== void 0) {
|
|
16826
|
+
dropTexture(kctx, record.s3);
|
|
16827
|
+
record.s3 = void 0;
|
|
16828
|
+
}
|
|
16829
|
+
record.direct = true;
|
|
16830
|
+
}
|
|
16831
|
+
/**
|
|
16609
16832
|
* Ends the loan of stage 2 when the first filter with inputs left the stack: the results are destroyed.
|
|
16610
16833
|
*
|
|
16611
16834
|
* @param kctx - The kept context.
|
|
@@ -16641,7 +16864,8 @@ function account(kctx, record) {
|
|
|
16641
16864
|
function placeQuad(sync, pixi, matrices, record, view) {
|
|
16642
16865
|
const { top, key } = record;
|
|
16643
16866
|
const parent = top.parent;
|
|
16644
|
-
const output = record.s3 ?? pixi.Texture.EMPTY;
|
|
16867
|
+
const output = (record.direct ? record.s1 : record.s3) ?? pixi.Texture.EMPTY;
|
|
16868
|
+
const alpha = record.direct ? NOW.alpha : 1;
|
|
16645
16869
|
if (record.quad === void 0 || record.quad.destroyed) {
|
|
16646
16870
|
record.quad = new pixi.Sprite(output);
|
|
16647
16871
|
record.quad.label = `kept:${labelOf$3(top)}`;
|
|
@@ -16655,8 +16879,9 @@ function placeQuad(sync, pixi, matrices, record, view) {
|
|
|
16655
16879
|
}
|
|
16656
16880
|
if (quad.zIndex !== top.zIndex) quad.zIndex = top.zIndex;
|
|
16657
16881
|
if (quad.blendMode !== top.blendMode) quad.blendMode = top.blendMode;
|
|
16882
|
+
if (quad.alpha !== alpha) quad.alpha = alpha;
|
|
16658
16883
|
const inverse = parent.getGlobalTransform(matrices.parent, false).invert();
|
|
16659
|
-
const Ps = key[KEY.Ps] ?? 0;
|
|
16884
|
+
const Ps = record.direct ? 0 : key[KEY.Ps] ?? 0;
|
|
16660
16885
|
const x = (key[KEY.X0] ?? 0) - Ps + NOW.tx - (key[KEY.tx] ?? 0);
|
|
16661
16886
|
const y = (key[KEY.Y0] ?? 0) - Ps + NOW.ty - (key[KEY.ty] ?? 0);
|
|
16662
16887
|
const { local } = matrices;
|
|
@@ -16800,6 +17025,17 @@ function noteMove(kctx, record) {
|
|
|
16800
17025
|
if (record.settle) kctx.demand.request();
|
|
16801
17026
|
}
|
|
16802
17027
|
/**
|
|
17028
|
+
* Tells whether the canvas has another size than at the take.
|
|
17029
|
+
*
|
|
17030
|
+
* @param kctx - The kept context.
|
|
17031
|
+
* @param key - The record's key.
|
|
17032
|
+
* @returns True when it does.
|
|
17033
|
+
*/
|
|
17034
|
+
function canvasChanged(kctx, key) {
|
|
17035
|
+
const screen = kctx.host.screen();
|
|
17036
|
+
return screen !== void 0 && (screen.width !== key[KEY.sw] || screen.height !== key[KEY.sh]);
|
|
17037
|
+
}
|
|
17038
|
+
/**
|
|
16803
17039
|
* A kept record's frame (P4.3): a stage-1 change retakes (three in a row go live and calm); otherwise a new chain
|
|
16804
17040
|
* version redoes stages 2 and 3, a filter value, the resolution, the padding or (placed) a move stage 3; at rest after
|
|
16805
17041
|
* an off-grid move one settle retake is owed.
|
|
@@ -16816,8 +17052,12 @@ function stepKept$1(kctx, pixi, matrices, record, view) {
|
|
|
16816
17052
|
churn(kctx, pixi, matrices, record, view);
|
|
16817
17053
|
return;
|
|
16818
17054
|
}
|
|
16819
|
-
record.churn = 0;
|
|
16820
17055
|
const moved = NOW.tx !== key[KEY.lastTx] || NOW.ty !== key[KEY.lastTy];
|
|
17056
|
+
if (record.cut && (moved || canvasChanged(kctx, key))) {
|
|
17057
|
+
churn(kctx, pixi, matrices, record, view);
|
|
17058
|
+
return;
|
|
17059
|
+
}
|
|
17060
|
+
record.churn = 0;
|
|
16821
17061
|
if (!moved && record.settle) {
|
|
16822
17062
|
retakeOrGoLive(kctx, pixi, matrices, record, view);
|
|
16823
17063
|
return;
|
|
@@ -16835,6 +17075,12 @@ function stepKept$1(kctx, pixi, matrices, record, view) {
|
|
|
16835
17075
|
*/
|
|
16836
17076
|
function refresh$1(kctx, pixi, matrices, record) {
|
|
16837
17077
|
const { key } = record;
|
|
17078
|
+
if (drawsDirect(NOW)) {
|
|
17079
|
+
if (record.direct) return;
|
|
17080
|
+
goDirect(kctx, record);
|
|
17081
|
+
account(kctx, record);
|
|
17082
|
+
return;
|
|
17083
|
+
}
|
|
16838
17084
|
const inputs = firstInputs(record.slots)?.inputs;
|
|
16839
17085
|
const stageTwoOwed = inputs !== void 0 && (record.dirtyS2 || inputs !== record.s2Of || inputs.version() !== record.s2InputsVersion || record.s1Version !== record.s2PictureVersion);
|
|
16840
17086
|
const inputsLeft = inputs === void 0 && record.s2Of !== void 0;
|
|
@@ -16846,6 +17092,7 @@ function refresh$1(kctx, pixi, matrices, record) {
|
|
|
16846
17092
|
padding: NOW.P
|
|
16847
17093
|
});
|
|
16848
17094
|
if (!stageThreeOwed) return;
|
|
17095
|
+
record.direct = false;
|
|
16849
17096
|
renderStage3(kctx, pixi, matrices, record, NOW);
|
|
16850
17097
|
account(kctx, record);
|
|
16851
17098
|
if (!stageTwoOwed) kctx.state.refreshesOpen += 1;
|
|
@@ -16915,7 +17162,7 @@ function stepCalm(kctx, record) {
|
|
|
16915
17162
|
function stepRecord(kctx, pixi, matrices, record, view) {
|
|
16916
17163
|
noteDrawing(kctx, record, BEFORE);
|
|
16917
17164
|
NOW.r = kctx.host.resolution();
|
|
16918
|
-
readStack(record.slots, NOW.r, NOW);
|
|
17165
|
+
readStack(record.slots, NOW.r, pixi.AlphaFilter, NOW);
|
|
16919
17166
|
if (eligible(kctx, record, view, NOW)) stepEligible(kctx, pixi, matrices, record, view);
|
|
16920
17167
|
else stepIneligible(kctx, record, view);
|
|
16921
17168
|
if (drawingChanged(kctx, record, BEFORE)) dirtyAbove(kctx, record);
|
|
@@ -17581,31 +17828,6 @@ function stopDemand(state) {
|
|
|
17581
17828
|
state.verify.reference = void 0;
|
|
17582
17829
|
}
|
|
17583
17830
|
//#endregion
|
|
17584
|
-
//#region src/plugins/renderer/monitor/clock.ts
|
|
17585
|
-
/**
|
|
17586
|
-
* @file renderer/monitor — the one renderer file that reads the page clock; lint L3 ignores it (eslint `ignores`). It
|
|
17587
|
-
* measures the page in agent builds: the agent phase, a line's `t`, an event's time between frames. Never a game's
|
|
17588
|
-
* state, whose time is `clock`.
|
|
17589
|
-
*/
|
|
17590
|
-
/**
|
|
17591
|
-
* Reads `globalThis.performance.now()` at call time, so a test stubs it.
|
|
17592
|
-
*
|
|
17593
|
-
* @returns Page-clock milliseconds.
|
|
17594
|
-
*/
|
|
17595
|
-
function pageNow() {
|
|
17596
|
-
return globalThis.performance.now();
|
|
17597
|
-
}
|
|
17598
|
-
/**
|
|
17599
|
-
* Turns page-clock milliseconds into page epoch milliseconds, `performance.timeOrigin + ms`, rounded to 0.01 ms: the
|
|
17600
|
-
* `t` of every log line.
|
|
17601
|
-
*
|
|
17602
|
-
* @param pageMs - Page-clock milliseconds.
|
|
17603
|
-
* @returns Epoch milliseconds.
|
|
17604
|
-
*/
|
|
17605
|
-
function epochOf(pageMs) {
|
|
17606
|
-
return Math.round((globalThis.performance.timeOrigin + pageMs) * 100) / 100;
|
|
17607
|
-
}
|
|
17608
|
-
//#endregion
|
|
17609
17831
|
//#region src/plugins/renderer/reasons.ts
|
|
17610
17832
|
/**
|
|
17611
17833
|
* @file renderer plugin — the reasons a frame is drawn, in ring order: the monitor stores a reason by its index. A
|
|
@@ -19265,9 +19487,9 @@ function wrapDevice(pc, device) {
|
|
|
19265
19487
|
* @returns The pipeline.
|
|
19266
19488
|
*/
|
|
19267
19489
|
value: function countedPipeline(descriptor) {
|
|
19268
|
-
const started = pageNow();
|
|
19490
|
+
const started = pageNow$1();
|
|
19269
19491
|
const made = createRenderPipeline.call(this, descriptor);
|
|
19270
|
-
recordCompile(sinks, pc.perf.frame, descriptor.label ?? null, pageNow() - started);
|
|
19492
|
+
recordCompile(sinks, pc.perf.frame, descriptor.label ?? null, pageNow$1() - started);
|
|
19271
19493
|
return made;
|
|
19272
19494
|
}
|
|
19273
19495
|
});
|
|
@@ -19282,9 +19504,9 @@ function wrapDevice(pc, device) {
|
|
|
19282
19504
|
* @returns The module.
|
|
19283
19505
|
*/
|
|
19284
19506
|
value: function countedModule(descriptor) {
|
|
19285
|
-
const started = pageNow();
|
|
19507
|
+
const started = pageNow$1();
|
|
19286
19508
|
const made = createShaderModule.call(this, descriptor);
|
|
19287
|
-
recordModule(sinks, pc.perf.frame, descriptor.label ?? null, pageNow() - started);
|
|
19509
|
+
recordModule(sinks, pc.perf.frame, descriptor.label ?? null, pageNow$1() - started);
|
|
19288
19510
|
return made;
|
|
19289
19511
|
}
|
|
19290
19512
|
});
|
|
@@ -19312,9 +19534,9 @@ function wrapGl(pc, gl) {
|
|
|
19312
19534
|
* @param program - The program.
|
|
19313
19535
|
*/
|
|
19314
19536
|
value: function countedLink(program) {
|
|
19315
|
-
const started = pageNow();
|
|
19537
|
+
const started = pageNow$1();
|
|
19316
19538
|
linkProgram.call(this, program);
|
|
19317
|
-
recordCompile(sinks, pc.perf.frame, null, pageNow() - started);
|
|
19539
|
+
recordCompile(sinks, pc.perf.frame, null, pageNow$1() - started);
|
|
19318
19540
|
}
|
|
19319
19541
|
});
|
|
19320
19542
|
return () => {
|
|
@@ -19980,7 +20202,7 @@ function headerLine(pc, thermal) {
|
|
|
19980
20202
|
return {
|
|
19981
20203
|
v: 1,
|
|
19982
20204
|
kind: "header",
|
|
19983
|
-
t: epochOf(pageNow()),
|
|
20205
|
+
t: epochOf(pageNow$1()),
|
|
19984
20206
|
build: buildId(),
|
|
19985
20207
|
timeOrigin: globalThis.performance.timeOrigin,
|
|
19986
20208
|
engine: typeof __MOKU_GAME_ENGINE__ === "string" ? __MOKU_GAME_ENGINE__ : null,
|
|
@@ -20500,7 +20722,7 @@ function eventLine(name, detail, frame) {
|
|
|
20500
20722
|
return {
|
|
20501
20723
|
v: 1,
|
|
20502
20724
|
kind: "event",
|
|
20503
|
-
t: epochOf(pageNow()),
|
|
20725
|
+
t: epochOf(pageNow$1()),
|
|
20504
20726
|
build: buildId(),
|
|
20505
20727
|
frame,
|
|
20506
20728
|
name,
|
|
@@ -20518,7 +20740,7 @@ function markLine(label, auto) {
|
|
|
20518
20740
|
return {
|
|
20519
20741
|
v: 1,
|
|
20520
20742
|
kind: "mark",
|
|
20521
|
-
t: epochOf(pageNow()),
|
|
20743
|
+
t: epochOf(pageNow$1()),
|
|
20522
20744
|
build: buildId(),
|
|
20523
20745
|
label,
|
|
20524
20746
|
auto
|
|
@@ -20535,7 +20757,7 @@ function thermalLine(reading) {
|
|
|
20535
20757
|
return {
|
|
20536
20758
|
v: 1,
|
|
20537
20759
|
kind: "thermal",
|
|
20538
|
-
t: epochOf(pageNow()),
|
|
20760
|
+
t: epochOf(pageNow$1()),
|
|
20539
20761
|
build: buildId(),
|
|
20540
20762
|
status: reading.status,
|
|
20541
20763
|
headroom: reading.headroom,
|
|
@@ -20677,7 +20899,7 @@ function buildStartup(pc) {
|
|
|
20677
20899
|
return {
|
|
20678
20900
|
v: 1,
|
|
20679
20901
|
kind: "startup",
|
|
20680
|
-
t: epochOf(pageNow()),
|
|
20902
|
+
t: epochOf(pageNow$1()),
|
|
20681
20903
|
build: buildId(),
|
|
20682
20904
|
htmlMs: responseEnd === void 0 ? null : roundTo(responseEnd, 2),
|
|
20683
20905
|
script,
|
|
@@ -21104,7 +21326,7 @@ function writeKept(pc, slot) {
|
|
|
21104
21326
|
* @param section - The `COST` index the time goes to.
|
|
21105
21327
|
*/
|
|
21106
21328
|
function lap(perf, section) {
|
|
21107
|
-
const now = pageNow();
|
|
21329
|
+
const now = pageNow$1();
|
|
21108
21330
|
perf.sectionsMs[section] = cellF64(perf.sectionsMs, section) + now - cellF64(perf.staged, 2);
|
|
21109
21331
|
perf.staged[2] = now;
|
|
21110
21332
|
}
|
|
@@ -21496,7 +21718,7 @@ function commitFrame(pc, measure) {
|
|
|
21496
21718
|
const sections = sinks.sections;
|
|
21497
21719
|
const slot = ring.written % ring.capacity;
|
|
21498
21720
|
const previous = ring.size === 0 ? -1 : ring.newest;
|
|
21499
|
-
perf.staged[2] = pageNow();
|
|
21721
|
+
perf.staged[2] = pageNow$1();
|
|
21500
21722
|
stageBudget(perf, measure);
|
|
21501
21723
|
writeMeasure(pc, slot, measure);
|
|
21502
21724
|
writeKept(pc, slot);
|
|
@@ -22116,7 +22338,7 @@ function notePauses(pc, reasons, paused, resumed) {
|
|
|
22116
22338
|
const detail = { reasons: [...reasons] };
|
|
22117
22339
|
if (paused) {
|
|
22118
22340
|
writeEvent(pc, "pause", detail);
|
|
22119
|
-
pc.perf.staged[1] = pageNow();
|
|
22341
|
+
pc.perf.staged[1] = pageNow$1();
|
|
22120
22342
|
flushPerf(pc);
|
|
22121
22343
|
} else if (resumed) {
|
|
22122
22344
|
writeEvent(pc, "resume", detail);
|
|
@@ -22138,7 +22360,7 @@ function noteChange(perf, change) {
|
|
|
22138
22360
|
* @param perf - The perf state.
|
|
22139
22361
|
*/
|
|
22140
22362
|
function beginAgent(perf) {
|
|
22141
|
-
if (Number.isNaN(perf.agentStart)) perf.agentStart = pageNow();
|
|
22363
|
+
if (Number.isNaN(perf.agentStart)) perf.agentStart = pageNow$1();
|
|
22142
22364
|
}
|
|
22143
22365
|
/**
|
|
22144
22366
|
* Closes the open agent span: its time goes into the agent phase of the frame interval it falls in, and to
|
|
@@ -22149,7 +22371,7 @@ function beginAgent(perf) {
|
|
|
22149
22371
|
function endAgent(pc) {
|
|
22150
22372
|
const { perf } = pc;
|
|
22151
22373
|
if (Number.isNaN(perf.agentStart)) return;
|
|
22152
|
-
const span = pageNow() - perf.agentStart;
|
|
22374
|
+
const span = pageNow$1() - perf.agentStart;
|
|
22153
22375
|
perf.agentStart = NaN;
|
|
22154
22376
|
perf.agentMs += span;
|
|
22155
22377
|
pc.ctx.deps.time.chargeAgent(span);
|
|
@@ -22192,7 +22414,7 @@ function attachFirst(pc) {
|
|
|
22192
22414
|
writeEvent(pc, "device-restored", { kind: host.kind() });
|
|
22193
22415
|
});
|
|
22194
22416
|
host.onTrim((reason, freedMb) => {
|
|
22195
|
-
perf.problems.trimAt = pageNow();
|
|
22417
|
+
perf.problems.trimAt = pageNow$1();
|
|
22196
22418
|
writeEvent(pc, "pool-trim", {
|
|
22197
22419
|
reason,
|
|
22198
22420
|
freedMb
|
|
@@ -22534,6 +22756,17 @@ function createMonitorApi(ctx, deps) {
|
|
|
22534
22756
|
}
|
|
22535
22757
|
if (pc === void 0) sinks.inFrame = false;
|
|
22536
22758
|
};
|
|
22759
|
+
/**
|
|
22760
|
+
* The agent span: `beginAgent` and `endAgent`, also the span the captures are taken in.
|
|
22761
|
+
*/
|
|
22762
|
+
const agentSpan = {
|
|
22763
|
+
begin: () => {
|
|
22764
|
+
if (typeof __MOKU_GAME_AGENT__ !== "undefined" && __MOKU_GAME_AGENT__ && pc !== void 0) beginAgent(pc.perf);
|
|
22765
|
+
},
|
|
22766
|
+
end: () => {
|
|
22767
|
+
if (typeof __MOKU_GAME_AGENT__ !== "undefined" && __MOKU_GAME_AGENT__ && pc !== void 0) endAgent(pc);
|
|
22768
|
+
}
|
|
22769
|
+
};
|
|
22537
22770
|
return {
|
|
22538
22771
|
stats: () => {
|
|
22539
22772
|
const usage = deps.host.textures();
|
|
@@ -22587,12 +22820,8 @@ function createMonitorApi(ctx, deps) {
|
|
|
22587
22820
|
event: (name, detail = NO_DETAIL) => {
|
|
22588
22821
|
if (typeof __MOKU_GAME_AGENT__ !== "undefined" && __MOKU_GAME_AGENT__ && pc !== void 0) writeEvent(pc, name, detail);
|
|
22589
22822
|
},
|
|
22590
|
-
beginAgent:
|
|
22591
|
-
|
|
22592
|
-
},
|
|
22593
|
-
endAgent: () => {
|
|
22594
|
-
if (typeof __MOKU_GAME_AGENT__ !== "undefined" && __MOKU_GAME_AGENT__ && pc !== void 0) endAgent(pc);
|
|
22595
|
-
},
|
|
22823
|
+
beginAgent: agentSpan.begin,
|
|
22824
|
+
endAgent: agentSpan.end,
|
|
22596
22825
|
sections: (next) => {
|
|
22597
22826
|
if (typeof __MOKU_GAME_AGENT__ !== "undefined" && __MOKU_GAME_AGENT__ && pc !== void 0) {
|
|
22598
22827
|
if (next === void 0) return pc.perf.sections;
|
|
@@ -22626,7 +22855,7 @@ function createMonitorApi(ctx, deps) {
|
|
|
22626
22855
|
state.lastDrawn = drawn;
|
|
22627
22856
|
notePasses(drawn);
|
|
22628
22857
|
if (typeof __MOKU_GAME_AGENT__ !== "undefined" && __MOKU_GAME_AGENT__ && pc !== void 0) pc.perf.drawn = drawn;
|
|
22629
|
-
if (drawn) serveCaptures(mctx);
|
|
22858
|
+
if (drawn) serveCaptures(mctx, agentSpan);
|
|
22630
22859
|
},
|
|
22631
22860
|
waiting: () => state.captures.length > 0,
|
|
22632
22861
|
changed: (change) => {
|
|
@@ -22647,7 +22876,7 @@ function createMonitorApi(ctx, deps) {
|
|
|
22647
22876
|
},
|
|
22648
22877
|
flush: () => {
|
|
22649
22878
|
if (typeof __MOKU_GAME_AGENT__ !== "undefined" && __MOKU_GAME_AGENT__ && pc !== void 0) {
|
|
22650
|
-
pc.perf.staged[1] = pageNow();
|
|
22879
|
+
pc.perf.staged[1] = pageNow$1();
|
|
22651
22880
|
flushPerf(pc);
|
|
22652
22881
|
}
|
|
22653
22882
|
},
|
|
@@ -23728,7 +23957,7 @@ function variantsOf(sctx) {
|
|
|
23728
23957
|
* @param subject - The subject.
|
|
23729
23958
|
* @param variants - Its variants.
|
|
23730
23959
|
*/
|
|
23731
|
-
function enqueue(warm, subject, variants) {
|
|
23960
|
+
function enqueue$1(warm, subject, variants) {
|
|
23732
23961
|
for (const variant of variants) warm.queue.push({
|
|
23733
23962
|
subject,
|
|
23734
23963
|
variant
|
|
@@ -23770,7 +23999,7 @@ function abandon(warm) {
|
|
|
23770
23999
|
*
|
|
23771
24000
|
* @param sctx - Domain context of the sync module.
|
|
23772
24001
|
*/
|
|
23773
|
-
function startWarm$
|
|
24002
|
+
function startWarm$2(sctx) {
|
|
23774
24003
|
const state = sctx.ctx.state.sync;
|
|
23775
24004
|
const { warm } = state;
|
|
23776
24005
|
dropObjects(warm);
|
|
@@ -23781,12 +24010,12 @@ function startWarm$1(sctx) {
|
|
|
23781
24010
|
warm.failed = false;
|
|
23782
24011
|
if (!canWarm(sctx)) return;
|
|
23783
24012
|
const variants = variantsOf(sctx);
|
|
23784
|
-
for (const subject of CONTENT) enqueue(warm, subject, variants);
|
|
24013
|
+
for (const subject of CONTENT) enqueue$1(warm, subject, variants);
|
|
23785
24014
|
const [font] = state.fonts.keys();
|
|
23786
24015
|
if (font !== void 0) {
|
|
23787
24016
|
warm.textFont = font;
|
|
23788
24017
|
warm.textQueued = true;
|
|
23789
|
-
enqueue(warm, "text", variants);
|
|
24018
|
+
enqueue$1(warm, "text", variants);
|
|
23790
24019
|
}
|
|
23791
24020
|
for (const filter of warm.filters) {
|
|
23792
24021
|
const entry = warm.waiting.get(filter);
|
|
@@ -23795,7 +24024,7 @@ function startWarm$1(sctx) {
|
|
|
23795
24024
|
resolve: []
|
|
23796
24025
|
});
|
|
23797
24026
|
else entry.left = variants.length;
|
|
23798
|
-
enqueue(warm, filter, variants);
|
|
24027
|
+
enqueue$1(warm, filter, variants);
|
|
23799
24028
|
}
|
|
23800
24029
|
sctx.deps.demand.request();
|
|
23801
24030
|
}
|
|
@@ -23843,7 +24072,7 @@ function warmFilter(sctx, filter) {
|
|
|
23843
24072
|
entry.left = variants.length;
|
|
23844
24073
|
warm.filters.add(filter);
|
|
23845
24074
|
warm.waiting.set(filter, entry);
|
|
23846
|
-
enqueue(warm, filter, variants);
|
|
24075
|
+
enqueue$1(warm, filter, variants);
|
|
23847
24076
|
sctx.deps.demand.request();
|
|
23848
24077
|
}
|
|
23849
24078
|
return new Promise((resolve) => {
|
|
@@ -24153,6 +24382,419 @@ function clearFonts(state) {
|
|
|
24153
24382
|
state.fontCache = void 0;
|
|
24154
24383
|
}
|
|
24155
24384
|
//#endregion
|
|
24385
|
+
//#region src/plugins/renderer/sync/outline.ts
|
|
24386
|
+
/** Above every child of the wrapper, whatever `Order` a child carries. */
|
|
24387
|
+
const OUTLINE_Z = Number.MAX_SAFE_INTEGER;
|
|
24388
|
+
const CYAN = 65535;
|
|
24389
|
+
const RED = 16711680;
|
|
24390
|
+
/**
|
|
24391
|
+
* Writes the slice widths a texture asks for, in the units it is drawn in: its default borders divided
|
|
24392
|
+
* by the resolution of its source. A texture without borders gets 0 on every side, never Pixi's 10. Written in place,
|
|
24393
|
+
* so a nine-slice write allocates nothing.
|
|
24394
|
+
*
|
|
24395
|
+
* @param texture - The texture a nine-slice draws, or `undefined` while nothing can draw.
|
|
24396
|
+
* @param out - The widths to write.
|
|
24397
|
+
* @returns `out`.
|
|
24398
|
+
*/
|
|
24399
|
+
function bordersInto(texture, out) {
|
|
24400
|
+
const borders = texture?.defaultBorders;
|
|
24401
|
+
if (texture === void 0 || borders === void 0) {
|
|
24402
|
+
out.left = 0;
|
|
24403
|
+
out.top = 0;
|
|
24404
|
+
out.right = 0;
|
|
24405
|
+
out.bottom = 0;
|
|
24406
|
+
return out;
|
|
24407
|
+
}
|
|
24408
|
+
const resolution = texture.source.resolution > 0 ? texture.source.resolution : 1;
|
|
24409
|
+
out.left = borders.left / resolution;
|
|
24410
|
+
out.top = borders.top / resolution;
|
|
24411
|
+
out.right = borders.right / resolution;
|
|
24412
|
+
out.bottom = borders.bottom / resolution;
|
|
24413
|
+
return out;
|
|
24414
|
+
}
|
|
24415
|
+
/**
|
|
24416
|
+
* The factor Pixi shrinks the corners of a nine-slice by when two of them would overlap.
|
|
24417
|
+
*
|
|
24418
|
+
* @param size - The drawn size.
|
|
24419
|
+
* @param size.width - Drawn width.
|
|
24420
|
+
* @param size.height - Drawn height.
|
|
24421
|
+
* @param borders - The slice widths.
|
|
24422
|
+
* @returns 1 when the corners fit, less when they overlap.
|
|
24423
|
+
* @example
|
|
24424
|
+
* ```ts
|
|
24425
|
+
* sliceScale({ width: 100, height: 200 }, { left: 72, top: 76, right: 72, bottom: 76 }); // 0.6944
|
|
24426
|
+
* ```
|
|
24427
|
+
*/
|
|
24428
|
+
function sliceScale(size, borders) {
|
|
24429
|
+
const across = borders.left + borders.right;
|
|
24430
|
+
const down = borders.top + borders.bottom;
|
|
24431
|
+
const scaleX = across > 0 && size.width < across ? size.width / across : 1;
|
|
24432
|
+
const scaleY = down > 0 && size.height < down ? size.height / down : 1;
|
|
24433
|
+
return Math.min(scaleX, scaleY);
|
|
24434
|
+
}
|
|
24435
|
+
/**
|
|
24436
|
+
* Strokes the bounds of a nine-slice and the four lines Pixi cuts it at, into the wrapper of its
|
|
24437
|
+
* view: cyan, red when the corners overlap or the texture is missing. The graphics is kept on the
|
|
24438
|
+
* view and redrawn in place.
|
|
24439
|
+
*
|
|
24440
|
+
* @param pixi - The Pixi module the renderer loaded.
|
|
24441
|
+
* @param wrapper - The wrapper of the view, which carries its pose.
|
|
24442
|
+
* @param view - The view of the nine-slice.
|
|
24443
|
+
* @param shape - Size, borders and whether the texture is missing.
|
|
24444
|
+
*/
|
|
24445
|
+
function drawOutline(pixi, wrapper, view, shape) {
|
|
24446
|
+
const outline = view.outline ?? new pixi.Graphics();
|
|
24447
|
+
const { width, height, borders } = shape;
|
|
24448
|
+
const scale = sliceScale(shape, borders);
|
|
24449
|
+
const left = borders.left * scale;
|
|
24450
|
+
const right = width - borders.right * scale;
|
|
24451
|
+
const top = borders.top * scale;
|
|
24452
|
+
const bottom = height - borders.bottom * scale;
|
|
24453
|
+
outline.label = `outline#${shape.entity}`;
|
|
24454
|
+
outline.zIndex = OUTLINE_Z;
|
|
24455
|
+
outline.clear();
|
|
24456
|
+
outline.rect(0, 0, width, height).moveTo(left, 0).lineTo(left, height).moveTo(right, 0).lineTo(right, height).moveTo(0, top).lineTo(width, top).moveTo(0, bottom).lineTo(width, bottom);
|
|
24457
|
+
outline.stroke({
|
|
24458
|
+
color: shape.missing || scale < 1 ? RED : CYAN,
|
|
24459
|
+
width: 1,
|
|
24460
|
+
pixelLine: true
|
|
24461
|
+
});
|
|
24462
|
+
if (outline.parent !== wrapper) wrapper.addChild(outline);
|
|
24463
|
+
view.outline = outline;
|
|
24464
|
+
}
|
|
24465
|
+
//#endregion
|
|
24466
|
+
//#region src/plugins/renderer/sync/hollow.ts
|
|
24467
|
+
/** The vertices across and down: the four cut lines of a nine-slice on each axis. */
|
|
24468
|
+
const SIDE = 4;
|
|
24469
|
+
/** The cells of the 3 × 3 slicing on each axis. */
|
|
24470
|
+
const CELLS = 3;
|
|
24471
|
+
/** The cell left out, row by row: the centre, (1, 1). */
|
|
24472
|
+
const CENTRE = 4;
|
|
24473
|
+
/** Indices of one quad: two triangles. */
|
|
24474
|
+
const QUAD = 6;
|
|
24475
|
+
/**
|
|
24476
|
+
* The index buffer of the rim: the two triangles of every cell of the 3 × 3 slicing but the centre, in Pixi's
|
|
24477
|
+
* `PlaneGeometry` winding. Static: written once per geometry.
|
|
24478
|
+
*
|
|
24479
|
+
* @returns 48 indices into the 16 vertices.
|
|
24480
|
+
* @example
|
|
24481
|
+
* ```ts
|
|
24482
|
+
* rimIndices().length; // 48
|
|
24483
|
+
* ```
|
|
24484
|
+
*/
|
|
24485
|
+
function rimIndices() {
|
|
24486
|
+
const indices = /* @__PURE__ */ new Uint32Array(48);
|
|
24487
|
+
let at = 0;
|
|
24488
|
+
for (let cell = 0; cell < 9; cell += 1) {
|
|
24489
|
+
if (cell === CENTRE) continue;
|
|
24490
|
+
const topLeft = Math.floor(cell / CELLS) * SIDE + cell % CELLS;
|
|
24491
|
+
const bottomLeft = topLeft + SIDE;
|
|
24492
|
+
indices.set([
|
|
24493
|
+
topLeft,
|
|
24494
|
+
topLeft + 1,
|
|
24495
|
+
bottomLeft,
|
|
24496
|
+
topLeft + 1,
|
|
24497
|
+
bottomLeft + 1,
|
|
24498
|
+
bottomLeft
|
|
24499
|
+
], at);
|
|
24500
|
+
at += QUAD;
|
|
24501
|
+
}
|
|
24502
|
+
return indices;
|
|
24503
|
+
}
|
|
24504
|
+
/**
|
|
24505
|
+
* Writes one row of the grid: its four vertices, one per cut line across, at the same `y`.
|
|
24506
|
+
*
|
|
24507
|
+
* @param target - The 32 numbers of the grid: x and y of each vertex, row by row.
|
|
24508
|
+
* @param row - The row, 0 to 3.
|
|
24509
|
+
* @param y - The row's line down.
|
|
24510
|
+
* @param across - The cut lines across.
|
|
24511
|
+
*/
|
|
24512
|
+
function writeRow(target, row, y, across) {
|
|
24513
|
+
const at = row * SIDE * 2;
|
|
24514
|
+
target[at] = across.start;
|
|
24515
|
+
target[at + 1] = y;
|
|
24516
|
+
target[at + 2] = across.near;
|
|
24517
|
+
target[at + 3] = y;
|
|
24518
|
+
target[at + 4] = across.far;
|
|
24519
|
+
target[at + 5] = y;
|
|
24520
|
+
target[at + 6] = across.end;
|
|
24521
|
+
target[at + 7] = y;
|
|
24522
|
+
}
|
|
24523
|
+
/**
|
|
24524
|
+
* Writes the 4 × 4 grid of the cut lines in place: Pixi's vertex order, row by row.
|
|
24525
|
+
*
|
|
24526
|
+
* @param target - The 32 numbers of the grid.
|
|
24527
|
+
* @param across - The cut lines across.
|
|
24528
|
+
* @param down - The cut lines down.
|
|
24529
|
+
*/
|
|
24530
|
+
function writeGrid(target, across, down) {
|
|
24531
|
+
writeRow(target, 0, down.start, across);
|
|
24532
|
+
writeRow(target, 1, down.near, across);
|
|
24533
|
+
writeRow(target, 2, down.far, across);
|
|
24534
|
+
writeRow(target, 3, down.end, across);
|
|
24535
|
+
}
|
|
24536
|
+
/**
|
|
24537
|
+
* Makes the class of the rim-only nine-slice over one loaded Pixi module.
|
|
24538
|
+
*
|
|
24539
|
+
* @param pixi - The Pixi module the renderer loaded.
|
|
24540
|
+
* @returns The class.
|
|
24541
|
+
*/
|
|
24542
|
+
function createHollowClass(pixi) {
|
|
24543
|
+
/** A nine-slice that draws its rim alone: Pixi's mesh over the 16 vertices of the slicing and its eight border cells. */
|
|
24544
|
+
class HollowNineSlice extends pixi.Mesh {
|
|
24545
|
+
/** Tells the rim-only object from Pixi's `NineSliceSprite`. */
|
|
24546
|
+
hollow = true;
|
|
24547
|
+
/** The slice widths, in the units the panel is drawn in. */
|
|
24548
|
+
borders = {
|
|
24549
|
+
left: 0,
|
|
24550
|
+
top: 0,
|
|
24551
|
+
right: 0,
|
|
24552
|
+
bottom: 0
|
|
24553
|
+
};
|
|
24554
|
+
/** The cut lines across, scratch of the next write. */
|
|
24555
|
+
across = {
|
|
24556
|
+
start: 0,
|
|
24557
|
+
near: 0,
|
|
24558
|
+
far: 0,
|
|
24559
|
+
end: 0
|
|
24560
|
+
};
|
|
24561
|
+
/** The cut lines down, scratch of the next write. */
|
|
24562
|
+
down = {
|
|
24563
|
+
start: 0,
|
|
24564
|
+
near: 0,
|
|
24565
|
+
far: 0,
|
|
24566
|
+
end: 0
|
|
24567
|
+
};
|
|
24568
|
+
/** The panel's width the positions are laid out for. */
|
|
24569
|
+
boxWidth = 0;
|
|
24570
|
+
/** The panel's height the positions are laid out for. */
|
|
24571
|
+
boxHeight = 0;
|
|
24572
|
+
/** False while Pixi's constructor writes the first texture: the geometry does not exist yet. */
|
|
24573
|
+
built = false;
|
|
24574
|
+
/**
|
|
24575
|
+
* Builds the mesh over a geometry of its own, 0 × 0 with no border, its uvs cut for the texture.
|
|
24576
|
+
*
|
|
24577
|
+
* @param texture - The texture it draws first.
|
|
24578
|
+
*/
|
|
24579
|
+
constructor(texture) {
|
|
24580
|
+
super({
|
|
24581
|
+
geometry: new pixi.MeshGeometry({
|
|
24582
|
+
positions: /* @__PURE__ */ new Float32Array(32),
|
|
24583
|
+
uvs: /* @__PURE__ */ new Float32Array(32),
|
|
24584
|
+
indices: rimIndices()
|
|
24585
|
+
}),
|
|
24586
|
+
texture
|
|
24587
|
+
});
|
|
24588
|
+
this.built = true;
|
|
24589
|
+
this.layoutUvs();
|
|
24590
|
+
}
|
|
24591
|
+
/**
|
|
24592
|
+
* The width of the left border column.
|
|
24593
|
+
*
|
|
24594
|
+
* @returns Units.
|
|
24595
|
+
*/
|
|
24596
|
+
get leftWidth() {
|
|
24597
|
+
return this.borders.left;
|
|
24598
|
+
}
|
|
24599
|
+
/**
|
|
24600
|
+
* Sets the width of the left border column: the positions and the uvs are written again.
|
|
24601
|
+
*
|
|
24602
|
+
* @param value - Units.
|
|
24603
|
+
*/
|
|
24604
|
+
set leftWidth(value) {
|
|
24605
|
+
if (this.borders.left === value) return;
|
|
24606
|
+
this.borders.left = value;
|
|
24607
|
+
this.layoutAll();
|
|
24608
|
+
}
|
|
24609
|
+
/**
|
|
24610
|
+
* The height of the top border row.
|
|
24611
|
+
*
|
|
24612
|
+
* @returns Units.
|
|
24613
|
+
*/
|
|
24614
|
+
get topHeight() {
|
|
24615
|
+
return this.borders.top;
|
|
24616
|
+
}
|
|
24617
|
+
/**
|
|
24618
|
+
* Sets the height of the top border row: the positions and the uvs are written again.
|
|
24619
|
+
*
|
|
24620
|
+
* @param value - Units.
|
|
24621
|
+
*/
|
|
24622
|
+
set topHeight(value) {
|
|
24623
|
+
if (this.borders.top === value) return;
|
|
24624
|
+
this.borders.top = value;
|
|
24625
|
+
this.layoutAll();
|
|
24626
|
+
}
|
|
24627
|
+
/**
|
|
24628
|
+
* The width of the right border column.
|
|
24629
|
+
*
|
|
24630
|
+
* @returns Units.
|
|
24631
|
+
*/
|
|
24632
|
+
get rightWidth() {
|
|
24633
|
+
return this.borders.right;
|
|
24634
|
+
}
|
|
24635
|
+
/**
|
|
24636
|
+
* Sets the width of the right border column: the positions and the uvs are written again.
|
|
24637
|
+
*
|
|
24638
|
+
* @param value - Units.
|
|
24639
|
+
*/
|
|
24640
|
+
set rightWidth(value) {
|
|
24641
|
+
if (this.borders.right === value) return;
|
|
24642
|
+
this.borders.right = value;
|
|
24643
|
+
this.layoutAll();
|
|
24644
|
+
}
|
|
24645
|
+
/**
|
|
24646
|
+
* The height of the bottom border row.
|
|
24647
|
+
*
|
|
24648
|
+
* @returns Units.
|
|
24649
|
+
*/
|
|
24650
|
+
get bottomHeight() {
|
|
24651
|
+
return this.borders.bottom;
|
|
24652
|
+
}
|
|
24653
|
+
/**
|
|
24654
|
+
* Sets the height of the bottom border row: the positions and the uvs are written again.
|
|
24655
|
+
*
|
|
24656
|
+
* @param value - Units.
|
|
24657
|
+
*/
|
|
24658
|
+
set bottomHeight(value) {
|
|
24659
|
+
if (this.borders.bottom === value) return;
|
|
24660
|
+
this.borders.bottom = value;
|
|
24661
|
+
this.layoutAll();
|
|
24662
|
+
}
|
|
24663
|
+
/**
|
|
24664
|
+
* The width of the panel, as on a `NineSliceSprite`: its box, never a scale.
|
|
24665
|
+
*
|
|
24666
|
+
* @returns Units.
|
|
24667
|
+
*/
|
|
24668
|
+
get width() {
|
|
24669
|
+
return this.boxWidth;
|
|
24670
|
+
}
|
|
24671
|
+
/**
|
|
24672
|
+
* Sets the width of the panel: the positions are written again.
|
|
24673
|
+
*
|
|
24674
|
+
* @param value - Units.
|
|
24675
|
+
*/
|
|
24676
|
+
set width(value) {
|
|
24677
|
+
if (this.boxWidth === value) return;
|
|
24678
|
+
this.boxWidth = value;
|
|
24679
|
+
this.layoutPositions();
|
|
24680
|
+
}
|
|
24681
|
+
/**
|
|
24682
|
+
* The height of the panel, as on a `NineSliceSprite`: its box, never a scale.
|
|
24683
|
+
*
|
|
24684
|
+
* @returns Units.
|
|
24685
|
+
*/
|
|
24686
|
+
get height() {
|
|
24687
|
+
return this.boxHeight;
|
|
24688
|
+
}
|
|
24689
|
+
/**
|
|
24690
|
+
* Sets the height of the panel: the positions are written again.
|
|
24691
|
+
*
|
|
24692
|
+
* @param value - Units.
|
|
24693
|
+
*/
|
|
24694
|
+
set height(value) {
|
|
24695
|
+
if (this.boxHeight === value) return;
|
|
24696
|
+
this.boxHeight = value;
|
|
24697
|
+
this.layoutPositions();
|
|
24698
|
+
}
|
|
24699
|
+
/**
|
|
24700
|
+
* The texture the rim is cut from.
|
|
24701
|
+
*
|
|
24702
|
+
* @returns The texture.
|
|
24703
|
+
*/
|
|
24704
|
+
get texture() {
|
|
24705
|
+
return super.texture;
|
|
24706
|
+
}
|
|
24707
|
+
/**
|
|
24708
|
+
* Sets the texture as Pixi's mesh does; the uvs are cut for its frame.
|
|
24709
|
+
*
|
|
24710
|
+
* @param value - The texture.
|
|
24711
|
+
*/
|
|
24712
|
+
set texture(value) {
|
|
24713
|
+
super.texture = value;
|
|
24714
|
+
if (this.built) this.layoutUvs();
|
|
24715
|
+
}
|
|
24716
|
+
/**
|
|
24717
|
+
* Frees the mesh as Pixi does, and its own geometry with it.
|
|
24718
|
+
*
|
|
24719
|
+
* @param options - Pixi's destroy options; a texture is freed only when they ask.
|
|
24720
|
+
*/
|
|
24721
|
+
destroy(options) {
|
|
24722
|
+
if (this.destroyed) return;
|
|
24723
|
+
const geometry = this.geometry;
|
|
24724
|
+
super.destroy(options);
|
|
24725
|
+
geometry.destroy(true);
|
|
24726
|
+
}
|
|
24727
|
+
/** Writes the positions and the uvs again: a border changed. */
|
|
24728
|
+
layoutAll() {
|
|
24729
|
+
this.layoutPositions();
|
|
24730
|
+
this.layoutUvs();
|
|
24731
|
+
}
|
|
24732
|
+
/**
|
|
24733
|
+
* Writes the 16 positions in place: the cut lines at the borders, all four shrunk by one factor when two corners
|
|
24734
|
+
* would overlap, as Pixi's `NineSliceGeometry` shrinks them.
|
|
24735
|
+
*/
|
|
24736
|
+
layoutPositions() {
|
|
24737
|
+
const across = this.across;
|
|
24738
|
+
const down = this.down;
|
|
24739
|
+
const borders = this.borders;
|
|
24740
|
+
const scale = sliceScale(this, borders);
|
|
24741
|
+
across.start = 0;
|
|
24742
|
+
across.near = borders.left * scale;
|
|
24743
|
+
across.far = this.boxWidth - borders.right * scale;
|
|
24744
|
+
across.end = this.boxWidth;
|
|
24745
|
+
down.start = 0;
|
|
24746
|
+
down.near = borders.top * scale;
|
|
24747
|
+
down.far = this.boxHeight - borders.bottom * scale;
|
|
24748
|
+
down.end = this.boxHeight;
|
|
24749
|
+
writeGrid(this.geometry.positions, across, down);
|
|
24750
|
+
this.geometry.getBuffer("aPosition").update();
|
|
24751
|
+
}
|
|
24752
|
+
/**
|
|
24753
|
+
* Writes the 16 uvs in place: the texture's frame (its trim, when it has one) cut at the unscaled borders, as
|
|
24754
|
+
* Pixi's `NineSliceGeometry` cuts it. Pixi maps them into an atlas page when it batches the mesh.
|
|
24755
|
+
*/
|
|
24756
|
+
layoutUvs() {
|
|
24757
|
+
const across = this.across;
|
|
24758
|
+
const down = this.down;
|
|
24759
|
+
const borders = this.borders;
|
|
24760
|
+
const texture = this.texture;
|
|
24761
|
+
const width = texture.width;
|
|
24762
|
+
const height = texture.height;
|
|
24763
|
+
const trim = texture.trim;
|
|
24764
|
+
const x = trim?.x ?? 0;
|
|
24765
|
+
const y = trim?.y ?? 0;
|
|
24766
|
+
const u0 = x / width;
|
|
24767
|
+
const v0 = y / height;
|
|
24768
|
+
const u1 = (x + (trim?.width ?? width)) / width;
|
|
24769
|
+
const v1 = (y + (trim?.height ?? height)) / height;
|
|
24770
|
+
const texelU = 1 / width;
|
|
24771
|
+
const texelV = 1 / height;
|
|
24772
|
+
across.start = u0;
|
|
24773
|
+
across.near = u0 + texelU * borders.left;
|
|
24774
|
+
across.far = u1 - texelU * borders.right;
|
|
24775
|
+
across.end = u1;
|
|
24776
|
+
down.start = v0;
|
|
24777
|
+
down.near = v0 + texelV * borders.top;
|
|
24778
|
+
down.far = v1 - texelV * borders.bottom;
|
|
24779
|
+
down.end = v1;
|
|
24780
|
+
writeGrid(this.geometry.uvs, across, down);
|
|
24781
|
+
this.geometry.getBuffer("aUV").update();
|
|
24782
|
+
}
|
|
24783
|
+
}
|
|
24784
|
+
return HollowNineSlice;
|
|
24785
|
+
}
|
|
24786
|
+
/**
|
|
24787
|
+
* Builds a rim-only nine-slice of Pixi's white texture, its class made at the first one over the loaded module.
|
|
24788
|
+
*
|
|
24789
|
+
* @param state - The sync branch of the plugin state, which keeps the class.
|
|
24790
|
+
* @param pixi - The Pixi module the renderer loaded.
|
|
24791
|
+
* @returns The object.
|
|
24792
|
+
*/
|
|
24793
|
+
function makeHollow(state, pixi) {
|
|
24794
|
+
state.hollowClass ??= createHollowClass(pixi);
|
|
24795
|
+
return new state.hollowClass(pixi.Texture.WHITE);
|
|
24796
|
+
}
|
|
24797
|
+
//#endregion
|
|
24156
24798
|
//#region src/plugins/renderer/sync/labels.ts
|
|
24157
24799
|
/**
|
|
24158
24800
|
* Builds the label of one view.
|
|
@@ -24189,15 +24831,25 @@ function isGraphics(object) {
|
|
|
24189
24831
|
return "roundRect" in object;
|
|
24190
24832
|
}
|
|
24191
24833
|
/**
|
|
24192
|
-
* Tells whether a display object
|
|
24834
|
+
* Tells whether a display object draws a nine-slice: Pixi's `NineSliceSprite`, or the engine's rim-only mesh of a
|
|
24835
|
+
* `hollow` one. Both carry the slice widths.
|
|
24193
24836
|
*
|
|
24194
24837
|
* @param object - The display object.
|
|
24195
|
-
* @returns True for
|
|
24838
|
+
* @returns True for either nine-slice object.
|
|
24196
24839
|
*/
|
|
24197
24840
|
function isNineSlice(object) {
|
|
24198
24841
|
return "leftWidth" in object;
|
|
24199
24842
|
}
|
|
24200
24843
|
/**
|
|
24844
|
+
* Tells whether a display object is the engine's rim-only nine-slice (F59).
|
|
24845
|
+
*
|
|
24846
|
+
* @param object - The display object.
|
|
24847
|
+
* @returns True for the hollow mesh, false for Pixi's `NineSliceSprite` and every other object.
|
|
24848
|
+
*/
|
|
24849
|
+
function isHollow(object) {
|
|
24850
|
+
return "hollow" in object;
|
|
24851
|
+
}
|
|
24852
|
+
/**
|
|
24201
24853
|
* Takes a display object out of the Pixi tree. Pixi containers are not DOM nodes, so the DOM
|
|
24202
24854
|
* helper the linter suggests does not exist on them.
|
|
24203
24855
|
*
|
|
@@ -24248,18 +24900,20 @@ function dropOutline(view) {
|
|
|
24248
24900
|
view.outline = void 0;
|
|
24249
24901
|
}
|
|
24250
24902
|
/**
|
|
24251
|
-
* The pool an object belongs to: its class and the texture it draws.
|
|
24903
|
+
* The pool an object belongs to: its class and the texture it draws. A rim-only nine-slice has a pool of its own, so
|
|
24904
|
+
* a filled panel never gets a hollow object back, nor the other way round.
|
|
24252
24905
|
*
|
|
24253
24906
|
* @param kind - Which component gave the entity its display object.
|
|
24254
24907
|
* @param textureKey - The asset key.
|
|
24908
|
+
* @param hollow - True for the rim-only object of a `NineSlice` with `hollow: true`.
|
|
24255
24909
|
* @returns The pool key.
|
|
24256
24910
|
* @example
|
|
24257
24911
|
* ```ts
|
|
24258
|
-
* poolKeyOf("
|
|
24912
|
+
* poolKeyOf("NineSlice", "glass.frost", true); // "NineSlice.hollow:glass.frost"
|
|
24259
24913
|
* ```
|
|
24260
24914
|
*/
|
|
24261
|
-
function poolKeyOf(kind, textureKey) {
|
|
24262
|
-
return `${kind}:${textureKey}`;
|
|
24915
|
+
function poolKeyOf(kind, textureKey, hollow) {
|
|
24916
|
+
return hollow ? `${kind}.hollow:${textureKey}` : `${kind}:${textureKey}`;
|
|
24263
24917
|
}
|
|
24264
24918
|
/**
|
|
24265
24919
|
* Brings the object of a view that left back to the state a fresh one has: detached, drawn, opaque, unmoved, white.
|
|
@@ -24269,9 +24923,17 @@ function poolKeyOf(kind, textureKey) {
|
|
|
24269
24923
|
* @param view - The view whose object goes back to its pool; its wrapper is gone already.
|
|
24270
24924
|
*/
|
|
24271
24925
|
function resetObject(view) {
|
|
24272
|
-
|
|
24273
|
-
detach$1(object);
|
|
24926
|
+
detach$1(view.object);
|
|
24274
24927
|
clearHidden(view);
|
|
24928
|
+
resetNode(view.object);
|
|
24929
|
+
}
|
|
24930
|
+
/**
|
|
24931
|
+
* Brings a detached object back to a fresh one's pose and look: drawn, opaque, unmoved, white for a sprite and a
|
|
24932
|
+
* graphics.
|
|
24933
|
+
*
|
|
24934
|
+
* @param object - The object, out of the tree.
|
|
24935
|
+
*/
|
|
24936
|
+
function resetNode(object) {
|
|
24275
24937
|
object.visible = true;
|
|
24276
24938
|
object.alpha = 1;
|
|
24277
24939
|
object.rotation = 0;
|
|
@@ -24321,7 +24983,6 @@ function oldestPool(state) {
|
|
|
24321
24983
|
* @param view - The view that left.
|
|
24322
24984
|
*/
|
|
24323
24985
|
function release$1(sctx, view) {
|
|
24324
|
-
const state = sctx.ctx.state.sync;
|
|
24325
24986
|
dropMask(view);
|
|
24326
24987
|
dropOutline(view);
|
|
24327
24988
|
clearFilters(view.object);
|
|
@@ -24344,15 +25005,50 @@ function release$1(sctx, view) {
|
|
|
24344
25005
|
view.display?.adapter.destroy(view.object);
|
|
24345
25006
|
return;
|
|
24346
25007
|
}
|
|
24347
|
-
|
|
24348
|
-
if (groups.has(view.object)) {
|
|
24349
|
-
view.object.disableRenderGroup();
|
|
24350
|
-
groups.delete(view.object);
|
|
24351
|
-
}
|
|
25008
|
+
dropGroup(sctx, view.object);
|
|
24352
25009
|
resetObject(view);
|
|
24353
|
-
|
|
24354
|
-
|
|
24355
|
-
|
|
25010
|
+
store$1(sctx, view.object, view.poolKey);
|
|
25011
|
+
}
|
|
25012
|
+
/**
|
|
25013
|
+
* Puts an object a view no longer draws with back into a pool, while the view goes on with another one: the
|
|
25014
|
+
* nine-slice whose `hollow` flipped (F59). Reset as `release` resets a view's object; its view keeps its hidden
|
|
25015
|
+
* reasons, which hang on the view's wrapper.
|
|
25016
|
+
*
|
|
25017
|
+
* @param sctx - Domain context of the sync module.
|
|
25018
|
+
* @param object - The object, still in the view's wrapper.
|
|
25019
|
+
* @param poolKey - The pool it belongs to.
|
|
25020
|
+
*/
|
|
25021
|
+
function releaseObject(sctx, object, poolKey) {
|
|
25022
|
+
dropGroup(sctx, object);
|
|
25023
|
+
detach$1(object);
|
|
25024
|
+
resetNode(object);
|
|
25025
|
+
store$1(sctx, object, poolKey);
|
|
25026
|
+
}
|
|
25027
|
+
/**
|
|
25028
|
+
* Takes away the render group the kept cache made of an object (spec 23 P9.3), before it is pooled.
|
|
25029
|
+
*
|
|
25030
|
+
* @param sctx - Domain context of the sync module.
|
|
25031
|
+
* @param object - The object.
|
|
25032
|
+
*/
|
|
25033
|
+
function dropGroup(sctx, object) {
|
|
25034
|
+
const groups = sctx.ctx.state.kept.madeGroups;
|
|
25035
|
+
if (!groups.has(object)) return;
|
|
25036
|
+
object.disableRenderGroup();
|
|
25037
|
+
groups.delete(object);
|
|
25038
|
+
}
|
|
25039
|
+
/**
|
|
25040
|
+
* Pushes a reset object into its pool and evicts the one that waited longest while the pools hold more than
|
|
25041
|
+
* `poolLimit`.
|
|
25042
|
+
*
|
|
25043
|
+
* @param sctx - Domain context of the sync module.
|
|
25044
|
+
* @param object - The reset object.
|
|
25045
|
+
* @param poolKey - Its pool.
|
|
25046
|
+
*/
|
|
25047
|
+
function store$1(sctx, object, poolKey) {
|
|
25048
|
+
const state = sctx.ctx.state.sync;
|
|
25049
|
+
const pool = state.pools.get(poolKey) ?? emptyPool();
|
|
25050
|
+
pool.push(object);
|
|
25051
|
+
state.pools.set(poolKey, pool);
|
|
24356
25052
|
state.pooled += 1;
|
|
24357
25053
|
while (state.pooled > sctx.ctx.config.poolLimit) {
|
|
24358
25054
|
const oldest = oldestPool(state);
|
|
@@ -24363,21 +25059,32 @@ function release$1(sctx, view) {
|
|
|
24363
25059
|
}
|
|
24364
25060
|
/**
|
|
24365
25061
|
* Destroys the pooled objects that draw one of these keys, so a bundle that left frees its GPU
|
|
24366
|
-
* memory instead of waiting for a reuse that resolves nothing.
|
|
25062
|
+
* memory instead of waiting for a reuse that resolves nothing: sprites, nine-slices and rim-only nine-slices.
|
|
24367
25063
|
*
|
|
24368
25064
|
* @param state - The sync branch of the plugin state.
|
|
24369
25065
|
* @param keys - The asset keys that went stale.
|
|
24370
25066
|
*/
|
|
24371
25067
|
function dropPooled(state, keys) {
|
|
24372
|
-
for (const key of keys)
|
|
24373
|
-
|
|
24374
|
-
|
|
24375
|
-
|
|
24376
|
-
state.pooled -= pool.length;
|
|
24377
|
-
state.pools.delete(poolKeyOf(kind, key));
|
|
25068
|
+
for (const key of keys) {
|
|
25069
|
+
dropPool(state, poolKeyOf("Sprite", key, false));
|
|
25070
|
+
dropPool(state, poolKeyOf("NineSlice", key, false));
|
|
25071
|
+
dropPool(state, poolKeyOf("NineSlice", key, true));
|
|
24378
25072
|
}
|
|
24379
25073
|
}
|
|
24380
25074
|
/**
|
|
25075
|
+
* Destroys one pool and everything in it.
|
|
25076
|
+
*
|
|
25077
|
+
* @param state - The sync branch of the plugin state.
|
|
25078
|
+
* @param poolKey - The pool.
|
|
25079
|
+
*/
|
|
25080
|
+
function dropPool(state, poolKey) {
|
|
25081
|
+
const pool = state.pools.get(poolKey);
|
|
25082
|
+
if (pool === void 0) return;
|
|
25083
|
+
for (const object of pool) object.destroy({ texture: false });
|
|
25084
|
+
state.pooled -= pool.length;
|
|
25085
|
+
state.pools.delete(poolKey);
|
|
25086
|
+
}
|
|
25087
|
+
/**
|
|
24381
25088
|
* Destroys everything the pools hold. Works on the state alone, because `onStop` has no context.
|
|
24382
25089
|
*
|
|
24383
25090
|
* @param state - The sync branch of the plugin state.
|
|
@@ -24543,85 +25250,6 @@ function clearLayers(state) {
|
|
|
24543
25250
|
state.hudLayer = void 0;
|
|
24544
25251
|
}
|
|
24545
25252
|
//#endregion
|
|
24546
|
-
//#region src/plugins/renderer/sync/outline.ts
|
|
24547
|
-
/** Above every child of the wrapper, whatever `Order` a child carries. */
|
|
24548
|
-
const OUTLINE_Z = Number.MAX_SAFE_INTEGER;
|
|
24549
|
-
const CYAN = 65535;
|
|
24550
|
-
const RED = 16711680;
|
|
24551
|
-
/**
|
|
24552
|
-
* The slice widths a texture asks for, in the units it is drawn in: its default borders divided
|
|
24553
|
-
* by the resolution of its source. A texture without borders gets 0 on every side, never Pixi's 10.
|
|
24554
|
-
*
|
|
24555
|
-
* @param texture - The texture a nine-slice draws, or `undefined` while nothing can draw.
|
|
24556
|
-
* @returns The four widths.
|
|
24557
|
-
*/
|
|
24558
|
-
function bordersOf(texture) {
|
|
24559
|
-
const borders = texture?.defaultBorders;
|
|
24560
|
-
if (texture === void 0 || borders === void 0) return {
|
|
24561
|
-
left: 0,
|
|
24562
|
-
top: 0,
|
|
24563
|
-
right: 0,
|
|
24564
|
-
bottom: 0
|
|
24565
|
-
};
|
|
24566
|
-
const resolution = texture.source.resolution > 0 ? texture.source.resolution : 1;
|
|
24567
|
-
return {
|
|
24568
|
-
left: borders.left / resolution,
|
|
24569
|
-
top: borders.top / resolution,
|
|
24570
|
-
right: borders.right / resolution,
|
|
24571
|
-
bottom: borders.bottom / resolution
|
|
24572
|
-
};
|
|
24573
|
-
}
|
|
24574
|
-
/**
|
|
24575
|
-
* The factor Pixi shrinks the corners of a nine-slice by when two of them would overlap.
|
|
24576
|
-
*
|
|
24577
|
-
* @param size - The drawn size.
|
|
24578
|
-
* @param size.width - Drawn width.
|
|
24579
|
-
* @param size.height - Drawn height.
|
|
24580
|
-
* @param borders - The slice widths.
|
|
24581
|
-
* @returns 1 when the corners fit, less when they overlap.
|
|
24582
|
-
* @example
|
|
24583
|
-
* ```ts
|
|
24584
|
-
* sliceScale({ width: 100, height: 200 }, { left: 72, top: 76, right: 72, bottom: 76 }); // 0.6944
|
|
24585
|
-
* ```
|
|
24586
|
-
*/
|
|
24587
|
-
function sliceScale(size, borders) {
|
|
24588
|
-
const across = borders.left + borders.right;
|
|
24589
|
-
const down = borders.top + borders.bottom;
|
|
24590
|
-
const scaleX = across > 0 && size.width < across ? size.width / across : 1;
|
|
24591
|
-
const scaleY = down > 0 && size.height < down ? size.height / down : 1;
|
|
24592
|
-
return Math.min(scaleX, scaleY);
|
|
24593
|
-
}
|
|
24594
|
-
/**
|
|
24595
|
-
* Strokes the bounds of a nine-slice and the four lines Pixi cuts it at, into the wrapper of its
|
|
24596
|
-
* view: cyan, red when the corners overlap or the texture is missing. The graphics is kept on the
|
|
24597
|
-
* view and redrawn in place.
|
|
24598
|
-
*
|
|
24599
|
-
* @param pixi - The Pixi module the renderer loaded.
|
|
24600
|
-
* @param wrapper - The wrapper of the view, which carries its pose.
|
|
24601
|
-
* @param view - The view of the nine-slice.
|
|
24602
|
-
* @param shape - Size, borders and whether the texture is missing.
|
|
24603
|
-
*/
|
|
24604
|
-
function drawOutline(pixi, wrapper, view, shape) {
|
|
24605
|
-
const outline = view.outline ?? new pixi.Graphics();
|
|
24606
|
-
const { width, height, borders } = shape;
|
|
24607
|
-
const scale = sliceScale(shape, borders);
|
|
24608
|
-
const left = borders.left * scale;
|
|
24609
|
-
const right = width - borders.right * scale;
|
|
24610
|
-
const top = borders.top * scale;
|
|
24611
|
-
const bottom = height - borders.bottom * scale;
|
|
24612
|
-
outline.label = `outline#${shape.entity}`;
|
|
24613
|
-
outline.zIndex = OUTLINE_Z;
|
|
24614
|
-
outline.clear();
|
|
24615
|
-
outline.rect(0, 0, width, height).moveTo(left, 0).lineTo(left, height).moveTo(right, 0).lineTo(right, height).moveTo(0, top).lineTo(width, top).moveTo(0, bottom).lineTo(width, bottom);
|
|
24616
|
-
outline.stroke({
|
|
24617
|
-
color: shape.missing || scale < 1 ? RED : CYAN,
|
|
24618
|
-
width: 1,
|
|
24619
|
-
pixelLine: true
|
|
24620
|
-
});
|
|
24621
|
-
if (outline.parent !== wrapper) wrapper.addChild(outline);
|
|
24622
|
-
view.outline = outline;
|
|
24623
|
-
}
|
|
24624
|
-
//#endregion
|
|
24625
25253
|
//#region src/plugins/renderer/sync/overlay-range.ts
|
|
24626
25254
|
/** A range retaken for a mark in this many frames in a row is drawn live instead (O8.4; spec 23's `CHURN_LIMIT`). */
|
|
24627
25255
|
const RETAKE_STREAK = 3;
|
|
@@ -26085,6 +26713,144 @@ function destroyTexture(state, texture) {
|
|
|
26085
26713
|
texture.destroy(true);
|
|
26086
26714
|
}
|
|
26087
26715
|
//#endregion
|
|
26716
|
+
//#region src/plugins/renderer/sync/upload.ts
|
|
26717
|
+
/** The calls of a source nobody waits for: none. */
|
|
26718
|
+
const NOBODY = Object.freeze([]);
|
|
26719
|
+
/**
|
|
26720
|
+
* The resolve of a waiter before its promise exists: answers nobody.
|
|
26721
|
+
*/
|
|
26722
|
+
function unanswered() {}
|
|
26723
|
+
/**
|
|
26724
|
+
* Creates the set of the sources uploaded on a device. It lives in its own non-exported function because lint rule L5
|
|
26725
|
+
* refuses a collection built inside an exported declaration.
|
|
26726
|
+
*
|
|
26727
|
+
* @returns An empty weak set.
|
|
26728
|
+
*/
|
|
26729
|
+
function emptyDone() {
|
|
26730
|
+
return /* @__PURE__ */ new WeakSet();
|
|
26731
|
+
}
|
|
26732
|
+
/**
|
|
26733
|
+
* Counts one source for a call: queued once whoever names it first, waited for once by each call, however many of its
|
|
26734
|
+
* textures share it. A source uploaded on this device, or destroyed, is not waited for.
|
|
26735
|
+
*
|
|
26736
|
+
* @param upload - The upload branch of the sync state.
|
|
26737
|
+
* @param source - The source of one texture of the call.
|
|
26738
|
+
* @param waiter - The call.
|
|
26739
|
+
*/
|
|
26740
|
+
function enqueue(upload, source, waiter) {
|
|
26741
|
+
if (source.destroyed || upload.done.has(source)) return;
|
|
26742
|
+
let waiters = upload.waiting.get(source);
|
|
26743
|
+
if (waiters === void 0) {
|
|
26744
|
+
waiters = [];
|
|
26745
|
+
upload.waiting.set(source, waiters);
|
|
26746
|
+
upload.queue.push(source);
|
|
26747
|
+
}
|
|
26748
|
+
if (waiters.at(-1) === waiter) return;
|
|
26749
|
+
waiters.push(waiter);
|
|
26750
|
+
waiter.left += 1;
|
|
26751
|
+
}
|
|
26752
|
+
/**
|
|
26753
|
+
* Queues the sources of textures for the GPU; resolves true once each went through `initSource` (the body of
|
|
26754
|
+
* `TexturesApi.upload`). Answers false at once while nothing draws or with `uploads: 0`, and true at once when every
|
|
26755
|
+
* source is on this device already. Asks for a frame.
|
|
26756
|
+
*
|
|
26757
|
+
* @param sctx - Domain context of the sync module.
|
|
26758
|
+
* @param textures - The textures.
|
|
26759
|
+
* @returns Whether every source is on the GPU.
|
|
26760
|
+
*/
|
|
26761
|
+
function uploadTextures(sctx, textures) {
|
|
26762
|
+
const { upload } = sctx.ctx.state.sync;
|
|
26763
|
+
if (sctx.ctx.config.uploads === 0 || !sctx.deps.host.ready()) return Promise.resolve(false);
|
|
26764
|
+
const waiter = {
|
|
26765
|
+
left: 0,
|
|
26766
|
+
resolve: unanswered
|
|
26767
|
+
};
|
|
26768
|
+
for (const texture of textures) enqueue(upload, texture.source, waiter);
|
|
26769
|
+
if (waiter.left === 0) return Promise.resolve(true);
|
|
26770
|
+
sctx.deps.demand.request();
|
|
26771
|
+
return new Promise((resolve) => {
|
|
26772
|
+
waiter.resolve = resolve;
|
|
26773
|
+
});
|
|
26774
|
+
}
|
|
26775
|
+
/**
|
|
26776
|
+
* Uploads one source, the error of a throw logged: the source counts as done either way, so a failing one is logged
|
|
26777
|
+
* once and never stops the queue.
|
|
26778
|
+
*
|
|
26779
|
+
* @param sctx - Domain context of the sync module.
|
|
26780
|
+
* @param upload - The upload branch of the sync state.
|
|
26781
|
+
* @param source - The source.
|
|
26782
|
+
*/
|
|
26783
|
+
function put(sctx, upload, source) {
|
|
26784
|
+
try {
|
|
26785
|
+
sctx.deps.host.initSource(source);
|
|
26786
|
+
} catch (error) {
|
|
26787
|
+
sctx.ctx.log.warn("renderer:upload-failed", {
|
|
26788
|
+
source: source.label,
|
|
26789
|
+
error
|
|
26790
|
+
});
|
|
26791
|
+
}
|
|
26792
|
+
upload.done.add(source);
|
|
26793
|
+
}
|
|
26794
|
+
/**
|
|
26795
|
+
* Counts a source off for the calls that wait for it; a call whose last source it was answers true.
|
|
26796
|
+
*
|
|
26797
|
+
* @param upload - The upload branch of the sync state.
|
|
26798
|
+
* @param source - The source uploaded or skipped.
|
|
26799
|
+
*/
|
|
26800
|
+
function settle$2(upload, source) {
|
|
26801
|
+
const waiters = upload.waiting.get(source) ?? NOBODY;
|
|
26802
|
+
upload.waiting.delete(source);
|
|
26803
|
+
for (const waiter of waiters) {
|
|
26804
|
+
waiter.left -= 1;
|
|
26805
|
+
if (waiter.left === 0) waiter.resolve(true);
|
|
26806
|
+
}
|
|
26807
|
+
}
|
|
26808
|
+
/**
|
|
26809
|
+
* Uploads up to `renderer.uploads` queued sources before the stage pass of a drawn frame; a source destroyed while it
|
|
26810
|
+
* waited is skipped and costs nothing of the budget. A queue that still holds sources asks for the next frame; one
|
|
26811
|
+
* that ran out empties. Reads two numbers and returns while the queue is empty.
|
|
26812
|
+
*
|
|
26813
|
+
* @param sctx - Domain context of the sync module.
|
|
26814
|
+
* @returns True when a source went to the GPU in this frame, so the frame is no sample of the adaptive rate.
|
|
26815
|
+
*/
|
|
26816
|
+
function uploadStep(sctx) {
|
|
26817
|
+
const { upload } = sctx.ctx.state.sync;
|
|
26818
|
+
if (upload.head >= upload.queue.length) return false;
|
|
26819
|
+
const budget = sctx.ctx.config.uploads;
|
|
26820
|
+
let made = 0;
|
|
26821
|
+
while (made < budget && upload.head < upload.queue.length) {
|
|
26822
|
+
const source = upload.queue[upload.head];
|
|
26823
|
+
upload.head += 1;
|
|
26824
|
+
if (source === void 0) continue;
|
|
26825
|
+
if (!source.destroyed) {
|
|
26826
|
+
put(sctx, upload, source);
|
|
26827
|
+
made += 1;
|
|
26828
|
+
}
|
|
26829
|
+
settle$2(upload, source);
|
|
26830
|
+
}
|
|
26831
|
+
if (upload.head < upload.queue.length) {
|
|
26832
|
+
sctx.deps.demand.request();
|
|
26833
|
+
return made > 0;
|
|
26834
|
+
}
|
|
26835
|
+
upload.queue.length = 0;
|
|
26836
|
+
upload.head = 0;
|
|
26837
|
+
return made > 0;
|
|
26838
|
+
}
|
|
26839
|
+
/**
|
|
26840
|
+
* Ends the queue of a device that goes, from state alone (`onStop` has no context): every waiting call answers false,
|
|
26841
|
+
* the queue empties, and the sources uploaded on it are forgotten, since a new device holds none of them.
|
|
26842
|
+
*
|
|
26843
|
+
* @param state - The sync branch of the plugin state.
|
|
26844
|
+
*/
|
|
26845
|
+
function stopUploads(state) {
|
|
26846
|
+
const { upload } = state;
|
|
26847
|
+
for (const waiters of upload.waiting.values()) for (const waiter of waiters) waiter.resolve(false);
|
|
26848
|
+
upload.waiting.clear();
|
|
26849
|
+
upload.queue.length = 0;
|
|
26850
|
+
upload.head = 0;
|
|
26851
|
+
upload.done = emptyDone();
|
|
26852
|
+
}
|
|
26853
|
+
//#endregion
|
|
26088
26854
|
//#region src/plugins/renderer/sync/views.ts
|
|
26089
26855
|
/**
|
|
26090
26856
|
* @file renderer/sync — one view per entity: build it from the components, write every value,
|
|
@@ -26104,6 +26870,23 @@ const PLACEHOLDER_BOX = Object.freeze({
|
|
|
26104
26870
|
* sync pass).
|
|
26105
26871
|
*/
|
|
26106
26872
|
const LAYOUT = createSpriteLayout();
|
|
26873
|
+
/** The slice widths of the nine-slice being written: per write, reused, as `LAYOUT`. */
|
|
26874
|
+
const BORDERS = {
|
|
26875
|
+
left: 0,
|
|
26876
|
+
top: 0,
|
|
26877
|
+
right: 0,
|
|
26878
|
+
bottom: 0
|
|
26879
|
+
};
|
|
26880
|
+
/** What the outline of the nine-slice being written is drawn from, written in place, as `LAYOUT`. */
|
|
26881
|
+
const OUTLINE = {
|
|
26882
|
+
entity: 0,
|
|
26883
|
+
width: 0,
|
|
26884
|
+
height: 0,
|
|
26885
|
+
borders: BORDERS,
|
|
26886
|
+
missing: false
|
|
26887
|
+
};
|
|
26888
|
+
/** The box a clipping nine-slice masks its children with, as the shape value `applyClip` reads, written in place. */
|
|
26889
|
+
const NINE_CLIP = { ...Shape.defaults };
|
|
26107
26890
|
/**
|
|
26108
26891
|
* The depth of a wrapper's own visual among the wrapper's children: a child at `Order` 0 or more draws above it, one
|
|
26109
26892
|
* at −1 or less below it, and a ui child at `zIndex` 0 (an `Order` between −0.5 and 0) above it too (spec 16 U1.8).
|
|
@@ -26204,26 +26987,31 @@ function visualOf(sctx, entity) {
|
|
|
26204
26987
|
if (sprite !== void 0) found.push({
|
|
26205
26988
|
kind: "Sprite",
|
|
26206
26989
|
textureKey: sprite.texture,
|
|
26990
|
+
hollow: false,
|
|
26207
26991
|
display: void 0
|
|
26208
26992
|
});
|
|
26209
26993
|
if (nine !== void 0) found.push({
|
|
26210
26994
|
kind: "NineSlice",
|
|
26211
26995
|
textureKey: nine.texture,
|
|
26996
|
+
hollow: nine.hollow === true,
|
|
26212
26997
|
display: void 0
|
|
26213
26998
|
});
|
|
26214
26999
|
if (ecs.has(entity, Shape)) found.push({
|
|
26215
27000
|
kind: "Shape",
|
|
26216
27001
|
textureKey: "",
|
|
27002
|
+
hollow: false,
|
|
26217
27003
|
display: void 0
|
|
26218
27004
|
});
|
|
26219
27005
|
if (ecs.has(entity, Display)) found.push({
|
|
26220
27006
|
kind: "Display",
|
|
26221
27007
|
textureKey: "",
|
|
27008
|
+
hollow: false,
|
|
26222
27009
|
display: void 0
|
|
26223
27010
|
});
|
|
26224
27011
|
for (const entry of adaptersOn(sctx, entity)) found.push({
|
|
26225
27012
|
kind: "adapter",
|
|
26226
27013
|
textureKey: "",
|
|
27014
|
+
hollow: false,
|
|
26227
27015
|
display: entry
|
|
26228
27016
|
});
|
|
26229
27017
|
if (found.length > 1) sctx.ctx.log.warn("renderer: entity has more than one visual", {
|
|
@@ -26244,29 +27032,10 @@ function retargetKey(state, entity, view, key) {
|
|
|
26244
27032
|
if (view.textureKey === key) return;
|
|
26245
27033
|
untrackKey(state, entity, view.textureKey);
|
|
26246
27034
|
view.textureKey = key;
|
|
26247
|
-
view.poolKey = poolKeyOf(view.kind, key);
|
|
27035
|
+
view.poolKey = poolKeyOf(view.kind, key, isHollow(view.object));
|
|
26248
27036
|
if (key !== "") trackKey(state, entity, key);
|
|
26249
27037
|
}
|
|
26250
27038
|
/**
|
|
26251
|
-
* Resolves a key and says whether the placeholder had to step in.
|
|
26252
|
-
*
|
|
26253
|
-
* @param sctx - Domain context of the sync module.
|
|
26254
|
-
* @param key - The asset key.
|
|
26255
|
-
* @returns The texture to draw and whether it is the placeholder.
|
|
26256
|
-
*/
|
|
26257
|
-
function textureFor(sctx, key) {
|
|
26258
|
-
const resolved = resolveTexture(sctx, key);
|
|
26259
|
-
if (resolved !== void 0) return {
|
|
26260
|
-
texture: resolved,
|
|
26261
|
-
missing: false
|
|
26262
|
-
};
|
|
26263
|
-
warnMissing(sctx, key);
|
|
26264
|
-
return {
|
|
26265
|
-
texture: placeholderTexture(sctx),
|
|
26266
|
-
missing: true
|
|
26267
|
-
};
|
|
26268
|
-
}
|
|
26269
|
-
/**
|
|
26270
27039
|
* Writes the texture and the tint of a sprite, each only when it differs from what Pixi holds.
|
|
26271
27040
|
*
|
|
26272
27041
|
* @param sctx - Domain context of the sync module.
|
|
@@ -26475,12 +27244,12 @@ function applyOutline(sctx, view, shape, debug, changed) {
|
|
|
26475
27244
|
sctx.ctx.state.sync.redraws += 1;
|
|
26476
27245
|
}
|
|
26477
27246
|
/**
|
|
26478
|
-
* Writes one number of a nine-slice only when it differs from what
|
|
26479
|
-
* panel on every write of a width, even an equal one.
|
|
27247
|
+
* Writes one number of a nine-slice only when it differs from what the object holds: Pixi rebuilds the
|
|
27248
|
+
* panel on every write of a width, even an equal one, and the rim-only object rewrites its vertices.
|
|
26480
27249
|
*
|
|
26481
27250
|
* @param sctx - Domain context of the sync module.
|
|
26482
27251
|
* @param entity - The entity.
|
|
26483
|
-
* @param object -
|
|
27252
|
+
* @param object - Pixi's nine-slice sprite, or the engine's rim-only one.
|
|
26484
27253
|
* @param field - Which number.
|
|
26485
27254
|
* @param value - The new number.
|
|
26486
27255
|
* @returns True when it was written.
|
|
@@ -26494,7 +27263,9 @@ function writeSlice(sctx, entity, object, field, value) {
|
|
|
26494
27263
|
/**
|
|
26495
27264
|
* Writes the `NineSlice` component onto its display object and recomputes the hit box. Pixi reads
|
|
26496
27265
|
* a texture's borders only in the constructor, so they are copied here on every write: a pooled
|
|
26497
|
-
* object, a new key and a reloaded bundle all get the insets of the texture they draw now.
|
|
27266
|
+
* object, a new key and a reloaded bundle all get the insets of the texture they draw now. A `hollow` that flipped
|
|
27267
|
+
* swaps the view's object first (F59). The hit box is the whole panel, hollow or not. A write that changes nothing,
|
|
27268
|
+
* or only the size, allocates nothing: the borders, the outline's shape and the clip's box are written in place.
|
|
26498
27269
|
*
|
|
26499
27270
|
* @param sctx - Domain context of the sync module.
|
|
26500
27271
|
* @param entity - The entity.
|
|
@@ -26502,11 +27273,16 @@ function writeSlice(sctx, entity, object, field, value) {
|
|
|
26502
27273
|
*/
|
|
26503
27274
|
function applyNineSlice(sctx, entity, view) {
|
|
26504
27275
|
const value = sctx.ctx.deps.world.ecs.get(entity, NineSlice);
|
|
27276
|
+
if (value === void 0 || !isNineSlice(view.object)) return;
|
|
27277
|
+
if (isHollow(view.object) !== (value.hollow === true)) swapSlice(sctx, entity, view);
|
|
26505
27278
|
const object = view.object;
|
|
26506
|
-
if (
|
|
27279
|
+
if (!isNineSlice(object)) return;
|
|
26507
27280
|
retargetKey(sctx.ctx.state.sync, entity, view, value.texture);
|
|
26508
|
-
const
|
|
26509
|
-
const
|
|
27281
|
+
const resolved = resolveTexture(sctx, value.texture);
|
|
27282
|
+
const missing = resolved === void 0;
|
|
27283
|
+
if (missing) warnMissing(sctx, value.texture);
|
|
27284
|
+
const texture = resolved ?? placeholderTexture(sctx);
|
|
27285
|
+
const borders = bordersInto(texture, BORDERS);
|
|
26510
27286
|
view.placeholder = missing;
|
|
26511
27287
|
let changed = false;
|
|
26512
27288
|
if (texture !== void 0 && object.texture !== texture) {
|
|
@@ -26522,25 +27298,59 @@ function applyNineSlice(sctx, entity, view) {
|
|
|
26522
27298
|
applyAlpha(sctx, entity, view, value);
|
|
26523
27299
|
changed = writeSlice(sctx, entity, object, "width", value.width) || changed;
|
|
26524
27300
|
changed = writeSlice(sctx, entity, object, "height", value.height) || changed;
|
|
26525
|
-
view.hitBox
|
|
26526
|
-
|
|
26527
|
-
|
|
26528
|
-
|
|
26529
|
-
|
|
26530
|
-
|
|
26531
|
-
|
|
26532
|
-
|
|
26533
|
-
|
|
26534
|
-
|
|
26535
|
-
|
|
26536
|
-
|
|
26537
|
-
|
|
26538
|
-
|
|
26539
|
-
|
|
26540
|
-
|
|
26541
|
-
|
|
26542
|
-
|
|
26543
|
-
|
|
27301
|
+
writeHitBox(view.hitBox, value.width, value.height);
|
|
27302
|
+
OUTLINE.entity = entity;
|
|
27303
|
+
OUTLINE.width = value.width;
|
|
27304
|
+
OUTLINE.height = value.height;
|
|
27305
|
+
OUTLINE.missing = missing;
|
|
27306
|
+
applyOutline(sctx, view, OUTLINE, value.debug, changed);
|
|
27307
|
+
NINE_CLIP.w = value.width;
|
|
27308
|
+
NINE_CLIP.h = value.height;
|
|
27309
|
+
NINE_CLIP.clip = value.clip;
|
|
27310
|
+
applyClip(sctx, entity, view, NINE_CLIP);
|
|
27311
|
+
}
|
|
27312
|
+
/**
|
|
27313
|
+
* A new nine-slice object of one kind: the engine's rim-only mesh, or Pixi's `NineSliceSprite`; both of the white
|
|
27314
|
+
* texture until the first write.
|
|
27315
|
+
*
|
|
27316
|
+
* @param sctx - Domain context of the sync module.
|
|
27317
|
+
* @param pixi - The Pixi module.
|
|
27318
|
+
* @param hollow - True for the rim-only object.
|
|
27319
|
+
* @returns The object.
|
|
27320
|
+
*/
|
|
27321
|
+
function newSlice(sctx, pixi, hollow) {
|
|
27322
|
+
return hollow ? makeHollow(sctx.ctx.state.sync, pixi) : new pixi.NineSliceSprite({ texture: pixi.Texture.WHITE });
|
|
27323
|
+
}
|
|
27324
|
+
/**
|
|
27325
|
+
* Gives a nine-slice view whose `hollow` flipped the other object (F59), on the write that flipped it: the view gets
|
|
27326
|
+
* its wrapper first (it keeps the pose, the alpha, the filters, the clip and the outline), then the other kind takes
|
|
27327
|
+
* the old object's place in it, out of its pool or new, and the old object goes back to its own pool. The entity, its
|
|
27328
|
+
* children and its hit box stay as they were; the caller writes the new object in full.
|
|
27329
|
+
*
|
|
27330
|
+
* @param sctx - Domain context of the sync module.
|
|
27331
|
+
* @param entity - The entity.
|
|
27332
|
+
* @param view - Its view, drawn by a nine-slice object.
|
|
27333
|
+
*/
|
|
27334
|
+
function swapSlice(sctx, entity, view) {
|
|
27335
|
+
const pixi = sctx.deps.host.pixi();
|
|
27336
|
+
const wrapper = ensureWrapper(sctx, entity);
|
|
27337
|
+
if (pixi === void 0 || wrapper === void 0) return;
|
|
27338
|
+
const state = sctx.ctx.state.sync;
|
|
27339
|
+
const old = view.object;
|
|
27340
|
+
const hollow = !isHollow(old);
|
|
27341
|
+
const poolKey = poolKeyOf("NineSlice", view.textureKey, hollow);
|
|
27342
|
+
const next = acquire(state, poolKey) ?? newSlice(sctx, pixi, hollow);
|
|
27343
|
+
markView(sctx, entity);
|
|
27344
|
+
next.label = old.label;
|
|
27345
|
+
next.zIndex = old.zIndex;
|
|
27346
|
+
wrapper.addChildAt(next, Math.max(0, wrapper.children.indexOf(old)));
|
|
27347
|
+
state.entityOf.delete(old);
|
|
27348
|
+
state.entityOf.set(next, entity);
|
|
27349
|
+
view.object = next;
|
|
27350
|
+
releaseObject(sctx, old, view.poolKey);
|
|
27351
|
+
view.poolKey = poolKey;
|
|
27352
|
+
writeRenderable(view);
|
|
27353
|
+
applyTransform(sctx, entity, view);
|
|
26544
27354
|
}
|
|
26545
27355
|
/**
|
|
26546
27356
|
* Gives a clipping view the masked container its children hang in, next to its own visual in the
|
|
@@ -26558,7 +27368,9 @@ function ensureClipped(pixi, entity, view, wrapper) {
|
|
|
26558
27368
|
const clipped = new pixi.Container();
|
|
26559
27369
|
clipped.label = `children#${entity}`;
|
|
26560
27370
|
clipped.sortableChildren = true;
|
|
26561
|
-
|
|
27371
|
+
let index = 0;
|
|
27372
|
+
for (let child = wrapper.children[0]; child !== void 0; child = wrapper.children[index]) if (child === view.object || child === view.outline) index += 1;
|
|
27373
|
+
else clipped.addChild(child);
|
|
26562
27374
|
wrapper.addChild(clipped);
|
|
26563
27375
|
view.clipped = clipped;
|
|
26564
27376
|
return clipped;
|
|
@@ -26990,6 +27802,7 @@ function attach$1(sctx, entity, view) {
|
|
|
26990
27802
|
* @param visual - Which component gives the entity its object, and its texture key.
|
|
26991
27803
|
* @param visual.kind - Which component gives the entity its object.
|
|
26992
27804
|
* @param visual.textureKey - The asset key the object draws.
|
|
27805
|
+
* @param visual.hollow - True for the rim-only object of a hollow `NineSlice`.
|
|
26993
27806
|
* @returns The object, or `undefined` while inert.
|
|
26994
27807
|
*/
|
|
26995
27808
|
function makeObject(sctx, entity, visual) {
|
|
@@ -27003,7 +27816,7 @@ function makeObject(sctx, entity, visual) {
|
|
|
27003
27816
|
const pixi = sctx.deps.host.pixi();
|
|
27004
27817
|
if (pixi === void 0) return void 0;
|
|
27005
27818
|
if (visual.display !== void 0) return adapterObject(sctx, entity, visual.display);
|
|
27006
|
-
const pooled = acquire(sctx.ctx.state.sync, poolKeyOf(visual.kind, visual.textureKey));
|
|
27819
|
+
const pooled = acquire(sctx.ctx.state.sync, poolKeyOf(visual.kind, visual.textureKey, visual.hollow));
|
|
27007
27820
|
if (pooled !== void 0) return {
|
|
27008
27821
|
object: pooled,
|
|
27009
27822
|
value: void 0
|
|
@@ -27017,7 +27830,7 @@ function makeObject(sctx, entity, visual) {
|
|
|
27017
27830
|
value: void 0
|
|
27018
27831
|
};
|
|
27019
27832
|
return {
|
|
27020
|
-
object:
|
|
27833
|
+
object: newSlice(sctx, pixi, visual.hollow),
|
|
27021
27834
|
value: void 0
|
|
27022
27835
|
};
|
|
27023
27836
|
}
|
|
@@ -27060,7 +27873,7 @@ function createView(sctx, entity) {
|
|
|
27060
27873
|
const view = {
|
|
27061
27874
|
object,
|
|
27062
27875
|
kind: visual.kind,
|
|
27063
|
-
poolKey: poolKeyOf(visual.kind, visual.textureKey),
|
|
27876
|
+
poolKey: poolKeyOf(visual.kind, visual.textureKey, visual.hollow),
|
|
27064
27877
|
layer: "",
|
|
27065
27878
|
textureKey: visual.textureKey,
|
|
27066
27879
|
wrapper: void 0,
|
|
@@ -27185,8 +27998,9 @@ function dropView(sctx, entity) {
|
|
|
27185
27998
|
release$1(sctx, view);
|
|
27186
27999
|
}
|
|
27187
28000
|
/**
|
|
27188
|
-
* Drops every view, every layer, every pool, every filter slot and filter area,
|
|
27189
|
-
* answer false, its probe tree is destroyed). Works on the state
|
|
28001
|
+
* Drops every view, every layer, every pool, every filter slot and filter area, the warm-up (its waiting promises
|
|
28002
|
+
* answer false, its probe tree is destroyed) and the upload queue (its waiting calls answer false). Works on the state
|
|
28003
|
+
* alone,
|
|
27190
28004
|
* because `onStop` has no context. A `Display` object belongs to the game: it is detached, never
|
|
27191
28005
|
* destroyed, and leaves without the filters, the filter area and the hidden reasons the renderer gave it.
|
|
27192
28006
|
*
|
|
@@ -27231,6 +28045,7 @@ function stopSync(state) {
|
|
|
27231
28045
|
state.areas.clear();
|
|
27232
28046
|
state.viewlessEntries = false;
|
|
27233
28047
|
stopWarm(state);
|
|
28048
|
+
stopUploads(state);
|
|
27234
28049
|
state.held.clear();
|
|
27235
28050
|
state.redraws = 0;
|
|
27236
28051
|
state.overdraw.listeners.length = 0;
|
|
@@ -27374,7 +28189,8 @@ function withDeps$8(ctx) {
|
|
|
27374
28189
|
* takes the same path: the backing store changes, the frame and the scale do not), then the
|
|
27375
28190
|
* overlay step (spec 22), then `kept` reads the marks before `demand` decides whether the frame is
|
|
27376
28191
|
* drawn and clears them; a drawn frame draws the probes of the warm-up onto the canvas first (F4: the
|
|
27377
|
-
* stage pass clears them, in the same task, so they never show), then the
|
|
28192
|
+
* stage pass clears them, in the same task, so they never show), then uploads the queued texture sources (F60), then
|
|
28193
|
+
* the kept pictures
|
|
27378
28194
|
* (`kept.flush`, so the canvas stays one pass, E7), then the stage, then the pixel leg of the kept
|
|
27379
28195
|
* oracle; `demand` settles the
|
|
27380
28196
|
* frame (the dev check, the pixel oracle), and `monitor` closes it and hands a drawn one to a
|
|
@@ -27409,10 +28225,11 @@ function renderFrame(ctx, modules) {
|
|
|
27409
28225
|
const drawn = modules.demand.decide(modules.monitor.waiting());
|
|
27410
28226
|
if (drawn) {
|
|
27411
28227
|
const probed = modules.sync.warmStep();
|
|
28228
|
+
const uploaded = modules.sync.uploadStep();
|
|
27412
28229
|
modules.kept.flush();
|
|
27413
28230
|
if (overdraw ? modules.sync.drawOverdraw(modules.host.render) : modules.host.render()) {
|
|
27414
28231
|
ctx.deps.time.frameDrawn();
|
|
27415
|
-
if (probed) ctx.deps.time.frameProbed();
|
|
28232
|
+
if (probed || uploaded) ctx.deps.time.frameProbed();
|
|
27416
28233
|
}
|
|
27417
28234
|
modules.kept.after();
|
|
27418
28235
|
}
|
|
@@ -29616,6 +30433,7 @@ function createSyncApi(ctx, deps) {
|
|
|
29616
30433
|
const forgetTree = () => {
|
|
29617
30434
|
deps.kept.reset();
|
|
29618
30435
|
forgetOverlays(state);
|
|
30436
|
+
stopUploads(state);
|
|
29619
30437
|
state.held.clear();
|
|
29620
30438
|
for (const view of state.views.values()) {
|
|
29621
30439
|
state.viewOfTop.delete(view.wrapper ?? view.object);
|
|
@@ -29658,7 +30476,7 @@ function createSyncApi(ctx, deps) {
|
|
|
29658
30476
|
state.removed.clear();
|
|
29659
30477
|
state.reparented.clear();
|
|
29660
30478
|
state.outlinesStale = false;
|
|
29661
|
-
startWarm$
|
|
30479
|
+
startWarm$2(sctx);
|
|
29662
30480
|
};
|
|
29663
30481
|
return {
|
|
29664
30482
|
hitTest: (x, y, accept) => hitTest(sctx, x, y, accept),
|
|
@@ -29685,7 +30503,8 @@ function createSyncApi(ctx, deps) {
|
|
|
29685
30503
|
if (state.root === void 0) return;
|
|
29686
30504
|
for (const key of keys) state.invalidated.add(key);
|
|
29687
30505
|
dropPooled(state, keys);
|
|
29688
|
-
}
|
|
30506
|
+
},
|
|
30507
|
+
upload: (textures) => uploadTextures(sctx, textures)
|
|
29689
30508
|
},
|
|
29690
30509
|
displays: { provide: (component, adapter) => provideDisplay(sctx, component, adapter, {
|
|
29691
30510
|
added: markAdded,
|
|
@@ -29733,6 +30552,7 @@ function createSyncApi(ctx, deps) {
|
|
|
29733
30552
|
stepFilters: () => applySwitched(state, deps.kept),
|
|
29734
30553
|
drainOverlayEvents: (monitor) => drainOverlayEvents(sctx, monitor),
|
|
29735
30554
|
warmStep: () => warmStep(sctx),
|
|
30555
|
+
uploadStep: () => uploadStep(sctx),
|
|
29736
30556
|
onWarm: (fn) => {
|
|
29737
30557
|
state.warm.listeners.push(fn);
|
|
29738
30558
|
},
|
|
@@ -30524,8 +31344,22 @@ function createWarmState() {
|
|
|
30524
31344
|
};
|
|
30525
31345
|
}
|
|
30526
31346
|
/**
|
|
31347
|
+
* Creates the empty upload queue: nothing queued, nobody waiting, nothing uploaded. Its own non-exported function, as
|
|
31348
|
+
* `emptyMap`.
|
|
31349
|
+
*
|
|
31350
|
+
* @returns The upload branch of the sync state.
|
|
31351
|
+
*/
|
|
31352
|
+
function createUploadState() {
|
|
31353
|
+
return {
|
|
31354
|
+
queue: [],
|
|
31355
|
+
head: 0,
|
|
31356
|
+
waiting: emptyMap$6(),
|
|
31357
|
+
done: emptyWeakSet()
|
|
31358
|
+
};
|
|
31359
|
+
}
|
|
31360
|
+
/**
|
|
30527
31361
|
* Creates the initial sync state: no root, no layers, no view, no orphan, no pool, no provider, no filter, no
|
|
30528
|
-
* filter area, no slice, no hidden mask, no overlay, no warm-up, no redraw counted and no unseen walk kept.
|
|
31362
|
+
* filter area, no slice, no hidden mask, no overlay, no warm-up, no upload, no redraw counted and no unseen walk kept.
|
|
30529
31363
|
*
|
|
30530
31364
|
* @param debug - The debug switches of the config; copied, so the frozen config stays untouched.
|
|
30531
31365
|
* @returns The sync branch of the plugin state.
|
|
@@ -30564,6 +31398,8 @@ function createSyncState(debug) {
|
|
|
30564
31398
|
areas: emptyMap$6(),
|
|
30565
31399
|
viewlessEntries: false,
|
|
30566
31400
|
warm: createWarmState(),
|
|
31401
|
+
upload: createUploadState(),
|
|
31402
|
+
hollowClass: void 0,
|
|
30567
31403
|
filterKinds: emptyWeakMap$1(),
|
|
30568
31404
|
filterOwners: emptyWeakMap$1(),
|
|
30569
31405
|
objectHidden: emptyWeakMap$1(),
|
|
@@ -30631,6 +31467,8 @@ const RING_FRAMES = {
|
|
|
30631
31467
|
};
|
|
30632
31468
|
/** The most probe draws of the warm-up a drawn frame may make. */
|
|
30633
31469
|
const MAX_WARM = 16;
|
|
31470
|
+
/** The most textures the upload queue may put on the GPU in one drawn frame: about 9 ms each on a Galaxy A26. */
|
|
31471
|
+
const MAX_UPLOADS = 8;
|
|
30634
31472
|
/**
|
|
30635
31473
|
* Tells a finite number of at least 0 from anything else a config can hold.
|
|
30636
31474
|
*
|
|
@@ -30677,14 +31515,14 @@ function checkAdaptiveScale(adaptiveScale) {
|
|
|
30677
31515
|
}
|
|
30678
31516
|
/**
|
|
30679
31517
|
* Checks the numbers of the config a game can get wrong, at `createApp`, in every build: the
|
|
30680
|
-
* resolution cap, the pool trim, the adaptive render scale, the performance monitor, the budget of the kept pictures
|
|
30681
|
-
*
|
|
31518
|
+
* resolution cap, the pool trim, the adaptive render scale, the performance monitor, the budget of the kept pictures,
|
|
31519
|
+
* the probe draws of the warm-up and the textures uploaded per drawn frame.
|
|
30682
31520
|
*
|
|
30683
31521
|
* @param config - The resolved plugin config.
|
|
30684
31522
|
* @throws {Error} When `maxResolution` is not a number above 0, `poolTrim` or `adaptiveScale` fails its check,
|
|
30685
31523
|
* `monitor.budgetMs` is neither `"rate"` nor a number above 0, `monitor.frames` is not a whole
|
|
30686
|
-
* number from 64 to 16384, `keptMb` is not a finite number of at least 0,
|
|
30687
|
-
* whole number from 0 to 16.
|
|
31524
|
+
* number from 64 to 16384, `keptMb` is not a finite number of at least 0, `warm` is not a
|
|
31525
|
+
* whole number from 0 to 16, or `uploads` is not a whole number from 0 to 8.
|
|
30688
31526
|
*/
|
|
30689
31527
|
function checkConfig(config) {
|
|
30690
31528
|
const { maxResolution, keptMb } = config;
|
|
@@ -30697,6 +31535,8 @@ function checkConfig(config) {
|
|
|
30697
31535
|
if (typeof keptMb !== "number" || !Number.isFinite(keptMb) || keptMb < 0) throw new Error(`[game] renderer.keptMb is ${String(keptMb)}.\n Give the MiB kept pictures may hold, or 0 to keep none.`);
|
|
30698
31536
|
const { warm } = config;
|
|
30699
31537
|
if (!Number.isInteger(warm) || warm < 0 || warm > MAX_WARM) throw new Error(`[game] renderer.warm is ${String(warm)}.\n Give the probe draws per frame, a whole number from 0 to 16.`);
|
|
31538
|
+
const { uploads } = config;
|
|
31539
|
+
if (!Number.isInteger(uploads) || uploads < 0 || uploads > MAX_UPLOADS) throw new Error(`[game] renderer.uploads is ${String(uploads)}.\n Give the textures uploaded per drawn frame, a whole number from 0 to 8.`);
|
|
30700
31540
|
}
|
|
30701
31541
|
/**
|
|
30702
31542
|
* Creates the initial renderer state: one branch per module, composed from the module state
|
|
@@ -30778,6 +31618,7 @@ const rendererPlugin = /*#__PURE__*/ createPlugin$1("renderer", {
|
|
|
30778
31618
|
onDemand: false,
|
|
30779
31619
|
keptMb: 64,
|
|
30780
31620
|
warm: 1,
|
|
31621
|
+
uploads: 1,
|
|
30781
31622
|
adaptiveScale: {
|
|
30782
31623
|
floor: .75,
|
|
30783
31624
|
devices: "phone"
|
|
@@ -34291,8 +35132,9 @@ function reportSettled(ctx, progress, signal) {
|
|
|
34291
35132
|
ctx.emit("assets:bundle-progress", { ...progress });
|
|
34292
35133
|
}
|
|
34293
35134
|
/**
|
|
34294
|
-
* Publishes a loaded bundle: what was loaded moves into the record, `
|
|
34295
|
-
* keys, the event goes out, the frame loop wakes and the
|
|
35135
|
+
* Publishes a loaded bundle: what was loaded moves into the record, a failure `ready` remembered
|
|
35136
|
+
* is forgotten, `renderer` re-resolves the keys, the event goes out, the frame loop wakes and the
|
|
35137
|
+
* budget is enforced.
|
|
34296
35138
|
*
|
|
34297
35139
|
* @param ctx - Domain context of the plugin.
|
|
34298
35140
|
* @param bundle - Name of the bundle.
|
|
@@ -34309,6 +35151,7 @@ function finish$1(ctx, bundle, entry, assets, reason) {
|
|
|
34309
35151
|
record.status = "loaded";
|
|
34310
35152
|
record.inflight = void 0;
|
|
34311
35153
|
touch(ctx.state, record);
|
|
35154
|
+
ctx.state.readyFailed.delete(bundle);
|
|
34312
35155
|
ctx.deps.renderer.sync.textures.invalidate(entry.files.map((file) => file.key));
|
|
34313
35156
|
ctx.emit("assets:bundle-loaded", {
|
|
34314
35157
|
bundle,
|
|
@@ -34712,9 +35555,9 @@ function releaseAssets(io, assets) {
|
|
|
34712
35555
|
assets.audio.clear();
|
|
34713
35556
|
}
|
|
34714
35557
|
/**
|
|
34715
|
-
* Frees one loaded bundle: the textures are destroyed, every companion drops
|
|
34716
|
-
* it, `renderer` is told that its keys are gone and the event goes out. A bundle
|
|
34717
|
-
* loaded is left alone.
|
|
35558
|
+
* Frees one loaded bundle: the textures are destroyed, its warm is forgotten, every companion drops
|
|
35559
|
+
* what travels with it, `renderer` is told that its keys are gone and the event goes out. A bundle
|
|
35560
|
+
* that is not loaded is left alone.
|
|
34718
35561
|
*
|
|
34719
35562
|
* @param ctx - Domain context of the plugin.
|
|
34720
35563
|
* @param bundle - Name of the bundle.
|
|
@@ -34728,6 +35571,7 @@ function unloadBundle(ctx, bundle, reason) {
|
|
|
34728
35571
|
releaseAssets(state.io, record);
|
|
34729
35572
|
record.status = "idle";
|
|
34730
35573
|
record.lastUsed = 0;
|
|
35574
|
+
state.warmed.delete(bundle);
|
|
34731
35575
|
unloadCompanions(ctx, state.companions, bundle);
|
|
34732
35576
|
const keys = entry.files.map((file) => file.key);
|
|
34733
35577
|
ctx.deps.renderer.sync.textures.invalidate(keys);
|
|
@@ -35378,9 +36222,125 @@ function startPreload(ctx) {
|
|
|
35378
36222
|
runQueue(ctx, queue).catch(ignoreFailure$1);
|
|
35379
36223
|
}
|
|
35380
36224
|
//#endregion
|
|
36225
|
+
//#region src/plugins/assets/ready.ts
|
|
36226
|
+
/**
|
|
36227
|
+
* @file assets plugin — a bundle ready to show. `warm` loads a bundle and puts its textures on the
|
|
36228
|
+
* GPU before a scene shows them (F60): on a Galaxy A26 the frame that showed 6 cold textures took
|
|
36229
|
+
* 55 ms, 8 ms once they were uploaded before. The `ready` effect lets a node rest on that work and
|
|
36230
|
+
* stay answerable (F52). Nothing here is on the frame path: one promise per bundle, and the inbox
|
|
36231
|
+
* event is posted from a promise.
|
|
36232
|
+
*/
|
|
36233
|
+
/**
|
|
36234
|
+
* Runs one warm: loads the bundle when it is not loaded, then hands every texture and atlas page
|
|
36235
|
+
* of it to the renderer's upload queue. The answer of the upload is not read: when the renderer
|
|
36236
|
+
* could not upload, the first draw does. A failure drops the entry, so the next `warm` tries again.
|
|
36237
|
+
*
|
|
36238
|
+
* @param ctx - Domain context of the plugin.
|
|
36239
|
+
* @param bundle - Name of a bundle of the manifest.
|
|
36240
|
+
* @param entry - The entry of this warm in `state.warmed`.
|
|
36241
|
+
* @returns A promise that resolves once the upload answered.
|
|
36242
|
+
* @throws {Error} When the load fails or is aborted.
|
|
36243
|
+
*/
|
|
36244
|
+
async function runWarm(ctx, bundle, entry) {
|
|
36245
|
+
try {
|
|
36246
|
+
await loadBundle(ctx, bundle, void 0, "request");
|
|
36247
|
+
const { textures, pages } = ctx.state.records.get(bundle) ?? emptyAssets();
|
|
36248
|
+
await ctx.deps.renderer.sync.textures.upload([...textures.values(), ...pages.values()]);
|
|
36249
|
+
entry.done = true;
|
|
36250
|
+
} catch (error) {
|
|
36251
|
+
if (ctx.state.warmed.get(bundle) === entry) ctx.state.warmed.delete(bundle);
|
|
36252
|
+
throw error;
|
|
36253
|
+
}
|
|
36254
|
+
}
|
|
36255
|
+
/**
|
|
36256
|
+
* Starts the one warm of a bundle and records it.
|
|
36257
|
+
*
|
|
36258
|
+
* @param ctx - Domain context of the plugin.
|
|
36259
|
+
* @param bundle - Name of a bundle of the manifest.
|
|
36260
|
+
* @returns The entry every later caller joins.
|
|
36261
|
+
*/
|
|
36262
|
+
function startWarm$1(ctx, bundle) {
|
|
36263
|
+
const entry = {
|
|
36264
|
+
promise: Promise.resolve(),
|
|
36265
|
+
done: false
|
|
36266
|
+
};
|
|
36267
|
+
ctx.state.warmed.set(bundle, entry);
|
|
36268
|
+
entry.promise = runWarm(ctx, bundle, entry);
|
|
36269
|
+
return entry;
|
|
36270
|
+
}
|
|
36271
|
+
/**
|
|
36272
|
+
* Warms one bundle, or joins its running or finished warm. Headless it resolves at once, whatever
|
|
36273
|
+
* the name, as `load` does.
|
|
36274
|
+
*
|
|
36275
|
+
* @param ctx - Domain context of the plugin.
|
|
36276
|
+
* @param bundle - Name of a bundle of the manifest.
|
|
36277
|
+
* @returns A promise that resolves once the bundle is loaded and its textures went to the GPU.
|
|
36278
|
+
* @throws {Error} When the manifest has no such bundle, and when the load fails or is aborted.
|
|
36279
|
+
*/
|
|
36280
|
+
async function warmBundle(ctx, bundle) {
|
|
36281
|
+
const state = ctx.state;
|
|
36282
|
+
if (state.io === void 0) return;
|
|
36283
|
+
if (state.manifest.bundles[bundle] === void 0) throw unknownBundle(bundle);
|
|
36284
|
+
await (state.warmed.get(bundle) ?? startWarm$1(ctx, bundle)).promise;
|
|
36285
|
+
}
|
|
36286
|
+
/**
|
|
36287
|
+
* Tells whether the `ready` effect counts a bundle as there: loaded and warmed, or its last warm
|
|
36288
|
+
* for `ready` failed.
|
|
36289
|
+
*
|
|
36290
|
+
* @param state - The plugin state.
|
|
36291
|
+
* @param bundle - Name of a bundle of the manifest.
|
|
36292
|
+
* @returns True when a node need not rest on it.
|
|
36293
|
+
*/
|
|
36294
|
+
function isThere(state, bundle) {
|
|
36295
|
+
if (state.readyFailed.has(bundle)) return true;
|
|
36296
|
+
return state.records.get(bundle)?.status === "loaded" && state.warmed.get(bundle)?.done === true;
|
|
36297
|
+
}
|
|
36298
|
+
/**
|
|
36299
|
+
* Warms one bundle for the `ready` effect. It never rejects: a failure that is not an abort marks
|
|
36300
|
+
* the bundle failed and is logged, so the node resting on it moves on; an abort (an unload, a stop)
|
|
36301
|
+
* marks nothing, and the next `ready` starts the bundle again.
|
|
36302
|
+
*
|
|
36303
|
+
* @param ctx - Domain context of the plugin.
|
|
36304
|
+
* @param bundle - Name of a bundle of the manifest.
|
|
36305
|
+
* @returns A promise that resolves once the warm settled.
|
|
36306
|
+
*/
|
|
36307
|
+
async function warmForReady(ctx, bundle) {
|
|
36308
|
+
try {
|
|
36309
|
+
await warmBundle(ctx, bundle);
|
|
36310
|
+
} catch (error) {
|
|
36311
|
+
if (isAbortError(error)) return;
|
|
36312
|
+
ctx.state.readyFailed.add(bundle);
|
|
36313
|
+
ctx.log.warn("assets:ready-failed", {
|
|
36314
|
+
bundle,
|
|
36315
|
+
error: String(error)
|
|
36316
|
+
});
|
|
36317
|
+
}
|
|
36318
|
+
}
|
|
36319
|
+
/**
|
|
36320
|
+
* The handler of the `ready` effect (F52). Headless it answers `true` before any name check, as the
|
|
36321
|
+
* `load` effect does. Every bundle there: `true`, and nothing is posted. Otherwise it starts the
|
|
36322
|
+
* warm of each bundle that is not there, answers `false`, and posts `{ type: "ready" }` into
|
|
36323
|
+
* `flow.inbox` once all of them settled. The posting does not wait on the node's signal: the warm
|
|
36324
|
+
* is shared work, and the inbox keeps only the latest `ready`.
|
|
36325
|
+
*
|
|
36326
|
+
* @param ctx - Domain context of the plugin.
|
|
36327
|
+
* @param bundles - The bundle names of the descriptor.
|
|
36328
|
+
* @returns True when the node may go on, false when it should rest until the inbox event `ready`.
|
|
36329
|
+
* @throws {Error} When the manifest has no such bundle.
|
|
36330
|
+
*/
|
|
36331
|
+
function answerReady(ctx, bundles) {
|
|
36332
|
+
const state = ctx.state;
|
|
36333
|
+
if (state.io === void 0) return true;
|
|
36334
|
+
for (const name of bundles) if (state.manifest.bundles[name] === void 0) throw unknownBundle(name);
|
|
36335
|
+
const missing = bundles.filter((name) => !isThere(state, name));
|
|
36336
|
+
if (missing.length === 0) return true;
|
|
36337
|
+
Promise.all(missing.map((name) => warmForReady(ctx, name))).then(() => ctx.deps.flow.inbox.post({ type: "ready" }));
|
|
36338
|
+
return false;
|
|
36339
|
+
}
|
|
36340
|
+
//#endregion
|
|
35381
36341
|
//#region src/plugins/assets/lifecycle.ts
|
|
35382
36342
|
/**
|
|
35383
|
-
* @file assets plugin — lifecycle: the
|
|
36343
|
+
* @file assets plugin — lifecycle: the seven registrations of `onInit`, the boot of `onStart`
|
|
35384
36344
|
* and the teardown that frees every texture and cancels every fetch.
|
|
35385
36345
|
*/
|
|
35386
36346
|
/**
|
|
@@ -35411,7 +36371,7 @@ function withDeps$6(ctx) {
|
|
|
35411
36371
|
};
|
|
35412
36372
|
}
|
|
35413
36373
|
/**
|
|
35414
|
-
* Reads the bundle names out of a `load` descriptor.
|
|
36374
|
+
* Reads the bundle names out of a `load` or a `ready` descriptor.
|
|
35415
36375
|
*
|
|
35416
36376
|
* @param descriptor - What the node awaited.
|
|
35417
36377
|
* @returns The bundle names, in the order the node listed them.
|
|
@@ -35494,17 +36454,17 @@ async function enterNode(ctx, node, run) {
|
|
|
35494
36454
|
}
|
|
35495
36455
|
}
|
|
35496
36456
|
/**
|
|
35497
|
-
* Connects the plugin in `onInit`: the `load` stage of `onEnter`, the
|
|
35498
|
-
*
|
|
35499
|
-
* and the system `assets.leave` of phase `sync`,
|
|
35500
|
-
* elements played their exit (F51). The
|
|
35501
|
-
* but the state.
|
|
36457
|
+
* Connects the plugin in `onInit`: the `load` stage of `onEnter`, the handlers of the `load` and
|
|
36458
|
+
* the `ready` effects (F52), both run in fast mode too, the texture provider of `renderer`, the
|
|
36459
|
+
* start and the end of an exit in `world`, counted, and the system `assets.leave` of phase `sync`,
|
|
36460
|
+
* which lets a leaving scene's bundles go once its elements played their exit (F51). The seven
|
|
36461
|
+
* removers go to the state, because `onStop` has nothing but the state.
|
|
35502
36462
|
*
|
|
35503
36463
|
* @param ctx - Kernel context of the assets plugin.
|
|
35504
36464
|
*/
|
|
35505
36465
|
function connectAssets(ctx) {
|
|
35506
36466
|
const assets = withDeps$6(ctx);
|
|
35507
|
-
assets.state.removers.push(assets.deps.flow.onEnter("load", (node, run) => enterNode(assets, node, run)), assets.deps.flow.fx.handle("load", (descriptor, run) => runLoadEffect(assets, descriptor, run), { runInFast: true }), assets.deps.renderer.sync.textures.provide((key) => lookupTexture(assets, key)), assets.deps.world.ecs.onAdded(Exiting, () => {
|
|
36467
|
+
assets.state.removers.push(assets.deps.flow.onEnter("load", (node, run) => enterNode(assets, node, run)), assets.deps.flow.fx.handle("load", (descriptor, run) => runLoadEffect(assets, descriptor, run), { runInFast: true }), assets.deps.flow.fx.handle("ready", (descriptor) => answerReady(assets, bundlesOfDescriptor(descriptor)), { runInFast: true }), assets.deps.renderer.sync.textures.provide((key) => lookupTexture(assets, key)), assets.deps.world.ecs.onAdded(Exiting, () => {
|
|
35508
36468
|
assets.state.exiting += 1;
|
|
35509
36469
|
}), assets.deps.world.ecs.onRemoved(Exiting, () => {
|
|
35510
36470
|
assets.state.exiting -= 1;
|
|
@@ -35584,7 +36544,7 @@ async function startAssets(ctx) {
|
|
|
35584
36544
|
}
|
|
35585
36545
|
/**
|
|
35586
36546
|
* Frees everything in `onStop`: the preload and every running load are aborted, every texture is
|
|
35587
|
-
* destroyed, the
|
|
36547
|
+
* destroyed, the seven registrations are removed and the registries are emptied, the companions
|
|
35588
36548
|
* too. A teardown context carries the state and nothing else, so no other plugin is called here:
|
|
35589
36549
|
* no companion's `unload` either, its plugin stopped before this one.
|
|
35590
36550
|
*
|
|
@@ -35607,6 +36567,8 @@ function releaseAll(state) {
|
|
|
35607
36567
|
state.featureOfFlow.clear();
|
|
35608
36568
|
state.pinned.clear();
|
|
35609
36569
|
state.warned.clear();
|
|
36570
|
+
state.warmed.clear();
|
|
36571
|
+
state.readyFailed.clear();
|
|
35610
36572
|
state.companions.length = 0;
|
|
35611
36573
|
state.current = void 0;
|
|
35612
36574
|
state.sceneId = void 0;
|
|
@@ -35753,6 +36715,7 @@ function createAssetsApi(ctx) {
|
|
|
35753
36715
|
const assets = withDeps$6(ctx);
|
|
35754
36716
|
return {
|
|
35755
36717
|
load: (bundle) => loadBundle(assets, bundle, void 0, "request"),
|
|
36718
|
+
warm: (bundle) => warmBundle(assets, bundle),
|
|
35756
36719
|
unload: (bundle) => unload(assets, bundle),
|
|
35757
36720
|
isLoaded: (bundle) => isLoaded(assets, bundle),
|
|
35758
36721
|
texture: (key) => lookupTexture(assets, key),
|
|
@@ -36430,7 +37393,9 @@ function createAssetsState() {
|
|
|
36430
37393
|
sceneLeaving: [],
|
|
36431
37394
|
exiting: 0,
|
|
36432
37395
|
companions: [],
|
|
36433
|
-
restPending: false
|
|
37396
|
+
restPending: false,
|
|
37397
|
+
readyFailed: emptySet$2(),
|
|
37398
|
+
warmed: emptyMap$3()
|
|
36434
37399
|
};
|
|
36435
37400
|
}
|
|
36436
37401
|
/**
|
|
@@ -41339,7 +42304,7 @@ function complete(ectx) {
|
|
|
41339
42304
|
ectx.log.info("effects:checks", {
|
|
41340
42305
|
definitions: checks.checked,
|
|
41341
42306
|
broken: checks.failed,
|
|
41342
|
-
ms: tenths(pageNow() - checks.startedAt)
|
|
42307
|
+
ms: tenths(pageNow$1() - checks.startedAt)
|
|
41343
42308
|
});
|
|
41344
42309
|
checks.resolve();
|
|
41345
42310
|
}
|
|
@@ -41482,7 +42447,7 @@ function checkGlsl(ectx, run, definition) {
|
|
|
41482
42447
|
function startChecks(ectx) {
|
|
41483
42448
|
const { checks } = ectx.state;
|
|
41484
42449
|
const backend = ectx.deps.renderer.host.kind();
|
|
41485
|
-
checks.startedAt = pageNow();
|
|
42450
|
+
checks.startedAt = pageNow$1();
|
|
41486
42451
|
for (const definition of checkList(ectx)) {
|
|
41487
42452
|
if (checks.status.has(definition)) continue;
|
|
41488
42453
|
checks.status.set(definition, "pending");
|
|
@@ -41618,12 +42583,12 @@ async function gateChecks(ectx, node, run) {
|
|
|
41618
42583
|
if (!ectx.state.checks.started) startChecks(ectx);
|
|
41619
42584
|
const { checks } = ectx.state;
|
|
41620
42585
|
if (checks.waiting === 0) return;
|
|
41621
|
-
const began = pageNow();
|
|
42586
|
+
const began = pageNow$1();
|
|
41622
42587
|
await Promise.race([checks.settled, whenAborted(run.signal)]);
|
|
41623
42588
|
if (run.signal.aborted) return;
|
|
41624
42589
|
ectx.log.info("effects:mount-waited", {
|
|
41625
42590
|
node: node.path,
|
|
41626
|
-
ms: tenths(pageNow() - began)
|
|
42591
|
+
ms: tenths(pageNow$1() - began)
|
|
41627
42592
|
});
|
|
41628
42593
|
}
|
|
41629
42594
|
//#endregion
|
|
@@ -52766,6 +53731,26 @@ function nineSliceClipped(element) {
|
|
|
52766
53731
|
};
|
|
52767
53732
|
}
|
|
52768
53733
|
/**
|
|
53734
|
+
* Reports an element whose style is `hollow` but names no nine-slice: only a nine-slice has a
|
|
53735
|
+
* centre to leave out, so the field does nothing there. `hollow: false` asks for nothing either way.
|
|
53736
|
+
*
|
|
53737
|
+
* @param element - The element to check.
|
|
53738
|
+
* @returns The finding, or `undefined`.
|
|
53739
|
+
* @example
|
|
53740
|
+
* ```ts
|
|
53741
|
+
* hollowWithoutNineSlice({ key: "memFrost", type: "stack", style: { hollow: true } } as Element);
|
|
53742
|
+
* // { rule: "hollow-without-nine-slice", key: "memFrost", detail: "stack" }
|
|
53743
|
+
* ```
|
|
53744
|
+
*/
|
|
53745
|
+
function hollowWithoutNineSlice(element) {
|
|
53746
|
+
if (element.style.hollow !== true || element.style.nineSlice !== void 0) return void 0;
|
|
53747
|
+
return {
|
|
53748
|
+
rule: "hollow-without-nine-slice",
|
|
53749
|
+
key: nameOf(element),
|
|
53750
|
+
detail: element.type
|
|
53751
|
+
};
|
|
53752
|
+
}
|
|
53753
|
+
/**
|
|
52769
53754
|
* Reports a root element whose style sets a `zIndex`: a root draws at the order of its layer,
|
|
52770
53755
|
* so the value is ignored.
|
|
52771
53756
|
*
|
|
@@ -52786,7 +53771,7 @@ function zIndexOnRoot(element) {
|
|
|
52786
53771
|
};
|
|
52787
53772
|
}
|
|
52788
53773
|
/**
|
|
52789
|
-
* Runs the
|
|
53774
|
+
* Runs the six rules over every live element.
|
|
52790
53775
|
*
|
|
52791
53776
|
* @param ctx - Domain context of the ui plugin.
|
|
52792
53777
|
* @returns One finding per rule and element, in element order.
|
|
@@ -52801,6 +53786,7 @@ function runLint(ctx) {
|
|
|
52801
53786
|
textOverflow(ctx, element),
|
|
52802
53787
|
absoluteWithoutReason(element),
|
|
52803
53788
|
nineSliceClipped(element),
|
|
53789
|
+
hollowWithoutNineSlice(element),
|
|
52804
53790
|
zIndexOnRoot(element)
|
|
52805
53791
|
]) if (finding !== void 0) findings.push(finding);
|
|
52806
53792
|
}
|
|
@@ -59985,19 +60971,48 @@ function load(bundle) {
|
|
|
59985
60971
|
};
|
|
59986
60972
|
}
|
|
59987
60973
|
/**
|
|
59988
|
-
*
|
|
60974
|
+
* Creates the effect a node awaits to rest on bundles and stay answerable (F52). The handler of the
|
|
60975
|
+
* kind `"ready"` is registered by this plugin and runs in fast mode too. It answers `true` when every
|
|
60976
|
+
* bundle is loaded and its textures went to the GPU (`assets.warm`), or its last load failed, so a
|
|
60977
|
+
* node never hangs on it. Otherwise it starts what is missing, answers `false`, and posts the world
|
|
60978
|
+
* event `ready` into `flow.inbox` once all of it settled: the node rests on `inbox: ["ready"]`
|
|
60979
|
+
* meanwhile, and Back still answers. A headless `assets` answers `true`; an app without `assets`,
|
|
60980
|
+
* such as the headless app of `game.headless()`, resolves `undefined`, hence `=== false`. A name
|
|
60981
|
+
* the manifest lacks throws, as for `load`.
|
|
59989
60982
|
*
|
|
59990
|
-
* @
|
|
60983
|
+
* @param bundle - One bundle name, or a list of them.
|
|
60984
|
+
* @returns The descriptor a transit node awaits.
|
|
59991
60985
|
* @example
|
|
59992
60986
|
* ```ts
|
|
59993
|
-
*
|
|
60987
|
+
* ready("ep01.memory"); // { kind: "ready", payload: { bundles: ["ep01.memory"] } }
|
|
60988
|
+
* // The transit node in front of the rest node `wait` (inbox: ["elapsed", "ready"]):
|
|
60989
|
+
* if ((await fx(ready(["ep01.memory", "ui"]))) === false) return out.wait(); // false: still loading
|
|
60990
|
+
* return out.open(); // true: loaded and on the GPU
|
|
60991
|
+
* ```
|
|
60992
|
+
*/
|
|
60993
|
+
function ready(bundle) {
|
|
60994
|
+
return {
|
|
60995
|
+
kind: "ready",
|
|
60996
|
+
payload: { bundles: typeof bundle === "string" ? [bundle] : [...bundle] }
|
|
60997
|
+
};
|
|
60998
|
+
}
|
|
60999
|
+
/**
|
|
61000
|
+
* Binds `defineBundles`, `load` and `ready` to one game's bundle keys. Type-only: the same
|
|
61001
|
+
* functions.
|
|
61002
|
+
*
|
|
61003
|
+
* @returns The three helpers whose keys are checked by the compiler.
|
|
61004
|
+
* @example
|
|
61005
|
+
* ```ts
|
|
61006
|
+
* const { load, ready } = bundlesFor<"board" | "board.chains">();
|
|
59994
61007
|
* load("board.chains"); // { kind: "load", payload: { bundles: ["board.chains"] } }
|
|
61008
|
+
* ready("board"); // { kind: "ready", payload: { bundles: ["board"] } }
|
|
59995
61009
|
* ```
|
|
59996
61010
|
*/
|
|
59997
61011
|
function bundlesFor() {
|
|
59998
61012
|
return {
|
|
59999
61013
|
defineBundles,
|
|
60000
|
-
load
|
|
61014
|
+
load,
|
|
61015
|
+
ready
|
|
60001
61016
|
};
|
|
60002
61017
|
}
|
|
60003
61018
|
//#endregion
|
|
@@ -61203,6 +62218,7 @@ function cubicBezier(x1, y1, x2, y2) {
|
|
|
61203
62218
|
* | renderer | monitor | { budgetMs: "rate", frames: 1024, stillFrames: 60, stillMpx: 0.25, churnPerSecond: 4, churnSeconds: 3, churnAfterTrimMs: 1000 }, the performance log of an agent build, the thresholds of its `problem` rules and `sections`, the sections it starts with (`MonitorSections`, every one on when left out); shallow merge: a game that sets `monitor` gives `budgetMs` and `frames`, a threshold it leaves out keeps its default, a section it leaves out is on |
|
|
61204
62219
|
* | renderer | keptMb | 64, MiB the kept pictures may hold: a filtered view that did not change is drawn from its picture, the least recently drawn goes first; 0 keeps none |
|
|
61205
62220
|
* | renderer | warm | 1, probe draws a drawn frame that create the GPU pipelines while the game loads; 0 creates each in the first frame that needs it |
|
|
62221
|
+
* | renderer | uploads | 1, texture sources `sync.textures.upload` puts on the GPU a drawn frame (~9 ms each on the A26); 0 turns the queue off |
|
|
61206
62222
|
* | input | tapSlopPx | 12 |
|
|
61207
62223
|
* | input | longPressMs | 450 |
|
|
61208
62224
|
* | input | dragStartPx | 8 |
|
|
@@ -61360,4 +62376,4 @@ const screen = [
|
|
|
61360
62376
|
uiPlugin
|
|
61361
62377
|
];
|
|
61362
62378
|
//#endregion
|
|
61363
|
-
export {
|
|
62379
|
+
export { sfx as $, refuseStart as $t, types_exports$10 as A, Noise as At, defineMotion as B, Frames as Bt, types_exports$3 as C, effectsPlugin as Ct, types_exports$7 as D, ColorMatrix as Dt, types_exports$6 as E, Blur as Et, types_exports$15 as F, scenesPlugin as Ft, external as G, PERF_CAUSES as Gt, platformPlugin as H, PASS_KINDS as Ht, types_exports$16 as I, assetsPlugin as It, mark as J, PROBLEM_RULES as Jt, frames as K, PERF_GAP_BUCKETS as Kt, types_exports$17 as L, animPlugin as Lt, types_exports$12 as M, defineFilter as Mt, types_exports$13 as N, debugPlugin as Nt, types_exports$8 as O, Displacement as Ot, types_exports$14 as P, audioPlugin as Pt, set as Q, flowPlugin as Qt, uiPlugin as R, AnimPlayer as Rt, types_exports$2 as S, messageDuration as St, types_exports$5 as T, Alpha as Tt, HAPTIC_KINDS as U, frameAt as Ut, textPlugin as V, rendererPlugin as Vt, defineAnimation as W, MONITOR_SECTIONS as Wt, play$1 as X, DEMAND_REASONS as Xt, parallel as Y, SHADER_WHATS as Yt, sequence as Z, worldPlugin as Zt, defineBundles as _, Touchable as _t, cubicBezier as a, SaveUnreadableError as an, wait as at, types_exports as b, i18nPlugin as bt, hint as c, clockPlugin as cn, DropTarget as ct, defineScene as d, Pointer as dt, exit as en, spawn as et, tr as f, PointerOver as ft, music as g, Tappable as gt, defineEmitter as h, Swipeable as ht, screen as i, modelPlugin as in, use as it, types_exports$11 as j, Outline as jt, types_exports$9 as k, Glow as kt, schedule as l, Held as lt, flattenFeatures as m, Pressed as mt, createPlugin as n, to as nn, stagger as nt, defineEffect as o, lifecyclePlugin as on, inputPlugin as ot, defineFeature as p, Pressable as pt, haptic as q, PERF_LOG_VERSION as qt, defineGame as r, type as rn, tween as rt, guide as s, timePlugin as sn, Draggable as st, createApp as t, slot as tn, spawned as tt, projection as u, Hovered as ut, load as v, Traceable as vt, types_exports$4 as w, Emitter as wt, types_exports$1 as x, messageArgument as xt, ready as y, Traced as yt, resolve as z, Animation as zt };
|