@rydr/game-sdk 1.16.0 → 1.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -0
- package/dist/client/HardwareStore.d.ts +6 -0
- package/dist/client/HardwareStore.d.ts.map +1 -1
- package/dist/client/HardwareStore.js +1 -0
- package/dist/client/HardwareStore.js.map +1 -1
- package/dist/client/PlatformClient.d.ts +4 -0
- package/dist/client/PlatformClient.d.ts.map +1 -1
- package/dist/client/PlatformClient.js +3 -0
- package/dist/client/PlatformClient.js.map +1 -1
- package/dist/host/PlatformHost.d.ts +6 -1
- package/dist/host/PlatformHost.d.ts.map +1 -1
- package/dist/host/PlatformHost.js +6 -0
- package/dist/host/PlatformHost.js.map +1 -1
- package/dist/protocol/capabilities.d.ts +2 -1
- package/dist/protocol/capabilities.d.ts.map +1 -1
- package/dist/protocol/capabilities.js.map +1 -1
- package/dist/protocol/guards.d.ts.map +1 -1
- package/dist/protocol/guards.js +1 -0
- package/dist/protocol/guards.js.map +1 -1
- package/dist/protocol/messages.d.ts +16 -1
- package/dist/protocol/messages.d.ts.map +1 -1
- package/dist/protocol/version.d.ts +1 -1
- package/dist/protocol/version.js +1 -1
- package/dist/three/index.d.ts +3 -0
- package/dist/three/index.d.ts.map +1 -1
- package/dist/three/index.js +3 -0
- package/dist/three/index.js.map +1 -1
- package/dist/three/merge.d.ts +88 -0
- package/dist/three/merge.d.ts.map +1 -0
- package/dist/three/merge.js +148 -0
- package/dist/three/merge.js.map +1 -0
- package/dist/three/perf-marks.d.ts +50 -0
- package/dist/three/perf-marks.d.ts.map +1 -0
- package/dist/three/perf-marks.js +86 -0
- package/dist/three/perf-marks.js.map +1 -0
- package/dist/three/perf-overlay.d.ts +104 -0
- package/dist/three/perf-overlay.d.ts.map +1 -0
- package/dist/three/perf-overlay.js +446 -0
- package/dist/three/perf-overlay.js.map +1 -0
- package/dist/three/world-loader.d.ts +10 -0
- package/dist/three/world-loader.d.ts.map +1 -1
- package/dist/three/world-loader.js +7 -0
- package/dist/three/world-loader.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* merge — collapse the per-mesh draw calls of a subtree into one batched mesh
|
|
3
|
+
* per material.
|
|
4
|
+
*
|
|
5
|
+
* three.js submits one draw call per visible mesh, so a scene full of static
|
|
6
|
+
* decoration (a platform world's ~1800 props) or many articulated units (each
|
|
7
|
+
* built from dozens of small parts) is dominated by draw-call CPU, not GPU or
|
|
8
|
+
* sim. The fix is the same primitive in both cases: **merge sibling meshes that
|
|
9
|
+
* share a material into one batched geometry, baking each mesh's transform into
|
|
10
|
+
* shared vertex data.** A platform world collapses to ≈one draw per material; a
|
|
11
|
+
* unit's static parts collapse to a handful.
|
|
12
|
+
*
|
|
13
|
+
* This is the single, SDK-owned implementation of that primitive — games never
|
|
14
|
+
* reimplement bucketing, transform-baking, `mergeGeometries`, material handling
|
|
15
|
+
* or dispose discipline. They pass only what the SDK can't know: which sub-nodes
|
|
16
|
+
* are animated ({@link MergeOptions.boundaries}) and which parts to leave alone
|
|
17
|
+
* ({@link MergeOptions.keepIndividual}). For static worlds even that disappears —
|
|
18
|
+
* see `loadWorld({ mergeStatics: true })`.
|
|
19
|
+
*
|
|
20
|
+
* Baking is destructive to per-mesh transforms: a merged mesh can no longer be
|
|
21
|
+
* moved, hidden, recoiled or scattered on its own. Opt a subtree OUT with
|
|
22
|
+
* `userData.__noMerge = true` on its root.
|
|
23
|
+
*/
|
|
24
|
+
import * as THREE from "three";
|
|
25
|
+
/** Count of draw calls before/after, for logging and draw-call audits. */
|
|
26
|
+
export interface MergeResult {
|
|
27
|
+
/** Mesh draw calls that were merged away. */
|
|
28
|
+
readonly before: number;
|
|
29
|
+
/** Batched mesh draw calls created (≈ one per material per island). */
|
|
30
|
+
readonly after: number;
|
|
31
|
+
}
|
|
32
|
+
export interface MergeOptions {
|
|
33
|
+
/**
|
|
34
|
+
* Sub-nodes that must keep their own transform (a rotating turret yaw,
|
|
35
|
+
* spinning wheels, a rotor hub). Each becomes a merge-island root: descendants
|
|
36
|
+
* are baked relative to it and the batch is parented under it, so the island
|
|
37
|
+
* keeps animating after the merge. Meshes never bake across an island
|
|
38
|
+
* boundary. Default: none — everything bakes relative to `root`.
|
|
39
|
+
*/
|
|
40
|
+
boundaries?: THREE.Object3D[];
|
|
41
|
+
/**
|
|
42
|
+
* How to bucket meshes for merging:
|
|
43
|
+
* - `'instance'` (default): by `material` identity. Static worlds already
|
|
44
|
+
* share one material instance across sibling props; the batch **reuses** that
|
|
45
|
+
* instance, so live opacity/color tweaks on the shared material carry through.
|
|
46
|
+
* - `'source'`: by a caller-provided source-material key. Articulated units
|
|
47
|
+
* clone each part's material (so per-part flash doesn't bleed), giving
|
|
48
|
+
* "same-palette" parts distinct UUIDs that `'instance'` would never batch.
|
|
49
|
+
* The batch gets a fresh clone of the source material, so per-material
|
|
50
|
+
* hit-flash still flashes the whole chunk.
|
|
51
|
+
*/
|
|
52
|
+
groupBy?: "instance" | "source";
|
|
53
|
+
/**
|
|
54
|
+
* Where the source material lives when `groupBy: 'source'`. Returning `null`
|
|
55
|
+
* leaves the mesh individual. Default: `mesh.userData.unit?.srcMat ?? null`.
|
|
56
|
+
*/
|
|
57
|
+
sourceMaterialAccessor?: (mesh: THREE.Mesh) => THREE.Material | null;
|
|
58
|
+
/** Predicate for "skip this mesh, keep it an individual draw" (recoiling barrels, etc.). */
|
|
59
|
+
keepIndividual?: (mesh: THREE.Mesh) => boolean;
|
|
60
|
+
/** Called once per created batch with the meshes it consumed — so callers can re-sync a parts list. */
|
|
61
|
+
onBatch?: (batch: THREE.Mesh, consumed: THREE.Mesh[]) => void;
|
|
62
|
+
/**
|
|
63
|
+
* Dispose consumed geometries (and their per-mesh materials) after merge.
|
|
64
|
+
* Default: `false` — safe for shared caches (the world GLB dedup clones shared
|
|
65
|
+
* geometry, so a source geom may back sibling clones). Owned-unit callers with
|
|
66
|
+
* private clones may set `true`. Never disposes a reused `'instance'` material
|
|
67
|
+
* or a `'source'` source material — those outlive the batch.
|
|
68
|
+
*/
|
|
69
|
+
disposeConsumed?: boolean;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Merge the mergeable meshes under `root` in place: detach the originals and add
|
|
73
|
+
* one batched mesh per (island, material, attribute-set, index-ness, renderOrder,
|
|
74
|
+
* shadow flags) bucket. Idempotent — sets `root.userData.__merged` and returns
|
|
75
|
+
* `{ before: 0, after: 0 }` on a second call.
|
|
76
|
+
*
|
|
77
|
+
* Transforms are baked into each island's LOCAL space, so `root`'s own transform
|
|
78
|
+
* (and each island's animation) still applies afterward. Buckets with a single
|
|
79
|
+
* mesh are left individual — same draw-call count, no wasted re-bake. Buckets
|
|
80
|
+
* `mergeGeometries` rejects (incompatible attributes) are left unmerged + warned.
|
|
81
|
+
*
|
|
82
|
+
* Skipped (left as individual draws): `userData.__noMerge` subtrees, hidden
|
|
83
|
+
* meshes (kept toggleable), skinned / morph-target / multi-material meshes (their
|
|
84
|
+
* per-mesh state can't be baked), `keepIndividual` matches, and — in `'source'`
|
|
85
|
+
* mode — meshes whose `sourceMaterialAccessor` returns `null`.
|
|
86
|
+
*/
|
|
87
|
+
export declare function mergeByMaterial(root: THREE.Object3D, opts?: MergeOptions): MergeResult;
|
|
88
|
+
//# sourceMappingURL=merge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge.d.ts","sourceRoot":"","sources":["../../src/three/merge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,0EAA0E;AAC1E,MAAM,WAAW,WAAW;IAC1B,6CAA6C;IAC7C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,uEAAuE;IACvE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;IAC9B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAC;IAChC;;;OAGG;IACH,sBAAsB,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;IACrE,4FAA4F;IAC5F,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC;IAC/C,uGAAuG;IACvG,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC;IAC9D;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAcD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,QAAQ,EAAE,IAAI,GAAE,YAAiB,GAAG,WAAW,CA+G1F"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* merge — collapse the per-mesh draw calls of a subtree into one batched mesh
|
|
3
|
+
* per material.
|
|
4
|
+
*
|
|
5
|
+
* three.js submits one draw call per visible mesh, so a scene full of static
|
|
6
|
+
* decoration (a platform world's ~1800 props) or many articulated units (each
|
|
7
|
+
* built from dozens of small parts) is dominated by draw-call CPU, not GPU or
|
|
8
|
+
* sim. The fix is the same primitive in both cases: **merge sibling meshes that
|
|
9
|
+
* share a material into one batched geometry, baking each mesh's transform into
|
|
10
|
+
* shared vertex data.** A platform world collapses to ≈one draw per material; a
|
|
11
|
+
* unit's static parts collapse to a handful.
|
|
12
|
+
*
|
|
13
|
+
* This is the single, SDK-owned implementation of that primitive — games never
|
|
14
|
+
* reimplement bucketing, transform-baking, `mergeGeometries`, material handling
|
|
15
|
+
* or dispose discipline. They pass only what the SDK can't know: which sub-nodes
|
|
16
|
+
* are animated ({@link MergeOptions.boundaries}) and which parts to leave alone
|
|
17
|
+
* ({@link MergeOptions.keepIndividual}). For static worlds even that disappears —
|
|
18
|
+
* see `loadWorld({ mergeStatics: true })`.
|
|
19
|
+
*
|
|
20
|
+
* Baking is destructive to per-mesh transforms: a merged mesh can no longer be
|
|
21
|
+
* moved, hidden, recoiled or scattered on its own. Opt a subtree OUT with
|
|
22
|
+
* `userData.__noMerge = true` on its root.
|
|
23
|
+
*/
|
|
24
|
+
import * as THREE from "three";
|
|
25
|
+
import { mergeGeometries } from "three/addons/utils/BufferGeometryUtils.js";
|
|
26
|
+
const defaultSourceAccessor = (mesh) => mesh.userData.unit?.srcMat ?? null;
|
|
27
|
+
/**
|
|
28
|
+
* Merge the mergeable meshes under `root` in place: detach the originals and add
|
|
29
|
+
* one batched mesh per (island, material, attribute-set, index-ness, renderOrder,
|
|
30
|
+
* shadow flags) bucket. Idempotent — sets `root.userData.__merged` and returns
|
|
31
|
+
* `{ before: 0, after: 0 }` on a second call.
|
|
32
|
+
*
|
|
33
|
+
* Transforms are baked into each island's LOCAL space, so `root`'s own transform
|
|
34
|
+
* (and each island's animation) still applies afterward. Buckets with a single
|
|
35
|
+
* mesh are left individual — same draw-call count, no wasted re-bake. Buckets
|
|
36
|
+
* `mergeGeometries` rejects (incompatible attributes) are left unmerged + warned.
|
|
37
|
+
*
|
|
38
|
+
* Skipped (left as individual draws): `userData.__noMerge` subtrees, hidden
|
|
39
|
+
* meshes (kept toggleable), skinned / morph-target / multi-material meshes (their
|
|
40
|
+
* per-mesh state can't be baked), `keepIndividual` matches, and — in `'source'`
|
|
41
|
+
* mode — meshes whose `sourceMaterialAccessor` returns `null`.
|
|
42
|
+
*/
|
|
43
|
+
export function mergeByMaterial(root, opts = {}) {
|
|
44
|
+
if (root.userData.__merged === true)
|
|
45
|
+
return { before: 0, after: 0 };
|
|
46
|
+
const groupBy = opts.groupBy ?? "instance";
|
|
47
|
+
const sourceAccessor = opts.sourceMaterialAccessor ?? defaultSourceAccessor;
|
|
48
|
+
const boundarySet = new Set(opts.boundaries ?? []);
|
|
49
|
+
root.updateMatrixWorld(true);
|
|
50
|
+
const islandRootFor = (mesh) => {
|
|
51
|
+
let n = mesh.parent;
|
|
52
|
+
while (n && n !== root) {
|
|
53
|
+
if (boundarySet.has(n))
|
|
54
|
+
return n;
|
|
55
|
+
n = n.parent;
|
|
56
|
+
}
|
|
57
|
+
return root;
|
|
58
|
+
};
|
|
59
|
+
// Cache an inverse-world matrix per island so each mesh bakes into island-local space.
|
|
60
|
+
const islandInverse = new Map();
|
|
61
|
+
const inverseFor = (island) => {
|
|
62
|
+
let inv = islandInverse.get(island);
|
|
63
|
+
if (!inv) {
|
|
64
|
+
island.updateWorldMatrix(true, false);
|
|
65
|
+
inv = new THREE.Matrix4().copy(island.matrixWorld).invert();
|
|
66
|
+
islandInverse.set(island, inv);
|
|
67
|
+
}
|
|
68
|
+
return inv;
|
|
69
|
+
};
|
|
70
|
+
const buckets = new Map();
|
|
71
|
+
const local = new THREE.Matrix4();
|
|
72
|
+
const visit = (obj) => {
|
|
73
|
+
if (obj.userData.__noMerge === true)
|
|
74
|
+
return; // skip animated/handle subtrees
|
|
75
|
+
if (obj.visible === false)
|
|
76
|
+
return; // keep hidden meshes toggleable
|
|
77
|
+
const mesh = obj;
|
|
78
|
+
if (mesh.isMesh && !mesh.isSkinnedMesh && !Array.isArray(mesh.material) && mesh.geometry) {
|
|
79
|
+
const morphs = mesh.geometry.morphAttributes;
|
|
80
|
+
const noMorph = !morphs || Object.keys(morphs).length === 0;
|
|
81
|
+
const keep = opts.keepIndividual?.(mesh) === true;
|
|
82
|
+
const keyMaterial = groupBy === "source" ? sourceAccessor(mesh) : mesh.material;
|
|
83
|
+
if (noMorph && !keep && keyMaterial) {
|
|
84
|
+
const geom = mesh.geometry;
|
|
85
|
+
const island = islandRootFor(mesh);
|
|
86
|
+
const attrSig = Object.keys(geom.attributes).sort().join(",");
|
|
87
|
+
const key = `${island.uuid}|${keyMaterial.uuid}|${attrSig}|${geom.index ? "i" : "n"}|${mesh.renderOrder}|${mesh.castShadow ? 1 : 0}|${mesh.receiveShadow ? 1 : 0}`;
|
|
88
|
+
mesh.updateWorldMatrix(true, false);
|
|
89
|
+
local.copy(inverseFor(island)).multiply(mesh.matrixWorld);
|
|
90
|
+
const baked = geom.clone();
|
|
91
|
+
baked.applyMatrix4(local);
|
|
92
|
+
let bucket = buckets.get(key);
|
|
93
|
+
if (!bucket) {
|
|
94
|
+
bucket = { keyMaterial, island, renderOrder: mesh.renderOrder, geometries: [], consumed: [] };
|
|
95
|
+
buckets.set(key, bucket);
|
|
96
|
+
}
|
|
97
|
+
bucket.geometries.push(baked);
|
|
98
|
+
bucket.consumed.push(mesh);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
for (const child of obj.children)
|
|
102
|
+
visit(child);
|
|
103
|
+
};
|
|
104
|
+
for (const child of root.children)
|
|
105
|
+
visit(child);
|
|
106
|
+
let before = 0;
|
|
107
|
+
let after = 0;
|
|
108
|
+
for (const bucket of buckets.values()) {
|
|
109
|
+
if (bucket.consumed.length < 2) {
|
|
110
|
+
// Nothing to batch — drop the throwaway bake, leave the original in place.
|
|
111
|
+
for (const g of bucket.geometries)
|
|
112
|
+
g.dispose();
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
const merged = mergeGeometries(bucket.geometries, false);
|
|
116
|
+
for (const g of bucket.geometries)
|
|
117
|
+
g.dispose(); // copied into `merged`
|
|
118
|
+
if (!merged) {
|
|
119
|
+
console.warn("[merge] skipped an incompatible material bucket");
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
const reference = bucket.consumed[0];
|
|
123
|
+
const material = groupBy === "source" ? bucket.keyMaterial.clone() : bucket.keyMaterial;
|
|
124
|
+
const batch = new THREE.Mesh(merged, material);
|
|
125
|
+
batch.name = "merged-batch";
|
|
126
|
+
batch.renderOrder = bucket.renderOrder;
|
|
127
|
+
batch.castShadow = reference.castShadow;
|
|
128
|
+
batch.receiveShadow = reference.receiveShadow;
|
|
129
|
+
bucket.island.add(batch);
|
|
130
|
+
for (const mesh of bucket.consumed) {
|
|
131
|
+
mesh.parent?.remove(mesh);
|
|
132
|
+
before++;
|
|
133
|
+
}
|
|
134
|
+
after++;
|
|
135
|
+
opts.onBatch?.(batch, bucket.consumed);
|
|
136
|
+
if (opts.disposeConsumed) {
|
|
137
|
+
for (const mesh of bucket.consumed) {
|
|
138
|
+
mesh.geometry?.dispose();
|
|
139
|
+
const m = mesh.material;
|
|
140
|
+
if (m && m !== bucket.keyMaterial)
|
|
141
|
+
m.dispose();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
root.userData.__merged = true;
|
|
146
|
+
return { before, after };
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=merge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge.js","sourceRoot":"","sources":["../../src/three/merge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,MAAM,2CAA2C,CAAC;AAkD5E,MAAM,qBAAqB,GAAG,CAAC,IAAgB,EAAyB,EAAE,CACvE,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAqC,IAAI,IAAI,CAAC;AAWrE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,eAAe,CAAC,IAAoB,EAAE,OAAqB,EAAE;IAC3E,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,KAAK,IAAI;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IAEpE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,UAAU,CAAC;IAC3C,MAAM,cAAc,GAAG,IAAI,CAAC,sBAAsB,IAAI,qBAAqB,CAAC;IAC5E,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;IAEnD,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAE7B,MAAM,aAAa,GAAG,CAAC,IAAoB,EAAkB,EAAE;QAC7D,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;QACpB,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YACvB,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;gBAAE,OAAO,CAAC,CAAC;YACjC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;QACf,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;IAEF,uFAAuF;IACvF,MAAM,aAAa,GAAG,IAAI,GAAG,EAAiC,CAAC;IAC/D,MAAM,UAAU,GAAG,CAAC,MAAsB,EAAiB,EAAE;QAC3D,IAAI,GAAG,GAAG,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YACtC,GAAG,GAAG,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,MAAM,EAAE,CAAC;YAC5D,aAAa,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACjC,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC,CAAC;IAEF,MAAM,OAAO,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC/C,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;IAElC,MAAM,KAAK,GAAG,CAAC,GAAmB,EAAQ,EAAE;QAC1C,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,KAAK,IAAI;YAAE,OAAO,CAAC,gCAAgC;QAC7E,IAAI,GAAG,CAAC,OAAO,KAAK,KAAK;YAAE,OAAO,CAAC,gCAAgC;QACnE,MAAM,IAAI,GAAG,GAAiE,CAAC;QAC/E,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,aAAa,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACzF,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC;YAC7C,MAAM,OAAO,GAAG,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;YAC5D,MAAM,IAAI,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC;YAClD,MAAM,WAAW,GACf,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAE,IAAI,CAAC,QAA2B,CAAC;YAClF,IAAI,OAAO,IAAI,CAAC,IAAI,IAAI,WAAW,EAAE,CAAC;gBACpC,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC;gBAC3B,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;gBACnC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC9D,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,IAAI,IAAI,WAAW,CAAC,IAAI,IAAI,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAEnK,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;gBACpC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;gBAC1D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;gBAC3B,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;gBAE1B,IAAI,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBAC9B,IAAI,CAAC,MAAM,EAAE,CAAC;oBACZ,MAAM,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;oBAC9F,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;gBAC3B,CAAC;gBACD,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC9B,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,QAAQ;YAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IACjD,CAAC,CAAC;IACF,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ;QAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IAEhD,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;QACtC,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/B,2EAA2E;YAC3E,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,UAAU;gBAAE,CAAC,CAAC,OAAO,EAAE,CAAC;YAC/C,SAAS;QACX,CAAC;QAED,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QACzD,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,UAAU;YAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,uBAAuB;QACvE,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;YAChE,SAAS;QACX,CAAC;QAED,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC;QACtC,MAAM,QAAQ,GAAG,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC;QACxF,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC/C,KAAK,CAAC,IAAI,GAAG,cAAc,CAAC;QAC5B,KAAK,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;QACvC,KAAK,CAAC,UAAU,GAAG,SAAS,CAAC,UAAU,CAAC;QACxC,KAAK,CAAC,aAAa,GAAG,SAAS,CAAC,aAAa,CAAC;QAC9C,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAEzB,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACnC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;YAC1B,MAAM,EAAE,CAAC;QACX,CAAC;QACD,KAAK,EAAE,CAAC;QAER,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QAEvC,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACzB,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;gBACnC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC;gBACzB,MAAM,CAAC,GAAG,IAAI,CAAC,QAAsC,CAAC;gBACtD,IAAI,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,WAAW;oBAAE,CAAC,CAAC,OAAO,EAAE,CAAC;YACjD,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC;IAC9B,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* perf-marks — lightweight timing instrumentation, shared so any rydr game's
|
|
3
|
+
* marks feed the same {@link PerfOverlay} panel.
|
|
4
|
+
*
|
|
5
|
+
* Toggle with `window.__PERF__ = true` (or `?perf=1`, handled by the overlay).
|
|
6
|
+
* When disabled every call is a cheap no-op, so it is safe to sprinkle through
|
|
7
|
+
* hot-path code.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* ```ts
|
|
11
|
+
* perfMark('frame.update'); // start a region
|
|
12
|
+
* … work …
|
|
13
|
+
* perfMeasure('frame.update'); // end the region, record elapsed ms
|
|
14
|
+
* window.__perfReport(); // { label: { avg, max, n } }
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* Browser-only (uses `performance.now()` + `window`). Part of the optional
|
|
18
|
+
* `@rydr/game-sdk/three` entry point.
|
|
19
|
+
*/
|
|
20
|
+
/** One label's rolling stats over the last {@link SAMPLES} measures. */
|
|
21
|
+
export interface PerfReportEntry {
|
|
22
|
+
avg: number;
|
|
23
|
+
max: number;
|
|
24
|
+
n: number;
|
|
25
|
+
}
|
|
26
|
+
/** Snapshot of every recorded label. */
|
|
27
|
+
export type PerfReport = Record<string, PerfReportEntry>;
|
|
28
|
+
declare global {
|
|
29
|
+
interface Window {
|
|
30
|
+
__PERF__?: boolean;
|
|
31
|
+
__perfReport?: () => PerfReport | null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** Start a timing region under `label`. No-op unless `window.__PERF__` is set. */
|
|
35
|
+
export declare function perfMark(label: string): void;
|
|
36
|
+
/**
|
|
37
|
+
* End the region opened by `perfMark(label)` and push the elapsed ms into a
|
|
38
|
+
* rolling ring buffer. No-op if no matching mark or perf is disabled.
|
|
39
|
+
*/
|
|
40
|
+
export declare function perfMeasure(label: string): void;
|
|
41
|
+
/** Snapshot every recorded label as `{ avg, max, n }`. null when perf is off. */
|
|
42
|
+
export declare function perfReport(): PerfReport | null;
|
|
43
|
+
/**
|
|
44
|
+
* Rolling average for a label, WITHOUT the `__PERF__` guard — the overlay reads
|
|
45
|
+
* these to render its phase breakdown regardless of global logging state.
|
|
46
|
+
*/
|
|
47
|
+
export declare function perfAvg(label: string): number;
|
|
48
|
+
/** Rolling peak for a label. Same no-guard rule as {@link perfAvg}. */
|
|
49
|
+
export declare function perfPeak(label: string): number;
|
|
50
|
+
//# sourceMappingURL=perf-marks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"perf-marks.d.ts","sourceRoot":"","sources":["../../src/three/perf-marks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAMH,wEAAwE;AACxE,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,CAAC,EAAE,MAAM,CAAC;CACX;AACD,wCAAwC;AACxC,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAEzD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,YAAY,CAAC,EAAE,MAAM,UAAU,GAAG,IAAI,CAAC;KACxC;CACF;AAMD,kFAAkF;AAClF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAG5C;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAY/C;AAED,iFAAiF;AACjF,wBAAgB,UAAU,IAAI,UAAU,GAAG,IAAI,CAU9C;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAI7C;AAED,uEAAuE;AACvE,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAI9C"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* perf-marks — lightweight timing instrumentation, shared so any rydr game's
|
|
3
|
+
* marks feed the same {@link PerfOverlay} panel.
|
|
4
|
+
*
|
|
5
|
+
* Toggle with `window.__PERF__ = true` (or `?perf=1`, handled by the overlay).
|
|
6
|
+
* When disabled every call is a cheap no-op, so it is safe to sprinkle through
|
|
7
|
+
* hot-path code.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* ```ts
|
|
11
|
+
* perfMark('frame.update'); // start a region
|
|
12
|
+
* … work …
|
|
13
|
+
* perfMeasure('frame.update'); // end the region, record elapsed ms
|
|
14
|
+
* window.__perfReport(); // { label: { avg, max, n } }
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* Browser-only (uses `performance.now()` + `window`). Part of the optional
|
|
18
|
+
* `@rydr/game-sdk/three` entry point.
|
|
19
|
+
*/
|
|
20
|
+
const SAMPLES = 60;
|
|
21
|
+
const marks = new Map();
|
|
22
|
+
const histories = new Map();
|
|
23
|
+
function enabled() {
|
|
24
|
+
return typeof window !== "undefined" && window.__PERF__ === true;
|
|
25
|
+
}
|
|
26
|
+
/** Start a timing region under `label`. No-op unless `window.__PERF__` is set. */
|
|
27
|
+
export function perfMark(label) {
|
|
28
|
+
if (!enabled())
|
|
29
|
+
return;
|
|
30
|
+
marks.set(label, performance.now());
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* End the region opened by `perfMark(label)` and push the elapsed ms into a
|
|
34
|
+
* rolling ring buffer. No-op if no matching mark or perf is disabled.
|
|
35
|
+
*/
|
|
36
|
+
export function perfMeasure(label) {
|
|
37
|
+
if (!enabled())
|
|
38
|
+
return;
|
|
39
|
+
const start = marks.get(label);
|
|
40
|
+
if (start == null)
|
|
41
|
+
return;
|
|
42
|
+
const ms = performance.now() - start;
|
|
43
|
+
let hist = histories.get(label);
|
|
44
|
+
if (!hist) {
|
|
45
|
+
hist = [];
|
|
46
|
+
histories.set(label, hist);
|
|
47
|
+
}
|
|
48
|
+
hist.push(ms);
|
|
49
|
+
if (hist.length > SAMPLES)
|
|
50
|
+
hist.shift();
|
|
51
|
+
}
|
|
52
|
+
/** Snapshot every recorded label as `{ avg, max, n }`. null when perf is off. */
|
|
53
|
+
export function perfReport() {
|
|
54
|
+
if (!enabled())
|
|
55
|
+
return null;
|
|
56
|
+
const out = {};
|
|
57
|
+
for (const [label, hist] of histories) {
|
|
58
|
+
if (!hist.length)
|
|
59
|
+
continue;
|
|
60
|
+
const avg = hist.reduce((a, b) => a + b, 0) / hist.length;
|
|
61
|
+
const max = Math.max(...hist);
|
|
62
|
+
out[label] = { avg: +avg.toFixed(2), max: +max.toFixed(2), n: hist.length };
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Rolling average for a label, WITHOUT the `__PERF__` guard — the overlay reads
|
|
68
|
+
* these to render its phase breakdown regardless of global logging state.
|
|
69
|
+
*/
|
|
70
|
+
export function perfAvg(label) {
|
|
71
|
+
const hist = histories.get(label);
|
|
72
|
+
if (!hist || !hist.length)
|
|
73
|
+
return 0;
|
|
74
|
+
return hist.reduce((a, b) => a + b, 0) / hist.length;
|
|
75
|
+
}
|
|
76
|
+
/** Rolling peak for a label. Same no-guard rule as {@link perfAvg}. */
|
|
77
|
+
export function perfPeak(label) {
|
|
78
|
+
const hist = histories.get(label);
|
|
79
|
+
if (!hist || !hist.length)
|
|
80
|
+
return 0;
|
|
81
|
+
return Math.max(...hist);
|
|
82
|
+
}
|
|
83
|
+
if (typeof window !== "undefined") {
|
|
84
|
+
window.__perfReport = perfReport;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=perf-marks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"perf-marks.js","sourceRoot":"","sources":["../../src/three/perf-marks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,OAAO,GAAG,EAAE,CAAC;AACnB,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;AACxC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAoB,CAAC;AAkB9C,SAAS,OAAO;IACd,OAAO,OAAO,MAAM,KAAK,WAAW,IAAI,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC;AACnE,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,QAAQ,CAAC,KAAa;IACpC,IAAI,CAAC,OAAO,EAAE;QAAE,OAAO;IACvB,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC;AACtC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,IAAI,CAAC,OAAO,EAAE;QAAE,OAAO;IACvB,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC/B,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO;IAC1B,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;IACrC,IAAI,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAChC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,IAAI,GAAG,EAAE,CAAC;QACV,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC7B,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACd,IAAI,IAAI,CAAC,MAAM,GAAG,OAAO;QAAE,IAAI,CAAC,KAAK,EAAE,CAAC;AAC1C,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC,OAAO,EAAE;QAAE,OAAO,IAAI,CAAC;IAC5B,MAAM,GAAG,GAAe,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,SAAS,EAAE,CAAC;QACtC,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,SAAS;QAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;QAC9B,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;IAC9E,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,OAAO,CAAC,KAAa;IACnC,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAClC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,OAAO,CAAC,CAAC;IACpC,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;AACvD,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,QAAQ,CAAC,KAAa;IACpC,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAClC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,OAAO,CAAC,CAAC;IACpC,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;IAClC,MAAM,CAAC,YAAY,GAAG,UAAU,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* perf-overlay — a shared, collapsible Three.js performance HUD for every rydr
|
|
3
|
+
* game. Shows FPS / CPU / GPU (via WebGL2 timer queries) / `renderer.info`, a
|
|
4
|
+
* `perfMark` phase breakdown, live entity counters, a copy-report button, and a
|
|
5
|
+
* generic draw-call audit. Default-off; zero cost when disabled.
|
|
6
|
+
*
|
|
7
|
+
* This is the SDK's first browser-UI module (the core protocol/client stay
|
|
8
|
+
* isomorphic). It is intentionally **self-contained**: it injects nothing
|
|
9
|
+
* global, depends on no CSS variables, and builds its own top-right overlay
|
|
10
|
+
* stack — so any Three.js game gets the panel by constructing it.
|
|
11
|
+
*
|
|
12
|
+
* Core is generic; each game extends it through a plain options object
|
|
13
|
+
* ({@link PerfOverlayOptions}) — `counters`, `phases`, `buttons`, `scene` — no
|
|
14
|
+
* formal capability interface (the surface is too small to warrant one).
|
|
15
|
+
*
|
|
16
|
+
* Enable: `?perf=1` on the page (or parent frame, for iframed games) or
|
|
17
|
+
* `window.__PERF__ = true`. Toggle the panel with the backtick key.
|
|
18
|
+
*
|
|
19
|
+
* Per-frame call order (mirrors a typical render loop):
|
|
20
|
+
* ```ts
|
|
21
|
+
* perf.frameStart();
|
|
22
|
+
* update();
|
|
23
|
+
* perf.gpuBegin(); render(); perf.gpuEnd();
|
|
24
|
+
* perf.frameEnd(dtSeconds);
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
import type * as THREE from "three";
|
|
28
|
+
/** Per-game extension surface — all optional. */
|
|
29
|
+
export interface PerfOverlayOptions {
|
|
30
|
+
/** Scene to drive the generic "Audit draw calls" button. Omit to hide it. */
|
|
31
|
+
scene?: THREE.Object3D;
|
|
32
|
+
/** Live entity counts → rendered as panel rows (e.g. `{ enemies, projectiles }`). */
|
|
33
|
+
counters?: () => Record<string, number>;
|
|
34
|
+
/** `perfMark` labels to surface as an avg/max breakdown (e.g. `['update','render']`). */
|
|
35
|
+
phases?: string[];
|
|
36
|
+
/** Extra action buttons (e.g. a renderer-specific "Toggle bloom"). */
|
|
37
|
+
buttons?: PerfButtonSpec[];
|
|
38
|
+
/** Pixel offset of the overlay stack from the top-right corner. Default
|
|
39
|
+
* `{ top: 8, right: 8 }`. Raise `right` to clear other top-right chrome
|
|
40
|
+
* (e.g. a host hamburger menu). */
|
|
41
|
+
offset?: {
|
|
42
|
+
top?: number;
|
|
43
|
+
right?: number;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/** A custom panel button. */
|
|
47
|
+
export interface PerfButtonSpec {
|
|
48
|
+
label: string;
|
|
49
|
+
/** CSS background tint; defaults to the neutral blue. */
|
|
50
|
+
color?: string;
|
|
51
|
+
onClick: () => void;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Bucket a scene's renderable objects (≈ draw calls) by top-level child, plus a
|
|
55
|
+
* material/geometry composition of the biggest bucket. Renderer-agnostic — the
|
|
56
|
+
* same audit the tower-defense game used, generalized over any `scene`.
|
|
57
|
+
*/
|
|
58
|
+
export declare function auditScene(scene: THREE.Object3D): string;
|
|
59
|
+
/**
|
|
60
|
+
* The performance overlay. Construct once with the canvas host + renderer, drive
|
|
61
|
+
* it from the render loop, and pass game specifics via {@link PerfOverlayOptions}.
|
|
62
|
+
*/
|
|
63
|
+
export declare class PerfOverlay {
|
|
64
|
+
private readonly renderer;
|
|
65
|
+
private readonly opts;
|
|
66
|
+
private readonly gl;
|
|
67
|
+
private readonly ext;
|
|
68
|
+
private readonly fps;
|
|
69
|
+
private readonly frameMs;
|
|
70
|
+
private readonly cpuMs;
|
|
71
|
+
private readonly gpuMs;
|
|
72
|
+
private prevFrameTime;
|
|
73
|
+
private cpuStart;
|
|
74
|
+
private readonly gpuPool;
|
|
75
|
+
private readonly gpuPending;
|
|
76
|
+
private gpuCurrent;
|
|
77
|
+
private lastInfo;
|
|
78
|
+
private domTick;
|
|
79
|
+
private readonly DOM_INTERVAL;
|
|
80
|
+
private visible;
|
|
81
|
+
private readonly stack;
|
|
82
|
+
private readonly pill;
|
|
83
|
+
private readonly panel;
|
|
84
|
+
private readonly pre;
|
|
85
|
+
private readonly reportOut;
|
|
86
|
+
private readonly onKey;
|
|
87
|
+
constructor(host: HTMLElement, renderer: THREE.WebGLRenderer, opts?: PerfOverlayOptions);
|
|
88
|
+
frameStart(): void;
|
|
89
|
+
gpuBegin(): void;
|
|
90
|
+
gpuEnd(): void;
|
|
91
|
+
/** End of frame. `dt` is seconds since last frame (drives the DOM throttle). */
|
|
92
|
+
frameEnd(dt: number): void;
|
|
93
|
+
toggle(): void;
|
|
94
|
+
destroy(): void;
|
|
95
|
+
private applyVisibility;
|
|
96
|
+
private makeButton;
|
|
97
|
+
private buildButtons;
|
|
98
|
+
private dumpReport;
|
|
99
|
+
private initGpuExt;
|
|
100
|
+
private pollGpu;
|
|
101
|
+
private updatePill;
|
|
102
|
+
private updateDom;
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=perf-overlay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"perf-overlay.d.ts","sourceRoot":"","sources":["../../src/three/perf-overlay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAIpC,iDAAiD;AACjD,MAAM,WAAW,kBAAkB;IACjC,6EAA6E;IAC7E,KAAK,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC;IACvB,qFAAqF;IACrF,QAAQ,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,yFAAyF;IACzF,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,sEAAsE;IACtE,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAC3B;;wCAEoC;IACpC,MAAM,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3C;AAED,6BAA6B;AAC7B,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AA6DD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,GAAG,MAAM,CA6FxD;AAED;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsB;IAC/C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAqB;IAC1C,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAiD;IACpE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA+B;IAEnD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAgB;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IACxC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IACtC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IAEtC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,QAAQ,CAAK;IAErB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAC5C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;IAC/C,OAAO,CAAC,UAAU,CAA2B;IAE7C,OAAO,CAAC,QAAQ,CAAkF;IAElG,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IAEtC,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiB;IACvC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAoB;IACzC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiB;IACvC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAiB;IACrC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiB;IAC3C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA6B;gBAEvC,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,CAAC,aAAa,EAAE,IAAI,GAAE,kBAAuB;IA2E3F,UAAU,IAAI,IAAI;IAWlB,QAAQ,IAAI,IAAI;IAShB,MAAM,IAAI,IAAI;IAQd,gFAAgF;IAChF,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAsB1B,MAAM,IAAI,IAAI;IAMd,OAAO,IAAI,IAAI;IAgBf,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,UAAU;IAYlB,OAAO,CAAC,YAAY;IAuBpB,OAAO,CAAC,UAAU;IA0BlB,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,OAAO;IAkBf,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,SAAS;CA6BlB"}
|