@needle-tools/engine 5.0.4 → 5.0.6-next.56fe65a
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 +16 -0
- package/components.needle.json +1 -1
- package/dist/{needle-engine.bundle-CYrPktak.umd.cjs → needle-engine.bundle-BakND7HQ.umd.cjs} +140 -139
- package/dist/{needle-engine.bundle-B3Km2VZ4.js → needle-engine.bundle-CsY10n4y.js} +8183 -7957
- package/dist/{needle-engine.bundle-CX-SJZzp.min.js → needle-engine.bundle-Drz4zRYf.min.js} +142 -141
- package/dist/needle-engine.d.ts +139 -14
- package/dist/needle-engine.js +560 -557
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/dist/{vendor-vHLk8sXu.js → vendor-CAcsI0eU.js} +116 -115
- package/dist/{vendor-CntUvmJu.umd.cjs → vendor-CEM38hLE.umd.cjs} +2 -2
- package/dist/{vendor-DPbfJJ4d.min.js → vendor-HRlxIBga.min.js} +2 -2
- package/lib/engine/api.d.ts +2 -0
- package/lib/engine/api.js +2 -0
- package/lib/engine/api.js.map +1 -1
- package/lib/engine/debug/debug_spatial_console.d.ts +2 -0
- package/lib/engine/debug/debug_spatial_console.js +10 -7
- package/lib/engine/debug/debug_spatial_console.js.map +1 -1
- package/lib/engine/engine_addressables.d.ts +2 -0
- package/lib/engine/engine_addressables.js +6 -3
- package/lib/engine/engine_addressables.js.map +1 -1
- package/lib/engine/engine_audio.d.ts +68 -0
- package/lib/engine/engine_audio.js +172 -0
- package/lib/engine/engine_audio.js.map +1 -1
- package/lib/engine/engine_gameobject.js +2 -2
- package/lib/engine/engine_gameobject.js.map +1 -1
- package/lib/engine/engine_init.js +8 -0
- package/lib/engine/engine_init.js.map +1 -1
- package/lib/engine/engine_mainloop_utils.js +5 -2
- package/lib/engine/engine_mainloop_utils.js.map +1 -1
- package/lib/engine/engine_serialization_builtin_serializer.js +27 -0
- package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.d.ts +9 -3
- package/lib/engine/webcomponents/needle-engine.js.map +1 -1
- package/lib/engine/xr/NeedleXRSession.d.ts +3 -2
- package/lib/engine/xr/NeedleXRSession.js +50 -14
- package/lib/engine/xr/NeedleXRSession.js.map +1 -1
- package/lib/engine-components/Animation.js +17 -16
- package/lib/engine-components/Animation.js.map +1 -1
- package/lib/engine-components/AnimatorController.d.ts +2 -0
- package/lib/engine-components/AnimatorController.js +4 -1
- package/lib/engine-components/AnimatorController.js.map +1 -1
- package/lib/engine-components/AudioSource.d.ts +19 -3
- package/lib/engine-components/AudioSource.js +121 -68
- package/lib/engine-components/AudioSource.js.map +1 -1
- package/lib/engine-components/DragControls.d.ts +7 -0
- package/lib/engine-components/DragControls.js +19 -0
- package/lib/engine-components/DragControls.js.map +1 -1
- package/lib/engine-components/NestedGltf.d.ts +19 -3
- package/lib/engine-components/NestedGltf.js +19 -3
- package/lib/engine-components/NestedGltf.js.map +1 -1
- package/lib/engine-components/Networking.d.ts +1 -1
- package/lib/engine-components/Networking.js +1 -1
- package/lib/engine-components/OrbitControls.js +16 -11
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/postprocessing/VolumeParameter.d.ts +2 -0
- package/lib/engine-components/postprocessing/VolumeParameter.js +4 -1
- package/lib/engine-components/postprocessing/VolumeParameter.js.map +1 -1
- package/lib/engine-components/ui/Canvas.d.ts +1 -1
- package/lib/engine-components/ui/Canvas.js +2 -8
- package/lib/engine-components/ui/Canvas.js.map +1 -1
- package/lib/engine-components/ui/Text.d.ts +8 -1
- package/lib/engine-components/ui/Text.js +29 -14
- package/lib/engine-components/ui/Text.js.map +1 -1
- package/lib/engine-components/web/CursorFollow.js +21 -12
- package/lib/engine-components/web/CursorFollow.js.map +1 -1
- package/lib/engine-components/webxr/WebXRImageTracking.js +4 -0
- package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
- package/package.json +2 -2
- package/plugins/vite/asap.js +17 -8
- package/plugins/vite/local-files-core.js +3 -3
- package/plugins/vite/local-files-utils.d.ts +3 -1
- package/plugins/vite/local-files-utils.js +29 -5
- package/src/engine/api.ts +3 -0
- package/src/engine/debug/debug_spatial_console.ts +10 -7
- package/src/engine/engine_addressables.ts +6 -3
- package/src/engine/engine_audio.ts +184 -0
- package/src/engine/engine_gameobject.ts +2 -2
- package/src/engine/engine_init.ts +8 -0
- package/src/engine/engine_mainloop_utils.ts +5 -2
- package/src/engine/engine_serialization_builtin_serializer.ts +31 -3
- package/src/engine/webcomponents/needle-engine.ts +9 -3
- package/src/engine/xr/NeedleXRSession.ts +48 -13
- package/src/engine-components/Animation.ts +19 -16
- package/src/engine-components/AnimatorController.ts +4 -1
- package/src/engine-components/AudioSource.ts +130 -79
- package/src/engine-components/DragControls.ts +18 -2
- package/src/engine-components/NestedGltf.ts +20 -4
- package/src/engine-components/Networking.ts +1 -1
- package/src/engine-components/OrbitControls.ts +18 -9
- package/src/engine-components/postprocessing/VolumeParameter.ts +4 -1
- package/src/engine-components/ui/Canvas.ts +2 -8
- package/src/engine-components/ui/Text.ts +43 -18
- package/src/engine-components/web/CursorFollow.ts +21 -13
- package/src/engine-components/webxr/WebXRImageTracking.ts +2 -0
|
@@ -4,6 +4,7 @@ import { isDevEnvironment, showBalloonMessage, showBalloonWarning } from "../eng
|
|
|
4
4
|
import { Behaviour, Component, GameObject } from "../engine-components/Component.js";
|
|
5
5
|
import { CallInfo, EventList } from "../engine-components/EventList.js";
|
|
6
6
|
import { AssetReference } from "./engine_addressables.js";
|
|
7
|
+
import { AudioClip } from "./engine_audio.js";
|
|
7
8
|
import { debugExtension } from "./engine_default_parameters.js";
|
|
8
9
|
import { SerializationContext, TypeSerializer } from "./engine_serialization_core.js";
|
|
9
10
|
import { RenderTexture } from "./engine_texture.js";
|
|
@@ -11,7 +12,7 @@ import { IComponent } from "./engine_types.js";
|
|
|
11
12
|
import { resolveUrl } from "./engine_utils.js";
|
|
12
13
|
import { RGBAColor } from "./js-extensions/index.js";
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
// #region Color
|
|
15
16
|
class ColorSerializer extends TypeSerializer {
|
|
16
17
|
constructor() {
|
|
17
18
|
super([Color, RGBAColor], "ColorSerializer")
|
|
@@ -35,6 +36,8 @@ class ColorSerializer extends TypeSerializer {
|
|
|
35
36
|
}
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
// #region Euler
|
|
40
|
+
|
|
38
41
|
class EulerSerializer extends TypeSerializer {
|
|
39
42
|
constructor() {
|
|
40
43
|
super([Euler], "EulerSerializer");
|
|
@@ -58,6 +61,8 @@ declare type ObjectData = {
|
|
|
58
61
|
node?: number;
|
|
59
62
|
guid?: string;
|
|
60
63
|
}
|
|
64
|
+
|
|
65
|
+
// #region ObjectSerializer
|
|
61
66
|
class ObjectSerializer extends TypeSerializer {
|
|
62
67
|
constructor() {
|
|
63
68
|
super(Object3D, "ObjectSerializer");
|
|
@@ -137,7 +142,7 @@ class ObjectSerializer extends TypeSerializer {
|
|
|
137
142
|
}
|
|
138
143
|
}
|
|
139
144
|
|
|
140
|
-
|
|
145
|
+
// #region ComponentSerializer
|
|
141
146
|
class ComponentSerializer extends TypeSerializer {
|
|
142
147
|
|
|
143
148
|
constructor() {
|
|
@@ -226,6 +231,7 @@ declare type EventListCall = {
|
|
|
226
231
|
|
|
227
232
|
const $eventListDebugInfo = Symbol("eventListDebugInfo");
|
|
228
233
|
|
|
234
|
+
// #region EventListSerializer
|
|
229
235
|
class EventListSerializer extends TypeSerializer {
|
|
230
236
|
constructor() {
|
|
231
237
|
super([EventList]);
|
|
@@ -371,6 +377,7 @@ class EventListSerializer extends TypeSerializer {
|
|
|
371
377
|
*/
|
|
372
378
|
const cloneOriginalMap = new WeakMap<Texture, Texture>();
|
|
373
379
|
|
|
380
|
+
// #region RenderTextureSerializer
|
|
374
381
|
export class RenderTextureSerializer extends TypeSerializer {
|
|
375
382
|
constructor() {
|
|
376
383
|
super([RenderTexture, WebGLRenderTarget]);
|
|
@@ -412,7 +419,7 @@ export class RenderTextureSerializer extends TypeSerializer {
|
|
|
412
419
|
}
|
|
413
420
|
}
|
|
414
421
|
|
|
415
|
-
|
|
422
|
+
// #region UriSerializer
|
|
416
423
|
export class UriSerializer extends TypeSerializer {
|
|
417
424
|
constructor() {
|
|
418
425
|
super([URL]);
|
|
@@ -430,7 +437,27 @@ export class UriSerializer extends TypeSerializer {
|
|
|
430
437
|
}
|
|
431
438
|
}
|
|
432
439
|
|
|
440
|
+
// #region AudioClipSerializer
|
|
441
|
+
class AudioClipSerializer extends TypeSerializer {
|
|
442
|
+
constructor() {
|
|
443
|
+
super([AudioClip]);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
onSerialize(_data: AudioClip, _context: SerializationContext) {
|
|
447
|
+
return null;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
onDeserialize(data: string, context: SerializationContext) {
|
|
451
|
+
if (typeof data === "string" && data.length > 0) {
|
|
452
|
+
const url = resolveUrl(context.gltfId, data);
|
|
453
|
+
if (url) return new AudioClip(url);
|
|
454
|
+
}
|
|
455
|
+
return undefined;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
433
459
|
|
|
460
|
+
// #region Init serializer
|
|
434
461
|
// Module-level references used by EventListSerializer internally
|
|
435
462
|
export let colorSerializer: ColorSerializer;
|
|
436
463
|
export let objectSerializer: ObjectSerializer;
|
|
@@ -460,4 +487,5 @@ export function initBuiltinSerializers() {
|
|
|
460
487
|
eventListSerializer = new EventListSerializer();
|
|
461
488
|
new RenderTextureSerializer();
|
|
462
489
|
new UriSerializer();
|
|
490
|
+
new AudioClipSerializer();
|
|
463
491
|
}
|
|
@@ -40,11 +40,17 @@ export interface NeedleEngineAttributes {
|
|
|
40
40
|
'hash': string;
|
|
41
41
|
/** Set to automatically add OrbitControls to the loaded scene. */
|
|
42
42
|
'camera-controls': string;
|
|
43
|
-
/** Override the default
|
|
43
|
+
/** Override the default Draco decoder/decompressor path. Can be a URL or a local path to a directory containing the Draco decoder files.
|
|
44
|
+
* @default "https://www.gstatic.com/draco/versioned/decoders/1.5.7/"
|
|
45
|
+
* @example <needle-engine dracoDecoderPath="./decoders/draco/"></needle-engine>
|
|
46
|
+
*/
|
|
44
47
|
'dracoDecoderPath': string;
|
|
45
|
-
/** Override the default
|
|
48
|
+
/** Override the default Draco decoder type. */
|
|
46
49
|
'dracoDecoderType': 'wasm' | 'js';
|
|
47
|
-
/** Override the default KTX2 transcoder/decoder path.
|
|
50
|
+
/** Override the default KTX2 transcoder/decoder path. Can be a URL or a local path to a directory containing the KTX2 transcoder files.
|
|
51
|
+
* @default "https://cdn.needle.tools/static/three/0.179.1/basis2/"
|
|
52
|
+
* @example <needle-engine ktx2DecoderPath="./decoders/ktx2/"></needle-engine>
|
|
53
|
+
*/
|
|
48
54
|
'ktx2DecoderPath': string;
|
|
49
55
|
/** Prevent context from being disposed when element is removed from DOM. */
|
|
50
56
|
'keep-alive': 'true' | 'false';
|
|
@@ -805,15 +805,16 @@ export class NeedleXRSession implements INeedleXRSession {
|
|
|
805
805
|
get viewerPose(): XRViewerPose | undefined { return this._viewerPose; }
|
|
806
806
|
|
|
807
807
|
|
|
808
|
-
/** @returns `true` if any image is currently being tracked */
|
|
809
|
-
/** returns true if images are currently being tracked */
|
|
808
|
+
/** @returns `true` if any image is currently being tracked or emulated */
|
|
810
809
|
get isTrackingImages() {
|
|
811
810
|
if (this.frame && "getImageTrackingResults" in this.frame && typeof this.frame.getImageTrackingResults === "function") {
|
|
812
811
|
try {
|
|
813
812
|
const trackingResult = this.frame.getImageTrackingResults();
|
|
814
813
|
for (const result of trackingResult) {
|
|
815
814
|
const state = result.trackingState;
|
|
816
|
-
if (state === "tracked")
|
|
815
|
+
if (state === "tracked" || state === "emulated") {
|
|
816
|
+
return true;
|
|
817
|
+
}
|
|
817
818
|
}
|
|
818
819
|
}
|
|
819
820
|
catch {
|
|
@@ -1018,6 +1019,8 @@ export class NeedleXRSession implements INeedleXRSession {
|
|
|
1018
1019
|
private readonly _xr_update_scripts: INeedleXRSessionEventReceiver[] = [];
|
|
1019
1020
|
/** scripts that are in the scene but inactive (e.g. disabled parent gameObject) */
|
|
1020
1021
|
private readonly _inactive_scripts: INeedleXRSessionEventReceiver[] = [];
|
|
1022
|
+
/** tracks scripts that have received onEnterXR — prevents spurious onLeaveXR calls */
|
|
1023
|
+
private readonly _scripts_in_xr = new Set<INeedleXRSessionEventReceiver>();
|
|
1021
1024
|
private readonly _controllerAdded: ControllerChangedEvt[];
|
|
1022
1025
|
private readonly _controllerRemoved: ControllerChangedEvt[];
|
|
1023
1026
|
private readonly _originalCameraWorldPosition?: Vector3 | null;
|
|
@@ -1128,7 +1131,18 @@ export class NeedleXRSession implements INeedleXRSession {
|
|
|
1128
1131
|
// we set the session on the webxr manager at the end because we want to receive inputsource events first
|
|
1129
1132
|
// e.g. in case there's a bug in the threejs codebase
|
|
1130
1133
|
this.context.xr = this;
|
|
1131
|
-
this.context.renderer.xr.setSession(this.session).then(this.onRendererSessionSet)
|
|
1134
|
+
this.context.renderer.xr.setSession(this.session).then(this.onRendererSessionSet)
|
|
1135
|
+
.catch(err => {
|
|
1136
|
+
// Workaround for WebXR emulators on localhost: the polyfilled XRSession fails the
|
|
1137
|
+
// native XRWebGLBinding constructor's instanceof check. Retry with layers disabled.
|
|
1138
|
+
// See https://github.com/meta-quest/immersive-web-emulator/issues/80
|
|
1139
|
+
if (isDevEnvironment() && err instanceof TypeError && typeof XRWebGLBinding !== "undefined") {
|
|
1140
|
+
console.error(`XRWebGLBinding failed (${err.message}).\nSee https://github.com/meta-quest/immersive-web-emulator/issues/80`);
|
|
1141
|
+
}
|
|
1142
|
+
else {
|
|
1143
|
+
console.error("renderer.xr.setSession failed:", err);
|
|
1144
|
+
}
|
|
1145
|
+
});
|
|
1132
1146
|
// disable three.js renderer controller autoUpdate (added in ac67b31e3548386f8a93e23a4176554c92bbd0d9)
|
|
1133
1147
|
if ("controllerAutoUpdate" in this.context.renderer.xr) {
|
|
1134
1148
|
console.debug("Disabling three.js controllerAutoUpdate");
|
|
@@ -1296,8 +1310,10 @@ export class NeedleXRSession implements INeedleXRSession {
|
|
|
1296
1310
|
// even if they might already be destroyed e.g. by the WebXR component (it destroys the default controller scripts)
|
|
1297
1311
|
// they should still receive this callback to be properly cleaned up
|
|
1298
1312
|
for (const listener of this._xr_scripts) {
|
|
1313
|
+
this._scripts_in_xr.delete(listener);
|
|
1299
1314
|
listener?.onLeaveXR?.({ xr: this });
|
|
1300
1315
|
}
|
|
1316
|
+
this._scripts_in_xr.clear();
|
|
1301
1317
|
|
|
1302
1318
|
this.sync?.onExitXR(this);
|
|
1303
1319
|
|
|
@@ -1364,10 +1380,17 @@ export class NeedleXRSession implements INeedleXRSession {
|
|
|
1364
1380
|
}
|
|
1365
1381
|
|
|
1366
1382
|
// make sure the camera is parented to the active rig
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1383
|
+
// Note: applyCustomForward() inserts _cameraRenderParent between rig and camera,
|
|
1384
|
+
// so the hierarchy is: rig → _cameraRenderParent → camera. We check the effective parent.
|
|
1385
|
+
if (this.rig) {
|
|
1386
|
+
const cameraObject = this._mainCamera?.gameObject ?? this.context.mainCamera;
|
|
1387
|
+
if (cameraObject) {
|
|
1388
|
+
const effectiveParent = cameraObject.parent === this._cameraRenderParent
|
|
1389
|
+
? this._cameraRenderParent.parent
|
|
1390
|
+
: cameraObject.parent;
|
|
1391
|
+
if (effectiveParent !== this.rig.gameObject) {
|
|
1392
|
+
this.rig.gameObject.add(cameraObject);
|
|
1393
|
+
}
|
|
1371
1394
|
}
|
|
1372
1395
|
}
|
|
1373
1396
|
|
|
@@ -1499,8 +1522,12 @@ export class NeedleXRSession implements INeedleXRSession {
|
|
|
1499
1522
|
}
|
|
1500
1523
|
|
|
1501
1524
|
//performance.mark('NeedleXRSession update scripts start');
|
|
1502
|
-
//
|
|
1503
|
-
|
|
1525
|
+
// check all XR scripts for destroyed or inactive state
|
|
1526
|
+
// this must cover _xr_scripts (not just _xr_update_scripts) so that scripts
|
|
1527
|
+
// without onUpdateXR are also detected as inactive when removed from the scene
|
|
1528
|
+
// iterate backwards since markInactive/removeScript modifies the array
|
|
1529
|
+
for (let i = this._xr_scripts.length - 1; i >= 0; i--) {
|
|
1530
|
+
const script = this._xr_scripts[i];
|
|
1504
1531
|
if (script.destroyed === true) {
|
|
1505
1532
|
this._script_to_remove.push(script);
|
|
1506
1533
|
continue;
|
|
@@ -1509,6 +1536,10 @@ export class NeedleXRSession implements INeedleXRSession {
|
|
|
1509
1536
|
this.markInactive(script);
|
|
1510
1537
|
continue;
|
|
1511
1538
|
}
|
|
1539
|
+
}
|
|
1540
|
+
// invoke update on scripts that have onUpdateXR
|
|
1541
|
+
for (const script of this._xr_update_scripts) {
|
|
1542
|
+
if (script.destroyed || script.activeAndEnabled === false) continue;
|
|
1512
1543
|
if (script.onUpdateXR) script.onUpdateXR(args);
|
|
1513
1544
|
}
|
|
1514
1545
|
//performance.mark('NeedleXRSession update scripts end');
|
|
@@ -1631,9 +1662,11 @@ export class NeedleXRSession implements INeedleXRSession {
|
|
|
1631
1662
|
const script = this._inactive_scripts[i];
|
|
1632
1663
|
if (script.activeAndEnabled) {
|
|
1633
1664
|
this._inactive_scripts.splice(i, 1);
|
|
1634
|
-
|
|
1635
|
-
this.
|
|
1636
|
-
|
|
1665
|
+
// addScript returns false if already re-added (e.g. via new_scripts_xr processing)
|
|
1666
|
+
if (this.addScript(script)) {
|
|
1667
|
+
this.invokeCallback_EnterXR(script);
|
|
1668
|
+
for (const ctrl of this.controllers) this.invokeCallback_ControllerAdded(script, ctrl);
|
|
1669
|
+
}
|
|
1637
1670
|
}
|
|
1638
1671
|
}
|
|
1639
1672
|
}
|
|
@@ -1654,6 +1687,7 @@ export class NeedleXRSession implements INeedleXRSession {
|
|
|
1654
1687
|
}
|
|
1655
1688
|
|
|
1656
1689
|
private invokeCallback_EnterXR(script: INeedleXRSessionEventReceiver) {
|
|
1690
|
+
this._scripts_in_xr.add(script);
|
|
1657
1691
|
if (script.onEnterXR) {
|
|
1658
1692
|
script.onEnterXR({ xr: this });
|
|
1659
1693
|
}
|
|
@@ -1669,6 +1703,7 @@ export class NeedleXRSession implements INeedleXRSession {
|
|
|
1669
1703
|
}
|
|
1670
1704
|
}
|
|
1671
1705
|
private invokeCallback_LeaveXR(script: INeedleXRSessionEventReceiver) {
|
|
1706
|
+
if (!this._scripts_in_xr.delete(script)) return;
|
|
1672
1707
|
if (script.onLeaveXR && !script.destroyed) {
|
|
1673
1708
|
script.onLeaveXR({ xr: this });
|
|
1674
1709
|
}
|
|
@@ -447,25 +447,13 @@ export class Animation extends Behaviour implements IAnimationComponent {
|
|
|
447
447
|
|
|
448
448
|
private internalOnPlay(action: AnimationAction, options: PlayOptions): Promise<AnimationAction> {
|
|
449
449
|
var existing = this.actions.find(a => a === action);
|
|
450
|
-
if (existing === action && existing.isRunning() && existing.time < existing.getClip().duration) {
|
|
451
|
-
const handle = this.tryFindHandle(action);
|
|
452
|
-
if (existing.paused) {
|
|
453
|
-
existing.paused = false;
|
|
454
|
-
}
|
|
455
|
-
if (handle) return handle.waitForFinish();
|
|
456
|
-
}
|
|
457
450
|
|
|
458
|
-
//
|
|
459
|
-
|
|
460
|
-
if (options.clampWhenFinished === undefined) options.clampWhenFinished = this.clampWhenFinished;
|
|
461
|
-
if (options.minMaxOffsetNormalized === undefined && this.randomStartTime) options.minMaxOffsetNormalized = this.minMaxOffsetNormalized;
|
|
462
|
-
if (options.minMaxSpeed === undefined) options.minMaxSpeed = this.minMaxSpeed;
|
|
463
|
-
|
|
464
|
-
// Reset currently running animations
|
|
451
|
+
// Stop other animations before the early-return check so exclusive always applies,
|
|
452
|
+
// even when the target animation is already running.
|
|
465
453
|
const stopOther = options?.exclusive ?? true;
|
|
466
454
|
if (stopOther) {
|
|
467
455
|
for (const act of this.actions) {
|
|
468
|
-
if (act
|
|
456
|
+
if (act !== action) {
|
|
469
457
|
if (options.fadeDuration) {
|
|
470
458
|
act.fadeOut(options.fadeDuration);
|
|
471
459
|
}
|
|
@@ -475,6 +463,20 @@ export class Animation extends Behaviour implements IAnimationComponent {
|
|
|
475
463
|
}
|
|
476
464
|
}
|
|
477
465
|
}
|
|
466
|
+
|
|
467
|
+
if (existing === action && existing.isRunning() && existing.time < existing.getClip().duration) {
|
|
468
|
+
const handle = this.tryFindHandle(action);
|
|
469
|
+
if (existing.paused) {
|
|
470
|
+
existing.paused = false;
|
|
471
|
+
}
|
|
472
|
+
if (handle) return handle.waitForFinish();
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// Assign defaults
|
|
476
|
+
if (options.loop === undefined) options.loop = this.loop;
|
|
477
|
+
if (options.clampWhenFinished === undefined) options.clampWhenFinished = this.clampWhenFinished;
|
|
478
|
+
if (options.minMaxOffsetNormalized === undefined && this.randomStartTime) options.minMaxOffsetNormalized = this.minMaxOffsetNormalized;
|
|
479
|
+
if (options.minMaxSpeed === undefined) options.minMaxSpeed = this.minMaxSpeed;
|
|
478
480
|
if (options?.fadeDuration) {
|
|
479
481
|
action.fadeIn(options.fadeDuration);
|
|
480
482
|
}
|
|
@@ -515,10 +517,11 @@ export class Animation extends Behaviour implements IAnimationComponent {
|
|
|
515
517
|
|
|
516
518
|
action.paused = false;
|
|
517
519
|
action.play();
|
|
520
|
+
if (debug) console.log("[Animation] Now Playing", action.getClip().name, action)
|
|
521
|
+
|
|
518
522
|
|
|
519
523
|
window.requestAnimationFrame(() => AnimationUtils.testIfRootCanAnimate(action));
|
|
520
524
|
|
|
521
|
-
if (debug) console.log("PLAY", action.getClip().name, action)
|
|
522
525
|
const handle = new AnimationHandle(action, this.mixer!, options, _ => {
|
|
523
526
|
this._handles.splice(this._handles.indexOf(handle), 1);
|
|
524
527
|
});
|
|
@@ -1316,4 +1316,7 @@ class AnimatorControllerSerializator extends TypeSerializer {
|
|
|
1316
1316
|
return undefined;
|
|
1317
1317
|
}
|
|
1318
1318
|
}
|
|
1319
|
-
|
|
1319
|
+
/** @internal */
|
|
1320
|
+
export function initAnimatorControllerSerializer() {
|
|
1321
|
+
new AnimatorControllerSerializator(AnimatorController);
|
|
1322
|
+
}
|