@codexo/exojs 0.6.9 → 0.6.11
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/CHANGELOG.md +102 -0
- package/dist/esm/animation/Easing.d.ts +45 -0
- package/dist/esm/animation/Easing.js +112 -0
- package/dist/esm/animation/Easing.js.map +1 -0
- package/dist/esm/animation/Tween.d.ts +100 -0
- package/dist/esm/animation/Tween.js +270 -0
- package/dist/esm/animation/Tween.js.map +1 -0
- package/dist/esm/animation/TweenManager.d.ts +30 -0
- package/dist/esm/animation/TweenManager.js +65 -0
- package/dist/esm/animation/TweenManager.js.map +1 -0
- package/dist/esm/animation/index.d.ts +4 -0
- package/dist/esm/animation/types.d.ts +10 -0
- package/dist/esm/animation/types.js +11 -0
- package/dist/esm/animation/types.js.map +1 -0
- package/dist/esm/core/Application.d.ts +2 -0
- package/dist/esm/core/Application.js +4 -0
- package/dist/esm/core/Application.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +4 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/math/geometry.js +3 -3
- package/dist/esm/math/geometry.js.map +1 -1
- package/dist/esm/math/triangulate.d.ts +17 -0
- package/dist/esm/math/triangulate.js +164 -0
- package/dist/esm/math/triangulate.js.map +1 -0
- package/dist/exo.esm.js +598 -620
- package/dist/exo.esm.js.map +1 -1
- package/package.json +2 -5
package/dist/exo.esm.js
CHANGED
|
@@ -1,3 +1,448 @@
|
|
|
1
|
+
const bounceOutFn = (t) => {
|
|
2
|
+
const n1 = 7.5625;
|
|
3
|
+
const d1 = 2.75;
|
|
4
|
+
if (t < 1 / d1) {
|
|
5
|
+
return n1 * t * t;
|
|
6
|
+
}
|
|
7
|
+
else if (t < 2 / d1) {
|
|
8
|
+
return n1 * (t -= 1.5 / d1) * t + 0.75;
|
|
9
|
+
}
|
|
10
|
+
else if (t < 2.5 / d1) {
|
|
11
|
+
return n1 * (t -= 2.25 / d1) * t + 0.9375;
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
return n1 * (t -= 2.625 / d1) * t + 0.984375;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Standard Robert Penner easing functions as static methods.
|
|
19
|
+
* Each function accepts a normalized time `t` in [0, 1] and returns a value
|
|
20
|
+
* that equals 0 at t=0 and 1 at t=1 (overshoot functions like back/elastic
|
|
21
|
+
* may exceed that range between the endpoints).
|
|
22
|
+
*
|
|
23
|
+
* Usage: `Ease.cubicOut`, `Ease.bounceIn`, etc.
|
|
24
|
+
*
|
|
25
|
+
* Note: only scalar numeric properties are supported in v1. Vector, Color, and
|
|
26
|
+
* Matrix interpolation are out of scope.
|
|
27
|
+
*/
|
|
28
|
+
class Ease {
|
|
29
|
+
static linear = (t) => t;
|
|
30
|
+
static quadIn = (t) => t * t;
|
|
31
|
+
static quadOut = (t) => t * (2 - t);
|
|
32
|
+
static quadInOut = (t) => t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
|
|
33
|
+
static cubicIn = (t) => t * t * t;
|
|
34
|
+
static cubicOut = (t) => (--t) * t * t + 1;
|
|
35
|
+
static cubicInOut = (t) => t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
|
|
36
|
+
static quartIn = (t) => t * t * t * t;
|
|
37
|
+
static quartOut = (t) => 1 - (--t) * t * t * t;
|
|
38
|
+
static quartInOut = (t) => t < 0.5 ? 8 * t * t * t * t : 1 - Math.pow(-2 * t + 2, 4) / 2;
|
|
39
|
+
static quintIn = (t) => t * t * t * t * t;
|
|
40
|
+
static quintOut = (t) => 1 + (--t) * t * t * t * t;
|
|
41
|
+
static quintInOut = (t) => t < 0.5 ? 16 * t * t * t * t * t : 1 - Math.pow(-2 * t + 2, 5) / 2;
|
|
42
|
+
static sineIn = (t) => 1 - Math.cos((t * Math.PI) / 2);
|
|
43
|
+
static sineOut = (t) => Math.sin((t * Math.PI) / 2);
|
|
44
|
+
static sineInOut = (t) => -(Math.cos(Math.PI * t) - 1) / 2;
|
|
45
|
+
static expoIn = (t) => t === 0 ? 0 : Math.pow(2, 10 * t - 10);
|
|
46
|
+
static expoOut = (t) => t === 1 ? 1 : 1 - Math.pow(2, -10 * t);
|
|
47
|
+
static expoInOut = (t) => {
|
|
48
|
+
if (t === 0)
|
|
49
|
+
return 0;
|
|
50
|
+
if (t === 1)
|
|
51
|
+
return 1;
|
|
52
|
+
return t < 0.5
|
|
53
|
+
? Math.pow(2, 20 * t - 10) / 2
|
|
54
|
+
: (2 - Math.pow(2, -20 * t + 10)) / 2;
|
|
55
|
+
};
|
|
56
|
+
static circIn = (t) => 1 - Math.sqrt(1 - Math.pow(t, 2));
|
|
57
|
+
static circOut = (t) => Math.sqrt(1 - Math.pow(t - 1, 2));
|
|
58
|
+
static circInOut = (t) => t < 0.5
|
|
59
|
+
? (1 - Math.sqrt(1 - Math.pow(2 * t, 2))) / 2
|
|
60
|
+
: (Math.sqrt(1 - Math.pow(-2 * t + 2, 2)) + 1) / 2;
|
|
61
|
+
static backIn = (t) => {
|
|
62
|
+
const c1 = 1.70158;
|
|
63
|
+
const c3 = c1 + 1;
|
|
64
|
+
return c3 * t * t * t - c1 * t * t;
|
|
65
|
+
};
|
|
66
|
+
static backOut = (t) => {
|
|
67
|
+
const c1 = 1.70158;
|
|
68
|
+
const c3 = c1 + 1;
|
|
69
|
+
return 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2);
|
|
70
|
+
};
|
|
71
|
+
static backInOut = (t) => {
|
|
72
|
+
const c1 = 1.70158;
|
|
73
|
+
const c2 = c1 * 1.525;
|
|
74
|
+
return t < 0.5
|
|
75
|
+
? (Math.pow(2 * t, 2) * ((c2 + 1) * 2 * t - c2)) / 2
|
|
76
|
+
: (Math.pow(2 * t - 2, 2) * ((c2 + 1) * (2 * t - 2) + c2) + 2) / 2;
|
|
77
|
+
};
|
|
78
|
+
static bounceOut = bounceOutFn;
|
|
79
|
+
static bounceIn = (t) => 1 - bounceOutFn(1 - t);
|
|
80
|
+
static bounceInOut = (t) => t < 0.5
|
|
81
|
+
? (1 - bounceOutFn(1 - 2 * t)) / 2
|
|
82
|
+
: (1 + bounceOutFn(2 * t - 1)) / 2;
|
|
83
|
+
static elasticIn = (t) => {
|
|
84
|
+
if (t === 0)
|
|
85
|
+
return 0;
|
|
86
|
+
if (t === 1)
|
|
87
|
+
return 1;
|
|
88
|
+
const c4 = (2 * Math.PI) / 3;
|
|
89
|
+
return -Math.pow(2, 10 * t - 10) * Math.sin((t * 10 - 10.75) * c4);
|
|
90
|
+
};
|
|
91
|
+
static elasticOut = (t) => {
|
|
92
|
+
if (t === 0)
|
|
93
|
+
return 0;
|
|
94
|
+
if (t === 1)
|
|
95
|
+
return 1;
|
|
96
|
+
const c4 = (2 * Math.PI) / 3;
|
|
97
|
+
return Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;
|
|
98
|
+
};
|
|
99
|
+
static elasticInOut = (t) => {
|
|
100
|
+
if (t === 0)
|
|
101
|
+
return 0;
|
|
102
|
+
if (t === 1)
|
|
103
|
+
return 1;
|
|
104
|
+
const c5 = (2 * Math.PI) / 4.5;
|
|
105
|
+
return t < 0.5
|
|
106
|
+
? -(Math.pow(2, 20 * t - 10) * Math.sin((20 * t - 11.125) * c5)) / 2
|
|
107
|
+
: (Math.pow(2, -20 * t + 10) * Math.sin((20 * t - 11.125) * c5)) / 2 + 1;
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
var TweenState;
|
|
112
|
+
(function (TweenState) {
|
|
113
|
+
TweenState["Idle"] = "idle";
|
|
114
|
+
TweenState["Active"] = "active";
|
|
115
|
+
TweenState["Paused"] = "paused";
|
|
116
|
+
TweenState["Complete"] = "complete";
|
|
117
|
+
TweenState["Stopped"] = "stopped";
|
|
118
|
+
})(TweenState || (TweenState = {}));
|
|
119
|
+
|
|
120
|
+
class Tween {
|
|
121
|
+
_target;
|
|
122
|
+
_state = TweenState.Idle;
|
|
123
|
+
_properties = {};
|
|
124
|
+
_startValues = null;
|
|
125
|
+
_duration = 0;
|
|
126
|
+
_delay = 0;
|
|
127
|
+
_easing = Ease.linear;
|
|
128
|
+
_elapsed = 0;
|
|
129
|
+
_delayElapsed = 0;
|
|
130
|
+
/**
|
|
131
|
+
* Remaining repeat cycles. -1 = infinite.
|
|
132
|
+
* At start this is set to _repeatTotal. Decremented on each cycle boundary.
|
|
133
|
+
*/
|
|
134
|
+
_repeatCount = 0;
|
|
135
|
+
/** The value as configured by .repeat(). Preserved for reset. */
|
|
136
|
+
_repeatTotal = 0;
|
|
137
|
+
_yoyo = false;
|
|
138
|
+
/** Current playback direction: 1 = forward, -1 = reverse. */
|
|
139
|
+
_direction = 1;
|
|
140
|
+
_onStart = null;
|
|
141
|
+
_onUpdate = null;
|
|
142
|
+
_onComplete = null;
|
|
143
|
+
_onRepeat = null;
|
|
144
|
+
_chained = null;
|
|
145
|
+
_manager = null;
|
|
146
|
+
/** Whether onStart has already fired this tween lifecycle. */
|
|
147
|
+
_startFired = false;
|
|
148
|
+
constructor(target) {
|
|
149
|
+
this._target = target;
|
|
150
|
+
}
|
|
151
|
+
get target() {
|
|
152
|
+
return this._target;
|
|
153
|
+
}
|
|
154
|
+
get state() {
|
|
155
|
+
return this._state;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Current eased progress in 0..1. Reflects the eased t after applying the
|
|
159
|
+
* easing function, not the raw elapsed/duration ratio.
|
|
160
|
+
*/
|
|
161
|
+
get progress() {
|
|
162
|
+
if (this._duration === 0)
|
|
163
|
+
return 1;
|
|
164
|
+
const rawT = Math.min(this._elapsed / this._duration, 1);
|
|
165
|
+
const t = this._direction === 1 ? rawT : 1 - rawT;
|
|
166
|
+
return this._easing(t);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Set target end-values and duration in seconds. Replaces any prior to().
|
|
170
|
+
* The starting values are captured lazily on first update() after start(),
|
|
171
|
+
* so mutating target between to() and start() is safe.
|
|
172
|
+
*/
|
|
173
|
+
to(properties, duration) {
|
|
174
|
+
this._properties = { ...properties };
|
|
175
|
+
this._duration = duration;
|
|
176
|
+
this._startValues = null;
|
|
177
|
+
return this;
|
|
178
|
+
}
|
|
179
|
+
/** Delay in seconds before the tween begins interpolating. Default 0. */
|
|
180
|
+
delay(seconds) {
|
|
181
|
+
this._delay = seconds;
|
|
182
|
+
return this;
|
|
183
|
+
}
|
|
184
|
+
/** Easing function applied to the normalized time. Default Ease.linear. */
|
|
185
|
+
easing(fn) {
|
|
186
|
+
this._easing = fn;
|
|
187
|
+
return this;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Number of additional repeat cycles. -1 = infinite. Default 0 (runs once).
|
|
191
|
+
* Note: repeat(2) means the animation runs 3 times total.
|
|
192
|
+
*/
|
|
193
|
+
repeat(count) {
|
|
194
|
+
this._repeatTotal = count;
|
|
195
|
+
return this;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Reverse playback direction on each repeat cycle. Only meaningful when
|
|
199
|
+
* combined with repeat(). Calling yoyo() without repeat() is a no-op.
|
|
200
|
+
*/
|
|
201
|
+
yoyo(enabled = true) {
|
|
202
|
+
this._yoyo = enabled;
|
|
203
|
+
return this;
|
|
204
|
+
}
|
|
205
|
+
onStart(callback) {
|
|
206
|
+
this._onStart = callback;
|
|
207
|
+
return this;
|
|
208
|
+
}
|
|
209
|
+
onUpdate(callback) {
|
|
210
|
+
this._onUpdate = callback;
|
|
211
|
+
return this;
|
|
212
|
+
}
|
|
213
|
+
onComplete(callback) {
|
|
214
|
+
this._onComplete = callback;
|
|
215
|
+
return this;
|
|
216
|
+
}
|
|
217
|
+
onRepeat(callback) {
|
|
218
|
+
this._onRepeat = callback;
|
|
219
|
+
return this;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Start the tween. If a manager owns this tween it is already tracked;
|
|
223
|
+
* otherwise this is a stand-alone tween driven by manual update() calls.
|
|
224
|
+
*/
|
|
225
|
+
start() {
|
|
226
|
+
this._state = TweenState.Active;
|
|
227
|
+
this._elapsed = 0;
|
|
228
|
+
this._delayElapsed = 0;
|
|
229
|
+
this._startValues = null;
|
|
230
|
+
this._startFired = false;
|
|
231
|
+
this._direction = 1;
|
|
232
|
+
this._repeatCount = this._repeatTotal;
|
|
233
|
+
return this;
|
|
234
|
+
}
|
|
235
|
+
/** Pause the tween. update() calls are ignored while paused. */
|
|
236
|
+
pause() {
|
|
237
|
+
if (this._state === TweenState.Active) {
|
|
238
|
+
this._state = TweenState.Paused;
|
|
239
|
+
}
|
|
240
|
+
return this;
|
|
241
|
+
}
|
|
242
|
+
/** Resume a paused tween from where it left off. */
|
|
243
|
+
resume() {
|
|
244
|
+
if (this._state === TweenState.Paused) {
|
|
245
|
+
this._state = TweenState.Active;
|
|
246
|
+
}
|
|
247
|
+
return this;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Stop the tween without finishing. Target properties stay at their
|
|
251
|
+
* current interpolated values. onComplete does NOT fire. The tween is
|
|
252
|
+
* removed from its manager if one is assigned.
|
|
253
|
+
*/
|
|
254
|
+
stop() {
|
|
255
|
+
if (this._state === TweenState.Active || this._state === TweenState.Paused) {
|
|
256
|
+
this._state = TweenState.Stopped;
|
|
257
|
+
this._manager?.remove(this);
|
|
258
|
+
}
|
|
259
|
+
return this;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* When this tween completes naturally, automatically start `next`.
|
|
263
|
+
* Returns `next` for fluent chaining:
|
|
264
|
+
* `fadeIn.chain(moveOut).start()` — note that start() here starts moveOut,
|
|
265
|
+
* so typically you only call start() on the first tween.
|
|
266
|
+
*/
|
|
267
|
+
chain(next) {
|
|
268
|
+
this._chained = next;
|
|
269
|
+
return next;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Attach this tween to a manager. Called by TweenManager.create() and
|
|
273
|
+
* TweenManager.add(). Not part of the public fluent API.
|
|
274
|
+
* @internal
|
|
275
|
+
*/
|
|
276
|
+
_attachManager(manager) {
|
|
277
|
+
this._manager = manager;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Advance the tween by deltaSeconds. Called by TweenManager each frame, or
|
|
281
|
+
* manually for stand-alone usage. No-ops when Paused, Stopped, or Complete.
|
|
282
|
+
*/
|
|
283
|
+
update(deltaSeconds) {
|
|
284
|
+
if (this._state !== TweenState.Active)
|
|
285
|
+
return;
|
|
286
|
+
// Handle delay phase.
|
|
287
|
+
if (this._delayElapsed < this._delay) {
|
|
288
|
+
this._delayElapsed += deltaSeconds;
|
|
289
|
+
if (this._delayElapsed < this._delay)
|
|
290
|
+
return;
|
|
291
|
+
// Carry overflow past delay into elapsed.
|
|
292
|
+
const overflow = this._delayElapsed - this._delay;
|
|
293
|
+
this._delayElapsed = this._delay;
|
|
294
|
+
deltaSeconds = overflow;
|
|
295
|
+
}
|
|
296
|
+
// Lazy snapshot of start values on the first update after delay.
|
|
297
|
+
if (this._startValues === null) {
|
|
298
|
+
this._captureStartValues();
|
|
299
|
+
}
|
|
300
|
+
// Fire onStart once.
|
|
301
|
+
if (!this._startFired) {
|
|
302
|
+
this._startFired = true;
|
|
303
|
+
this._onStart?.();
|
|
304
|
+
}
|
|
305
|
+
this._elapsed += deltaSeconds;
|
|
306
|
+
// Clamp to duration for this cycle.
|
|
307
|
+
if (this._elapsed >= this._duration) {
|
|
308
|
+
this._elapsed = this._duration;
|
|
309
|
+
}
|
|
310
|
+
// Apply interpolation.
|
|
311
|
+
this._applyProgress();
|
|
312
|
+
if (this._elapsed >= this._duration) {
|
|
313
|
+
// Cycle complete.
|
|
314
|
+
const hasMoreRepeats = this._repeatCount === -1 || this._repeatCount > 0;
|
|
315
|
+
if (hasMoreRepeats) {
|
|
316
|
+
// Decrement repeat counter (skip for infinite).
|
|
317
|
+
if (this._repeatCount !== -1) {
|
|
318
|
+
this._repeatCount--;
|
|
319
|
+
}
|
|
320
|
+
this._onRepeat?.();
|
|
321
|
+
// Flip direction for yoyo.
|
|
322
|
+
if (this._yoyo) {
|
|
323
|
+
this._direction = this._direction === 1 ? -1 : 1;
|
|
324
|
+
}
|
|
325
|
+
// Reset elapsed for next cycle; carry overflow.
|
|
326
|
+
const overflow = this._elapsed - this._duration;
|
|
327
|
+
this._elapsed = overflow > 0 ? Math.min(overflow, this._duration) : 0;
|
|
328
|
+
this._startFired = false; // allow onStart to re-fire next cycle? No — spec says once.
|
|
329
|
+
// Actually spec says onStart fires when actual interpolation begins.
|
|
330
|
+
// For repeats it fires once total at the very first cycle.
|
|
331
|
+
// Re-reading spec: "onStart fires AFTER the delay (when actual interpolation begins)".
|
|
332
|
+
// We'll keep it as one-shot across the full lifecycle; don't reset _startFired.
|
|
333
|
+
this._startFired = true;
|
|
334
|
+
// Apply progress for any overflow.
|
|
335
|
+
if (overflow > 0) {
|
|
336
|
+
this._applyProgress();
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
// All cycles done.
|
|
341
|
+
this._complete();
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
_captureStartValues() {
|
|
346
|
+
const snap = {};
|
|
347
|
+
const keys = Object.keys(this._properties);
|
|
348
|
+
for (const key of keys) {
|
|
349
|
+
const val = this._target[key];
|
|
350
|
+
if (typeof val !== 'number') {
|
|
351
|
+
console.warn(`Tween: property "${String(key)}" is not a number on target ` +
|
|
352
|
+
`(got ${typeof val}). It will be skipped.`);
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
snap[String(key)] = val;
|
|
356
|
+
}
|
|
357
|
+
this._startValues = snap;
|
|
358
|
+
}
|
|
359
|
+
_applyProgress() {
|
|
360
|
+
if (this._startValues === null)
|
|
361
|
+
return;
|
|
362
|
+
const rawT = this._duration === 0 ? 1 : Math.min(this._elapsed / this._duration, 1);
|
|
363
|
+
const t = this._direction === 1 ? rawT : 1 - rawT;
|
|
364
|
+
const easedT = this._easing(t);
|
|
365
|
+
const keys = Object.keys(this._startValues);
|
|
366
|
+
for (const key of keys) {
|
|
367
|
+
const start = this._startValues[key];
|
|
368
|
+
const end = this._properties[key];
|
|
369
|
+
this._target[key] = start + (end - start) * easedT;
|
|
370
|
+
}
|
|
371
|
+
this._onUpdate?.(easedT);
|
|
372
|
+
}
|
|
373
|
+
_complete() {
|
|
374
|
+
// Ensure the target is at its final interpolated position.
|
|
375
|
+
this._elapsed = this._duration;
|
|
376
|
+
this._applyProgress();
|
|
377
|
+
this._state = TweenState.Complete;
|
|
378
|
+
this._manager?.remove(this);
|
|
379
|
+
this._onComplete?.();
|
|
380
|
+
// Fire chained tween, if any.
|
|
381
|
+
this._chained?.start();
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
class TweenManager {
|
|
386
|
+
_tweens = [];
|
|
387
|
+
_destroyed = false;
|
|
388
|
+
/**
|
|
389
|
+
* Create a new Tween targeting `target`, register it with this manager, and
|
|
390
|
+
* return it. Call .to(...).start() on the result to begin animating.
|
|
391
|
+
*/
|
|
392
|
+
create(target) {
|
|
393
|
+
const tween = new Tween(target);
|
|
394
|
+
tween._attachManager(this);
|
|
395
|
+
this._tweens.push(tween);
|
|
396
|
+
return tween;
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Explicitly add a stand-alone Tween (created via `new Tween(target)`)
|
|
400
|
+
* to this manager so it participates in the update loop.
|
|
401
|
+
*/
|
|
402
|
+
add(tween) {
|
|
403
|
+
tween._attachManager(this);
|
|
404
|
+
if (!this._tweens.includes(tween)) {
|
|
405
|
+
this._tweens.push(tween);
|
|
406
|
+
}
|
|
407
|
+
return this;
|
|
408
|
+
}
|
|
409
|
+
/** Remove a tween from the manager. Called automatically on stop/complete. */
|
|
410
|
+
remove(tween) {
|
|
411
|
+
const index = this._tweens.indexOf(tween);
|
|
412
|
+
if (index !== -1) {
|
|
413
|
+
this._tweens.splice(index, 1);
|
|
414
|
+
}
|
|
415
|
+
return this;
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Advance all active tweens by deltaSeconds. Called once per frame by
|
|
419
|
+
* Application.update(). Uses a snapshot of the list so that callbacks that
|
|
420
|
+
* add or remove tweens do not corrupt mid-iteration.
|
|
421
|
+
*/
|
|
422
|
+
update(deltaSeconds) {
|
|
423
|
+
if (this._destroyed)
|
|
424
|
+
return this;
|
|
425
|
+
const snapshot = this._tweens.slice();
|
|
426
|
+
for (const tween of snapshot) {
|
|
427
|
+
tween.update(deltaSeconds);
|
|
428
|
+
}
|
|
429
|
+
return this;
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Remove all tweens immediately. No callbacks (onComplete etc.) fire.
|
|
433
|
+
* The tweens' states are left as-is; they are simply evicted from the list.
|
|
434
|
+
*/
|
|
435
|
+
clear() {
|
|
436
|
+
this._tweens = [];
|
|
437
|
+
return this;
|
|
438
|
+
}
|
|
439
|
+
/** Tear down the manager. Clears tweens and makes subsequent updates no-ops. */
|
|
440
|
+
destroy() {
|
|
441
|
+
this.clear();
|
|
442
|
+
this._destroyed = true;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
1
446
|
let temp$9 = null;
|
|
2
447
|
class Size {
|
|
3
448
|
_width;
|
|
@@ -706,7 +1151,7 @@ const trimRotation = (degrees) => {
|
|
|
706
1151
|
const degreesToRadians = (degree) => degree * radiansPerDegree;
|
|
707
1152
|
const radiansToDegrees = (radian) => radian * degreesPerRadian;
|
|
708
1153
|
const clamp = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
709
|
-
const sign
|
|
1154
|
+
const sign = (value) => (value && (value < 0 ? -1 : 1));
|
|
710
1155
|
const lerp = (startValue, endValue, ratio) => (((1 - ratio) * startValue) + (ratio * endValue));
|
|
711
1156
|
const isPowerOfTwo = (value) => ((value !== 0) && ((value & (value - 1)) === 0));
|
|
712
1157
|
const inRange = (value, min, max) => (value >= Math.min(min, max) && value <= Math.max(min, max));
|
|
@@ -14578,6 +15023,7 @@ class Application {
|
|
|
14578
15023
|
loader;
|
|
14579
15024
|
inputManager;
|
|
14580
15025
|
sceneManager;
|
|
15026
|
+
tweens = new TweenManager();
|
|
14581
15027
|
onResize = new Signal();
|
|
14582
15028
|
_updateHandler;
|
|
14583
15029
|
_startupClock = new Clock();
|
|
@@ -14669,6 +15115,7 @@ class Application {
|
|
|
14669
15115
|
const frameStart = performance.now();
|
|
14670
15116
|
this.backend.resetStats();
|
|
14671
15117
|
this.inputManager.update();
|
|
15118
|
+
this.tweens.update(frameDelta.seconds);
|
|
14672
15119
|
const runtimeView = this.backend.view;
|
|
14673
15120
|
if (runtimeView && typeof runtimeView.update === 'function') {
|
|
14674
15121
|
runtimeView.update(frameDelta.milliseconds);
|
|
@@ -14704,6 +15151,7 @@ class Application {
|
|
|
14704
15151
|
this.stop();
|
|
14705
15152
|
this.loader.destroy();
|
|
14706
15153
|
this.inputManager.destroy();
|
|
15154
|
+
this.tweens.destroy();
|
|
14707
15155
|
this._backend.destroy();
|
|
14708
15156
|
this.sceneManager.destroy();
|
|
14709
15157
|
this._startupClock.destroy();
|
|
@@ -15452,636 +15900,166 @@ class Input {
|
|
|
15452
15900
|
}
|
|
15453
15901
|
}
|
|
15454
15902
|
|
|
15455
|
-
|
|
15456
|
-
|
|
15457
|
-
|
|
15458
|
-
|
|
15459
|
-
|
|
15460
|
-
|
|
15461
|
-
|
|
15462
|
-
|
|
15463
|
-
|
|
15464
|
-
|
|
15465
|
-
|
|
15466
|
-
|
|
15467
|
-
|
|
15468
|
-
|
|
15469
|
-
|
|
15470
|
-
|
|
15471
|
-
|
|
15472
|
-
|
|
15473
|
-
|
|
15474
|
-
|
|
15475
|
-
|
|
15476
|
-
|
|
15477
|
-
|
|
15478
|
-
|
|
15479
|
-
|
|
15480
|
-
|
|
15481
|
-
|
|
15482
|
-
|
|
15483
|
-
|
|
15484
|
-
|
|
15485
|
-
|
|
15486
|
-
|
|
15487
|
-
|
|
15488
|
-
|
|
15489
|
-
|
|
15490
|
-
|
|
15491
|
-
|
|
15492
|
-
|
|
15493
|
-
|
|
15494
|
-
|
|
15495
|
-
|
|
15496
|
-
|
|
15497
|
-
|
|
15498
|
-
|
|
15499
|
-
|
|
15500
|
-
|
|
15501
|
-
|
|
15502
|
-
|
|
15503
|
-
|
|
15504
|
-
|
|
15505
|
-
|
|
15506
|
-
|
|
15507
|
-
|
|
15508
|
-
|
|
15509
|
-
|
|
15510
|
-
|
|
15511
|
-
|
|
15512
|
-
|
|
15513
|
-
|
|
15514
|
-
|
|
15515
|
-
|
|
15516
|
-
|
|
15517
|
-
|
|
15518
|
-
|
|
15519
|
-
|
|
15520
|
-
|
|
15521
|
-
|
|
15522
|
-
|
|
15523
|
-
|
|
15524
|
-
|
|
15525
|
-
|
|
15526
|
-
|
|
15527
|
-
|
|
15528
|
-
|
|
15529
|
-
p = p.next;
|
|
15530
|
-
}
|
|
15531
|
-
} while (again || p !== end);
|
|
15532
|
-
|
|
15533
|
-
return end;
|
|
15534
|
-
}
|
|
15535
|
-
|
|
15536
|
-
// main ear slicing loop which triangulates a polygon (given as a linked list)
|
|
15537
|
-
function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) {
|
|
15538
|
-
if (!ear) return;
|
|
15539
|
-
|
|
15540
|
-
// interlink polygon nodes in z-order
|
|
15541
|
-
if (!pass && invSize) indexCurve(ear, minX, minY, invSize);
|
|
15542
|
-
|
|
15543
|
-
let stop = ear;
|
|
15544
|
-
|
|
15545
|
-
// iterate through ears, slicing them one by one
|
|
15546
|
-
while (ear.prev !== ear.next) {
|
|
15547
|
-
const prev = ear.prev;
|
|
15548
|
-
const next = ear.next;
|
|
15549
|
-
|
|
15550
|
-
if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) {
|
|
15551
|
-
triangles.push(prev.i, ear.i, next.i); // cut off the triangle
|
|
15552
|
-
|
|
15553
|
-
removeNode(ear);
|
|
15554
|
-
|
|
15555
|
-
// skipping the next vertex leads to less sliver triangles
|
|
15556
|
-
ear = next.next;
|
|
15557
|
-
stop = next.next;
|
|
15558
|
-
|
|
15559
|
-
continue;
|
|
15560
|
-
}
|
|
15561
|
-
|
|
15562
|
-
ear = next;
|
|
15563
|
-
|
|
15564
|
-
// if we looped through the whole remaining polygon and can't find any more ears
|
|
15565
|
-
if (ear === stop) {
|
|
15566
|
-
// try filtering points and slicing again
|
|
15567
|
-
if (!pass) {
|
|
15568
|
-
earcutLinked(filterPoints(ear), triangles, dim, minX, minY, invSize, 1);
|
|
15569
|
-
|
|
15570
|
-
// if this didn't work, try curing all small self-intersections locally
|
|
15571
|
-
} else if (pass === 1) {
|
|
15572
|
-
ear = cureLocalIntersections(filterPoints(ear), triangles);
|
|
15573
|
-
earcutLinked(ear, triangles, dim, minX, minY, invSize, 2);
|
|
15574
|
-
|
|
15575
|
-
// as a last resort, try splitting the remaining polygon into two
|
|
15576
|
-
} else if (pass === 2) {
|
|
15577
|
-
splitEarcut(ear, triangles, dim, minX, minY, invSize);
|
|
15903
|
+
/**
|
|
15904
|
+
* Triangulate a simple 2D polygon by ear-clipping.
|
|
15905
|
+
*
|
|
15906
|
+
* Input: `vertices` is a flat sequence of (x, y) pairs (length must be even,
|
|
15907
|
+
* minimum 6 = 3 vertices). Polygon may be CW or CCW; the algorithm normalises
|
|
15908
|
+
* to CCW internally.
|
|
15909
|
+
*
|
|
15910
|
+
* Output: a `Uint32Array` of indices in groups of 3 (per triangle), referencing
|
|
15911
|
+
* vertex positions (the i-th vertex spans `vertices[2*i], vertices[2*i + 1]`).
|
|
15912
|
+
*
|
|
15913
|
+
* Polygons that are degenerate (all collinear), zero-area, or self-intersecting
|
|
15914
|
+
* may produce incomplete output but must not throw or hang.
|
|
15915
|
+
*
|
|
15916
|
+
* @param vertices flat (x, y) pairs
|
|
15917
|
+
* @returns triangle index list (length is multiple of 3)
|
|
15918
|
+
*/
|
|
15919
|
+
function triangulate(vertices) {
|
|
15920
|
+
const n = vertices.length >> 1;
|
|
15921
|
+
if (n < 3) {
|
|
15922
|
+
return new Uint32Array(0);
|
|
15923
|
+
}
|
|
15924
|
+
if (n === 3) {
|
|
15925
|
+
// Return in CCW order; swap if input triangle is CW.
|
|
15926
|
+
const ax = vertices[0], ay = vertices[1];
|
|
15927
|
+
const bx = vertices[2], by = vertices[3];
|
|
15928
|
+
const cx = vertices[4], cy = vertices[5];
|
|
15929
|
+
return isCcwTriangle(ax, ay, bx, by, cx, cy)
|
|
15930
|
+
? new Uint32Array([0, 1, 2])
|
|
15931
|
+
: new Uint32Array([2, 1, 0]);
|
|
15932
|
+
}
|
|
15933
|
+
// Build doubly-linked list of vertex indices.
|
|
15934
|
+
const prev = new Uint32Array(n);
|
|
15935
|
+
const next = new Uint32Array(n);
|
|
15936
|
+
for (let i = 0; i < n; i++) {
|
|
15937
|
+
prev[i] = (i + n - 1) % n;
|
|
15938
|
+
next[i] = (i + 1) % n;
|
|
15939
|
+
}
|
|
15940
|
+
// Normalise to CCW: compute signed area; if negative (CW), reverse the list.
|
|
15941
|
+
if (signedArea(vertices) < 0) {
|
|
15942
|
+
for (let i = 0; i < n; i++) {
|
|
15943
|
+
const tmp = prev[i];
|
|
15944
|
+
prev[i] = next[i];
|
|
15945
|
+
next[i] = tmp;
|
|
15946
|
+
}
|
|
15947
|
+
}
|
|
15948
|
+
const maxTriangles = n - 2;
|
|
15949
|
+
const out = new Uint32Array(maxTriangles * 3);
|
|
15950
|
+
let outIdx = 0;
|
|
15951
|
+
let remaining = n;
|
|
15952
|
+
let current = 0;
|
|
15953
|
+
// Ear-clipping: at most O(n^2) iterations; bail after one full pass finds no ear.
|
|
15954
|
+
while (remaining > 3) {
|
|
15955
|
+
// Try each remaining vertex as a potential ear, one full pass at a time.
|
|
15956
|
+
let earFound = false;
|
|
15957
|
+
const passStart = current;
|
|
15958
|
+
do {
|
|
15959
|
+
const p = prev[current];
|
|
15960
|
+
const nx = next[current];
|
|
15961
|
+
const v = current;
|
|
15962
|
+
const ax = vertices[p * 2], ay = vertices[p * 2 + 1];
|
|
15963
|
+
const bx = vertices[v * 2], by = vertices[v * 2 + 1];
|
|
15964
|
+
const cx = vertices[nx * 2], cy = vertices[nx * 2 + 1];
|
|
15965
|
+
if (isCcwTriangle(ax, ay, bx, by, cx, cy) && isEar(vertices, prev, next, p, v, nx)) {
|
|
15966
|
+
// Emit triangle (prev, v, next).
|
|
15967
|
+
out[outIdx++] = p;
|
|
15968
|
+
out[outIdx++] = v;
|
|
15969
|
+
out[outIdx++] = nx;
|
|
15970
|
+
// Remove v from the list.
|
|
15971
|
+
next[p] = nx;
|
|
15972
|
+
prev[nx] = p;
|
|
15973
|
+
remaining--;
|
|
15974
|
+
earFound = true;
|
|
15975
|
+
current = nx;
|
|
15976
|
+
break;
|
|
15578
15977
|
}
|
|
15579
|
-
|
|
15978
|
+
current = next[current];
|
|
15979
|
+
} while (current !== passStart);
|
|
15980
|
+
if (!earFound) {
|
|
15981
|
+
// Degenerate polygon: no ear found in a full pass; bail out.
|
|
15580
15982
|
break;
|
|
15581
15983
|
}
|
|
15582
15984
|
}
|
|
15583
|
-
|
|
15584
|
-
|
|
15585
|
-
|
|
15586
|
-
|
|
15587
|
-
|
|
15588
|
-
|
|
15589
|
-
|
|
15590
|
-
|
|
15591
|
-
|
|
15592
|
-
|
|
15593
|
-
|
|
15594
|
-
|
|
15595
|
-
|
|
15596
|
-
// triangle bbox
|
|
15597
|
-
const x0 = Math.min(ax, bx, cx),
|
|
15598
|
-
y0 = Math.min(ay, by, cy),
|
|
15599
|
-
x1 = Math.max(ax, bx, cx),
|
|
15600
|
-
y1 = Math.max(ay, by, cy);
|
|
15601
|
-
|
|
15602
|
-
let p = c.next;
|
|
15603
|
-
while (p !== a) {
|
|
15604
|
-
if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 &&
|
|
15605
|
-
pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, p.x, p.y) &&
|
|
15606
|
-
area(p.prev, p, p.next) >= 0) return false;
|
|
15607
|
-
p = p.next;
|
|
15608
|
-
}
|
|
15609
|
-
|
|
15610
|
-
return true;
|
|
15611
|
-
}
|
|
15612
|
-
|
|
15613
|
-
function isEarHashed(ear, minX, minY, invSize) {
|
|
15614
|
-
const a = ear.prev,
|
|
15615
|
-
b = ear,
|
|
15616
|
-
c = ear.next;
|
|
15617
|
-
|
|
15618
|
-
if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
|
|
15619
|
-
|
|
15620
|
-
const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;
|
|
15621
|
-
|
|
15622
|
-
// triangle bbox
|
|
15623
|
-
const x0 = Math.min(ax, bx, cx),
|
|
15624
|
-
y0 = Math.min(ay, by, cy),
|
|
15625
|
-
x1 = Math.max(ax, bx, cx),
|
|
15626
|
-
y1 = Math.max(ay, by, cy);
|
|
15627
|
-
|
|
15628
|
-
// z-order range for the current triangle bbox;
|
|
15629
|
-
const minZ = zOrder(x0, y0, minX, minY, invSize),
|
|
15630
|
-
maxZ = zOrder(x1, y1, minX, minY, invSize);
|
|
15631
|
-
|
|
15632
|
-
let p = ear.prevZ,
|
|
15633
|
-
n = ear.nextZ;
|
|
15634
|
-
|
|
15635
|
-
// look for points inside the triangle in both directions
|
|
15636
|
-
while (p && p.z >= minZ && n && n.z <= maxZ) {
|
|
15637
|
-
if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c &&
|
|
15638
|
-
pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
|
|
15639
|
-
p = p.prevZ;
|
|
15640
|
-
|
|
15641
|
-
if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c &&
|
|
15642
|
-
pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
|
|
15643
|
-
n = n.nextZ;
|
|
15644
|
-
}
|
|
15645
|
-
|
|
15646
|
-
// look for remaining points in decreasing z-order
|
|
15647
|
-
while (p && p.z >= minZ) {
|
|
15648
|
-
if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c &&
|
|
15649
|
-
pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
|
|
15650
|
-
p = p.prevZ;
|
|
15651
|
-
}
|
|
15652
|
-
|
|
15653
|
-
// look for remaining points in increasing z-order
|
|
15654
|
-
while (n && n.z <= maxZ) {
|
|
15655
|
-
if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c &&
|
|
15656
|
-
pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
|
|
15657
|
-
n = n.nextZ;
|
|
15658
|
-
}
|
|
15659
|
-
|
|
15660
|
-
return true;
|
|
15661
|
-
}
|
|
15662
|
-
|
|
15663
|
-
// go through all polygon nodes and cure small local self-intersections
|
|
15664
|
-
function cureLocalIntersections(start, triangles) {
|
|
15665
|
-
let p = start;
|
|
15666
|
-
do {
|
|
15667
|
-
const a = p.prev,
|
|
15668
|
-
b = p.next.next;
|
|
15669
|
-
|
|
15670
|
-
if (!equals(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) {
|
|
15671
|
-
|
|
15672
|
-
triangles.push(a.i, p.i, b.i);
|
|
15673
|
-
|
|
15674
|
-
// remove two nodes involved
|
|
15675
|
-
removeNode(p);
|
|
15676
|
-
removeNode(p.next);
|
|
15677
|
-
|
|
15678
|
-
p = start = b;
|
|
15985
|
+
// Emit the final triangle if exactly 3 vertices remain.
|
|
15986
|
+
// Emit in CCW order (the linked-list direction may be CW after prior clips on concave polygons).
|
|
15987
|
+
if (remaining === 3) {
|
|
15988
|
+
const pa = prev[current];
|
|
15989
|
+
const nc = next[current];
|
|
15990
|
+
const ax = vertices[pa * 2], ay = vertices[pa * 2 + 1];
|
|
15991
|
+
const bx = vertices[current * 2], by = vertices[current * 2 + 1];
|
|
15992
|
+
const cx = vertices[nc * 2], cy = vertices[nc * 2 + 1];
|
|
15993
|
+
if (isCcwTriangle(ax, ay, bx, by, cx, cy)) {
|
|
15994
|
+
out[outIdx++] = pa;
|
|
15995
|
+
out[outIdx++] = current;
|
|
15996
|
+
out[outIdx++] = nc;
|
|
15679
15997
|
}
|
|
15680
|
-
|
|
15681
|
-
|
|
15682
|
-
|
|
15683
|
-
|
|
15684
|
-
}
|
|
15685
|
-
|
|
15686
|
-
// try splitting polygon into two and triangulate them independently
|
|
15687
|
-
function splitEarcut(start, triangles, dim, minX, minY, invSize) {
|
|
15688
|
-
// look for a valid diagonal that divides the polygon into two
|
|
15689
|
-
let a = start;
|
|
15690
|
-
do {
|
|
15691
|
-
let b = a.next.next;
|
|
15692
|
-
while (b !== a.prev) {
|
|
15693
|
-
if (a.i !== b.i && isValidDiagonal(a, b)) {
|
|
15694
|
-
// split the polygon in two by the diagonal
|
|
15695
|
-
let c = splitPolygon(a, b);
|
|
15696
|
-
|
|
15697
|
-
// filter colinear points around the cuts
|
|
15698
|
-
a = filterPoints(a, a.next);
|
|
15699
|
-
c = filterPoints(c, c.next);
|
|
15700
|
-
|
|
15701
|
-
// run earcut on each half
|
|
15702
|
-
earcutLinked(a, triangles, dim, minX, minY, invSize, 0);
|
|
15703
|
-
earcutLinked(c, triangles, dim, minX, minY, invSize, 0);
|
|
15704
|
-
return;
|
|
15705
|
-
}
|
|
15706
|
-
b = b.next;
|
|
15707
|
-
}
|
|
15708
|
-
a = a.next;
|
|
15709
|
-
} while (a !== start);
|
|
15710
|
-
}
|
|
15711
|
-
|
|
15712
|
-
// link every hole into the outer loop, producing a single-ring polygon without holes
|
|
15713
|
-
function eliminateHoles(data, holeIndices, outerNode, dim) {
|
|
15714
|
-
const queue = [];
|
|
15715
|
-
|
|
15716
|
-
for (let i = 0, len = holeIndices.length; i < len; i++) {
|
|
15717
|
-
const start = holeIndices[i] * dim;
|
|
15718
|
-
const end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
|
|
15719
|
-
const list = linkedList(data, start, end, dim, false);
|
|
15720
|
-
if (list === list.next) list.steiner = true;
|
|
15721
|
-
queue.push(getLeftmost(list));
|
|
15722
|
-
}
|
|
15723
|
-
|
|
15724
|
-
queue.sort(compareXYSlope);
|
|
15725
|
-
|
|
15726
|
-
// process holes from left to right
|
|
15727
|
-
for (let i = 0; i < queue.length; i++) {
|
|
15728
|
-
outerNode = eliminateHole(queue[i], outerNode);
|
|
15729
|
-
}
|
|
15730
|
-
|
|
15731
|
-
return outerNode;
|
|
15732
|
-
}
|
|
15733
|
-
|
|
15734
|
-
function compareXYSlope(a, b) {
|
|
15735
|
-
let result = a.x - b.x;
|
|
15736
|
-
// when the left-most point of 2 holes meet at a vertex, sort the holes counterclockwise so that when we find
|
|
15737
|
-
// the bridge to the outer shell is always the point that they meet at.
|
|
15738
|
-
if (result === 0) {
|
|
15739
|
-
result = a.y - b.y;
|
|
15740
|
-
if (result === 0) {
|
|
15741
|
-
const aSlope = (a.next.y - a.y) / (a.next.x - a.x);
|
|
15742
|
-
const bSlope = (b.next.y - b.y) / (b.next.x - b.x);
|
|
15743
|
-
result = aSlope - bSlope;
|
|
15998
|
+
else {
|
|
15999
|
+
out[outIdx++] = nc;
|
|
16000
|
+
out[outIdx++] = current;
|
|
16001
|
+
out[outIdx++] = pa;
|
|
15744
16002
|
}
|
|
15745
16003
|
}
|
|
15746
|
-
return
|
|
15747
|
-
}
|
|
15748
|
-
|
|
15749
|
-
// find a bridge between vertices that connects hole with an outer ring and link it
|
|
15750
|
-
function eliminateHole(hole, outerNode) {
|
|
15751
|
-
const bridge = findHoleBridge(hole, outerNode);
|
|
15752
|
-
if (!bridge) {
|
|
15753
|
-
return outerNode;
|
|
15754
|
-
}
|
|
15755
|
-
|
|
15756
|
-
const bridgeReverse = splitPolygon(bridge, hole);
|
|
15757
|
-
|
|
15758
|
-
// filter collinear points around the cuts
|
|
15759
|
-
filterPoints(bridgeReverse, bridgeReverse.next);
|
|
15760
|
-
return filterPoints(bridge, bridge.next);
|
|
16004
|
+
return out.subarray(0, outIdx);
|
|
15761
16005
|
}
|
|
15762
|
-
|
|
15763
|
-
|
|
15764
|
-
|
|
15765
|
-
let
|
|
15766
|
-
|
|
15767
|
-
|
|
15768
|
-
|
|
15769
|
-
|
|
15770
|
-
|
|
15771
|
-
|
|
15772
|
-
|
|
15773
|
-
|
|
15774
|
-
|
|
15775
|
-
do {
|
|
15776
|
-
if (equals(hole, p.next)) return p.next;
|
|
15777
|
-
else if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {
|
|
15778
|
-
const x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
|
|
15779
|
-
if (x <= hx && x > qx) {
|
|
15780
|
-
qx = x;
|
|
15781
|
-
m = p.x < p.next.x ? p : p.next;
|
|
15782
|
-
if (x === hx) return m; // hole touches outer segment; pick leftmost endpoint
|
|
15783
|
-
}
|
|
15784
|
-
}
|
|
15785
|
-
p = p.next;
|
|
15786
|
-
} while (p !== outerNode);
|
|
15787
|
-
|
|
15788
|
-
if (!m) return null;
|
|
15789
|
-
|
|
15790
|
-
// look for points inside the triangle of hole point, segment intersection and endpoint;
|
|
15791
|
-
// if there are no points found, we have a valid connection;
|
|
15792
|
-
// otherwise choose the point of the minimum angle with the ray as connection point
|
|
15793
|
-
|
|
15794
|
-
const stop = m;
|
|
15795
|
-
const mx = m.x;
|
|
15796
|
-
const my = m.y;
|
|
15797
|
-
let tanMin = Infinity;
|
|
15798
|
-
|
|
15799
|
-
p = m;
|
|
15800
|
-
|
|
15801
|
-
do {
|
|
15802
|
-
if (hx >= p.x && p.x >= mx && hx !== p.x &&
|
|
15803
|
-
pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) {
|
|
15804
|
-
|
|
15805
|
-
const tan = Math.abs(hy - p.y) / (hx - p.x); // tangential
|
|
15806
|
-
|
|
15807
|
-
if (locallyInside(p, hole) &&
|
|
15808
|
-
(tan < tanMin || (tan === tanMin && (p.x > m.x || (p.x === m.x && sectorContainsSector(m, p)))))) {
|
|
15809
|
-
m = p;
|
|
15810
|
-
tanMin = tan;
|
|
15811
|
-
}
|
|
15812
|
-
}
|
|
15813
|
-
|
|
15814
|
-
p = p.next;
|
|
15815
|
-
} while (p !== stop);
|
|
15816
|
-
|
|
15817
|
-
return m;
|
|
16006
|
+
/** Shoelace signed area. Positive = CCW (mathematical orientation), negative = CW. */
|
|
16007
|
+
function signedArea(vertices) {
|
|
16008
|
+
const n = vertices.length >> 1;
|
|
16009
|
+
let area = 0;
|
|
16010
|
+
for (let i = 0; i < n; i++) {
|
|
16011
|
+
const j = (i + 1) % n;
|
|
16012
|
+
const x0 = vertices[i * 2];
|
|
16013
|
+
const y0 = vertices[i * 2 + 1];
|
|
16014
|
+
const x1 = vertices[j * 2];
|
|
16015
|
+
const y1 = vertices[j * 2 + 1];
|
|
16016
|
+
area += (x0 * y1) - (x1 * y0);
|
|
16017
|
+
}
|
|
16018
|
+
return area; // Positive = CCW, negative = CW.
|
|
15818
16019
|
}
|
|
15819
|
-
|
|
15820
|
-
|
|
15821
|
-
|
|
15822
|
-
|
|
16020
|
+
/**
|
|
16021
|
+
* Returns true if the triangle (a, b, c) has a counter-clockwise (CCW) winding.
|
|
16022
|
+
* Uses the cross product of (b-a) × (c-a); positive = CCW.
|
|
16023
|
+
*/
|
|
16024
|
+
function isCcwTriangle(ax, ay, bx, by, cx, cy) {
|
|
16025
|
+
return ((bx - ax) * (cy - ay) - (by - ay) * (cx - ax)) > 0;
|
|
15823
16026
|
}
|
|
15824
|
-
|
|
15825
|
-
|
|
15826
|
-
|
|
15827
|
-
|
|
15828
|
-
|
|
15829
|
-
|
|
15830
|
-
|
|
15831
|
-
|
|
15832
|
-
|
|
15833
|
-
|
|
15834
|
-
|
|
15835
|
-
|
|
15836
|
-
p.prevZ = null;
|
|
15837
|
-
|
|
15838
|
-
sortLinked(p);
|
|
16027
|
+
/**
|
|
16028
|
+
* Returns true if point (px, py) lies strictly inside triangle (a, b, c).
|
|
16029
|
+
* Uses sign-of-cross-products. Boundary points (including corners) return false.
|
|
16030
|
+
*/
|
|
16031
|
+
function pointInTriangle(px, py, ax, ay, bx, by, cx, cy) {
|
|
16032
|
+
const d1 = (px - bx) * (ay - by) - (ax - bx) * (py - by);
|
|
16033
|
+
const d2 = (px - cx) * (by - cy) - (bx - cx) * (py - cy);
|
|
16034
|
+
const d3 = (px - ax) * (cy - ay) - (cx - ax) * (py - ay);
|
|
16035
|
+
const hasNeg = (d1 < 0) || (d2 < 0) || (d3 < 0);
|
|
16036
|
+
const hasPos = (d1 > 0) || (d2 > 0) || (d3 > 0);
|
|
16037
|
+
// Strictly inside: all same sign and none are exactly zero (exclude boundary).
|
|
16038
|
+
return !(hasNeg && hasPos) && (d1 !== 0) && (d2 !== 0) && (d3 !== 0);
|
|
15839
16039
|
}
|
|
15840
|
-
|
|
15841
|
-
|
|
15842
|
-
|
|
15843
|
-
|
|
15844
|
-
|
|
15845
|
-
|
|
15846
|
-
|
|
15847
|
-
|
|
15848
|
-
|
|
15849
|
-
|
|
15850
|
-
|
|
15851
|
-
|
|
15852
|
-
|
|
15853
|
-
|
|
15854
|
-
|
|
15855
|
-
|
|
15856
|
-
|
|
15857
|
-
|
|
15858
|
-
for (let i = 0; i < inSize; i++) {
|
|
15859
|
-
pSize++;
|
|
15860
|
-
q = q.nextZ;
|
|
15861
|
-
if (!q) break;
|
|
15862
|
-
}
|
|
15863
|
-
let qSize = inSize;
|
|
15864
|
-
|
|
15865
|
-
while (pSize > 0 || (qSize > 0 && q)) {
|
|
15866
|
-
|
|
15867
|
-
if (pSize !== 0 && (qSize === 0 || !q || p.z <= q.z)) {
|
|
15868
|
-
e = p;
|
|
15869
|
-
p = p.nextZ;
|
|
15870
|
-
pSize--;
|
|
15871
|
-
} else {
|
|
15872
|
-
e = q;
|
|
15873
|
-
q = q.nextZ;
|
|
15874
|
-
qSize--;
|
|
15875
|
-
}
|
|
15876
|
-
|
|
15877
|
-
if (tail) tail.nextZ = e;
|
|
15878
|
-
else list = e;
|
|
15879
|
-
|
|
15880
|
-
e.prevZ = tail;
|
|
15881
|
-
tail = e;
|
|
16040
|
+
/**
|
|
16041
|
+
* Returns true if vertex v is an ear: the triangle (prevIdx, v, nextIdx) contains
|
|
16042
|
+
* no other polygon vertex strictly inside it.
|
|
16043
|
+
*/
|
|
16044
|
+
function isEar(vertices, prev, next, prevIdx, v, nextIdx) {
|
|
16045
|
+
const ax = vertices[prevIdx * 2], ay = vertices[prevIdx * 2 + 1];
|
|
16046
|
+
const bx = vertices[v * 2], by = vertices[v * 2 + 1];
|
|
16047
|
+
const cx = vertices[nextIdx * 2], cy = vertices[nextIdx * 2 + 1];
|
|
16048
|
+
// Walk all remaining vertices and check if any lie strictly inside the ear triangle.
|
|
16049
|
+
// Skip the three ear vertices themselves — they can never be "inside" by strict test,
|
|
16050
|
+
// but we exclude them explicitly for clarity and to avoid floating-point edge cases.
|
|
16051
|
+
let node = next[nextIdx];
|
|
16052
|
+
while (node !== prevIdx) {
|
|
16053
|
+
if (node !== v) {
|
|
16054
|
+
const px = vertices[node * 2];
|
|
16055
|
+
const py = vertices[node * 2 + 1];
|
|
16056
|
+
if (pointInTriangle(px, py, ax, ay, bx, by, cx, cy)) {
|
|
16057
|
+
return false;
|
|
15882
16058
|
}
|
|
15883
|
-
|
|
15884
|
-
p = q;
|
|
15885
16059
|
}
|
|
15886
|
-
|
|
15887
|
-
tail.nextZ = null;
|
|
15888
|
-
inSize *= 2;
|
|
15889
|
-
|
|
15890
|
-
} while (numMerges > 1);
|
|
15891
|
-
|
|
15892
|
-
return list;
|
|
15893
|
-
}
|
|
15894
|
-
|
|
15895
|
-
// z-order of a point given coords and inverse of the longer side of data bbox
|
|
15896
|
-
function zOrder(x, y, minX, minY, invSize) {
|
|
15897
|
-
// coords are transformed into non-negative 15-bit integer range
|
|
15898
|
-
x = (x - minX) * invSize | 0;
|
|
15899
|
-
y = (y - minY) * invSize | 0;
|
|
15900
|
-
|
|
15901
|
-
x = (x | (x << 8)) & 0x00FF00FF;
|
|
15902
|
-
x = (x | (x << 4)) & 0x0F0F0F0F;
|
|
15903
|
-
x = (x | (x << 2)) & 0x33333333;
|
|
15904
|
-
x = (x | (x << 1)) & 0x55555555;
|
|
15905
|
-
|
|
15906
|
-
y = (y | (y << 8)) & 0x00FF00FF;
|
|
15907
|
-
y = (y | (y << 4)) & 0x0F0F0F0F;
|
|
15908
|
-
y = (y | (y << 2)) & 0x33333333;
|
|
15909
|
-
y = (y | (y << 1)) & 0x55555555;
|
|
15910
|
-
|
|
15911
|
-
return x | (y << 1);
|
|
15912
|
-
}
|
|
15913
|
-
|
|
15914
|
-
// find the leftmost node of a polygon ring
|
|
15915
|
-
function getLeftmost(start) {
|
|
15916
|
-
let p = start,
|
|
15917
|
-
leftmost = start;
|
|
15918
|
-
do {
|
|
15919
|
-
if (p.x < leftmost.x || (p.x === leftmost.x && p.y < leftmost.y)) leftmost = p;
|
|
15920
|
-
p = p.next;
|
|
15921
|
-
} while (p !== start);
|
|
15922
|
-
|
|
15923
|
-
return leftmost;
|
|
15924
|
-
}
|
|
15925
|
-
|
|
15926
|
-
// check if a point lies within a convex triangle
|
|
15927
|
-
function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
|
|
15928
|
-
return (cx - px) * (ay - py) >= (ax - px) * (cy - py) &&
|
|
15929
|
-
(ax - px) * (by - py) >= (bx - px) * (ay - py) &&
|
|
15930
|
-
(bx - px) * (cy - py) >= (cx - px) * (by - py);
|
|
15931
|
-
}
|
|
15932
|
-
|
|
15933
|
-
// check if a point lies within a convex triangle but false if its equal to the first point of the triangle
|
|
15934
|
-
function pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, px, py) {
|
|
15935
|
-
return !(ax === px && ay === py) && pointInTriangle(ax, ay, bx, by, cx, cy, px, py);
|
|
15936
|
-
}
|
|
15937
|
-
|
|
15938
|
-
// check if a diagonal between two polygon nodes is valid (lies in polygon interior)
|
|
15939
|
-
function isValidDiagonal(a, b) {
|
|
15940
|
-
return a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) && // doesn't intersect other edges
|
|
15941
|
-
(locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && // locally visible
|
|
15942
|
-
(area(a.prev, a, b.prev) || area(a, b.prev, b)) || // does not create opposite-facing sectors
|
|
15943
|
-
equals(a, b) && area(a.prev, a, a.next) > 0 && area(b.prev, b, b.next) > 0); // special zero-length case
|
|
15944
|
-
}
|
|
15945
|
-
|
|
15946
|
-
// signed area of a triangle
|
|
15947
|
-
function area(p, q, r) {
|
|
15948
|
-
return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
|
|
15949
|
-
}
|
|
15950
|
-
|
|
15951
|
-
// check if two points are equal
|
|
15952
|
-
function equals(p1, p2) {
|
|
15953
|
-
return p1.x === p2.x && p1.y === p2.y;
|
|
15954
|
-
}
|
|
15955
|
-
|
|
15956
|
-
// check if two segments intersect
|
|
15957
|
-
function intersects(p1, q1, p2, q2) {
|
|
15958
|
-
const o1 = sign(area(p1, q1, p2));
|
|
15959
|
-
const o2 = sign(area(p1, q1, q2));
|
|
15960
|
-
const o3 = sign(area(p2, q2, p1));
|
|
15961
|
-
const o4 = sign(area(p2, q2, q1));
|
|
15962
|
-
|
|
15963
|
-
if (o1 !== o2 && o3 !== o4) return true; // general case
|
|
15964
|
-
|
|
15965
|
-
if (o1 === 0 && onSegment(p1, p2, q1)) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1
|
|
15966
|
-
if (o2 === 0 && onSegment(p1, q2, q1)) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1
|
|
15967
|
-
if (o3 === 0 && onSegment(p2, p1, q2)) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2
|
|
15968
|
-
if (o4 === 0 && onSegment(p2, q1, q2)) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2
|
|
15969
|
-
|
|
15970
|
-
return false;
|
|
15971
|
-
}
|
|
15972
|
-
|
|
15973
|
-
// for collinear points p, q, r, check if point q lies on segment pr
|
|
15974
|
-
function onSegment(p, q, r) {
|
|
15975
|
-
return q.x <= Math.max(p.x, r.x) && q.x >= Math.min(p.x, r.x) && q.y <= Math.max(p.y, r.y) && q.y >= Math.min(p.y, r.y);
|
|
15976
|
-
}
|
|
15977
|
-
|
|
15978
|
-
function sign(num) {
|
|
15979
|
-
return num > 0 ? 1 : num < 0 ? -1 : 0;
|
|
15980
|
-
}
|
|
15981
|
-
|
|
15982
|
-
// check if a polygon diagonal intersects any polygon segments
|
|
15983
|
-
function intersectsPolygon(a, b) {
|
|
15984
|
-
let p = a;
|
|
15985
|
-
do {
|
|
15986
|
-
if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&
|
|
15987
|
-
intersects(p, p.next, a, b)) return true;
|
|
15988
|
-
p = p.next;
|
|
15989
|
-
} while (p !== a);
|
|
15990
|
-
|
|
15991
|
-
return false;
|
|
15992
|
-
}
|
|
15993
|
-
|
|
15994
|
-
// check if a polygon diagonal is locally inside the polygon
|
|
15995
|
-
function locallyInside(a, b) {
|
|
15996
|
-
return area(a.prev, a, a.next) < 0 ?
|
|
15997
|
-
area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 :
|
|
15998
|
-
area(a, b, a.prev) < 0 || area(a, a.next, b) < 0;
|
|
15999
|
-
}
|
|
16000
|
-
|
|
16001
|
-
// check if the middle point of a polygon diagonal is inside the polygon
|
|
16002
|
-
function middleInside(a, b) {
|
|
16003
|
-
let p = a;
|
|
16004
|
-
let inside = false;
|
|
16005
|
-
const px = (a.x + b.x) / 2;
|
|
16006
|
-
const py = (a.y + b.y) / 2;
|
|
16007
|
-
do {
|
|
16008
|
-
if (((p.y > py) !== (p.next.y > py)) && p.next.y !== p.y &&
|
|
16009
|
-
(px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x))
|
|
16010
|
-
inside = !inside;
|
|
16011
|
-
p = p.next;
|
|
16012
|
-
} while (p !== a);
|
|
16013
|
-
|
|
16014
|
-
return inside;
|
|
16015
|
-
}
|
|
16016
|
-
|
|
16017
|
-
// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
|
|
16018
|
-
// if one belongs to the outer ring and another to a hole, it merges it into a single ring
|
|
16019
|
-
function splitPolygon(a, b) {
|
|
16020
|
-
const a2 = createNode(a.i, a.x, a.y),
|
|
16021
|
-
b2 = createNode(b.i, b.x, b.y),
|
|
16022
|
-
an = a.next,
|
|
16023
|
-
bp = b.prev;
|
|
16024
|
-
|
|
16025
|
-
a.next = b;
|
|
16026
|
-
b.prev = a;
|
|
16027
|
-
|
|
16028
|
-
a2.next = an;
|
|
16029
|
-
an.prev = a2;
|
|
16030
|
-
|
|
16031
|
-
b2.next = a2;
|
|
16032
|
-
a2.prev = b2;
|
|
16033
|
-
|
|
16034
|
-
bp.next = b2;
|
|
16035
|
-
b2.prev = bp;
|
|
16036
|
-
|
|
16037
|
-
return b2;
|
|
16038
|
-
}
|
|
16039
|
-
|
|
16040
|
-
// create a node and optionally link it with previous one (in a circular doubly linked list)
|
|
16041
|
-
function insertNode(i, x, y, last) {
|
|
16042
|
-
const p = createNode(i, x, y);
|
|
16043
|
-
|
|
16044
|
-
if (!last) {
|
|
16045
|
-
p.prev = p;
|
|
16046
|
-
p.next = p;
|
|
16047
|
-
|
|
16048
|
-
} else {
|
|
16049
|
-
p.next = last.next;
|
|
16050
|
-
p.prev = last;
|
|
16051
|
-
last.next.prev = p;
|
|
16052
|
-
last.next = p;
|
|
16060
|
+
node = next[node];
|
|
16053
16061
|
}
|
|
16054
|
-
return
|
|
16055
|
-
}
|
|
16056
|
-
|
|
16057
|
-
function removeNode(p) {
|
|
16058
|
-
p.next.prev = p.prev;
|
|
16059
|
-
p.prev.next = p.next;
|
|
16060
|
-
|
|
16061
|
-
if (p.prevZ) p.prevZ.nextZ = p.nextZ;
|
|
16062
|
-
if (p.nextZ) p.nextZ.prevZ = p.prevZ;
|
|
16063
|
-
}
|
|
16064
|
-
|
|
16065
|
-
function createNode(i, x, y) {
|
|
16066
|
-
return {
|
|
16067
|
-
i, // vertex index in coordinates array
|
|
16068
|
-
x, y, // vertex coordinates
|
|
16069
|
-
prev: null, // previous and next vertex nodes in a polygon ring
|
|
16070
|
-
next: null,
|
|
16071
|
-
z: 0, // z-order curve value
|
|
16072
|
-
prevZ: null, // previous and next nodes in z-order
|
|
16073
|
-
nextZ: null,
|
|
16074
|
-
steiner: false // indicates whether this is a steiner point
|
|
16075
|
-
};
|
|
16076
|
-
}
|
|
16077
|
-
|
|
16078
|
-
function signedArea(data, start, end, dim) {
|
|
16079
|
-
let sum = 0;
|
|
16080
|
-
for (let i = start, j = end - dim; i < end; i += dim) {
|
|
16081
|
-
sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
|
|
16082
|
-
j = i;
|
|
16083
|
-
}
|
|
16084
|
-
return sum;
|
|
16062
|
+
return true;
|
|
16085
16063
|
}
|
|
16086
16064
|
|
|
16087
16065
|
const buildLine = (startX, startY, endX, endY, width) => {
|
|
@@ -16285,13 +16263,13 @@ const buildPolygon = (points) => {
|
|
|
16285
16263
|
throw new Error('At least three X/Y pairs are required to build a polygon.');
|
|
16286
16264
|
}
|
|
16287
16265
|
const length = points.length / 2;
|
|
16288
|
-
const triangles =
|
|
16266
|
+
const triangles = triangulate(points);
|
|
16289
16267
|
const vertices = new Float32Array(points.length);
|
|
16290
16268
|
for (let i = 0; i < length; i++) {
|
|
16291
16269
|
vertices[i * 2] = points[i * 2];
|
|
16292
16270
|
vertices[(i * 2) + 1] = points[(i * 2) + 1];
|
|
16293
16271
|
}
|
|
16294
|
-
const indices =
|
|
16272
|
+
const indices = new Uint16Array(triangles);
|
|
16295
16273
|
return { vertices, indices, points };
|
|
16296
16274
|
};
|
|
16297
16275
|
const buildRectangle = (x, y, width, height) => {
|
|
@@ -18759,5 +18737,5 @@ class IndexedDbStore {
|
|
|
18759
18737
|
}
|
|
18760
18738
|
}
|
|
18761
18739
|
|
|
18762
|
-
export { AbstractAssetFactory, AbstractMedia, AbstractWebGl2BatchedRenderer, AbstractWebGl2Renderer, AbstractWebGpuRenderer, AnimatedSprite, Application, ApplicationStatus, ArcadeStickGamepadMapping, AudioAnalyser, BinaryFactory, BlendModes, BlurFilter, Bounds, BufferTypes, BufferUsage, BundleLoadError, CacheFirstStrategy, CallbackRenderPass, Capabilities, ChannelOffset, ChannelSize, Circle, Clock, CollisionType, Color, ColorAffector, ColorFilter, Container, Drawable, DynamicGlyphAtlas, Ellipse, FactoryRegistry, Filter, Flags, FontFactory, ForceAffector, GameCubeGamepadMapping, Gamepad, GamepadChannel, GamepadControl, GamepadMapping, GamepadMappingFamily, GamepadPromptLayouts, GenericDualAnalogGamepadMapping, Graphics, ImageFactory, IndexedDbDatabase, IndexedDbStore, Input, InputManager, Interval, JoyConLeftGamepadMapping, JoyConRightGamepadMapping, Json, JsonFactory, Keyboard, Line, Loader, Matrix, Mesh, Music, MusicFactory, NetworkOnlyStrategy, ObservableSize, ObservableVector, Particle, ParticleOptions, ParticleSystem, PlayStationGamepadMapping, Pointer, PointerState, PointerStateFlag, PolarVector, Polygon, Quadtree, Random, Rectangle, RenderBackendType, RenderNode, RenderTarget, RenderTargetPass, RenderTexture, RendererRegistry, RenderingPrimitives, Sampler, ScaleAffector, ScaleModes, Scene, SceneManager, SceneNode, Segment, Shader, ShaderAttribute, ShaderPrimitives, ShaderUniform, Signal, Size, Sound, SoundFactory, Sprite, SpriteFlags, Spritesheet, SteamControllerGamepadMapping, SvgAsset, SvgFactory, SwitchProGamepadMapping, Text, TextAsset, TextFactory, TextStyle, Texture, TextureFactory, Time, Timer, TorqueAffector, UniversalEmitter, Vector, Video, VideoFactory, View, ViewFlags, VoronoiRegion, VttAsset, VttFactory, WasmFactory, WebGl2Backend, WebGl2MeshRenderer, WebGl2ParticleRenderer, WebGl2RenderBuffer, WebGl2ShaderBlock, WebGl2SpriteRenderer, WebGl2VertexArrayObject, WebGpuBackend, WebGpuMeshRenderer, WebGpuParticleRenderer, WebGpuSpriteRenderer, WrapModes, XboxGamepadMapping, bezierCurveTo, buildCircle, buildEllipse, buildLine, buildPath, buildPolygon, buildRectangle, buildStar, builtInGamepadDefinitions, canvasSourceToDataUrl, clamp, createRenderStats, createWebGl2ShaderProgram, decodeAudioData, defineAssetManifest, degreesPerRadian, degreesToRadians, determineMimeType, emptyArrayBuffer, getAudioContext, getCanvasSourceSize, getCollisionCircleCircle, getCollisionCircleRectangle, getCollisionPolygonCircle, getCollisionRectangleRectangle, getCollisionSat, getDistance, getOfflineAudioContext, getPreciseTime, getTextureSourceSize, getVoronoiRegion$1 as getVoronoiRegion, getWebGpuBlendState, hours, inRange, intersectionCircleCircle, intersectionCircleEllipse, intersectionCirclePoly, intersectionEllipseEllipse, intersectionEllipsePoly, intersectionLineCircle, intersectionLineEllipse, intersectionLineLine, intersectionLinePoly, intersectionLineRect, intersectionPointCircle, intersectionPointEllipse, intersectionPointLine, intersectionPointPoint, intersectionPointPoly, intersectionPointRect, intersectionPolyPoly, intersectionRectCircle, intersectionRectEllipse, intersectionRectPoly, intersectionRectRect, intersectionSat, isAudioContextReady, isPowerOfTwo, layoutText, lerp, matchesIds, maxPointers, milliseconds, minutes, noop$1 as noop, normalizeIds, onAudioContextReady, parseGamepadDescriptor, pointerSlotSize, quadraticCurveTo, radiansPerDegree, radiansToDegrees, rand, removeArrayItems, resetRenderStats, resolveDefinition, resolveGamepadDefinition, seconds, sign
|
|
18740
|
+
export { AbstractAssetFactory, AbstractMedia, AbstractWebGl2BatchedRenderer, AbstractWebGl2Renderer, AbstractWebGpuRenderer, AnimatedSprite, Application, ApplicationStatus, ArcadeStickGamepadMapping, AudioAnalyser, BinaryFactory, BlendModes, BlurFilter, Bounds, BufferTypes, BufferUsage, BundleLoadError, CacheFirstStrategy, CallbackRenderPass, Capabilities, ChannelOffset, ChannelSize, Circle, Clock, CollisionType, Color, ColorAffector, ColorFilter, Container, Drawable, DynamicGlyphAtlas, Ease, Ellipse, FactoryRegistry, Filter, Flags, FontFactory, ForceAffector, GameCubeGamepadMapping, Gamepad, GamepadChannel, GamepadControl, GamepadMapping, GamepadMappingFamily, GamepadPromptLayouts, GenericDualAnalogGamepadMapping, Graphics, ImageFactory, IndexedDbDatabase, IndexedDbStore, Input, InputManager, Interval, JoyConLeftGamepadMapping, JoyConRightGamepadMapping, Json, JsonFactory, Keyboard, Line, Loader, Matrix, Mesh, Music, MusicFactory, NetworkOnlyStrategy, ObservableSize, ObservableVector, Particle, ParticleOptions, ParticleSystem, PlayStationGamepadMapping, Pointer, PointerState, PointerStateFlag, PolarVector, Polygon, Quadtree, Random, Rectangle, RenderBackendType, RenderNode, RenderTarget, RenderTargetPass, RenderTexture, RendererRegistry, RenderingPrimitives, Sampler, ScaleAffector, ScaleModes, Scene, SceneManager, SceneNode, Segment, Shader, ShaderAttribute, ShaderPrimitives, ShaderUniform, Signal, Size, Sound, SoundFactory, Sprite, SpriteFlags, Spritesheet, SteamControllerGamepadMapping, SvgAsset, SvgFactory, SwitchProGamepadMapping, Text, TextAsset, TextFactory, TextStyle, Texture, TextureFactory, Time, Timer, TorqueAffector, Tween, TweenManager, TweenState, UniversalEmitter, Vector, Video, VideoFactory, View, ViewFlags, VoronoiRegion, VttAsset, VttFactory, WasmFactory, WebGl2Backend, WebGl2MeshRenderer, WebGl2ParticleRenderer, WebGl2RenderBuffer, WebGl2ShaderBlock, WebGl2SpriteRenderer, WebGl2VertexArrayObject, WebGpuBackend, WebGpuMeshRenderer, WebGpuParticleRenderer, WebGpuSpriteRenderer, WrapModes, XboxGamepadMapping, bezierCurveTo, buildCircle, buildEllipse, buildLine, buildPath, buildPolygon, buildRectangle, buildStar, builtInGamepadDefinitions, canvasSourceToDataUrl, clamp, createRenderStats, createWebGl2ShaderProgram, decodeAudioData, defineAssetManifest, degreesPerRadian, degreesToRadians, determineMimeType, emptyArrayBuffer, getAudioContext, getCanvasSourceSize, getCollisionCircleCircle, getCollisionCircleRectangle, getCollisionPolygonCircle, getCollisionRectangleRectangle, getCollisionSat, getDistance, getOfflineAudioContext, getPreciseTime, getTextureSourceSize, getVoronoiRegion$1 as getVoronoiRegion, getWebGpuBlendState, hours, inRange, intersectionCircleCircle, intersectionCircleEllipse, intersectionCirclePoly, intersectionEllipseEllipse, intersectionEllipsePoly, intersectionLineCircle, intersectionLineEllipse, intersectionLineLine, intersectionLinePoly, intersectionLineRect, intersectionPointCircle, intersectionPointEllipse, intersectionPointLine, intersectionPointPoint, intersectionPointPoly, intersectionPointRect, intersectionPolyPoly, intersectionRectCircle, intersectionRectEllipse, intersectionRectPoly, intersectionRectRect, intersectionSat, isAudioContextReady, isPowerOfTwo, layoutText, lerp, matchesIds, maxPointers, milliseconds, minutes, noop$1 as noop, normalizeIds, onAudioContextReady, parseGamepadDescriptor, pointerSlotSize, quadraticCurveTo, radiansPerDegree, radiansToDegrees, rand, removeArrayItems, resetRenderStats, resolveDefinition, resolveGamepadDefinition, seconds, sign, stopEvent, supportsCodec, supportsEventOptions, supportsIndexedDb, supportsPointerEvents, supportsTouchEvents, supportsWebAudio, tau, trimRotation, webGl2PrimitiveArrayConstructors, webGl2PrimitiveByteSizeMapping, webGl2PrimitiveTypeNames };
|
|
18763
18741
|
//# sourceMappingURL=exo.esm.js.map
|