@ringozz/godot 4.7.1-8 → 4.7.1-9
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 +123 -123
- package/package.json +5 -2
- package/src/assets.d.ts +116 -116
- package/src/boot.browser.ts +39 -0
- package/src/boot.ts +15 -26
- package/src/debug.ts +236 -236
- package/src/index.ts +40 -40
- package/src/load.ts +210 -210
- package/src/preload.ts +198 -198
- package/src/runtime.ts +71 -72
- package/src/web-image.ts +118 -118
package/src/debug.ts
CHANGED
|
@@ -1,236 +1,236 @@
|
|
|
1
|
-
/**********************************************************************
|
|
2
|
-
Copyright (c) Vladimir Davidovich. All rights reserved.
|
|
3
|
-
***********************************************************************/
|
|
4
|
-
|
|
5
|
-
import { Rect2, str, varToStr, Vector3 } from './index.ts';
|
|
6
|
-
import { CanvasItem } from '../gen/classes/CanvasItem.ts';
|
|
7
|
-
import { ClassDB } from '../gen/classes/ClassDB.ts';
|
|
8
|
-
import { Control } from '../gen/classes/Control.ts';
|
|
9
|
-
import { DisplayServer } from '../gen/classes/DisplayServer.ts';
|
|
10
|
-
import { Engine } from '../gen/classes/Engine.ts';
|
|
11
|
-
import { Node } from '../gen/classes/Node.ts';
|
|
12
|
-
import { Node3D } from '../gen/classes/Node3D.ts';
|
|
13
|
-
import { OS } from '../gen/classes/OS.ts';
|
|
14
|
-
import { Time } from '../gen/classes/Time.ts';
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Dump a Godot value or object as a string.
|
|
18
|
-
* Value types (vectors, arrays, dictionaries, …) render via Godot's `str()`.
|
|
19
|
-
* Objects dump via Godot's `var_to_str` — its own property walk + recursion —
|
|
20
|
-
* with the node's `name` prepended when present.
|
|
21
|
-
*
|
|
22
|
-
* @param obj - Any Godot wrapper (Node, Resource, …), value type, or plain value
|
|
23
|
-
*/
|
|
24
|
-
export function dumpStr(obj: unknown): string {
|
|
25
|
-
if (obj == null || typeof obj !== 'object') return String(obj);
|
|
26
|
-
|
|
27
|
-
// Value types & heap containers (Vector3, Array, Dictionary, …) have no getClass() —
|
|
28
|
-
// let Godot's str() render them.
|
|
29
|
-
if (!(obj as any).getClass) return str(obj as any);
|
|
30
|
-
|
|
31
|
-
const dump = varToStr(obj as any);
|
|
32
|
-
let name: unknown;
|
|
33
|
-
try { name = (obj as any).name; } catch { name = undefined; }
|
|
34
|
-
return name === undefined || name === null || name === '' ? dump : `${name}: ${dump}`;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Serialize a scene subtree as a tree-formatted string.
|
|
39
|
-
*
|
|
40
|
-
* @param node - Root node to start from
|
|
41
|
-
* @param depth - Max depth (default 99)
|
|
42
|
-
*/
|
|
43
|
-
export function dumpTreeStr(node: Node, depth = 99): string {
|
|
44
|
-
const lines: string[] = [];
|
|
45
|
-
(function walk(n: Node, d: number, ind: string) {
|
|
46
|
-
if (d <= 0) return;
|
|
47
|
-
lines.push(`${ind}${n.getClass()} "${n.name}" (${n.getChildCount()} children)`);
|
|
48
|
-
for (let i = 0; i < n.getChildCount(); i++) {
|
|
49
|
-
const c = n.getChild(i);
|
|
50
|
-
if (c) walk(c as Node, d - 1, ind + ' ');
|
|
51
|
-
}
|
|
52
|
-
})(node, depth, '');
|
|
53
|
-
return lines.join('\n');
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Return a snapshot of engine runtime stats as a formatted string.
|
|
58
|
-
*
|
|
59
|
-
* Includes process frames, FPS, physics frames, node count, time scale,
|
|
60
|
-
* and main-loop class. Never throws: `Engine.getMainLoop()` can be null or
|
|
61
|
-
* throw while the engine is starting/stopping, in which case those rows show `N/A`.
|
|
62
|
-
*/
|
|
63
|
-
export function statsStr(): string {
|
|
64
|
-
let tree: any = null;
|
|
65
|
-
try { tree = Engine.getMainLoop(); } catch { tree = null; }
|
|
66
|
-
return [
|
|
67
|
-
`Frames: ${Engine.getProcessFrames()}`,
|
|
68
|
-
`FPS: ${Engine.getFramesPerSecond()}`,
|
|
69
|
-
`Physics: ${Engine.getPhysicsFrames()}`,
|
|
70
|
-
`Nodes: ${tree?.getNodeCount?.() ?? 'N/A'}`,
|
|
71
|
-
`Time scale: ${Engine.timeScale}`,
|
|
72
|
-
`Main loop: ${tree ? tree.getClass() : 'N/A'}`,
|
|
73
|
-
].join('\n');
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Run `gc()` and report how much heap was freed.
|
|
78
|
-
* Requires the `--expose-gc` Node.js flag.
|
|
79
|
-
*/
|
|
80
|
-
export function gc(): string {
|
|
81
|
-
const before = globalThis.process?.memoryUsage?.().heapUsed;
|
|
82
|
-
if (globalThis.Bun)
|
|
83
|
-
globalThis.Bun.gc(true);
|
|
84
|
-
else if (globalThis.gc)
|
|
85
|
-
globalThis.gc({ type: 'major', execution: 'sync' });
|
|
86
|
-
else
|
|
87
|
-
return 'gc() unavailable — need --expose-gc';
|
|
88
|
-
|
|
89
|
-
const after = globalThis.process?.memoryUsage?.().heapUsed;
|
|
90
|
-
const freed = typeof before === 'number' && typeof after === 'number' ? (before - after) / 1024 : 0;
|
|
91
|
-
return `GC: freed ${freed.toFixed(0)} KB`;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* `DOMRect` is not a global in Bun (desktop), but `getBoundingClientRect()`
|
|
96
|
-
* constructs one. Install a minimal spec-compatible polyfill on desktop so the
|
|
97
|
-
* helper works identically on desktop and web (browsers already define it).
|
|
98
|
-
*/
|
|
99
|
-
function ensureDOMRect(): void {
|
|
100
|
-
if (typeof (globalThis as any).DOMRect !== 'undefined') return;
|
|
101
|
-
(globalThis as any).DOMRect = class DOMRect {
|
|
102
|
-
x: number;
|
|
103
|
-
y: number;
|
|
104
|
-
width: number;
|
|
105
|
-
height: number;
|
|
106
|
-
constructor(x = 0, y = 0, width = 0, height = 0) {
|
|
107
|
-
this.x = x;
|
|
108
|
-
this.y = y;
|
|
109
|
-
this.width = width;
|
|
110
|
-
this.height = height;
|
|
111
|
-
}
|
|
112
|
-
get left() { return this.x; }
|
|
113
|
-
get top() { return this.y; }
|
|
114
|
-
get right() { return this.x + this.width; }
|
|
115
|
-
get bottom() { return this.y + this.height; }
|
|
116
|
-
toJSON() { return { x: this.x, y: this.y, width: this.width, height: this.height }; }
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Bootstrap the debugging environment.
|
|
122
|
-
*
|
|
123
|
-
* - Exposes common singletons (`Engine`, `OS`, `ClassDB`, `Time`) and all
|
|
124
|
-
* debug utility functions on `globalThis.$` so they're reachable from
|
|
125
|
-
* breakpoints in any module.
|
|
126
|
-
* - Registers an `uncaughtException` handler that logs but keeps the process
|
|
127
|
-
* alive for interactive debugging.
|
|
128
|
-
* - Polyfills `DOMRect` (needed by `getBoundingClientRect()` on desktop).
|
|
129
|
-
*/
|
|
130
|
-
export function initDebug(): void {
|
|
131
|
-
globalThis.process?.on?.('uncaughtException', (err, origin) => {
|
|
132
|
-
console.error(`\n✗ ${origin}:`, err.stack);
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
ensureDOMRect();
|
|
136
|
-
|
|
137
|
-
Object.defineProperty(CanvasItem.prototype, 'getBoundingClientRect', {
|
|
138
|
-
configurable: true,
|
|
139
|
-
value(this: CanvasItem): DOMRect | null {
|
|
140
|
-
const scale = DisplayServer.screenGetScale();
|
|
141
|
-
if (this instanceof Control) {
|
|
142
|
-
const rc = (this as Control).getGlobalRect();
|
|
143
|
-
return new DOMRect(
|
|
144
|
-
rc.position.x / scale, rc.position.y / scale,
|
|
145
|
-
rc.size.x / scale, rc.size.y / scale,
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (typeof (this as any).getRect !== 'function') return null;
|
|
150
|
-
|
|
151
|
-
const rect = (this as any).getRect() as Rect2;
|
|
152
|
-
const t = this.getScreenTransform();
|
|
153
|
-
|
|
154
|
-
const pos = rect.position;
|
|
155
|
-
const sz = rect.size;
|
|
156
|
-
const tx = t.x;
|
|
157
|
-
const ty = t.y;
|
|
158
|
-
const to = t.origin;
|
|
159
|
-
|
|
160
|
-
const x0 = pos.x, y0 = pos.y;
|
|
161
|
-
const x1 = x0 + sz.x, y1 = y0 + sz.y;
|
|
162
|
-
const txx = tx.x, txy = tx.y;
|
|
163
|
-
const tyx = ty.x, tyy = ty.y;
|
|
164
|
-
const tox = to.x, toy = to.y;
|
|
165
|
-
|
|
166
|
-
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
167
|
-
const accum = (px: number, py: number) => {
|
|
168
|
-
if (px < minX) minX = px; if (py < minY) minY = py;
|
|
169
|
-
if (px > maxX) maxX = px; if (py > maxY) maxY = py;
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
accum(txx * x0 + tyx * y0 + tox, txy * x0 + tyy * y0 + toy);
|
|
173
|
-
accum(txx * x1 + tyx * y0 + tox, txy * x1 + tyy * y0 + toy);
|
|
174
|
-
accum(txx * x0 + tyx * y1 + tox, txy * x0 + tyy * y1 + toy);
|
|
175
|
-
accum(txx * x1 + tyx * y1 + tox, txy * x1 + tyy * y1 + toy);
|
|
176
|
-
|
|
177
|
-
return new DOMRect(
|
|
178
|
-
minX / scale, minY / scale,
|
|
179
|
-
(maxX - minX) / scale, (maxY - minY) / scale,
|
|
180
|
-
);
|
|
181
|
-
},
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
Object.defineProperty(Node3D.prototype, 'getBoundingClientRect', {
|
|
185
|
-
configurable: true,
|
|
186
|
-
value(this: Node3D): DOMRect | null {
|
|
187
|
-
if (typeof (this as any).getAabb !== 'function') return null;
|
|
188
|
-
|
|
189
|
-
const aabb = (this as any).getAabb();
|
|
190
|
-
const gt = this.globalTransform;
|
|
191
|
-
const viewport = this.getViewport();
|
|
192
|
-
if (!viewport) return null;
|
|
193
|
-
const camera = viewport.getCamera3d();
|
|
194
|
-
if (!camera) return null;
|
|
195
|
-
const scale = DisplayServer.screenGetScale();
|
|
196
|
-
|
|
197
|
-
const b = gt.basis;
|
|
198
|
-
const bx = b.x, by = b.y, bz = b.z;
|
|
199
|
-
const o = gt.origin;
|
|
200
|
-
const p = aabb.position, e = aabb.end;
|
|
201
|
-
|
|
202
|
-
const [px, py, pz] = [p.x, p.y, p.z];
|
|
203
|
-
const [ex, ey, ez] = [e.x, e.y, e.z];
|
|
204
|
-
const [bxx, bxy, bxz] = [bx.x, bx.y, bx.z];
|
|
205
|
-
const [byx, byy, byz] = [by.x, by.y, by.z];
|
|
206
|
-
const [bzx, bzy, bzz] = [bz.x, bz.y, bz.z];
|
|
207
|
-
const [ox, oy, oz] = [o.x, o.y, o.z];
|
|
208
|
-
|
|
209
|
-
const corners = [
|
|
210
|
-
[px, py, pz], [ex, py, pz], [px, ey, pz], [ex, ey, pz],
|
|
211
|
-
[px, py, ez], [ex, py, ez], [px, ey, ez], [ex, ey, ez],
|
|
212
|
-
];
|
|
213
|
-
|
|
214
|
-
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
215
|
-
|
|
216
|
-
for (const [cx, cy, cz] of corners) {
|
|
217
|
-
const wx = bxx * cx + byx * cy + bzx * cz + ox;
|
|
218
|
-
const wy = bxy * cx + byy * cy + bzy * cz + oy;
|
|
219
|
-
const wz = bxz * cx + byz * cy + bzz * cz + oz;
|
|
220
|
-
const s = camera.unprojectPosition(new Vector3(wx, wy, wz));
|
|
221
|
-
if (s.x < minX) minX = s.x; if (s.y < minY) minY = s.y;
|
|
222
|
-
if (s.x > maxX) maxX = s.x; if (s.y > maxY) maxY = s.y;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
return new DOMRect(
|
|
226
|
-
minX / scale, minY / scale,
|
|
227
|
-
(maxX - minX) / scale, (maxY - minY) / scale,
|
|
228
|
-
);
|
|
229
|
-
},
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
(globalThis as any).$ = {
|
|
233
|
-
Engine, OS, ClassDB, Time,
|
|
234
|
-
dumpStr, dumpTreeStr, statsStr, gc,
|
|
235
|
-
};
|
|
236
|
-
}
|
|
1
|
+
/**********************************************************************
|
|
2
|
+
Copyright (c) Vladimir Davidovich. All rights reserved.
|
|
3
|
+
***********************************************************************/
|
|
4
|
+
|
|
5
|
+
import { Rect2, str, varToStr, Vector3 } from './index.ts';
|
|
6
|
+
import { CanvasItem } from '../gen/classes/CanvasItem.ts';
|
|
7
|
+
import { ClassDB } from '../gen/classes/ClassDB.ts';
|
|
8
|
+
import { Control } from '../gen/classes/Control.ts';
|
|
9
|
+
import { DisplayServer } from '../gen/classes/DisplayServer.ts';
|
|
10
|
+
import { Engine } from '../gen/classes/Engine.ts';
|
|
11
|
+
import { Node } from '../gen/classes/Node.ts';
|
|
12
|
+
import { Node3D } from '../gen/classes/Node3D.ts';
|
|
13
|
+
import { OS } from '../gen/classes/OS.ts';
|
|
14
|
+
import { Time } from '../gen/classes/Time.ts';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Dump a Godot value or object as a string.
|
|
18
|
+
* Value types (vectors, arrays, dictionaries, …) render via Godot's `str()`.
|
|
19
|
+
* Objects dump via Godot's `var_to_str` — its own property walk + recursion —
|
|
20
|
+
* with the node's `name` prepended when present.
|
|
21
|
+
*
|
|
22
|
+
* @param obj - Any Godot wrapper (Node, Resource, …), value type, or plain value
|
|
23
|
+
*/
|
|
24
|
+
export function dumpStr(obj: unknown): string {
|
|
25
|
+
if (obj == null || typeof obj !== 'object') return String(obj);
|
|
26
|
+
|
|
27
|
+
// Value types & heap containers (Vector3, Array, Dictionary, …) have no getClass() —
|
|
28
|
+
// let Godot's str() render them.
|
|
29
|
+
if (!(obj as any).getClass) return str(obj as any);
|
|
30
|
+
|
|
31
|
+
const dump = varToStr(obj as any);
|
|
32
|
+
let name: unknown;
|
|
33
|
+
try { name = (obj as any).name; } catch { name = undefined; }
|
|
34
|
+
return name === undefined || name === null || name === '' ? dump : `${name}: ${dump}`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Serialize a scene subtree as a tree-formatted string.
|
|
39
|
+
*
|
|
40
|
+
* @param node - Root node to start from
|
|
41
|
+
* @param depth - Max depth (default 99)
|
|
42
|
+
*/
|
|
43
|
+
export function dumpTreeStr(node: Node, depth = 99): string {
|
|
44
|
+
const lines: string[] = [];
|
|
45
|
+
(function walk(n: Node, d: number, ind: string) {
|
|
46
|
+
if (d <= 0) return;
|
|
47
|
+
lines.push(`${ind}${n.getClass()} "${n.name}" (${n.getChildCount()} children)`);
|
|
48
|
+
for (let i = 0; i < n.getChildCount(); i++) {
|
|
49
|
+
const c = n.getChild(i);
|
|
50
|
+
if (c) walk(c as Node, d - 1, ind + ' ');
|
|
51
|
+
}
|
|
52
|
+
})(node, depth, '');
|
|
53
|
+
return lines.join('\n');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Return a snapshot of engine runtime stats as a formatted string.
|
|
58
|
+
*
|
|
59
|
+
* Includes process frames, FPS, physics frames, node count, time scale,
|
|
60
|
+
* and main-loop class. Never throws: `Engine.getMainLoop()` can be null or
|
|
61
|
+
* throw while the engine is starting/stopping, in which case those rows show `N/A`.
|
|
62
|
+
*/
|
|
63
|
+
export function statsStr(): string {
|
|
64
|
+
let tree: any = null;
|
|
65
|
+
try { tree = Engine.getMainLoop(); } catch { tree = null; }
|
|
66
|
+
return [
|
|
67
|
+
`Frames: ${Engine.getProcessFrames()}`,
|
|
68
|
+
`FPS: ${Engine.getFramesPerSecond()}`,
|
|
69
|
+
`Physics: ${Engine.getPhysicsFrames()}`,
|
|
70
|
+
`Nodes: ${tree?.getNodeCount?.() ?? 'N/A'}`,
|
|
71
|
+
`Time scale: ${Engine.timeScale}`,
|
|
72
|
+
`Main loop: ${tree ? tree.getClass() : 'N/A'}`,
|
|
73
|
+
].join('\n');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Run `gc()` and report how much heap was freed.
|
|
78
|
+
* Requires the `--expose-gc` Node.js flag.
|
|
79
|
+
*/
|
|
80
|
+
export function gc(): string {
|
|
81
|
+
const before = globalThis.process?.memoryUsage?.().heapUsed;
|
|
82
|
+
if (globalThis.Bun)
|
|
83
|
+
globalThis.Bun.gc(true);
|
|
84
|
+
else if (globalThis.gc)
|
|
85
|
+
globalThis.gc({ type: 'major', execution: 'sync' });
|
|
86
|
+
else
|
|
87
|
+
return 'gc() unavailable — need --expose-gc';
|
|
88
|
+
|
|
89
|
+
const after = globalThis.process?.memoryUsage?.().heapUsed;
|
|
90
|
+
const freed = typeof before === 'number' && typeof after === 'number' ? (before - after) / 1024 : 0;
|
|
91
|
+
return `GC: freed ${freed.toFixed(0)} KB`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* `DOMRect` is not a global in Bun (desktop), but `getBoundingClientRect()`
|
|
96
|
+
* constructs one. Install a minimal spec-compatible polyfill on desktop so the
|
|
97
|
+
* helper works identically on desktop and web (browsers already define it).
|
|
98
|
+
*/
|
|
99
|
+
function ensureDOMRect(): void {
|
|
100
|
+
if (typeof (globalThis as any).DOMRect !== 'undefined') return;
|
|
101
|
+
(globalThis as any).DOMRect = class DOMRect {
|
|
102
|
+
x: number;
|
|
103
|
+
y: number;
|
|
104
|
+
width: number;
|
|
105
|
+
height: number;
|
|
106
|
+
constructor(x = 0, y = 0, width = 0, height = 0) {
|
|
107
|
+
this.x = x;
|
|
108
|
+
this.y = y;
|
|
109
|
+
this.width = width;
|
|
110
|
+
this.height = height;
|
|
111
|
+
}
|
|
112
|
+
get left() { return this.x; }
|
|
113
|
+
get top() { return this.y; }
|
|
114
|
+
get right() { return this.x + this.width; }
|
|
115
|
+
get bottom() { return this.y + this.height; }
|
|
116
|
+
toJSON() { return { x: this.x, y: this.y, width: this.width, height: this.height }; }
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Bootstrap the debugging environment.
|
|
122
|
+
*
|
|
123
|
+
* - Exposes common singletons (`Engine`, `OS`, `ClassDB`, `Time`) and all
|
|
124
|
+
* debug utility functions on `globalThis.$` so they're reachable from
|
|
125
|
+
* breakpoints in any module.
|
|
126
|
+
* - Registers an `uncaughtException` handler that logs but keeps the process
|
|
127
|
+
* alive for interactive debugging.
|
|
128
|
+
* - Polyfills `DOMRect` (needed by `getBoundingClientRect()` on desktop).
|
|
129
|
+
*/
|
|
130
|
+
export function initDebug(): void {
|
|
131
|
+
globalThis.process?.on?.('uncaughtException', (err, origin) => {
|
|
132
|
+
console.error(`\n✗ ${origin}:`, err.stack);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
ensureDOMRect();
|
|
136
|
+
|
|
137
|
+
Object.defineProperty(CanvasItem.prototype, 'getBoundingClientRect', {
|
|
138
|
+
configurable: true,
|
|
139
|
+
value(this: CanvasItem): DOMRect | null {
|
|
140
|
+
const scale = DisplayServer.screenGetScale();
|
|
141
|
+
if (this instanceof Control) {
|
|
142
|
+
const rc = (this as Control).getGlobalRect();
|
|
143
|
+
return new DOMRect(
|
|
144
|
+
rc.position.x / scale, rc.position.y / scale,
|
|
145
|
+
rc.size.x / scale, rc.size.y / scale,
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (typeof (this as any).getRect !== 'function') return null;
|
|
150
|
+
|
|
151
|
+
const rect = (this as any).getRect() as Rect2;
|
|
152
|
+
const t = this.getScreenTransform();
|
|
153
|
+
|
|
154
|
+
const pos = rect.position;
|
|
155
|
+
const sz = rect.size;
|
|
156
|
+
const tx = t.x;
|
|
157
|
+
const ty = t.y;
|
|
158
|
+
const to = t.origin;
|
|
159
|
+
|
|
160
|
+
const x0 = pos.x, y0 = pos.y;
|
|
161
|
+
const x1 = x0 + sz.x, y1 = y0 + sz.y;
|
|
162
|
+
const txx = tx.x, txy = tx.y;
|
|
163
|
+
const tyx = ty.x, tyy = ty.y;
|
|
164
|
+
const tox = to.x, toy = to.y;
|
|
165
|
+
|
|
166
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
167
|
+
const accum = (px: number, py: number) => {
|
|
168
|
+
if (px < minX) minX = px; if (py < minY) minY = py;
|
|
169
|
+
if (px > maxX) maxX = px; if (py > maxY) maxY = py;
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
accum(txx * x0 + tyx * y0 + tox, txy * x0 + tyy * y0 + toy);
|
|
173
|
+
accum(txx * x1 + tyx * y0 + tox, txy * x1 + tyy * y0 + toy);
|
|
174
|
+
accum(txx * x0 + tyx * y1 + tox, txy * x0 + tyy * y1 + toy);
|
|
175
|
+
accum(txx * x1 + tyx * y1 + tox, txy * x1 + tyy * y1 + toy);
|
|
176
|
+
|
|
177
|
+
return new DOMRect(
|
|
178
|
+
minX / scale, minY / scale,
|
|
179
|
+
(maxX - minX) / scale, (maxY - minY) / scale,
|
|
180
|
+
);
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
Object.defineProperty(Node3D.prototype, 'getBoundingClientRect', {
|
|
185
|
+
configurable: true,
|
|
186
|
+
value(this: Node3D): DOMRect | null {
|
|
187
|
+
if (typeof (this as any).getAabb !== 'function') return null;
|
|
188
|
+
|
|
189
|
+
const aabb = (this as any).getAabb();
|
|
190
|
+
const gt = this.globalTransform;
|
|
191
|
+
const viewport = this.getViewport();
|
|
192
|
+
if (!viewport) return null;
|
|
193
|
+
const camera = viewport.getCamera3d();
|
|
194
|
+
if (!camera) return null;
|
|
195
|
+
const scale = DisplayServer.screenGetScale();
|
|
196
|
+
|
|
197
|
+
const b = gt.basis;
|
|
198
|
+
const bx = b.x, by = b.y, bz = b.z;
|
|
199
|
+
const o = gt.origin;
|
|
200
|
+
const p = aabb.position, e = aabb.end;
|
|
201
|
+
|
|
202
|
+
const [px, py, pz] = [p.x, p.y, p.z];
|
|
203
|
+
const [ex, ey, ez] = [e.x, e.y, e.z];
|
|
204
|
+
const [bxx, bxy, bxz] = [bx.x, bx.y, bx.z];
|
|
205
|
+
const [byx, byy, byz] = [by.x, by.y, by.z];
|
|
206
|
+
const [bzx, bzy, bzz] = [bz.x, bz.y, bz.z];
|
|
207
|
+
const [ox, oy, oz] = [o.x, o.y, o.z];
|
|
208
|
+
|
|
209
|
+
const corners = [
|
|
210
|
+
[px, py, pz], [ex, py, pz], [px, ey, pz], [ex, ey, pz],
|
|
211
|
+
[px, py, ez], [ex, py, ez], [px, ey, ez], [ex, ey, ez],
|
|
212
|
+
];
|
|
213
|
+
|
|
214
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
215
|
+
|
|
216
|
+
for (const [cx, cy, cz] of corners) {
|
|
217
|
+
const wx = bxx * cx + byx * cy + bzx * cz + ox;
|
|
218
|
+
const wy = bxy * cx + byy * cy + bzy * cz + oy;
|
|
219
|
+
const wz = bxz * cx + byz * cy + bzz * cz + oz;
|
|
220
|
+
const s = camera.unprojectPosition(new Vector3(wx, wy, wz));
|
|
221
|
+
if (s.x < minX) minX = s.x; if (s.y < minY) minY = s.y;
|
|
222
|
+
if (s.x > maxX) maxX = s.x; if (s.y > maxY) maxY = s.y;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return new DOMRect(
|
|
226
|
+
minX / scale, minY / scale,
|
|
227
|
+
(maxX - minX) / scale, (maxY - minY) / scale,
|
|
228
|
+
);
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
(globalThis as any).$ = {
|
|
233
|
+
Engine, OS, ClassDB, Time,
|
|
234
|
+
dumpStr, dumpTreeStr, statsStr, gc,
|
|
235
|
+
};
|
|
236
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
/**********************************************************************
|
|
2
|
-
Copyright (c) Vladimir Davidovich. All rights reserved.
|
|
3
|
-
***********************************************************************/
|
|
4
|
-
|
|
5
|
-
export * from '../gen/index.ts';
|
|
6
|
-
import * as ValueTypes from '../gen/value-types/index.ts';
|
|
7
|
-
import * as HeapTypes from '../gen/heap-types/index.ts';
|
|
8
|
-
import { Engine } from '../gen/classes/Engine.ts';
|
|
9
|
-
import { GodotInstance } from '../gen/classes/GodotInstance.ts';
|
|
10
|
-
import { SceneTree } from '../gen/classes/SceneTree.ts';
|
|
11
|
-
import { Window } from '../gen/classes/Window.ts';
|
|
12
|
-
import { gc } from './debug.ts';
|
|
13
|
-
import { cancelAnimationFrame, getGodot, requestAnimationFrame } from './runtime.ts';
|
|
14
|
-
|
|
15
|
-
// ---- make sure these classes are not tree-shaked ----
|
|
16
|
-
void ValueTypes;
|
|
17
|
-
void HeapTypes;
|
|
18
|
-
void GodotInstance;
|
|
19
|
-
void SceneTree;
|
|
20
|
-
void Window;
|
|
21
|
-
|
|
22
|
-
// ---- globalThis browser-compat API ----
|
|
23
|
-
Object.assign(globalThis as any, { requestAnimationFrame, cancelAnimationFrame });
|
|
24
|
-
|
|
25
|
-
// ---- GodotInstance frame pump (engine already started by C++ InitModule) ----
|
|
26
|
-
export async function runGodot(signal?: AbortSignal, unmount?: () => PromiseLike<void>) {
|
|
27
|
-
signal?.throwIfAborted();
|
|
28
|
-
signal?.addEventListener('abort', () => {
|
|
29
|
-
(Engine.getMainLoop() as SceneTree)?.quit();
|
|
30
|
-
}, { once: true });
|
|
31
|
-
|
|
32
|
-
const godot = getGodot();
|
|
33
|
-
while (!godot.iteration())
|
|
34
|
-
await new Promise(requestAnimationFrame);
|
|
35
|
-
|
|
36
|
-
await unmount?.();
|
|
37
|
-
console.log(gc());
|
|
38
|
-
return godot.free();
|
|
39
|
-
}
|
|
40
|
-
|
|
1
|
+
/**********************************************************************
|
|
2
|
+
Copyright (c) Vladimir Davidovich. All rights reserved.
|
|
3
|
+
***********************************************************************/
|
|
4
|
+
|
|
5
|
+
export * from '../gen/index.ts';
|
|
6
|
+
import * as ValueTypes from '../gen/value-types/index.ts';
|
|
7
|
+
import * as HeapTypes from '../gen/heap-types/index.ts';
|
|
8
|
+
import { Engine } from '../gen/classes/Engine.ts';
|
|
9
|
+
import { GodotInstance } from '../gen/classes/GodotInstance.ts';
|
|
10
|
+
import { SceneTree } from '../gen/classes/SceneTree.ts';
|
|
11
|
+
import { Window } from '../gen/classes/Window.ts';
|
|
12
|
+
import { gc } from './debug.ts';
|
|
13
|
+
import { cancelAnimationFrame, getGodot, requestAnimationFrame } from './runtime.ts';
|
|
14
|
+
|
|
15
|
+
// ---- make sure these classes are not tree-shaked ----
|
|
16
|
+
void ValueTypes;
|
|
17
|
+
void HeapTypes;
|
|
18
|
+
void GodotInstance;
|
|
19
|
+
void SceneTree;
|
|
20
|
+
void Window;
|
|
21
|
+
|
|
22
|
+
// ---- globalThis browser-compat API ----
|
|
23
|
+
Object.assign(globalThis as any, { requestAnimationFrame, cancelAnimationFrame });
|
|
24
|
+
|
|
25
|
+
// ---- GodotInstance frame pump (engine already started by C++ InitModule) ----
|
|
26
|
+
export async function runGodot(signal?: AbortSignal, unmount?: () => PromiseLike<void>) {
|
|
27
|
+
signal?.throwIfAborted();
|
|
28
|
+
signal?.addEventListener('abort', () => {
|
|
29
|
+
(Engine.getMainLoop() as SceneTree)?.quit();
|
|
30
|
+
}, { once: true });
|
|
31
|
+
|
|
32
|
+
const godot = getGodot();
|
|
33
|
+
while (!godot.iteration())
|
|
34
|
+
await new Promise(requestAnimationFrame);
|
|
35
|
+
|
|
36
|
+
await unmount?.();
|
|
37
|
+
console.log(gc());
|
|
38
|
+
return godot.free();
|
|
39
|
+
}
|
|
40
|
+
|