@@ -34,6 +34,7 @@
|
|
34
34
|
export * from "./engine_physics_rapier.js";
|
35
35
|
export * from "./engine_scenelighting.js";
|
36
36
|
export * from "./engine_input.js";
|
37
|
+
export * from "./engine_lifecycle_api.js";
|
37
38
|
export * from "./engine_math.js";
|
38
39
|
export * from "./js-extensions/index.js";
|
39
40
|
export * from "./engine_scenetools.js";
|
@@ -27,8 +27,14 @@
|
|
27
27
|
|
28
28
|
|
29
29
|
let userInteractionRegistered = false;
|
30
|
+
const userInteractionCallbacks: Function[] = [];
|
30
31
|
function onUserInteraction() {
|
32
|
+
if(userInteractionRegistered) return;
|
33
|
+
if(isDevEnvironment()) console.log("User interaction registered: audio can now be played");
|
31
34
|
userInteractionRegistered = true;
|
35
|
+
const copy = [...userInteractionCallbacks];
|
36
|
+
userInteractionCallbacks.length = 0;
|
37
|
+
copy.forEach(cb => cb());
|
32
38
|
}
|
33
39
|
document.addEventListener('pointerdown', onUserInteraction);
|
34
40
|
document.addEventListener('click', onUserInteraction);
|
@@ -41,15 +47,14 @@
|
|
41
47
|
return userInteractionRegistered;
|
42
48
|
}
|
43
49
|
|
44
|
-
private static callbacks: Function[] = [];
|
45
50
|
public static registerWaitForAllowAudio(cb: Function) {
|
46
51
|
if (cb !== null) {
|
47
52
|
if (userInteractionRegistered) {
|
48
53
|
cb();
|
49
54
|
return;
|
50
55
|
}
|
51
|
-
if (
|
52
|
-
|
56
|
+
if (userInteractionCallbacks.indexOf(cb) === -1)
|
57
|
+
userInteractionCallbacks.push(cb);
|
53
58
|
}
|
54
59
|
}
|
55
60
|
|
@@ -146,6 +151,7 @@
|
|
146
151
|
|
147
152
|
|
148
153
|
awake() {
|
154
|
+
if(debug) console.log(this);
|
149
155
|
this.audioLoader = new AudioLoader();
|
150
156
|
if (this.playOnAwake) this.shouldPlay = true;
|
151
157
|
}
|
@@ -73,7 +73,7 @@
|
|
73
73
|
|
74
74
|
onEnable() {
|
75
75
|
super.onEnable();
|
76
|
-
this.context.physics.engine?.addSphereCollider(this
|
76
|
+
this.context.physics.engine?.addSphereCollider(this);
|
77
77
|
watchWrite(this.gameObject.scale, this.updateProperties);
|
78
78
|
}
|
79
79
|
|
@@ -98,7 +98,7 @@
|
|
98
98
|
|
99
99
|
onEnable() {
|
100
100
|
super.onEnable();
|
101
|
-
this.context.physics.engine?.addBoxCollider(this, this.
|
101
|
+
this.context.physics.engine?.addBoxCollider(this, this.size);
|
102
102
|
}
|
103
103
|
|
104
104
|
onValidate(): void {
|
@@ -155,7 +155,7 @@
|
|
155
155
|
|
156
156
|
onEnable() {
|
157
157
|
super.onEnable();
|
158
|
-
this.context.physics.engine?.addCapsuleCollider(this, this.
|
158
|
+
this.context.physics.engine?.addCapsuleCollider(this, this.height, this.radius);
|
159
159
|
}
|
160
160
|
|
161
161
|
}
|
@@ -34,6 +34,7 @@
|
|
34
34
|
import { getLoader } from './engine_gltf.js';
|
35
35
|
import { isLocalNetwork } from './engine_networking_utils.js';
|
36
36
|
import { WaitForPromise } from './engine_coroutine.js';
|
37
|
+
import { invokeLifecycleFunctions } from './engine_lifecycle_functions_internal.js';
|
37
38
|
|
38
39
|
|
39
40
|
const debug = utils.getParam("debugcontext");
|
@@ -88,6 +89,7 @@
|
|
88
89
|
}
|
89
90
|
|
90
91
|
export enum FrameEvent {
|
92
|
+
Start = -1,
|
91
93
|
EarlyUpdate = 0,
|
92
94
|
Update = 1,
|
93
95
|
LateUpdate = 2,
|
@@ -1000,6 +1002,7 @@
|
|
1000
1002
|
looputils.processNewScripts(this);
|
1001
1003
|
looputils.updateIsActive(this.scene);
|
1002
1004
|
looputils.processStart(this);
|
1005
|
+
invokeLifecycleFunctions(this, FrameEvent.Start);
|
1003
1006
|
|
1004
1007
|
while (this._cameraStack.length > 0 && (!this.mainCameraComponent || this.mainCameraComponent.destroyed)) {
|
1005
1008
|
this._cameraStack.splice(this._cameraStack.length - 1, 1);
|
@@ -1024,6 +1027,7 @@
|
|
1024
1027
|
}
|
1025
1028
|
}
|
1026
1029
|
this.executeCoroutines(FrameEvent.EarlyUpdate);
|
1030
|
+
invokeLifecycleFunctions(this, FrameEvent.EarlyUpdate);
|
1027
1031
|
if (this.onHandlePaused()) return false;
|
1028
1032
|
|
1029
1033
|
this._currentFrameEvent = FrameEvent.Update;
|
@@ -1037,6 +1041,7 @@
|
|
1037
1041
|
}
|
1038
1042
|
}
|
1039
1043
|
this.executeCoroutines(FrameEvent.Update);
|
1044
|
+
invokeLifecycleFunctions(this, FrameEvent.Update);
|
1040
1045
|
if (this.onHandlePaused()) return false;
|
1041
1046
|
|
1042
1047
|
this._currentFrameEvent = FrameEvent.LateUpdate;
|
@@ -1052,6 +1057,7 @@
|
|
1052
1057
|
|
1053
1058
|
// this.mainLight = null;
|
1054
1059
|
this.executeCoroutines(FrameEvent.LateUpdate);
|
1060
|
+
invokeLifecycleFunctions(this, FrameEvent.LateUpdate);
|
1055
1061
|
if (this.onHandlePaused()) return false;
|
1056
1062
|
|
1057
1063
|
if (this.physicsSteps === undefined) {
|
@@ -1079,6 +1085,7 @@
|
|
1079
1085
|
}
|
1080
1086
|
|
1081
1087
|
this.executeCoroutines(FrameEvent.OnBeforeRender);
|
1088
|
+
invokeLifecycleFunctions(this, FrameEvent.OnBeforeRender);
|
1082
1089
|
|
1083
1090
|
if (this._sizeChanged)
|
1084
1091
|
this.updateSize();
|
@@ -1130,6 +1137,7 @@
|
|
1130
1137
|
}
|
1131
1138
|
|
1132
1139
|
this.executeCoroutines(FrameEvent.OnAfterRender);
|
1140
|
+
invokeLifecycleFunctions(this, FrameEvent.OnAfterRender);
|
1133
1141
|
|
1134
1142
|
if (this.post_render_callbacks) {
|
1135
1143
|
for (const i in this.post_render_callbacks) {
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import
|
1
|
+
import { safeInvoke } from "./engine_generic_utils.js";
|
2
2
|
import * as constants from "./engine_constants.js";
|
3
3
|
import { getParam } from './engine_utils.js';
|
4
4
|
import { CubeCamera, Object3D, Scene, WebGLCubeRenderTarget } from 'three';
|
@@ -95,7 +95,7 @@
|
|
95
95
|
}
|
96
96
|
updateActiveInHierarchyWithoutEventCall(script.gameObject);
|
97
97
|
if (script.activeAndEnabled)
|
98
|
-
|
98
|
+
safeInvoke(script.__internalAwake.bind(script));
|
99
99
|
|
100
100
|
// registerPrewarmObject(script.gameObject, context);
|
101
101
|
}
|
@@ -119,7 +119,7 @@
|
|
119
119
|
if (script.activeAndEnabled === false) continue;
|
120
120
|
if (script.__internalEnable !== undefined) {
|
121
121
|
script.enabled = true;
|
122
|
-
|
122
|
+
safeInvoke(script.__internalEnable.bind(script));
|
123
123
|
}
|
124
124
|
}
|
125
125
|
catch (err) {
|
@@ -178,11 +178,11 @@
|
|
178
178
|
}
|
179
179
|
// keep them in queue until script has started
|
180
180
|
// call awake if the script was inactive before
|
181
|
-
|
181
|
+
safeInvoke(script.__internalAwake.bind(script));
|
182
182
|
if (script.enabled) {
|
183
|
-
|
183
|
+
safeInvoke(script.__internalEnable.bind(script));
|
184
184
|
// now call start
|
185
|
-
|
185
|
+
safeInvoke(script.__internalStart.bind(script));
|
186
186
|
context.new_script_start.splice(i, 1);
|
187
187
|
i--;
|
188
188
|
}
|
@@ -285,7 +285,7 @@
|
|
285
285
|
perComponent(go, comp => {
|
286
286
|
if (activeInHierarchy) {
|
287
287
|
if (comp.enabled) {
|
288
|
-
|
288
|
+
safeInvoke(comp.__internalAwake.bind(comp));
|
289
289
|
if (comp.enabled) {
|
290
290
|
comp["__didEnable"] = true;
|
291
291
|
comp.onEnable();
|
@@ -500,7 +500,7 @@
|
|
500
500
|
this.world?.free();
|
501
501
|
}
|
502
502
|
|
503
|
-
async addBoxCollider(collider: ICollider,
|
503
|
+
async addBoxCollider(collider: ICollider, size: Vector3) {
|
504
504
|
if (!this._isInitialized)
|
505
505
|
await this.initialize(collider.context);
|
506
506
|
if (!collider.activeAndEnabled) return;
|
@@ -531,10 +531,10 @@
|
|
531
531
|
// const mask = objectLayerMask & ~2;
|
532
532
|
// TODO: https://rapier.rs/docs/user_guides/javascript/colliders/#collision-groups-and-solver-groups
|
533
533
|
// desc.setCollisionGroups(objectLayerMask);
|
534
|
-
this.createCollider(collider, desc
|
534
|
+
this.createCollider(collider, desc);
|
535
535
|
}
|
536
536
|
|
537
|
-
async addSphereCollider(collider: ICollider
|
537
|
+
async addSphereCollider(collider: ICollider) {
|
538
538
|
if (!this._isInitialized)
|
539
539
|
await this.initialize(collider.context);
|
540
540
|
if (!collider.activeAndEnabled) return;
|
@@ -543,11 +543,11 @@
|
|
543
543
|
return;
|
544
544
|
}
|
545
545
|
const desc = ColliderDesc.ball(.5);
|
546
|
-
this.createCollider(collider, desc
|
546
|
+
this.createCollider(collider, desc);
|
547
547
|
this.updateProperties(collider);
|
548
548
|
}
|
549
549
|
|
550
|
-
async addCapsuleCollider(collider: ICollider,
|
550
|
+
async addCapsuleCollider(collider: ICollider, height: number, radius: number) {
|
551
551
|
if (!this._isInitialized)
|
552
552
|
await this.initialize(collider.context);
|
553
553
|
if (!collider.activeAndEnabled) return;
|
@@ -565,7 +565,7 @@
|
|
565
565
|
height = Math.max(height, finalRadius * 2);
|
566
566
|
const hh = Mathf.clamp((height * .5 * scale.y) - (radius * scale.x), 0, Number.MAX_SAFE_INTEGER);
|
567
567
|
const desc = ColliderDesc.capsule(hh, finalRadius);
|
568
|
-
this.createCollider(collider, desc
|
568
|
+
this.createCollider(collider, desc);
|
569
569
|
}
|
570
570
|
|
571
571
|
async addMeshCollider(collider: ICollider, mesh: Mesh, convex: boolean, scale: Vector3) {
|
@@ -684,22 +684,21 @@
|
|
684
684
|
return component;
|
685
685
|
}
|
686
686
|
|
687
|
-
private createCollider(collider: ICollider, desc: ColliderDesc
|
687
|
+
private createCollider(collider: ICollider, desc: ColliderDesc) {
|
688
688
|
if (!this.world) throw new Error("Physics world not initialized");
|
689
689
|
const matrix = this._tempMatrix;
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
690
|
+
let rigidBody: RigidBody | undefined = undefined;
|
691
|
+
if (!collider.attachedRigidbody) {
|
692
|
+
if(debugPhysics) console.log("Create collider without rigidbody", collider.name);
|
693
|
+
matrix.makeRotationFromQuaternion(getWorldQuaternion(collider.gameObject));
|
694
|
+
matrix.setPosition(getWorldPosition(collider.gameObject));
|
695
|
+
}
|
696
|
+
else {
|
697
|
+
rigidBody = this.getRigidbody(collider, this._tempMatrix);
|
698
|
+
}
|
694
699
|
|
695
700
|
matrix.decompose(this._tempPosition, this._tempQuaternion, this._tempScale);
|
696
|
-
|
697
|
-
if (center) {
|
698
|
-
center.multiply(this._tempScale);
|
699
|
-
this._tempPosition.x -= center.x;
|
700
|
-
this._tempPosition.y += center.y;
|
701
|
-
this._tempPosition.z += center.z;
|
702
|
-
}
|
701
|
+
this.tryApplyCenter(collider, this._tempPosition);
|
703
702
|
desc.setTranslation(this._tempPosition.x, this._tempPosition.y, this._tempPosition.z);
|
704
703
|
desc.setRotation(this._tempQuaternion);
|
705
704
|
desc.setSensor(collider.isTrigger);
|
@@ -752,7 +751,7 @@
|
|
752
751
|
// if we want to use explicit mass properties, we need to set the collider density to 0
|
753
752
|
// otherwise rapier will compute the mass properties based on the collider shape and density
|
754
753
|
// https://rapier.rs/docs/user_guides/javascript/rigid_bodies#mass-properties
|
755
|
-
if (
|
754
|
+
if (collider.attachedRigidbody?.autoMass === false) {
|
756
755
|
desc.setDensity(.000001);
|
757
756
|
desc.setMass(.000001);
|
758
757
|
}
|
@@ -778,14 +777,13 @@
|
|
778
777
|
}
|
779
778
|
}
|
780
779
|
|
781
|
-
private getRigidbody(collider: ICollider, _matrix: Matrix4):
|
780
|
+
private getRigidbody(collider: ICollider, _matrix: Matrix4): RigidBody {
|
782
781
|
|
783
782
|
if (!this.world) throw new Error("Physics world not initialized");
|
784
783
|
let rigidBody: RigidBody | null = null;
|
785
784
|
let useExplicitMassProperties = false;
|
786
785
|
|
787
786
|
if (collider.attachedRigidbody) {
|
788
|
-
|
789
787
|
const rb = collider.attachedRigidbody;
|
790
788
|
rigidBody = rb[$bodyKey];
|
791
789
|
useExplicitMassProperties = rb.autoMass === false;
|
@@ -805,10 +803,9 @@
|
|
805
803
|
rb[$bodyKey] = rigidBody;
|
806
804
|
this.internalUpdateRigidbodyProperties(rb, rigidBody);
|
807
805
|
this.getRigidbodyRelativeMatrix(collider.gameObject, rb.gameObject, _matrix);
|
808
|
-
|
806
|
+
collider[$colliderRigidbody] = rigidBody;
|
809
807
|
}
|
810
808
|
else {
|
811
|
-
|
812
809
|
const rigidBodyDesc = RAPIER.RigidBodyDesc.kinematicPositionBased();
|
813
810
|
const pos = getWorldPosition(collider.gameObject);
|
814
811
|
rigidBodyDesc.setTranslation(pos.x, pos.y, pos.z);
|
@@ -816,12 +813,10 @@
|
|
816
813
|
rigidBody = this.world.createRigidBody(rigidBodyDesc);
|
817
814
|
_matrix.identity();
|
818
815
|
rigidBody[$componentKey] = null;
|
819
|
-
|
820
816
|
}
|
821
817
|
|
822
|
-
collider[$colliderRigidbody] = rigidBody;
|
823
818
|
|
824
|
-
return
|
819
|
+
return rigidBody;
|
825
820
|
}
|
826
821
|
|
827
822
|
private internal_getRigidbody(rb: IRigidbody | ICollider): RigidBody | null {
|
@@ -1001,6 +996,8 @@
|
|
1001
996
|
const rigidbody = body.parent();
|
1002
997
|
if (rigidbody)
|
1003
998
|
this.syncPhysicsBody(obj.gameObject, rigidbody, true, true);
|
999
|
+
else
|
1000
|
+
this.syncPhysicsBody(obj.gameObject, body, true, true);
|
1004
1001
|
continue;
|
1005
1002
|
}
|
1006
1003
|
|
@@ -1024,33 +1021,47 @@
|
|
1024
1021
|
}
|
1025
1022
|
}
|
1026
1023
|
|
1027
|
-
private syncPhysicsBody(obj: Object3D, body: RigidBody, translation: boolean, rotation: boolean) {
|
1024
|
+
private syncPhysicsBody(obj: Object3D, body: RigidBody | Collider, translation: boolean, rotation: boolean) {
|
1028
1025
|
|
1029
1026
|
// const bodyType = body.bodyType();
|
1030
1027
|
// const previous = physicsBody.translation();
|
1031
1028
|
// const vel = physicsBody.linvel();
|
1032
1029
|
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1030
|
+
if (body instanceof RigidBody) {
|
1031
|
+
const worldPosition = getWorldPosition(obj, this._tempPosition);
|
1032
|
+
const worldQuaternion = getWorldQuaternion(obj, this._tempQuaternion);
|
1033
|
+
const type = body.bodyType();
|
1034
|
+
switch (type) {
|
1035
|
+
case RigidBodyType.Fixed:
|
1036
|
+
case RigidBodyType.KinematicPositionBased:
|
1037
|
+
case RigidBodyType.KinematicVelocityBased:
|
1038
|
+
if (translation)
|
1039
|
+
body.setNextKinematicTranslation(worldPosition);
|
1040
|
+
if (rotation)
|
1041
|
+
body.setNextKinematicRotation(worldQuaternion);
|
1042
|
+
break;
|
1043
|
+
default:
|
1044
|
+
if (translation)
|
1045
|
+
body.setTranslation(worldPosition, false);
|
1046
|
+
if (rotation)
|
1047
|
+
body.setRotation(worldQuaternion, false);
|
1048
|
+
break;
|
1051
1049
|
|
1050
|
+
}
|
1051
|
+
body.wakeUp();
|
1052
1052
|
}
|
1053
|
-
body
|
1053
|
+
else if (body instanceof Collider) {
|
1054
|
+
const worldPosition = getWorldPosition(obj, this._tempPosition);
|
1055
|
+
const worldQuaternion = getWorldQuaternion(obj, this._tempQuaternion);
|
1056
|
+
const collider = body[$componentKey] as ICollider;
|
1057
|
+
this.tryApplyCenter(collider, worldPosition);
|
1058
|
+
if (translation)
|
1059
|
+
body.setTranslation(worldPosition);
|
1060
|
+
if (rotation)
|
1061
|
+
body.setRotation(worldQuaternion);
|
1062
|
+
|
1063
|
+
}
|
1064
|
+
|
1054
1065
|
// physicsBody.setBodyType(RAPIER.RigidBodyType.Fixed);
|
1055
1066
|
// physicsBody.setLinvel(vel, false);
|
1056
1067
|
|
@@ -1078,6 +1089,18 @@
|
|
1078
1089
|
// body.setBodyType(bodyType);
|
1079
1090
|
}
|
1080
1091
|
|
1092
|
+
private tryApplyCenter(collider: ICollider, targetVector: Vector3) {
|
1093
|
+
const center = collider.center;
|
1094
|
+
if (center && collider.gameObject) {
|
1095
|
+
getWorldScale(collider.gameObject, this._tempScale);
|
1096
|
+
center.multiply(this._tempScale);
|
1097
|
+
// TODO: fix export of center in editor integrations so we dont have to flip here
|
1098
|
+
targetVector.x -= center.x;
|
1099
|
+
targetVector.y += center.y;
|
1100
|
+
targetVector.z += center.z;
|
1101
|
+
}
|
1102
|
+
}
|
1103
|
+
|
1081
1104
|
private static _matricesBuffer: Matrix4[] = [];
|
1082
1105
|
private getRigidbodyRelativeMatrix(comp: Object3D, rigidbody: Object3D, mat: Matrix4, matrices?: Matrix4[]): Matrix4 {
|
1083
1106
|
// collect all matrices to the rigidbody and then build the rigidbody relative matrix
|
@@ -5,9 +5,20 @@
|
|
5
5
|
|
6
6
|
const _prevVisible = Symbol("previous-visibility");
|
7
7
|
|
8
|
+
/**
|
9
|
+
* A RenderTexture can be used to render a scene to a texture automatically by assigning it to the `Camera` component's `targetTexture` property.
|
10
|
+
* You can then assign the `RenderTexture.texture` to materials to be displayed
|
11
|
+
* @example ```ts
|
12
|
+
* // create new RenderTexture with a resolution
|
13
|
+
* const rt = new RenderTexture(256, 256);
|
14
|
+
* // assign to a camera
|
15
|
+
* myCameraComponent.targetTexture = rt;
|
16
|
+
* // assign to a material
|
17
|
+
* myMaterial.map = rt.texture;
|
18
|
+
* ```
|
19
|
+
*/
|
8
20
|
export class RenderTexture extends WebGLRenderTarget {
|
9
21
|
|
10
|
-
|
11
22
|
render(scene: Object3D, camera: Camera, renderer: WebGLRenderer | EffectComposer) {
|
12
23
|
if (renderer instanceof EffectComposer) {
|
13
24
|
if (!this["_unsupported_effectcomposer_warning"]) {
|
@@ -257,6 +257,7 @@
|
|
257
257
|
attachedRigidbody: IRigidbody | null;
|
258
258
|
isTrigger: boolean;
|
259
259
|
sharedMaterial?: PhysicsMaterial;
|
260
|
+
center?: Vec3 & { multiply(vec: Vec3) };
|
260
261
|
updateProperties(): void;
|
261
262
|
updatePhysicsMaterial(): void;
|
262
263
|
}
|
@@ -455,9 +456,9 @@
|
|
455
456
|
sphereOverlap(point: Vector3, radius: number): Array<SphereOverlapResult>;
|
456
457
|
|
457
458
|
// Collider methods
|
458
|
-
addSphereCollider(collider: ICollider
|
459
|
-
addBoxCollider(collider: ICollider,
|
460
|
-
addCapsuleCollider(collider: ICollider,
|
459
|
+
addSphereCollider(collider: ICollider);
|
460
|
+
addBoxCollider(collider: ICollider, size: Vector3);
|
461
|
+
addCapsuleCollider(collider: ICollider, radius: number, height: number);
|
461
462
|
addMeshCollider(collider: ICollider, mesh: Mesh, convex: boolean, scale: Vector3);
|
462
463
|
|
463
464
|
updatePhysicsMaterial(collider:ICollider);
|
@@ -16,6 +16,9 @@
|
|
16
16
|
}
|
17
17
|
from "../../engine/engine_three_utils.js";
|
18
18
|
|
19
|
+
import { TransformControlsGizmo } from "three/examples/jsm/controls/TransformControls.js";
|
20
|
+
|
21
|
+
|
19
22
|
// used to decorate cloned object3D objects with the same added components defined above
|
20
23
|
export function apply(object: Object3D) {
|
21
24
|
if (object && object.isObject3D === true) {
|
@@ -102,6 +105,10 @@
|
|
102
105
|
if (!Object.getOwnPropertyDescriptor(Object3D.prototype, "worldPosition")) {
|
103
106
|
Object.defineProperty(Object3D.prototype, "worldPosition", {
|
104
107
|
get: function () {
|
108
|
+
// TODO: would be great to remove this - just a workaround because the TransformControlsGizmo also defines this
|
109
|
+
if (this instanceof TransformControlsGizmo) {
|
110
|
+
return getWorldPosition(this["object"]);
|
111
|
+
}
|
105
112
|
return getWorldPosition(this);
|
106
113
|
},
|
107
114
|
set: function (val: Vector3) {
|
@@ -113,6 +120,9 @@
|
|
113
120
|
if (!Object.getOwnPropertyDescriptor(Object3D.prototype, "worldQuaternion")) {
|
114
121
|
Object.defineProperty(Object3D.prototype, "worldQuaternion", {
|
115
122
|
get: function () {
|
123
|
+
if (this instanceof TransformControlsGizmo) {
|
124
|
+
return getWorldQuaternion(this["object"]);
|
125
|
+
}
|
116
126
|
return getWorldQuaternion(this);
|
117
127
|
},
|
118
128
|
set: function (val: Quaternion) {
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { TypeStore } from "./../engine_typestore.js"
|
2
|
-
|
2
|
+
|
3
3
|
// Import types
|
4
4
|
import { __Ignore } from "../../engine-components/codegen/components.js";
|
5
5
|
import { ActionBuilder } from "../../engine-components/export/usdz/extensions/behavior/BehavioursBuilder.js";
|
@@ -219,7 +219,7 @@
|
|
219
219
|
import { XRGrabRendering } from "../../engine-components/webxr/WebXRGrabRendering.js";
|
220
220
|
import { XRRig } from "../../engine-components/webxr/WebXRRig.js";
|
221
221
|
import { XRState } from "../../engine-components/XRFlag.js";
|
222
|
-
|
222
|
+
|
223
223
|
// Register types
|
224
224
|
TypeStore.add("__Ignore", __Ignore);
|
225
225
|
TypeStore.add("ActionBuilder", ActionBuilder);
|
@@ -50,21 +50,18 @@
|
|
50
50
|
if (this.control) {
|
51
51
|
this.context.scene.add(this.control);
|
52
52
|
this.control.attach(this.gameObject);
|
53
|
-
|
54
|
-
this.control?.addEventListener('dragging-changed', this.
|
55
|
-
this.
|
53
|
+
|
54
|
+
this.control?.addEventListener('dragging-changed', this.onControlChangedEvent);
|
55
|
+
window.addEventListener('keydown', this.windowKeyDownListener);
|
56
|
+
window.addEventListener('keyup', this.windowKeyUpListener);
|
56
57
|
}
|
57
58
|
}
|
58
59
|
|
59
|
-
private changeEventListener?: any;
|
60
|
-
private windowKeyDownListener?: any;
|
61
|
-
private windowKeyUpListener?: any;
|
62
|
-
|
63
60
|
onDisable() {
|
64
61
|
this.control?.removeFromParent();
|
65
|
-
|
66
|
-
|
67
|
-
this.
|
62
|
+
this.control?.removeEventListener('dragging-changed', this.onControlChangedEvent);
|
63
|
+
window.removeEventListener('keydown', this.windowKeyDownListener);
|
64
|
+
window.removeEventListener('keyup', this.windowKeyUpListener);
|
68
65
|
}
|
69
66
|
|
70
67
|
enableSnapping() {
|
@@ -83,7 +80,7 @@
|
|
83
80
|
}
|
84
81
|
}
|
85
82
|
|
86
|
-
private onControlChangedEvent(event) {
|
83
|
+
private onControlChangedEvent = (event) => {
|
87
84
|
const orbit = this.orbit;
|
88
85
|
if (orbit) orbit.enabled = !event.value;
|
89
86
|
if (event.value) {
|
@@ -95,85 +92,67 @@
|
|
95
92
|
}
|
96
93
|
}
|
97
94
|
|
98
|
-
private addWindowEvents() {
|
99
|
-
const control = this.control;
|
100
|
-
if (!control) return;
|
101
95
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
96
|
+
private windowKeyDownListener = (event) => {
|
97
|
+
if (!this.enabled) return;
|
98
|
+
if (!this.control) return;
|
99
|
+
switch (event.keyCode) {
|
106
100
|
|
107
|
-
|
108
|
-
|
109
|
-
|
101
|
+
case 81: // Q
|
102
|
+
this.control.setSpace(this.control.space === 'local' ? 'world' : 'local');
|
103
|
+
break;
|
110
104
|
|
111
|
-
|
112
|
-
|
113
|
-
|
105
|
+
case 16: // Shift
|
106
|
+
this.enableSnapping();
|
107
|
+
break;
|
114
108
|
|
115
|
-
|
116
|
-
|
117
|
-
|
109
|
+
case 87: // W
|
110
|
+
this.control.setMode('translate');
|
111
|
+
break;
|
118
112
|
|
119
|
-
|
120
|
-
|
121
|
-
|
113
|
+
case 69: // E
|
114
|
+
this.control.setMode('rotate');
|
115
|
+
break;
|
122
116
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
117
|
+
case 82: // R
|
118
|
+
this.control.setMode('scale');
|
119
|
+
break;
|
120
|
+
case 187:
|
121
|
+
case 107: // +, =, num+
|
122
|
+
this.control.setSize(this.control.size + 0.1);
|
123
|
+
break;
|
130
124
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
125
|
+
case 189:
|
126
|
+
case 109: // -, _, num-
|
127
|
+
this.control.setSize(Math.max(this.control.size - 0.1, 0.1));
|
128
|
+
break;
|
135
129
|
|
136
|
-
|
137
|
-
|
138
|
-
|
130
|
+
case 88: // X
|
131
|
+
this.control.showX = !this.control.showX;
|
132
|
+
break;
|
139
133
|
|
140
|
-
|
141
|
-
|
142
|
-
|
134
|
+
case 89: // Y
|
135
|
+
this.control.showY = !this.control.showY;
|
136
|
+
break;
|
143
137
|
|
144
|
-
|
145
|
-
|
146
|
-
|
138
|
+
case 90: // Z
|
139
|
+
this.control.showZ = !this.control.showZ;
|
140
|
+
break;
|
147
141
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
}
|
153
|
-
|
154
|
-
};
|
142
|
+
case 32: // Spacebar
|
143
|
+
this.control.enabled = !this.control.enabled;
|
144
|
+
break;
|
155
145
|
}
|
146
|
+
}
|
156
147
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
break;
|
148
|
+
private windowKeyUpListener = (event) => {
|
149
|
+
if (!this.enabled) return;
|
150
|
+
switch (event.keyCode) {
|
151
|
+
case 16: // Shift
|
152
|
+
this.disableSnapping();
|
153
|
+
break;
|
164
154
|
|
165
|
-
}
|
166
|
-
|
167
|
-
};
|
168
155
|
}
|
169
156
|
|
170
|
-
|
171
|
-
window.addEventListener('keydown', this.windowKeyDownListener);
|
172
|
-
window.addEventListener('keyup', this.windowKeyUpListener);
|
173
157
|
}
|
174
|
-
|
175
|
-
private removeWindowEvents() {
|
176
|
-
window.removeEventListener('keydown', this.windowKeyDownListener);
|
177
|
-
window.removeEventListener('keyup', this.windowKeyUpListener);
|
178
|
-
}
|
179
158
|
}
|
@@ -247,8 +247,11 @@
|
|
247
247
|
if (!frame) return;
|
248
248
|
|
249
249
|
if (frame.session && !("getImageTrackingResults" in frame)) {
|
250
|
-
const warning = "Image tracking is currently not supported on this device. On Chrome for Android, you can enable the <a href=\"
|
251
|
-
|
250
|
+
const warning = "Image tracking is currently not supported on this device. On Chrome for Android, you can enable the <a target=\"_blank\" href=\"#\" onclick=\"() => console.log('I')\">chrome://flags/#webxr-incubations</a> flag.";
|
251
|
+
if (!this["didPrintWarning"]) {
|
252
|
+
this["didPrintWarning"] = true;
|
253
|
+
console.log(warning);
|
254
|
+
}
|
252
255
|
showBalloonWarning(warning);
|
253
256
|
return;
|
254
257
|
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import { FrameEvent } from "./engine_context.js";
|
2
|
+
import { LifecycleMethod, registerCallback } from "./engine_lifecycle_functions_internal.js";
|
3
|
+
|
4
|
+
|
5
|
+
/** Register a callback in the engine start event */
|
6
|
+
export function onStart(cb: LifecycleMethod) {
|
7
|
+
registerCallback(cb, FrameEvent.Start);
|
8
|
+
}
|
9
|
+
|
10
|
+
|
11
|
+
/** Register a callback in the engine update event
|
12
|
+
* called every frame
|
13
|
+
* */
|
14
|
+
export function onUpdate(cb: LifecycleMethod) {
|
15
|
+
registerCallback(cb, FrameEvent.Update);
|
16
|
+
}
|
@@ -0,0 +1,35 @@
|
|
1
|
+
import { safeInvoke } from "./engine_generic_utils.js";
|
2
|
+
import { FrameEvent, type Context } from "./engine_context.js";
|
3
|
+
|
4
|
+
export declare type LifecycleMethod = (ctx: Context) => void;
|
5
|
+
|
6
|
+
const allMethods = new Map<FrameEvent, Array<LifecycleMethod>>();
|
7
|
+
|
8
|
+
export function registerCallback(cb: LifecycleMethod, evt: FrameEvent) {
|
9
|
+
if (!allMethods.has(evt)) {
|
10
|
+
allMethods.set(evt, new Array<LifecycleMethod>());
|
11
|
+
}
|
12
|
+
allMethods.get(evt)!.push(cb);
|
13
|
+
}
|
14
|
+
|
15
|
+
export function invokeLifecycleFunctions(ctx: Context, evt: FrameEvent) {
|
16
|
+
const methods = allMethods.get(evt);
|
17
|
+
if (methods) {
|
18
|
+
if (methods.length > 0) {
|
19
|
+
let array = methods;
|
20
|
+
if (evt === FrameEvent.Start) {
|
21
|
+
array = [...methods];
|
22
|
+
methods.length = 0;
|
23
|
+
}
|
24
|
+
invoke(ctx, array);
|
25
|
+
}
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
|
30
|
+
function invoke(ctx: Context, methods: Array<LifecycleMethod>) {
|
31
|
+
for (let i = methods.length - 1; i >= 0; i--) {
|
32
|
+
const method = methods[i];
|
33
|
+
safeInvoke(method, ctx);
|
34
|
+
}
|
35
|
+
}
|