File without changes
|
@@ -68,6 +68,7 @@
|
|
68
68
|
return "assets";
|
69
69
|
}
|
70
70
|
|
71
|
+
/** @returns the fullpath of the build */
|
71
72
|
export function getOutputDirectory() {
|
72
73
|
const projectConfig = tryLoadProjectConfig();
|
73
74
|
return process.cwd() + "/" + (projectConfig?.buildDirectory || "dist");
|
@@ -36,7 +36,10 @@
|
|
36
36
|
const needleConfig = tryLoadProjectConfig();
|
37
37
|
if (needleConfig) {
|
38
38
|
assetsDirName = needleConfig.assetsDirectory;
|
39
|
-
while(assetsDirName.startsWith('/')) assetsDirName = assetsDirName.substring(1);
|
39
|
+
while (assetsDirName.startsWith('/')) assetsDirName = assetsDirName.substring(1);
|
40
|
+
|
41
|
+
if (needleConfig.buildDirectory)
|
42
|
+
outdirName = needleConfig.buildDirectory;
|
40
43
|
}
|
41
44
|
|
42
45
|
if (copyIncludesFromEngine !== false) {
|
@@ -26,7 +26,7 @@
|
|
26
26
|
// console.log("Update vite defines -------------------------------------------");
|
27
27
|
if (!viteConfig.define) viteConfig.define = {};
|
28
28
|
const version = tryGetNeedleEngineVersion();
|
29
|
-
console.log("Needle Engine Version:"
|
29
|
+
console.log("Needle Engine Version: " + version, needleEngineConfig?.generator ?? "(unknown generator)");
|
30
30
|
if (version)
|
31
31
|
viteConfig.define.NEEDLE_ENGINE_VERSION = "\"" + version + "\"";
|
32
32
|
if (needleEngineConfig)
|
@@ -42,6 +42,9 @@
|
|
42
42
|
if (viteConfig.define.NEEDLE_USE_RAPIER === undefined) {
|
43
43
|
viteConfig.define.NEEDLE_USE_RAPIER = useRapier;
|
44
44
|
}
|
45
|
+
|
46
|
+
// this gives a timestamp containing the timezone
|
47
|
+
viteConfig.define.NEEDLE_PROJECT_BUILD_TIME = "\"" + new Date().toString() + "\"";
|
45
48
|
}
|
46
49
|
}
|
47
50
|
}
|
@@ -39,11 +39,14 @@
|
|
39
39
|
});
|
40
40
|
}
|
41
41
|
|
42
|
-
function triggerReloadOnClients() {
|
43
|
-
log(
|
44
|
-
|
45
|
-
|
46
|
-
|
42
|
+
async function triggerReloadOnClients() {
|
43
|
+
log(`Triggering reload on ${currentClients.size} clients...`)
|
44
|
+
for (const client of currentClients) {
|
45
|
+
client.send(JSON.stringify({ type: "full-reload" }));
|
46
|
+
}
|
47
|
+
return new Promise((resolve) => {
|
48
|
+
setTimeout(resolve, 100);
|
49
|
+
});
|
47
50
|
}
|
48
51
|
|
49
52
|
|
@@ -81,9 +84,6 @@
|
|
81
84
|
modified = true;
|
82
85
|
}
|
83
86
|
if (modified || requireInstall) {
|
84
|
-
if (modified) {
|
85
|
-
log("package.json has changed. Require install?", requireInstall)
|
86
|
-
}
|
87
87
|
|
88
88
|
let requireReload = false;
|
89
89
|
if (!requireInstall) {
|
@@ -95,7 +95,7 @@
|
|
95
95
|
if (newPackageJson.dependencies) {
|
96
96
|
for (const key in newPackageJson.dependencies) {
|
97
97
|
if (packageJson.dependencies[key] !== newPackageJson.dependencies[key] && newPackageJson.dependencies[key] !== undefined) {
|
98
|
-
log("
|
98
|
+
log("Detected new dependency: " + key)
|
99
99
|
requireReload = true;
|
100
100
|
requireInstall = true;
|
101
101
|
}
|
@@ -104,13 +104,16 @@
|
|
104
104
|
if (packageJson.devDependencies) {
|
105
105
|
for (const key in packageJson.devDependencies) {
|
106
106
|
if (packageJson.devDependencies[key] !== newPackageJson.devDependencies[key] && newPackageJson.devDependencies[key] !== undefined) {
|
107
|
-
log("
|
107
|
+
log("Detected new devDependency: " + key)
|
108
108
|
requireReload = true;
|
109
109
|
requireInstall = true;
|
110
110
|
}
|
111
111
|
}
|
112
112
|
}
|
113
113
|
|
114
|
+
if (modified) {
|
115
|
+
log("package.json has changed. Require install: " + (requireInstall ? "yes" : "no"))
|
116
|
+
}
|
114
117
|
|
115
118
|
packageJsonSize = packageJsonStat.size;
|
116
119
|
lastEditTime = packageJsonStat.mtime;
|
@@ -119,7 +122,7 @@
|
|
119
122
|
restart(server, projectDir, cachePath);
|
120
123
|
}
|
121
124
|
}
|
122
|
-
},
|
125
|
+
}, 2000);
|
123
126
|
}
|
124
127
|
|
125
128
|
function testIfInstallIsRequired(projectDir, packageJson) {
|
@@ -142,7 +145,7 @@
|
|
142
145
|
}
|
143
146
|
}
|
144
147
|
}
|
145
|
-
log("Dependency not installed"
|
148
|
+
log("Dependency not installed: " + key)
|
146
149
|
return true;
|
147
150
|
}
|
148
151
|
else {
|
@@ -161,9 +164,11 @@
|
|
161
164
|
const isRange = expectedVersion.includes("^") || expectedVersion.includes(">") || expectedVersion.includes("<");
|
162
165
|
if (!isRange) {
|
163
166
|
const packageJsonPath = path.join(depPath, "package.json");
|
167
|
+
/** @type {String} */
|
164
168
|
const installedVersion = JSON.parse(readFileSync(packageJsonPath, "utf8")).version;
|
165
|
-
|
166
|
-
|
169
|
+
// fix check for cases where the version contains a alias e.g. npm:[email protected]
|
170
|
+
if (expectedVersion.trimEnd().endsWith(installedVersion.trim()) == false) {
|
171
|
+
log(`Dependency ${key} is installed but version is not the right one. Expected \"${expectedVersion}/" but got \"${installedVersion}\"`)
|
167
172
|
return true;
|
168
173
|
}
|
169
174
|
}
|
@@ -194,13 +199,13 @@
|
|
194
199
|
}
|
195
200
|
|
196
201
|
if (id !== restartId) return;
|
197
|
-
if (Date.now() - lastRestartTime <
|
202
|
+
if (Date.now() - lastRestartTime < 3000) return;
|
198
203
|
log("Restarting server...")
|
199
204
|
lastRestartTime = Date.now();
|
200
205
|
requireInstall = false;
|
201
206
|
if (existsSync(cachePath))
|
202
207
|
rmSync(cachePath, { recursive: true, force: true });
|
203
|
-
triggerReloadOnClients();
|
208
|
+
await triggerReloadOnClients();
|
204
209
|
|
205
210
|
// touch vite config to trigger reload
|
206
211
|
// const viteConfigPath = path.join(projectDir, "vite.config.js");
|
@@ -212,8 +217,9 @@
|
|
212
217
|
// }
|
213
218
|
|
214
219
|
// check if server is running
|
215
|
-
if (server.httpServer.listening)
|
220
|
+
if (server.httpServer.listening) {
|
216
221
|
server.restart();
|
222
|
+
}
|
217
223
|
isRunningRestart = false;
|
218
224
|
console.log("-----------------------------------------------")
|
219
225
|
}
|
@@ -42,6 +42,7 @@
|
|
42
42
|
|
43
43
|
import { vite_4_4_hack } from "./vite-4.4-hack.js";
|
44
44
|
import { needleImportsLogger } from "./imports-logger.js";
|
45
|
+
import { needleBuildInfo } from "./buildinfo.js";
|
45
46
|
|
46
47
|
|
47
48
|
export * from "./gzip.js";
|
@@ -57,6 +58,8 @@
|
|
57
58
|
*/
|
58
59
|
export const needlePlugins = async (command, config, userSettings) => {
|
59
60
|
|
61
|
+
if(!config) config = {}
|
62
|
+
|
60
63
|
// ensure we have user settings initialized with defaults
|
61
64
|
userSettings = { ...defaultUserSettings, ...userSettings }
|
62
65
|
const array = [
|
@@ -67,6 +70,7 @@
|
|
67
70
|
needlePoster(command, config, userSettings),
|
68
71
|
needleReload(command, config, userSettings),
|
69
72
|
needleBuild(command, config, userSettings),
|
73
|
+
needleBuildInfo(command, config, userSettings),
|
70
74
|
needleCopyFiles(command, config, userSettings),
|
71
75
|
needleTransformCodegen(command, config, userSettings),
|
72
76
|
needleDrop(command, config, userSettings),
|
@@ -109,6 +109,8 @@
|
|
109
109
|
}
|
110
110
|
else console.log("WARN: could not find needle engine package.json")
|
111
111
|
|
112
|
+
tags.push({ tag: 'meta', attrs: { name: 'needle:buildtime', content: new Date().toISOString() } });
|
113
|
+
|
112
114
|
return { html, tags }
|
113
115
|
},
|
114
116
|
}
|
@@ -1,6 +1,7 @@
|
|
1
|
-
import {
|
1
|
+
import { BufferGeometry,Material, Matrix4, Object3D } from "three";
|
2
|
+
|
3
|
+
import { USDDocument,USDObject } from "../../ThreeUSDZExporter.js";
|
2
4
|
import { ActionBuilder, ActionModel } from "./BehavioursBuilder.js";
|
3
|
-
import { USDObject, USDDocument } from "../../ThreeUSDZExporter.js";
|
4
5
|
|
5
6
|
export abstract class DocumentAction {
|
6
7
|
|
@@ -1,7 +1,8 @@
|
|
1
|
-
import { Behaviour, GameObject } from "./Component.js";
|
2
|
-
import * as utils from "./../engine/engine_three_utils.js";
|
3
1
|
import { Vector3 } from "three";
|
2
|
+
|
4
3
|
import { serializable } from "../engine/engine_serialization_decorator.js";
|
4
|
+
import * as utils from "./../engine/engine_three_utils.js";
|
5
|
+
import { Behaviour, GameObject } from "./Component.js";
|
5
6
|
|
6
7
|
export class AlignmentConstraint extends Behaviour {
|
7
8
|
|
@@ -1,10 +1,11 @@
|
|
1
|
-
import { Behaviour } from "./Component.js";
|
2
1
|
import { AnimationAction, AnimationClip, AnimationMixer, LoopOnce, LoopRepeat } from "three";
|
3
|
-
|
2
|
+
|
3
|
+
import { Mathf } from "../engine/engine_math.js";
|
4
4
|
import { serializable } from "../engine/engine_serialization_decorator.js";
|
5
|
-
import { Mathf } from "../engine/engine_math.js";
|
6
5
|
import type { Vec2 } from "../engine/engine_types.js";
|
7
6
|
import { getParam } from "../engine/engine_utils.js";
|
7
|
+
import { MixerEvent } from "./Animator.js";
|
8
|
+
import { Behaviour } from "./Component.js";
|
8
9
|
|
9
10
|
const debug = getParam("debuganimation");
|
10
11
|
|
@@ -1,9 +1,10 @@
|
|
1
|
+
import { AnimationClip, Bone,Interpolant, KeyframeTrack, Matrix4, Object3D, PropertyBinding, Quaternion, Vector3 } from "three";
|
2
|
+
|
3
|
+
import { getParam } from "../../../../engine/engine_utils.js";
|
4
|
+
import { Animator } from "../../../Animator.js";
|
1
5
|
import { GameObject } from "../../../Component.js";
|
2
|
-
import { getParam } from "../../../../engine/engine_utils.js";
|
3
|
-
import { USDObject, buildMatrix, findStructuralNodesInBoneHierarchy, usdNumberFormatting as fn, getPathToSkeleton } from "../ThreeUSDZExporter.js";
|
4
6
|
import type { IUSDExporterExtension } from "../Extension.js";
|
5
|
-
import {
|
6
|
-
import { Animator } from "../../../Animator.js";
|
7
|
+
import { buildMatrix, findStructuralNodesInBoneHierarchy, getPathToSkeleton,usdNumberFormatting as fn, USDObject } from "../ThreeUSDZExporter.js";
|
7
8
|
|
8
9
|
const debug = getParam("debugusdzanimation");
|
9
10
|
const debugSerialization = getParam("debugusdzanimationserialization");
|
@@ -23,6 +23,22 @@
|
|
23
23
|
@serializable(Keyframe)
|
24
24
|
keys!: Array<Keyframe>;
|
25
25
|
|
26
|
+
clone() {
|
27
|
+
const curve = new AnimationCurve();
|
28
|
+
curve.keys = this.keys?.map(k => {
|
29
|
+
const key = new Keyframe();
|
30
|
+
key.time = k.time;
|
31
|
+
key.value = k.value;
|
32
|
+
key.inTangent = k.inTangent;
|
33
|
+
key.inWeight = k.inWeight;
|
34
|
+
key.outTangent = k.outTangent;
|
35
|
+
key.outWeight = k.outWeight;
|
36
|
+
key.weightedMode = k.weightedMode;
|
37
|
+
return key;
|
38
|
+
}) || [];
|
39
|
+
return curve;
|
40
|
+
}
|
41
|
+
|
26
42
|
get duration(): number {
|
27
43
|
if (!this.keys || this.keys.length == 0) return 0;
|
28
44
|
return this.keys[this.keys.length - 1].time;
|
@@ -38,9 +54,9 @@
|
|
38
54
|
for (let i = 0; i < this.keys.length; i++) {
|
39
55
|
const kf = this.keys[i];
|
40
56
|
if (kf.time <= time) {
|
41
|
-
const hasNextKeyframe = i+1 < this.keys.length;
|
57
|
+
const hasNextKeyframe = i + 1 < this.keys.length;
|
42
58
|
if (hasNextKeyframe) {
|
43
|
-
const nextKf = this.keys[i+1];
|
59
|
+
const nextKf = this.keys[i + 1];
|
44
60
|
// if the next
|
45
61
|
if (nextKf.time < time) continue;
|
46
62
|
// tangents are set to Infinity if interpolation is set to constant - in that case we should always return the floored value
|
@@ -1,11 +1,12 @@
|
|
1
|
+
import { Object3D } from "three";
|
1
2
|
import type { GLTF } from "three/examples/jsm/loaders/GLTFLoader.js";
|
3
|
+
|
4
|
+
import { addNewComponent } from "../engine/engine_components.js";
|
2
5
|
import { ContextEvent, ContextRegistry } from "../engine/engine_context_registry.js";
|
3
|
-
import {
|
6
|
+
import { Animation } from "./Animation.js";
|
4
7
|
import { Animator } from "./Animator.js";
|
5
|
-
import { Animation } from "./Animation.js";
|
6
8
|
import { GameObject } from "./Component.js";
|
7
9
|
import { PlayableDirector } from "./timeline/PlayableDirector.js";
|
8
|
-
import { Object3D } from "three";
|
9
10
|
|
10
11
|
|
11
12
|
const $objectAnimationKey = Symbol("objectIsAnimatedData");
|
@@ -1,9 +1,10 @@
|
|
1
|
+
import { AnimationClip,Object3D } from "three";
|
2
|
+
|
3
|
+
import { getParam } from "../../../../engine/engine_utils.js";
|
4
|
+
import { Animation } from "../../../Animation.js";
|
1
5
|
import { Animator } from "../../../Animator.js";
|
2
|
-
import {
|
3
|
-
import { Object3D, AnimationClip } from "three";
|
6
|
+
import { Behaviour, GameObject } from "../../../Component.js";
|
4
7
|
import { AnimationExtension } from "../extensions/Animation.js";
|
5
|
-
import { Behaviour, GameObject } from "../../../Component.js";
|
6
|
-
import { getParam } from "../../../../engine/engine_utils.js";
|
7
8
|
import { PlayAnimationOnClick } from "../extensions/behavior/BehaviourComponents.js";
|
8
9
|
|
9
10
|
const debug = getParam("debugusdz");
|
@@ -1,11 +1,12 @@
|
|
1
|
-
import {
|
2
|
-
|
1
|
+
import type { AnimationAction, AnimationActionLoopStyles, AnimationMixer } from "three";
|
2
|
+
|
3
|
+
import { Mathf } from "../engine/engine_math.js";
|
4
|
+
import { serializable } from "../engine/engine_serialization_decorator.js";
|
3
5
|
import { getParam } from "../engine/engine_utils.js";
|
4
6
|
import type { AnimatorControllerModel } from "../engine/extensions/NEEDLE_animator_controller_model.js";
|
7
|
+
import { getObjectAnimated } from "./AnimationUtils.js";
|
5
8
|
import { AnimatorController } from "./AnimatorController.js";
|
6
|
-
import {
|
7
|
-
import { Mathf } from "../engine/engine_math.js";
|
8
|
-
import { getObjectAnimated } from "./AnimationUtils.js";
|
9
|
+
import { Behaviour } from "./Component.js";
|
9
10
|
|
10
11
|
const debug = getParam("debuganimator");
|
11
12
|
|
@@ -1,15 +1,16 @@
|
|
1
|
-
import { Animator } from "./Animator.js";
|
2
|
-
import type { AnimatorControllerModel, Condition, State, Transition } from "../engine/extensions/NEEDLE_animator_controller_model.js";
|
3
|
-
import { AnimatorConditionMode, AnimatorControllerParameterType, AnimatorStateInfo, createMotion, StateMachineBehaviour } from "../engine/extensions/NEEDLE_animator_controller_model.js";
|
4
1
|
import { AnimationAction, AnimationClip, AnimationMixer, AxesHelper, Euler, KeyframeTrack, LoopOnce, Object3D, Quaternion, Vector3 } from "three";
|
5
|
-
|
2
|
+
|
3
|
+
import { isDevEnvironment } from "../engine/debug/index.js";
|
4
|
+
import { Mathf } from "../engine/engine_math.js";
|
5
|
+
import { InstantiateIdProvider } from "../engine/engine_networking_instantiate.js";
|
6
|
+
import { assign,SerializationContext, TypeSerializer } from "../engine/engine_serialization_core.js";
|
6
7
|
import { Context } from "../engine/engine_setup.js";
|
8
|
+
import { isAnimationAction } from "../engine/engine_three_utils.js";
|
7
9
|
import { TypeStore } from "../engine/engine_typestore.js";
|
8
|
-
import {
|
9
|
-
import {
|
10
|
-
import {
|
11
|
-
import {
|
12
|
-
import { InstantiateIdProvider } from "../engine/engine_networking_instantiate.js";
|
10
|
+
import { deepClone, getParam } from "../engine/engine_utils.js";
|
11
|
+
import type { AnimatorControllerModel, Condition, State, Transition } from "../engine/extensions/NEEDLE_animator_controller_model.js";
|
12
|
+
import { AnimatorConditionMode, AnimatorControllerParameterType, AnimatorStateInfo, createMotion, StateMachineBehaviour } from "../engine/extensions/NEEDLE_animator_controller_model.js";
|
13
|
+
import { Animator } from "./Animator.js";
|
13
14
|
|
14
15
|
const debug = getParam("debuganimatorcontroller");
|
15
16
|
const debugRootMotion = getParam("debugrootmotion");
|
@@ -212,6 +213,7 @@
|
|
212
213
|
console.warn("AnimatorController has not been resolved, can not create model from string", this.model);
|
213
214
|
return null;
|
214
215
|
}
|
216
|
+
if (debug) console.warn("AnimatorController clone()", this.model);
|
215
217
|
// clone runtime controller but dont clone clip or action
|
216
218
|
const clonedModel = deepClone(this.model, (_owner, _key, _value) => {
|
217
219
|
if (_value === null || _value === undefined) return true;
|
@@ -224,6 +226,8 @@
|
|
224
226
|
}
|
225
227
|
// dont clone AnimationClip
|
226
228
|
if (_value["tracks"] !== undefined) return false;
|
229
|
+
// when assigned __concreteInstance during serialization
|
230
|
+
if (_value instanceof AnimatorController) return false;
|
227
231
|
return true;
|
228
232
|
}) as AnimatorControllerModel;
|
229
233
|
console.assert(clonedModel !== this.model);
|
@@ -581,7 +585,7 @@
|
|
581
585
|
}
|
582
586
|
|
583
587
|
private createActions(_animator: Animator) {
|
584
|
-
|
588
|
+
if (debug) console.log("AnimatorController createActions", this.model);
|
585
589
|
for (const layer of this.model.layers) {
|
586
590
|
const sm = layer.stateMachine;
|
587
591
|
for (let index = 0; index < sm.states.length; index++) {
|
@@ -608,8 +612,13 @@
|
|
608
612
|
if (this.animator && state.motion.clips) {
|
609
613
|
// TODO: we have to compare by name because on instantiate we clone objects but not the node object
|
610
614
|
const mapping = state.motion.clips?.find(e => e.node.name === this.animator?.gameObject?.name);
|
611
|
-
|
612
|
-
|
615
|
+
if (!mapping) {
|
616
|
+
if (debug || isDevEnvironment()) {
|
617
|
+
console.warn("Could not find clip for animator \"" + this.animator?.gameObject?.name + "\"", state.motion.clips.map(c => c.node.name));
|
618
|
+
}
|
619
|
+
}
|
620
|
+
else
|
621
|
+
state.motion.clip = mapping.clip;
|
613
622
|
}
|
614
623
|
|
615
624
|
// ensure we have a clip to blend to
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import { EdgeDetectionMode, SMAAEffect, SMAAPreset } from "postprocessing";
|
2
|
+
|
2
3
|
import { serializable } from "../../../engine/engine_serialization.js";
|
3
4
|
import { type EffectProviderResult, PostProcessingEffect } from "../PostProcessingEffect.js";
|
4
5
|
import { VolumeParameter } from "../VolumeParameter.js";
|
@@ -1,22 +1,20 @@
|
|
1
|
+
export * from "./codegen/components.js";
|
1
2
|
export { Behaviour, Component, GameObject } from "./Component.js"
|
2
|
-
export * from "./codegen/components.js";
|
3
3
|
|
4
4
|
// We dont want to export everything in the extensions
|
5
|
+
export { ClearFlags } from "./Camera.js"
|
6
|
+
export * from "./export/index.js"
|
7
|
+
export * from "./js-extensions/Object3D.js";
|
5
8
|
export * from "./js-extensions/RGBAColor.js";
|
6
|
-
export * from "./js-extensions/Object3D.js";
|
7
|
-
export * from "./XRFlag.js"
|
8
|
-
|
9
|
-
export * from "./export/index.js"
|
10
9
|
export * from "./postprocessing/index.js"
|
10
|
+
export { type ISceneEventListener } from "./SceneSwitcher.js";
|
11
11
|
export * from "./timeline/index.js"
|
12
12
|
export * from "./ui/index.js"
|
13
13
|
export * from "./webxr/index.js"
|
14
|
+
export * from "./webxr/XRFlag.js"
|
14
15
|
|
15
|
-
export { ClearFlags } from "./Camera.js"
|
16
|
-
export { type ISceneEventListener } from "./SceneSwitcher.js";
|
17
|
-
|
18
16
|
import "./CameraUtils.js"
|
19
17
|
import "./AnimationUtils.js"
|
20
18
|
|
21
19
|
export { ParticleSystemBaseBehaviour, type QParticle, type QParticleBehaviour } from "./ParticleSystem.js"
|
22
|
-
|
20
|
+
export { ParticleSystemShapeType } from "./ParticleSystemModules.js"
|
@@ -1,42 +1,42 @@
|
|
1
1
|
|
2
|
-
export * from "./
|
2
|
+
export * from "./debug/index.js";
|
3
3
|
export * from "./engine_addressables.js";
|
4
4
|
export * from "./engine_application.js";
|
5
5
|
export * from "./engine_assetdatabase.js";
|
6
|
-
export * from "./engine_create_objects.js";
|
7
|
-
export * from "./engine_components_internal.js";
|
8
6
|
export * from "./engine_components.js";
|
9
7
|
export * from "./engine_components_internal.js";
|
8
|
+
export * from "./engine_components_internal.js";
|
9
|
+
export * from "./engine_constants.js";
|
10
|
+
export * from "./engine_context.js";
|
10
11
|
export * from "./engine_context_registry.js";
|
11
|
-
export * from "./engine_context.js";
|
12
12
|
export * from "./engine_coroutine.js"
|
13
|
-
export * from "./
|
14
|
-
export * from "./debug/index.js";
|
13
|
+
export * from "./engine_create_objects.js";
|
15
14
|
export * from "./engine_element.js";
|
15
|
+
export * from "./engine_element_attributes.js";
|
16
16
|
export * from "./engine_element_loading.js";
|
17
|
-
export * from "./
|
17
|
+
export * from "./engine_gameobject.js";
|
18
18
|
export { Gizmos } from "./engine_gizmos.js"
|
19
19
|
export * from "./engine_gltf.js";
|
20
20
|
export * from "./engine_hot_reload.js";
|
21
|
-
export * from "./
|
21
|
+
export * from "./engine_input.js";
|
22
|
+
export { InstancingUtil } from "./engine_instancing.js";
|
23
|
+
export { hasIndieLicense,hasProLicense } from "./engine_license.js";
|
24
|
+
export * from "./engine_lifecycle_api.js";
|
25
|
+
export * from "./engine_math.js";
|
22
26
|
export * from "./engine_networking.js";
|
23
|
-
export * from "./engine_networking_types.js";
|
24
27
|
export { syncField } from "./engine_networking_auto.js";
|
25
28
|
export * from "./engine_networking_files.js";
|
26
29
|
export * from "./engine_networking_instantiate.js";
|
30
|
+
export * from "./engine_networking_peer.js";
|
27
31
|
export * from "./engine_networking_streams.js";
|
32
|
+
export * from "./engine_networking_types.js";
|
28
33
|
export * from "./engine_networking_utils.js";
|
29
|
-
export * from "./engine_networking_peer.js";
|
30
34
|
export * from "./engine_patcher.js";
|
31
|
-
export * from "./engine_playerview.js";
|
32
35
|
export * from "./engine_physics.js";
|
33
36
|
export * from "./engine_physics.types.js";
|
34
37
|
export * from "./engine_physics_rapier.js";
|
38
|
+
export * from "./engine_playerview.js";
|
35
39
|
export * from "./engine_scenelighting.js";
|
36
|
-
export * from "./engine_input.js";
|
37
|
-
export * from "./engine_lifecycle_api.js";
|
38
|
-
export * from "./engine_math.js";
|
39
|
-
export * from "./js-extensions/index.js";
|
40
40
|
export * from "./engine_scenetools.js";
|
41
41
|
export * from "./engine_serialization.js";
|
42
42
|
export { type ISerializable } from "./engine_serialization_core.js";
|
@@ -44,12 +44,11 @@
|
|
44
44
|
export * from "./engine_three_utils.js";
|
45
45
|
export * from "./engine_time.js";
|
46
46
|
export * from "./engine_types.js";
|
47
|
+
export { registerType,TypeStore } from "./engine_typestore.js";
|
48
|
+
export { prefix,validate } from "./engine_util_decorator.js";
|
49
|
+
export * from "./engine_utils.js";
|
47
50
|
export * from "./engine_utils_screenshot.js";
|
48
51
|
export * from "./engine_web_api.js";
|
49
|
-
export * from "./
|
50
|
-
|
51
|
-
export
|
52
|
-
|
53
|
-
export { InstancingUtil } from "./engine_instancing.js";
|
54
|
-
export { validate, prefix } from "./engine_util_decorator.js";
|
55
|
-
export { hasProLicense, hasIndieLicense } from "./engine_license.js";
|
52
|
+
export * from "./engine_xr.js";
|
53
|
+
export * from "./extensions/index.js";
|
54
|
+
export * from "./js-extensions/index.js";
|
@@ -1,8 +1,9 @@
|
|
1
|
+
import { Object3D } from "three";
|
2
|
+
|
3
|
+
import { AudioSource } from "../../../../AudioSource.js";
|
1
4
|
import { GameObject } from "../../../../Component.js";
|
2
5
|
import type { IUSDExporterExtension } from "../../Extension.js";
|
3
6
|
import { USDObject, USDWriter, USDZExporterContext } from "../../ThreeUSDZExporter.js";
|
4
|
-
import { Object3D } from "three";
|
5
|
-
import { AudioSource } from "../../../../AudioSource.js";
|
6
7
|
|
7
8
|
export class AudioExtension implements IUSDExporterExtension {
|
8
9
|
|
@@ -1,7 +1,8 @@
|
|
1
|
-
import { Behaviour, GameObject } from "./Component.js";
|
2
1
|
import { AudioListener as ThreeAudioListener } from "three";
|
2
|
+
|
3
3
|
import { AudioSource } from "./AudioSource.js";
|
4
4
|
import { Camera } from "./Camera.js";
|
5
|
+
import { Behaviour, GameObject } from "./Component.js";
|
5
6
|
|
6
7
|
|
7
8
|
export class AudioListener extends Behaviour {
|
@@ -1,11 +1,14 @@
|
|
1
|
-
import {
|
1
|
+
import { Audio, AudioContext, AudioLoader, PositionalAudio, Vector3 } from "three";
|
2
2
|
import { PositionalAudioHelper } from 'three/examples/jsm/helpers/PositionalAudioHelper.js';
|
3
|
+
|
4
|
+
import { isDevEnvironment } from "../engine/debug/index.js";
|
5
|
+
import { ApplicationEvents } from "../engine/engine_application.js";
|
6
|
+
import { Mathf } from "../engine/engine_math.js";
|
7
|
+
import { serializable } from "../engine/engine_serialization_decorator.js";
|
8
|
+
import { getTempVector } from "../engine/engine_three_utils.js";
|
9
|
+
import * as utils from "../engine/engine_utils.js";
|
3
10
|
import { AudioListener } from "./AudioListener.js";
|
4
|
-
import
|
5
|
-
import { serializable } from "../engine/engine_serialization_decorator.js";
|
6
|
-
import { ApplicationEvents } from "../engine/engine_application.js";
|
7
|
-
import { Audio, AudioContext, AudioLoader, PositionalAudio } from "three";
|
8
|
-
import { isDevEnvironment } from "../engine/debug/index.js";
|
11
|
+
import { Behaviour, GameObject } from "./Component.js";
|
9
12
|
|
10
13
|
|
11
14
|
const debug = utils.getParam("debugaudio");
|
@@ -65,6 +68,9 @@
|
|
65
68
|
playOnAwake: boolean = false;
|
66
69
|
|
67
70
|
@serializable()
|
71
|
+
preload: boolean = false;
|
72
|
+
|
73
|
+
@serializable()
|
68
74
|
get loop(): boolean {
|
69
75
|
if (this.sound) this._loop = this.sound.getLoop();
|
70
76
|
return this._loop;
|
@@ -140,23 +146,69 @@
|
|
140
146
|
if (!listener && this.context.mainCamera) listener = GameObject.addNewComponent(this.context.mainCamera, AudioListener);
|
141
147
|
if (listener?.listener) {
|
142
148
|
this.sound = new PositionalAudio(listener.listener);
|
143
|
-
this.gameObject
|
149
|
+
this.gameObject?.add(this.sound);
|
150
|
+
|
151
|
+
// this._listener = listener;
|
152
|
+
// this._originalSoundMatrixWorldFunction = this.sound.updateMatrixWorld;
|
153
|
+
// this.sound.updateMatrixWorld = this._onSoundMatrixWorld;
|
144
154
|
}
|
145
155
|
else if (debug) console.warn("No audio listener found in scene - can not play audio");
|
146
156
|
}
|
147
157
|
return this.sound;
|
148
158
|
}
|
149
159
|
|
160
|
+
// This is a hacky workaround to get the PositionalAudio behave like a 2D audio source
|
161
|
+
// private _listener: AudioListener | null = null;
|
162
|
+
// private _originalSoundMatrixWorldFunction: Function | null = null;
|
163
|
+
// private _onSoundMatrixWorld = (force: boolean) => {
|
164
|
+
// if (this._spatialBlend > .05) {
|
165
|
+
// if (this._originalSoundMatrixWorldFunction) {
|
166
|
+
// this._originalSoundMatrixWorldFunction.call(this.sound, force);
|
167
|
+
// }
|
168
|
+
// }
|
169
|
+
// else {
|
170
|
+
// // we use another object's matrix world function (but bound to the positional audio)
|
171
|
+
// // this is just a little trick to prevent calling the PositionalAudio's updateMatrixWorld function
|
172
|
+
// this.gameObject.updateMatrixWorld?.call(this.sound, force);
|
173
|
+
// if (this.sound && this._listener) {
|
174
|
+
// this.sound.gain.connect(this._listener.listener.getInput());
|
175
|
+
// // const pos = getTempVector().setFromMatrixPosition(this._listener.gameObject.matrixWorld);
|
176
|
+
// // const ctx = this.sound.context;
|
177
|
+
// // const delay = this._listener.listener.timeDelta;
|
178
|
+
// // const time = ctx.currentTime ;
|
179
|
+
// // this.sound.panner.positionX.setValueAtTime(pos.x, time);
|
180
|
+
// // this.sound.panner.positionY.setValueAtTime(pos.y, time);
|
181
|
+
// // this.sound.panner.positionZ.setValueAtTime(pos.z, time);
|
182
|
+
// // this.sound.panner.orientationX.setValueAtTime(0, time);
|
183
|
+
// // this.sound.panner.orientationY.setValueAtTime(0, time);
|
184
|
+
// // this.sound.panner.orientationZ.setValueAtTime(-1, time);
|
185
|
+
// }
|
186
|
+
// }
|
187
|
+
// }
|
188
|
+
|
150
189
|
public get ShouldPlay(): boolean { return this.shouldPlay; }
|
151
190
|
|
191
|
+
/** Get the audio context from the Sound */
|
192
|
+
public get audioContext() {
|
193
|
+
return this.sound?.context;
|
194
|
+
}
|
152
195
|
|
153
196
|
awake() {
|
154
|
-
if(debug) console.log(this);
|
197
|
+
if (debug) console.log(this);
|
155
198
|
this.audioLoader = new AudioLoader();
|
156
199
|
if (this.playOnAwake) this.shouldPlay = true;
|
200
|
+
|
201
|
+
if (this.preload) {
|
202
|
+
if (typeof this.clip === "string") {
|
203
|
+
this.audioLoader.load(this.clip, this.createAudio, () => { }, console.error);
|
204
|
+
}
|
205
|
+
}
|
157
206
|
}
|
158
207
|
|
159
208
|
onEnable(): void {
|
209
|
+
if (this.sound)
|
210
|
+
this.gameObject.add(this.sound);
|
211
|
+
|
160
212
|
if (!AudioSource.userInteractionRegistered) {
|
161
213
|
AudioSource.registerWaitForAllowAudio(() => {
|
162
214
|
if (this.enabled && !this.destroyed && this.shouldPlay)
|
@@ -202,50 +254,56 @@
|
|
202
254
|
this.sound?.setVolume(this.volume);
|
203
255
|
}
|
204
256
|
|
205
|
-
private lerp = (x, y, a) => x * (1 - a) + y * a;
|
206
|
-
|
207
257
|
private createAudio = (buffer?: AudioBuffer) => {
|
208
|
-
if (debug) console.log("
|
209
|
-
AudioSource.registerWaitForAllowAudio(() => {
|
210
|
-
if (debug)
|
211
|
-
console.log("finished loading", buffer);
|
258
|
+
if (debug) console.log("AudioBuffer finished loading", buffer);
|
212
259
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
if (sound.isPlaying)
|
219
|
-
sound.stop();
|
260
|
+
const sound = this.Sound;
|
261
|
+
if (!sound) {
|
262
|
+
if (debug) console.warn("Failed getting sound?", this.name);
|
263
|
+
return;
|
264
|
+
}
|
220
265
|
|
221
|
-
|
222
|
-
|
223
|
-
sound.loop = this._loop;
|
224
|
-
if (this.context.application.muted) sound.setVolume(0);
|
225
|
-
else sound.setVolume(this.volume);
|
226
|
-
sound.autoplay = this.shouldPlay;
|
227
|
-
// sound.setDistanceModel('linear');
|
228
|
-
// sound.setRolloffFactor(1);
|
229
|
-
this.applySpatialDistanceSettings();
|
230
|
-
// sound.setDirectionalCone(180, 360, 0.1);
|
231
|
-
if (sound.isPlaying)
|
232
|
-
sound.stop();
|
266
|
+
if (sound.isPlaying)
|
267
|
+
sound.stop();
|
233
268
|
|
234
|
-
|
269
|
+
if (buffer) sound.setBuffer(buffer);
|
270
|
+
sound.loop = this._loop;
|
271
|
+
if (this.context.application.muted) sound.setVolume(0);
|
272
|
+
else sound.setVolume(this.volume);
|
273
|
+
sound.autoplay = this.shouldPlay && AudioSource.userInteractionRegistered;
|
235
274
|
|
236
|
-
|
237
|
-
|
238
|
-
|
275
|
+
this.applySpatialDistanceSettings();
|
276
|
+
|
277
|
+
if (sound.isPlaying)
|
278
|
+
sound.stop();
|
279
|
+
|
280
|
+
// const src = sound.context.createBufferSource();
|
281
|
+
// src.buffer = sound.buffer;
|
282
|
+
// src.connect(sound.panner);
|
283
|
+
// src.start(this.audioContext?.currentTime);
|
284
|
+
// const gain = sound.context.createGain();
|
285
|
+
// gain.gain.value = 1 - this.spatialBlend;
|
286
|
+
// src.connect(gain);
|
287
|
+
|
288
|
+
// make sure we only play the sound if the user has interacted with the page
|
289
|
+
AudioSource.registerWaitForAllowAudio(this.__onAllowAudioCallback);
|
239
290
|
}
|
291
|
+
private __onAllowAudioCallback = () => {
|
292
|
+
if (this.shouldPlay)
|
293
|
+
this.play();
|
294
|
+
}
|
240
295
|
|
241
296
|
private applySpatialDistanceSettings() {
|
242
297
|
const sound = this.sound;
|
243
298
|
if (!sound) return;
|
244
299
|
this._needUpdateSpatialDistanceSettings = false;
|
245
|
-
const dist =
|
300
|
+
const dist = Mathf.lerp(10 * this._maxDistance / Math.max(0.0001, this.spatialBlend), this._minDistance, this.spatialBlend);
|
246
301
|
if (debug) console.log(this.name, this._minDistance, this._maxDistance, this.spatialBlend, "Ref distance=" + dist);
|
247
302
|
sound.setRefDistance(dist);
|
248
303
|
sound.setMaxDistance(Math.max(0.01, this._maxDistance));
|
304
|
+
// sound.setRolloffFactor(this.spatialBlend);
|
305
|
+
// sound.panner.positionZ.automationRate
|
306
|
+
|
249
307
|
// https://developer.mozilla.org/en-US/docs/Web/API/PannerNode/distanceModel
|
250
308
|
switch (this.rollOffMode) {
|
251
309
|
case AudioRolloffMode.Logarithmic:
|
@@ -269,7 +327,7 @@
|
|
269
327
|
}
|
270
328
|
}
|
271
329
|
|
272
|
-
private onNewClip(clip?: string | MediaStream) {
|
330
|
+
private async onNewClip(clip?: string | MediaStream) {
|
273
331
|
if (clip) this.clip = clip;
|
274
332
|
if (typeof clip === "string") {
|
275
333
|
if (debug)
|
@@ -285,7 +343,10 @@
|
|
285
343
|
this._lastClipStartedLoading = clip;
|
286
344
|
if (debug)
|
287
345
|
console.log("load audio", clip);
|
288
|
-
this.audioLoader.
|
346
|
+
const buffer = await this.audioLoader.loadAsync(clip).catch(console.error);
|
347
|
+
this._lastClipStartedLoading = null;
|
348
|
+
if (buffer)
|
349
|
+
this.createAudio(buffer);
|
289
350
|
}
|
290
351
|
else console.warn("Unsupported audio clip type", clip)
|
291
352
|
}
|
@@ -328,6 +389,7 @@
|
|
328
389
|
if (this.sound && !this.sound.isPlaying) {
|
329
390
|
const muted = this.context.application.muted;
|
330
391
|
if (muted) this.sound.setVolume(0);
|
392
|
+
this.gameObject?.add(this.sound);
|
331
393
|
|
332
394
|
if (this.clip instanceof MediaStream) {
|
333
395
|
|
@@ -411,7 +473,7 @@
|
|
411
473
|
this._hasEnded = true;
|
412
474
|
if (debug)
|
413
475
|
console.log("Audio clip ended", this.clip);
|
414
|
-
this.
|
476
|
+
this.dispatchEvent(new CustomEvent("ended", { detail: this }));
|
415
477
|
}
|
416
478
|
|
417
479
|
// this.gameObject.position.x = Math.sin(time.time) * 2;
|
@@ -1,11 +1,12 @@
|
|
1
1
|
import * as THREE from "three";
|
2
|
+
|
3
|
+
import { OwnershipModel } from "../../engine/engine_networking.js";
|
4
|
+
import type { IModel } from "../../engine/engine_networking_types.js";
|
5
|
+
import { Context } from "../../engine/engine_setup.js";
|
6
|
+
import * as utils from "../../engine/engine_three_utils.js";
|
2
7
|
import { TypeStore } from "../../engine/engine_typestore.js";
|
3
8
|
import { Behaviour, GameObject } from "../Component.js";
|
4
9
|
import { AvatarMarker } from "../webxr/WebXRAvatar.js";
|
5
|
-
import * as utils from "../../engine/engine_three_utils.js";
|
6
|
-
import { OwnershipModel } from "../../engine/engine_networking.js";
|
7
|
-
import { Context } from "../../engine/engine_setup.js";
|
8
|
-
import type { IModel } from "../../engine/engine_networking_types.js";
|
9
10
|
|
10
11
|
export class Avatar_POI {
|
11
12
|
|
@@ -1,9 +1,10 @@
|
|
1
|
+
import { Object3D } from "three";
|
2
|
+
|
3
|
+
import { serializable } from "../../engine/engine_serialization_decorator.js";
|
4
|
+
import * as utils from "../../engine/engine_utils.js";
|
1
5
|
import { Behaviour, GameObject } from "../Component.js";
|
2
6
|
import { Voip } from "../Voip.js";
|
3
7
|
import { AvatarMarker } from "../webxr/WebXRAvatar.js";
|
4
|
-
import * as utils from "../../engine/engine_utils.js";
|
5
|
-
import { Object3D } from "three";
|
6
|
-
import { serializable } from "../../engine/engine_serialization_decorator.js";
|
7
8
|
|
8
9
|
const debug = utils.getParam("debugmouth");
|
9
10
|
|
@@ -1,7 +1,8 @@
|
|
1
1
|
import { Object3D } from "three";
|
2
|
+
|
3
|
+
import { serializable } from "../../engine/engine_serialization_decorator.js";
|
2
4
|
import { Behaviour, GameObject } from "../Component.js";
|
3
|
-
import { XRFlag, XRState } from "../XRFlag.js";
|
4
|
-
import { serializable } from "../../engine/engine_serialization_decorator.js";
|
5
|
+
import { XRFlag, XRState } from "../webxr/XRFlag.js";
|
5
6
|
|
6
7
|
|
7
8
|
export class AvatarBlink_Simple extends Behaviour {
|
@@ -1,10 +1,11 @@
|
|
1
|
-
import { Behaviour, GameObject } from "../Component.js";
|
2
|
-
import * as utils from "../../engine/engine_three_utils.js"
|
3
1
|
import * as THREE from "three";
|
4
|
-
import { Avatar_Brain_LookAt } from "./Avatar_Brain_LookAt.js";
|
5
|
-
import { serializable } from "../../engine/engine_serialization_decorator.js";
|
6
2
|
import { Object3D } from "three";
|
7
3
|
|
4
|
+
import { serializable } from "../../engine/engine_serialization_decorator.js";
|
5
|
+
import * as utils from "../../engine/engine_three_utils.js"
|
6
|
+
import { Behaviour, GameObject } from "../Component.js";
|
7
|
+
import { Avatar_Brain_LookAt } from "./Avatar_Brain_LookAt.js";
|
8
|
+
|
8
9
|
export class AvatarEyeLook_Rotation extends Behaviour {
|
9
10
|
|
10
11
|
@serializable(Object3D)
|
@@ -1,12 +1,13 @@
|
|
1
|
+
import { Box3, Object3D, Vector3 } from "three";
|
1
2
|
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
2
|
-
|
3
|
+
|
4
|
+
import { InstantiateOptions } from "../engine/engine_gameobject.js";
|
5
|
+
import { getLoader } from "../engine/engine_gltf.js";
|
3
6
|
import * as loaders from "../engine/engine_loaders.js"
|
4
7
|
import { Context } from "../engine/engine_setup.js";
|
8
|
+
import * as utils from "../engine/engine_utils.js"
|
9
|
+
import { download_file } from "../engine/engine_web_api.js";
|
5
10
|
import { GameObject } from "./Component.js";
|
6
|
-
import { download_file } from "../engine/engine_web_api.js";
|
7
|
-
import { getLoader } from "../engine/engine_gltf.js";
|
8
|
-
import { InstantiateOptions } from "../engine/engine_gameobject.js";
|
9
|
-
import { Box3, Object3D, Vector3 } from "three";
|
10
11
|
|
11
12
|
const debug = utils.getParam("debugavatar");
|
12
13
|
|
@@ -1,7 +1,8 @@
|
|
1
|
-
import {
|
1
|
+
import { AxesHelper as _AxesHelper } from "three";
|
2
|
+
|
2
3
|
import * as params from "../engine/engine_default_parameters.js";
|
3
4
|
import { serializable } from "../engine/engine_serialization_decorator.js";
|
4
|
-
import {
|
5
|
+
import { Behaviour } from "./Component.js";
|
5
6
|
|
6
7
|
export class AxesHelper extends Behaviour {
|
7
8
|
@serializable()
|
@@ -1,11 +1,12 @@
|
|
1
1
|
// import { Canvas } from './Canvas.js';
|
2
|
+
import { AxesHelper, Object3D } from 'three';
|
2
3
|
import * as ThreeMeshUI from 'three-mesh-ui';
|
4
|
+
|
5
|
+
import { showGizmos } from '../../engine/engine_default_parameters.js';
|
6
|
+
import { getParam } from '../../engine/engine_utils.js';
|
3
7
|
import { Behaviour, GameObject } from "../Component.js";
|
4
8
|
import { EventSystem } from "./EventSystem.js";
|
5
|
-
import { showGizmos } from '../../engine/engine_default_parameters.js';
|
6
|
-
import { AxesHelper, Object3D } from 'three';
|
7
9
|
import type { ICanvas } from './Interfaces.js';
|
8
|
-
import { getParam } from '../../engine/engine_utils.js';
|
9
10
|
export const includesDir = "./include";
|
10
11
|
|
11
12
|
const debug = getParam("debugshadowcomponents");
|
@@ -24,22 +25,38 @@
|
|
24
25
|
|
25
26
|
export const $shadowDomOwner = Symbol("shadowDomOwner");
|
26
27
|
|
28
|
+
/** Derive from this class if you want to implement your own UI components
|
29
|
+
* It provides utility methods and simplifies managing the underlying three-mesh-ui hierarchy
|
30
|
+
*/
|
27
31
|
export class BaseUIComponent extends Behaviour {
|
28
32
|
|
33
|
+
/** Is this object on the root of the UI hierarchy ? */
|
29
34
|
isRoot() { return this.Root?.gameObject === this.gameObject; }
|
30
35
|
|
36
|
+
/** Access the parent canvas component */
|
31
37
|
get canvas() {
|
32
38
|
const cv = this.Root as any as ICanvas;
|
33
39
|
if (cv?.isCanvas) return cv;
|
34
40
|
return null;
|
35
41
|
}
|
42
|
+
/** @deprecated use `canvas` */
|
43
|
+
protected get Canvas() {
|
44
|
+
return this.canvas;
|
45
|
+
}
|
36
46
|
|
47
|
+
/** Mark the UI dirty which will trigger an THREE-Mesh-UI update */
|
37
48
|
markDirty() {
|
38
49
|
EventSystem.markUIDirty(this.context);
|
39
50
|
}
|
40
51
|
|
41
|
-
|
52
|
+
/** the underlying three-mesh-ui */
|
53
|
+
get shadowComponent() { return this._shadowComponent }
|
54
|
+
private set shadowComponent(val: Object3D | null) {
|
55
|
+
this._shadowComponent = val;
|
56
|
+
}
|
42
57
|
|
58
|
+
private _shadowComponent: Object3D | null = null;
|
59
|
+
|
43
60
|
private _controlsChildLayout = true;
|
44
61
|
get controlsChildLayout(): boolean { return this._controlsChildLayout; }
|
45
62
|
set controlsChildLayout(val: boolean) {
|
@@ -58,11 +75,6 @@
|
|
58
75
|
return this._root;
|
59
76
|
}
|
60
77
|
|
61
|
-
// TODO: rename to canvas
|
62
|
-
protected get Canvas() {
|
63
|
-
return this.canvas;
|
64
|
-
}
|
65
|
-
|
66
78
|
// private _intermediate?: Object3D;
|
67
79
|
protected _parentComponent?: BaseUIComponent | null = undefined;
|
68
80
|
|
@@ -77,7 +89,10 @@
|
|
77
89
|
super.onEnable();
|
78
90
|
}
|
79
91
|
|
80
|
-
|
92
|
+
/** Add a three-mesh-ui object to the UI hierarchy
|
93
|
+
* @param container the three-mesh-ui object to add
|
94
|
+
* @param parent the parent component to add the object to
|
95
|
+
*/
|
81
96
|
protected addShadowComponent(container: any, parent?: BaseUIComponent) {
|
82
97
|
|
83
98
|
this.removeShadowComponent();
|
@@ -134,21 +149,7 @@
|
|
134
149
|
if(debug) console.log(this.shadowComponent)
|
135
150
|
}
|
136
151
|
|
137
|
-
|
138
|
-
set(_state: object) {
|
139
|
-
// if (!this.shadowComponent) return;
|
140
|
-
// this.traverseOwnedShadowComponents(this.shadowComponent, this, o => {
|
141
|
-
// for (const ch of o.children) {
|
142
|
-
// console.log(this, ch);
|
143
|
-
// if (ch.isUI && typeof ch.set === "function") {
|
144
|
-
// // ch.set(state);
|
145
|
-
// // ch.update(true, true, true);
|
146
|
-
// }
|
147
|
-
// }
|
148
|
-
// })
|
149
|
-
}
|
150
|
-
|
151
|
-
protected setShadowComponentOwner(current: Object3D | null | undefined) {
|
152
|
+
protected setShadowComponentOwner(current: ThreeMeshUI.MeshUIBaseElement | Object3D | null | undefined) {
|
152
153
|
if (!current) return;
|
153
154
|
// TODO: only traverse our own hierarchy, we can stop if we find another owner
|
154
155
|
if (current[$shadowDomOwner] === undefined || current[$shadowDomOwner] === this) {
|
@@ -171,6 +172,7 @@
|
|
171
172
|
}
|
172
173
|
}
|
173
174
|
|
175
|
+
/** Remove the underlying UI object from the hierarchy */
|
174
176
|
protected removeShadowComponent() {
|
175
177
|
if (this.shadowComponent) {
|
176
178
|
this.shadowComponent.removeFromParent();
|
@@ -1,7 +1,8 @@
|
|
1
|
-
import { Behaviour, GameObject } from "./Component.js";
|
2
|
-
import * as utils from "./../engine/engine_three_utils.js";
|
3
1
|
import { Vector3 } from "three";
|
4
2
|
|
3
|
+
import * as utils from "./../engine/engine_three_utils.js";
|
4
|
+
import { Behaviour, GameObject } from "./Component.js";
|
5
|
+
|
5
6
|
export class BasicIKConstraint extends Behaviour {
|
6
7
|
|
7
8
|
private from!: GameObject;
|
@@ -1,8 +1,8 @@
|
|
1
|
+
import { getParam } from "../../../../../engine/engine_utils.js";
|
1
2
|
import { GameObject } from "../../../../Component.js";
|
2
3
|
import type { IUSDExporterExtension } from "../../Extension.js";
|
3
4
|
import { USDObject, USDWriter, USDZExporterContext } from "../../ThreeUSDZExporter.js";
|
4
5
|
import { BehaviorModel } from "./BehavioursBuilder.js";
|
5
|
-
import { getParam } from "../../../../../engine/engine_utils.js";
|
6
6
|
|
7
7
|
const debug = getParam("debugusdz");
|
8
8
|
|
@@ -1,21 +1,20 @@
|
|
1
|
+
import { Group,Material, Mesh, Object3D, Quaternion, Vector3 } from "three";
|
2
|
+
|
3
|
+
import { isDevEnvironment, showBalloonWarning } from "../../../../../engine/debug/index.js";
|
4
|
+
import { serializable } from "../../../../../engine/engine_serialization_decorator.js";
|
5
|
+
import { getWorldPosition, getWorldQuaternion, getWorldScale, setWorldPosition, setWorldQuaternion, setWorldScale } from "../../../../../engine/engine_three_utils.js";
|
6
|
+
import type { State } from "../../../../../engine/extensions/NEEDLE_animator_controller_model.js";
|
7
|
+
import { NEEDLE_progressive } from "../../../../../engine/extensions/NEEDLE_progressive.js";
|
8
|
+
import { Animator } from "../../../../Animator.js";
|
9
|
+
import { AudioSource } from "../../../../AudioSource.js";
|
1
10
|
import { Behaviour, GameObject } from "../../../../Component.js";
|
2
|
-
import { Animator } from "../../../../Animator.js";
|
3
11
|
import { Renderer } from "../../../../Renderer.js";
|
4
|
-
import { serializable } from "../../../../../engine/engine_serialization_decorator.js";
|
5
12
|
import type { IPointerClickHandler, PointerEventData } from "../../../../ui/PointerEvents.js";
|
13
|
+
import { ObjectRaycaster,Raycaster } from "../../../../ui/Raycaster.js";
|
14
|
+
import { USDDocument, USDObject, USDZExporterContext } from "../../ThreeUSDZExporter.js";
|
6
15
|
import { AnimationExtension, RegisteredAnimationInfo, type UsdzAnimation } from "../Animation.js";
|
7
|
-
import { getWorldPosition, getWorldQuaternion, getWorldScale, setWorldPosition, setWorldQuaternion, setWorldScale } from "../../../../../engine/engine_three_utils.js";
|
8
|
-
|
9
|
-
import { Object3D, Material, Vector3, Quaternion, Mesh, Group } from "three";
|
10
|
-
import { USDDocument, USDObject, USDZExporterContext } from "../../ThreeUSDZExporter.js";
|
11
|
-
|
12
16
|
import type { BehaviorExtension, UsdzBehaviour } from "./Behaviour.js";
|
13
|
-
import { ActionBuilder, ActionModel, AuralMode, BehaviorModel, type IBehaviorElement, MotionType, PlayAction, Space, TriggerBuilder
|
14
|
-
import { AudioSource } from "../../../../AudioSource.js";
|
15
|
-
import { NEEDLE_progressive } from "../../../../../engine/extensions/NEEDLE_progressive.js";
|
16
|
-
import { isDevEnvironment, showBalloonWarning } from "../../../../../engine/debug/index.js";
|
17
|
-
import { Raycaster, ObjectRaycaster } from "../../../../ui/Raycaster.js";
|
18
|
-
import type { State } from "../../../../../engine/extensions/NEEDLE_animator_controller_model.js";
|
17
|
+
import { ActionBuilder, ActionModel, AuralMode, BehaviorModel, GroupActionModel, type IBehaviorElement, MotionType, MultiplePerformOperation,PlayAction, Space, TriggerBuilder } from "./BehavioursBuilder.js";
|
19
18
|
|
20
19
|
function ensureRaycaster(obj: GameObject) {
|
21
20
|
if (!obj) return;
|
@@ -1,8 +1,8 @@
|
|
1
1
|
import { Object3D } from "three";
|
2
|
-
import { USDDocument, USDObject, USDWriter, makeNameSafeForUSD } from "../../ThreeUSDZExporter.js";
|
3
2
|
|
3
|
+
import { getParam } from "../../../../../engine/engine_utils.js";
|
4
|
+
import { makeNameSafeForUSD,USDDocument, USDObject, USDWriter } from "../../ThreeUSDZExporter.js";
|
4
5
|
import { BehaviorExtension } from "./Behaviour.js";
|
5
|
-
import { getParam } from "../../../../../engine/engine_utils.js";
|
6
6
|
|
7
7
|
const debug = getParam("debugusdz");
|
8
8
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import { BlendFunction, BloomEffect, SelectiveBloomEffect } from "postprocessing";
|
2
|
+
|
2
3
|
import { serializable } from "../../../engine/engine_serialization.js";
|
3
4
|
import { PostProcessingEffect } from "../PostProcessingEffect.js";
|
4
5
|
import { VolumeParameter } from "../VolumeParameter.js";
|
@@ -1,8 +1,9 @@
|
|
1
|
-
import {
|
2
|
-
|
1
|
+
import { Box3, Color, type ColorRepresentation, LineSegments, Object3D, Vector3 } from "three";
|
2
|
+
|
3
3
|
import { CreateWireCube, Gizmos } from "../engine/engine_gizmos.js";
|
4
4
|
import { getWorldPosition, getWorldScale } from "../engine/engine_three_utils.js";
|
5
|
-
import {
|
5
|
+
import { getParam } from "../engine/engine_utils.js";
|
6
|
+
import { Behaviour } from "./Component.js";
|
6
7
|
|
7
8
|
const gizmos = getParam("gizmos");
|
8
9
|
const debug = getParam("debugboxhelper");
|
@@ -1,15 +1,15 @@
|
|
1
|
+
import { showBalloonMessage } from "../../engine/debug/index.js";
|
2
|
+
import { Gizmos } from "../../engine/engine_gizmos.js";
|
3
|
+
import { PointerType } from "../../engine/engine_input.js";
|
4
|
+
import { serializable } from "../../engine/engine_serialization_decorator.js";
|
5
|
+
import { getParam } from "../../engine/engine_utils.js";
|
6
|
+
import { Animator } from "../Animator.js";
|
1
7
|
import { Behaviour, GameObject } from "../Component.js";
|
2
8
|
import { EventList } from "../EventList.js";
|
9
|
+
import { RGBAColor } from "../js-extensions/RGBAColor.js";
|
10
|
+
import { Image } from "./Image.js";
|
3
11
|
import type { IPointerClickHandler, IPointerEnterHandler, IPointerEventHandler, IPointerExitHandler, PointerEventData } from "./PointerEvents.js";
|
4
|
-
import { Image } from "./Image.js";
|
5
|
-
import { RGBAColor } from "../js-extensions/RGBAColor.js";
|
6
|
-
import { serializable } from "../../engine/engine_serialization_decorator.js";
|
7
|
-
import { Animator } from "../Animator.js";
|
8
|
-
import { getParam } from "../../engine/engine_utils.js";
|
9
|
-
import { showBalloonMessage } from "../../engine/debug/index.js";
|
10
12
|
import { GraphicRaycaster, ObjectRaycaster, Raycaster } from "./Raycaster.js";
|
11
|
-
import { PointerType } from "../../engine/engine_input.js";
|
12
|
-
import { Gizmos } from "../../engine/engine_gizmos.js";
|
13
13
|
|
14
14
|
const debug = getParam("debugbutton");
|
15
15
|
|
@@ -65,12 +65,12 @@
|
|
65
65
|
@serializable(EventList)
|
66
66
|
onClick?: EventList;
|
67
67
|
|
68
|
-
private _isHovered:
|
68
|
+
private _isHovered: number = 0;
|
69
69
|
|
70
70
|
onPointerEnter(_) {
|
71
|
+
this._isHovered += 1;
|
71
72
|
if (debug)
|
72
|
-
console.
|
73
|
-
this._isHovered = true;
|
73
|
+
console.warn("Button Enter", this._isHovered, this.animationTriggers?.highlightedTrigger, this.animator);
|
74
74
|
if (!this.interactable) return;
|
75
75
|
if (this.transition == Transition.Animation && this.animationTriggers && this.animator) {
|
76
76
|
this.animator.setTrigger(this.animationTriggers.highlightedTrigger);
|
@@ -82,10 +82,12 @@
|
|
82
82
|
}
|
83
83
|
|
84
84
|
onPointerExit() {
|
85
|
+
this._isHovered -= 1;
|
85
86
|
if (debug)
|
86
|
-
console.log("Button Exit", this.animationTriggers?.highlightedTrigger, this.animator);
|
87
|
-
this._isHovered = false;
|
87
|
+
console.log("Button Exit", this._isHovered, this.animationTriggers?.highlightedTrigger, this.animator);
|
88
88
|
if (!this.interactable) return;
|
89
|
+
if (this._isHovered > 0) return;
|
90
|
+
this._isHovered = 0;
|
89
91
|
if (this.transition == Transition.Animation && this.animationTriggers && this.animator) {
|
90
92
|
this.animator.setTrigger(this.animationTriggers.normalTrigger);
|
91
93
|
}
|
@@ -120,10 +122,10 @@
|
|
120
122
|
}
|
121
123
|
|
122
124
|
onPointerClick(args: PointerEventData) {
|
123
|
-
if (!this.interactable
|
125
|
+
if (!this.interactable) return;
|
124
126
|
|
127
|
+
if (args.button !== 0 && args.event.pointerType === PointerType.Mouse) return;
|
125
128
|
// Button clicks should only run with left mouse button while using mouse
|
126
|
-
if(args.pointerId !== 0 && this.context.input.getIsMouse(args.pointerId)) return;
|
127
129
|
if (debug) {
|
128
130
|
console.warn("Button Click", this.onClick);
|
129
131
|
showBalloonMessage("CLICKED button " + this.name + " at " + this.context.time.frameCount);
|
@@ -1,17 +1,17 @@
|
|
1
|
+
import { EquirectangularReflectionMapping, OrthographicCamera, PerspectiveCamera, Ray, SRGBColorSpace, Vector3 } from "three";
|
2
|
+
import { Texture } from "three";
|
3
|
+
|
4
|
+
import { isDevEnvironment, showBalloonMessage, showBalloonWarning } from "../engine/debug/index.js";
|
5
|
+
import { Gizmos } from "../engine/engine_gizmos.js";
|
6
|
+
import { serializable } from "../engine/engine_serialization_decorator.js";
|
7
|
+
import { Context } from "../engine/engine_setup.js";
|
8
|
+
import { RenderTexture } from "../engine/engine_texture.js";
|
9
|
+
import { getWorldPosition } from "../engine/engine_three_utils.js";
|
10
|
+
import type { ICamera } from "../engine/engine_types.js"
|
11
|
+
import { getParam } from "../engine/engine_utils.js";
|
1
12
|
import { Behaviour, GameObject } from "./Component.js";
|
2
|
-
import { getParam } from "../engine/engine_utils.js";
|
3
|
-
import { serializable } from "../engine/engine_serialization_decorator.js";
|
4
13
|
import { RGBAColor } from "./js-extensions/RGBAColor.js";
|
5
|
-
import { Context, XRSessionMode } from "../engine/engine_setup.js";
|
6
|
-
import type { ICamera } from "../engine/engine_types.js"
|
7
|
-
import { isDevEnvironment, showBalloonMessage, showBalloonWarning } from "../engine/debug/index.js";
|
8
|
-
import { getWorldPosition } from "../engine/engine_three_utils.js";
|
9
|
-
import { Gizmos } from "../engine/engine_gizmos.js";
|
10
|
-
|
11
|
-
import { EquirectangularReflectionMapping, OrthographicCamera, PerspectiveCamera, Ray, SRGBColorSpace, Vector3 } from "three";
|
12
14
|
import { OrbitControls } from "./OrbitControls.js";
|
13
|
-
import { RenderTexture } from "../engine/engine_texture.js";
|
14
|
-
import { Texture } from "three";
|
15
15
|
|
16
16
|
export enum ClearFlags {
|
17
17
|
Skybox = 1,
|
@@ -350,7 +350,6 @@
|
|
350
350
|
if (this._backgroundBlurriness !== undefined)
|
351
351
|
this.context.scene.backgroundBlurriness = this._backgroundBlurriness;
|
352
352
|
if (this._backgroundIntensity !== undefined)
|
353
|
-
//@ts-ignore
|
354
353
|
this.context.scene.backgroundIntensity = this._backgroundIntensity;
|
355
354
|
|
356
355
|
break;
|
@@ -392,7 +391,7 @@
|
|
392
391
|
if (debug)
|
393
392
|
showBalloonMessage("Environment blend mode: " + environmentBlendMode + " on " + navigator.userAgent);
|
394
393
|
let transparent = environmentBlendMode === 'additive' || environmentBlendMode === 'alpha-blend';
|
395
|
-
if (context.
|
394
|
+
if (context.isInAR) {
|
396
395
|
if (environmentBlendMode === "opaque") {
|
397
396
|
// workaround for Quest 2 returning opaque when it should be alpha-blend
|
398
397
|
// check user agent if this is the Quest browser and return true if so
|
@@ -1,14 +1,15 @@
|
|
1
|
-
import {
|
1
|
+
import { Object3D } from "three";
|
2
|
+
|
3
|
+
import { getCameraController } from "../engine/engine_camera.js";
|
2
4
|
import { addNewComponent, getOrAddComponent } from "../engine/engine_components.js";
|
3
|
-
import {
|
4
|
-
import type { ICamera, IContext } from "../engine/engine_types.js";
|
5
|
-
import { RGBAColor } from "./js-extensions/RGBAColor.js";
|
5
|
+
import { Context } from "../engine/engine_context.js";
|
6
6
|
import { ContextEvent, ContextRegistry } from "../engine/engine_context_registry.js";
|
7
|
-
import { getCameraController } from "../engine/engine_camera.js";
|
8
|
-
import { Camera, ClearFlags } from "./Camera.js";
|
9
7
|
import { NeedleEngineHTMLElement } from "../engine/engine_element.js";
|
8
|
+
import type { ICamera, IContext } from "../engine/engine_types.js";
|
10
9
|
import { getParam } from "../engine/engine_utils.js";
|
11
|
-
import {
|
10
|
+
import { Camera, ClearFlags } from "./Camera.js";
|
11
|
+
import { RGBAColor } from "./js-extensions/RGBAColor.js";
|
12
|
+
import { OrbitControls } from "./OrbitControls.js";
|
12
13
|
|
13
14
|
const debug = getParam("debugmissingcamera");
|
14
15
|
|
@@ -1,17 +1,19 @@
|
|
1
|
-
import {
|
1
|
+
import { Matrix4, Object3D } from "three";
|
2
|
+
import * as ThreeMeshUI from 'three-mesh-ui'
|
3
|
+
|
4
|
+
import { Mathf } from "../../engine/engine_math.js";
|
2
5
|
import { serializable } from "../../engine/engine_serialization_decorator.js";
|
3
6
|
import { FrameEvent } from "../../engine/engine_setup.js";
|
7
|
+
import { delayForFrames, getParam } from "../../engine/engine_utils.js";
|
8
|
+
import { NeedleXREventArgs } from "../../engine/xr/index.js";
|
9
|
+
import { Camera } from "../Camera.js";
|
10
|
+
import { GameObject } from "../Component.js";
|
4
11
|
import { BaseUIComponent, UIRootComponent } from "./BaseUIComponent.js";
|
5
|
-
import {
|
6
|
-
import { Matrix4, Object3D } from "three";
|
7
|
-
import { RectTransform } from "./RectTransform.js";
|
12
|
+
import { EventSystem } from "./EventSystem.js";
|
8
13
|
import type { ICanvas, ICanvasEventReceiver, ILayoutGroup, IRectTransform } from "./Interfaces.js";
|
9
|
-
import { Camera } from "../Camera.js";
|
10
|
-
import { EventSystem } from "./EventSystem.js";
|
11
|
-
import * as ThreeMeshUI from 'three-mesh-ui'
|
12
|
-
import { getParam } from "../../engine/engine_utils.js";
|
13
14
|
import { LayoutGroup } from "./Layout.js";
|
14
|
-
import {
|
15
|
+
import { RectTransform } from "./RectTransform.js";
|
16
|
+
import { updateRenderSettings as updateRenderSettingsRecursive } from "./Utils.js";
|
15
17
|
|
16
18
|
export enum RenderMode {
|
17
19
|
ScreenSpaceOverlay = 0,
|
@@ -200,19 +202,37 @@
|
|
200
202
|
}
|
201
203
|
}
|
202
204
|
|
205
|
+
async onEnterXR(args: NeedleXREventArgs) {
|
206
|
+
// workaround for https://linear.app/needle/issue/NE-4114
|
207
|
+
if (this.screenspace) {
|
208
|
+
if (args.xr.isVR || args.xr.isPassThrough) {
|
209
|
+
this.gameObject.visible = false;
|
210
|
+
}
|
211
|
+
}
|
212
|
+
else {
|
213
|
+
this.gameObject.visible = false;
|
214
|
+
await delayForFrames(1).then(()=>{
|
215
|
+
this.gameObject.visible = true;
|
216
|
+
});
|
217
|
+
}
|
218
|
+
}
|
219
|
+
onLeaveXR(args: NeedleXREventArgs): void {
|
220
|
+
if (this.screenspace) {
|
221
|
+
if (args.xr.isVR || args.xr.isPassThrough) {
|
222
|
+
this.gameObject.visible = true;
|
223
|
+
}
|
224
|
+
}
|
225
|
+
}
|
226
|
+
|
203
227
|
onBeforeRenderRoutine = () => {
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
this.
|
209
|
-
this.shadowComponent?.updateWorldMatrix(true, true);
|
210
|
-
this.invokeBeforeRenderEvents();
|
211
|
-
EventSystem.ensureUpdateMeshUI(ThreeMeshUI, this.context, true);
|
228
|
+
this.previousParent = this.gameObject.parent;
|
229
|
+
if ((this.context.xr?.isVR || this.context.xr?.isPassThrough) && this.screenspace) {
|
230
|
+
// see https://linear.app/needle/issue/NE-4114
|
231
|
+
this.gameObject.visible = false;
|
232
|
+
this.gameObject.removeFromParent();
|
212
233
|
return;
|
213
234
|
}
|
214
235
|
|
215
|
-
this.previousParent = this.gameObject.parent;
|
216
236
|
// console.log(this.previousParent?.name + "/" + this.gameObject.name);
|
217
237
|
|
218
238
|
if (this.renderOnTop || this.screenspace) {
|
@@ -231,7 +251,12 @@
|
|
231
251
|
}
|
232
252
|
|
233
253
|
onAfterRenderRoutine = () => {
|
234
|
-
if(this.context.
|
254
|
+
if ((this.context.xr?.isVR || this.context.xr?.isPassThrough) && this.screenspace) {
|
255
|
+
this.previousParent?.add(this.gameObject);
|
256
|
+
// this is currently causing an error during XR (https://linear.app/needle/issue/NE-4114)
|
257
|
+
// this.gameObject.visible = true;
|
258
|
+
return;
|
259
|
+
}
|
235
260
|
if ((this.screenspace || this.renderOnTop) && this.previousParent && this.context.mainCamera) {
|
236
261
|
if (this.screenspace) {
|
237
262
|
const camObj = this.context.mainCamera;
|
@@ -276,7 +301,7 @@
|
|
276
301
|
for (const ch of this._rectTransforms) {
|
277
302
|
if (matrixWorldChanged) ch.markDirty();
|
278
303
|
let layout = this._layoutGroups.get(ch.gameObject);
|
279
|
-
if(ch.isDirty && !layout){
|
304
|
+
if (ch.isDirty && !layout) {
|
280
305
|
layout = ch.gameObject.getComponentInParent(LayoutGroup) as LayoutGroup;
|
281
306
|
}
|
282
307
|
if (ch.isDirty || layout?.isDirty) {
|
@@ -1,9 +1,9 @@
|
|
1
|
-
import {
|
1
|
+
import { serializable } from "../../engine/engine_serialization_decorator.js";
|
2
2
|
import { FrameEvent } from "../../engine/engine_setup.js";
|
3
3
|
import { Behaviour, GameObject } from "../Component.js";
|
4
|
+
import { BaseUIComponent } from "./BaseUIComponent.js";
|
5
|
+
import { Graphic } from "./Graphic.js";
|
4
6
|
import { type ICanvasGroup, type IHasAlphaFactor } from "./Interfaces.js";
|
5
|
-
import { serializable } from "../../engine/engine_serialization_decorator.js";
|
6
|
-
import { BaseUIComponent } from "./BaseUIComponent.js";
|
7
7
|
|
8
8
|
|
9
9
|
export class CanvasGroup extends Behaviour implements ICanvasGroup {
|
@@ -1,14 +1,15 @@
|
|
1
1
|
import { Quaternion, Ray, Vector2, Vector3 } from "three";
|
2
|
+
|
2
3
|
import { Mathf } from "../engine/engine_math.js";
|
4
|
+
import { RaycastOptions } from "../engine/engine_physics.js";
|
3
5
|
import { serializable } from "../engine/engine_serialization.js";
|
6
|
+
import { getWorldPosition } from "../engine/engine_three_utils.js";
|
4
7
|
import { Collision } from "../engine/engine_types.js";
|
8
|
+
import { getParam } from "../engine/engine_utils.js";
|
9
|
+
import { Animator } from "./Animator.js"
|
5
10
|
import { CapsuleCollider } from "./Collider.js";
|
6
11
|
import { Behaviour, GameObject } from "./Component.js";
|
7
12
|
import { Rigidbody } from "./RigidBody.js";
|
8
|
-
import { Animator } from "./Animator.js"
|
9
|
-
import { RaycastOptions } from "../engine/engine_physics.js";
|
10
|
-
import { getWorldPosition } from "../engine/engine_three_utils.js";
|
11
|
-
import { getParam } from "../engine/engine_utils.js";
|
12
13
|
|
13
14
|
const debug = getParam("debugcharactercontroller");
|
14
15
|
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import { ChromaticAberrationEffect } from "postprocessing";
|
2
2
|
import { Vector2 } from "three";
|
3
|
+
|
3
4
|
import { serializable } from "../../../engine/engine_serialization.js";
|
4
5
|
import { type EffectProviderResult, PostProcessingEffect } from "../PostProcessingEffect.js";
|
5
6
|
import { VolumeParameter } from "../VolumeParameter.js";
|
@@ -1,13 +1,14 @@
|
|
1
|
-
import {
|
2
|
-
|
1
|
+
import { Group, Mesh, Vector3 } from "three"
|
2
|
+
|
3
|
+
import type { PhysicsMaterial } from "../engine/engine_physics.types.js";
|
3
4
|
import { serializable } from "../engine/engine_serialization_decorator.js";
|
4
|
-
import {
|
5
|
+
import { getWorldScale } from "../engine/engine_three_utils.js";
|
5
6
|
// import { IColliderProvider, registerColliderProvider } from "../engine/engine_physics.js";
|
6
7
|
import type { IBoxCollider, ICollider, ISphereCollider } from "../engine/engine_types.js";
|
7
|
-
import { getWorldScale } from "../engine/engine_three_utils.js";
|
8
|
-
import type { PhysicsMaterial } from "../engine/engine_physics.types.js";
|
9
8
|
import { validate } from "../engine/engine_util_decorator.js";
|
10
9
|
import { unwatchWrite, watchWrite } from "../engine/engine_utils.js";
|
10
|
+
import { Behaviour } from "./Component.js";
|
11
|
+
import { Rigidbody } from "./RigidBody.js";
|
11
12
|
|
12
13
|
|
13
14
|
export class Collider extends Behaviour implements ICollider {
|
@@ -105,8 +106,14 @@
|
|
105
106
|
onEnable() {
|
106
107
|
super.onEnable();
|
107
108
|
this.context.physics.engine?.addBoxCollider(this, this.size);
|
109
|
+
watchWrite(this.gameObject.scale, this.updateProperties);
|
108
110
|
}
|
109
111
|
|
112
|
+
onDisable(): void {
|
113
|
+
super.onDisable();
|
114
|
+
unwatchWrite(this.gameObject.scale, this.updateProperties);
|
115
|
+
}
|
116
|
+
|
110
117
|
onValidate(): void {
|
111
118
|
this.updateProperties();
|
112
119
|
}
|
@@ -1,9 +1,10 @@
|
|
1
1
|
import { BrightnessContrastEffect, HueSaturationEffect } from "postprocessing";
|
2
|
+
import { LinearToneMapping, NoToneMapping } from "three";
|
3
|
+
|
2
4
|
import { serializable } from "../../../engine/engine_serialization.js";
|
3
5
|
import { type EffectProviderResult, PostProcessingEffect } from "../PostProcessingEffect.js";
|
4
6
|
import { VolumeParameter } from "../VolumeParameter.js";
|
5
7
|
import { registerCustomEffectType } from "../VolumeProfile.js";
|
6
|
-
import { LinearToneMapping, NoToneMapping } from "three";
|
7
8
|
|
8
9
|
|
9
10
|
export class ColorAdjustments extends PostProcessingEffect {
|
@@ -1,15 +1,17 @@
|
|
1
|
-
import {
|
2
|
-
|
1
|
+
import { Euler, Object3D, Quaternion, Scene, Vector3 } from "three";
|
2
|
+
|
3
|
+
import { isDevEnvironment } from "../engine/debug/index.js";
|
4
|
+
import { addNewComponent, destroyComponentInstance, findObjectOfType, findObjectsOfType, getComponent, getComponentInChildren, getComponentInParent, getComponents, getComponentsInChildren, getComponentsInParent, getOrAddComponent, moveComponentInstance, removeComponent } from "../engine/engine_components.js";
|
3
5
|
import { activeInHierarchyFieldName } from "../engine/engine_constants.js";
|
4
|
-
import {
|
6
|
+
import { destroy, findByGuid, foreachComponent, HideFlags, IInstantiateOptions, instantiate, isActiveInHierarchy, isActiveSelf, isDestroyed, isUsingInstancing, markAsInstancedRendered, setActive } from "../engine/engine_gameobject.js";
|
5
7
|
import * as main from "../engine/engine_mainloop_utils.js";
|
6
8
|
import { syncDestroy, syncInstantiate } from "../engine/engine_networking_instantiate.js";
|
7
|
-
import
|
8
|
-
import
|
9
|
-
import {
|
9
|
+
import { Context, FrameEvent } from "../engine/engine_setup.js";
|
10
|
+
import * as threeutils from "../engine/engine_three_utils.js";
|
11
|
+
import type { Collision, Constructor, ConstructorConcrete, GuidsMap, ICollider, IComponent, IGameObject, SourceIdentifier } from "../engine/engine_types.js";
|
12
|
+
import { INeedleXRSessionEventReceiver, NeedleXRControllerEventArgs, NeedleXREventArgs } from "../engine/engine_xr.js";
|
13
|
+
import { IPointerEventHandler, PointerEventData } from "./ui/PointerEvents.js";
|
10
14
|
|
11
|
-
import { Euler, Object3D, Quaternion, Scene, Vector3 } from "three";
|
12
|
-
import { showBalloonWarning, isDevEnvironment } from "../engine/debug/index.js";
|
13
15
|
|
14
16
|
// export interface ISerializationCallbackReceiver {
|
15
17
|
// onBeforeSerialize?(): object | void;
|
@@ -81,8 +83,8 @@
|
|
81
83
|
* @param instance object to instantiate
|
82
84
|
* @param opts options for the instantiation (e.g. with what parent, position, etc.)
|
83
85
|
*/
|
84
|
-
public static instantiate(instance: GameObject | Object3D
|
85
|
-
return instantiate(instance, opts) as GameObject
|
86
|
+
public static instantiate(instance: GameObject | Object3D, opts: IInstantiateOptions | null = null): GameObject {
|
87
|
+
return instantiate(instance, opts) as GameObject;
|
86
88
|
}
|
87
89
|
|
88
90
|
/** Destroys a object on all connected clients (if you are in a networked session)
|
@@ -123,7 +125,7 @@
|
|
123
125
|
main.addScriptToArrays(comp, context!);
|
124
126
|
if (comp.__internalDidAwakeAndStart) return;
|
125
127
|
if (context!.new_script_start.includes(comp) === false) {
|
126
|
-
context!.new_script_start.push(comp as
|
128
|
+
context!.new_script_start.push(comp as Component);
|
127
129
|
}
|
128
130
|
}, true);
|
129
131
|
}
|
@@ -254,7 +256,7 @@
|
|
254
256
|
return getComponentsInParent(go, typeName, arr);
|
255
257
|
}
|
256
258
|
|
257
|
-
public static getAllComponents(go: IGameObject | Object3D):
|
259
|
+
public static getAllComponents(go: IGameObject | Object3D): Component[] {
|
258
260
|
const componentsList = go.userData?.components;
|
259
261
|
const newList = [...componentsList];
|
260
262
|
return newList;
|
@@ -294,7 +296,7 @@
|
|
294
296
|
abstract set worldQuaternion(val: Quaternion);
|
295
297
|
abstract get worldQuaternion(): Quaternion;
|
296
298
|
abstract set worldRotation(val: Vector3);
|
297
|
-
abstract get worldRotation(): Vector3;
|
299
|
+
abstract get worldRotation(): Vector3;
|
298
300
|
abstract set worldScale(val: Vector3);
|
299
301
|
abstract get worldScale(): Vector3;
|
300
302
|
|
@@ -305,17 +307,28 @@
|
|
305
307
|
|
306
308
|
|
307
309
|
|
308
|
-
|
310
|
+
/** Needle Engine component base class. Derive from this component to implement your own using the provided lifecycle methods. Components can be added to threejs objects using `GameObject.addComponent`.
|
311
|
+
*
|
312
|
+
* The most common lifecycle methods are `awake`, `start`, `onEanble`, `onDisable` `update` and `onDestroy`.
|
313
|
+
* XR specific callbacks include `onEnterXR`, `onLeaveXR`, `onUpdateXR`, `onControllerAdded` and `onControllerRemoved`.
|
314
|
+
* To receive pointer events implement `onPointerDown`, `onPointerUp`, `onPointerEnter`, `onPointerExit` and `onPointerMove`.
|
315
|
+
*/
|
316
|
+
export abstract class Component implements IComponent, EventTarget,
|
317
|
+
Partial<INeedleXRSessionEventReceiver>,
|
318
|
+
Partial<IPointerEventHandler>
|
319
|
+
{
|
309
320
|
|
310
321
|
get isComponent(): boolean { return true; }
|
311
322
|
|
312
323
|
private __context: Context | undefined;
|
324
|
+
/** Use the context to get access to many Needle Engine features and use physics, timing, access the camera or scene */
|
313
325
|
get context(): Context {
|
314
326
|
return this.__context ?? Context.Current;
|
315
327
|
}
|
316
328
|
set context(context: Context) {
|
317
329
|
this.__context = context;
|
318
330
|
}
|
331
|
+
/** shorthand for `this.context.scene` */
|
319
332
|
get scene(): Scene { return this.context.scene; }
|
320
333
|
|
321
334
|
get layer(): number {
|
@@ -355,7 +368,7 @@
|
|
355
368
|
return this.gameObject?.userData.hideFlags;
|
356
369
|
}
|
357
370
|
|
358
|
-
|
371
|
+
/** @returns true if the object is enabled and active in the hierarchy */
|
359
372
|
get activeAndEnabled(): boolean {
|
360
373
|
if (this.destroyed) return false;
|
361
374
|
if (this.__isEnabled === false) return false;
|
@@ -385,19 +398,27 @@
|
|
385
398
|
this.gameObject[activeInHierarchyFieldName] = val;
|
386
399
|
}
|
387
400
|
|
401
|
+
/** the object this component is attached to. Note that this is a threejs Object3D with some additional features */
|
388
402
|
gameObject!: GameObject;
|
403
|
+
/** the unique identifier for this component */
|
389
404
|
guid: string = "invalid";
|
405
|
+
/** holds the source identifier this object was created with/from (e.g. if it was part of a glTF file the sourceId holds the url to the glTF) */
|
390
406
|
sourceId?: SourceIdentifier;
|
391
407
|
// transform: Object3D = nullObject;
|
392
408
|
|
393
409
|
/** called on a component with a map of old to new guids (e.g. when instantiate generated new guids and e.g. timeline track bindings needs to remape them) */
|
394
410
|
resolveGuids?(guidsMap: GuidsMap): void;
|
395
411
|
|
396
|
-
/** called once when the component becomes active for the first time
|
412
|
+
/** called once when the component becomes active for the first time (once per component)
|
413
|
+
* This is the first callback to be called */
|
397
414
|
awake() { }
|
398
|
-
/** called every time when the component gets enabled (this is invoked after awake and before start)
|
415
|
+
/** called every time when the component gets enabled (this is invoked after awake and before start)
|
416
|
+
* or when it becomes active in the hierarchy (e.g. if a parent object or this.gameObject gets set to visible)
|
417
|
+
*/
|
399
418
|
onEnable() { }
|
419
|
+
/** called every time the component gets disabled or if a parent object (or this.gameObject) gets set to invisible */
|
400
420
|
onDisable() { }
|
421
|
+
/** Called when the component gets destroyed */
|
401
422
|
onDestroy() {
|
402
423
|
this.__destroyed = true;
|
403
424
|
}
|
@@ -409,11 +430,17 @@
|
|
409
430
|
/** Called for all scripts when the context gets paused or unpaused */
|
410
431
|
onPausedChanged?(isPaused: boolean, wasPaused: boolean): void;
|
411
432
|
|
433
|
+
/** called at the beginning of a frame (once per component) */
|
412
434
|
start?(): void;
|
435
|
+
/** first callback in a frame (called every frame when implemented) */
|
413
436
|
earlyUpdate?(): void;
|
437
|
+
/** regular callback in a frame (called every frame when implemented) */
|
414
438
|
update?(): void;
|
439
|
+
/** late callback in a frame (called every frame when implemented) */
|
415
440
|
lateUpdate?(): void;
|
441
|
+
/** called before the scene gets rendered in the main update loop */
|
416
442
|
onBeforeRender?(frame: XRFrame | null): void;
|
443
|
+
/** called after the scene was rendered */
|
417
444
|
onAfterRender?(): void;
|
418
445
|
|
419
446
|
onCollisionEnter?(col: Collision);
|
@@ -424,18 +451,79 @@
|
|
424
451
|
onTriggerStay?(col: ICollider);
|
425
452
|
onTriggerExit?(col: ICollider);
|
426
453
|
|
454
|
+
|
455
|
+
/** Optional callback, you can implement this to only get callbacks for VR or AR sessions if necessary.
|
456
|
+
* @returns true if the mode is supported (if false the mode is not supported by this component and it will not receive XR callbacks for this mode)
|
457
|
+
*/
|
458
|
+
supportsXR?(mode: XRSessionMode): boolean;
|
459
|
+
/** Called before the XR session is requested. Use this callback if you want to modify the session init features */
|
460
|
+
onBeforeXR?(mode: XRSessionMode, args: XRSessionInit): void;
|
461
|
+
/** Callback when this component joins a xr session (or becomes active in a running XR session) */
|
462
|
+
onEnterXR?(args: NeedleXREventArgs): void;
|
463
|
+
/** Callback when a xr session updates (while it is still active in XR session) */
|
464
|
+
onUpdateXR?(args: NeedleXREventArgs): void;
|
465
|
+
/** Callback when this component exists a xr session (or when it becomes inactive in a running XR session) */
|
466
|
+
onLeaveXR?(args: NeedleXREventArgs): void;
|
467
|
+
/** Callback when a controller is connected/added while in a XR session
|
468
|
+
* OR when the component joins a running XR session that has already connected controllers
|
469
|
+
* OR when the component becomes active during a running XR session that has already connected controllers */
|
470
|
+
onXRControllerAdded?(args: NeedleXRControllerEventArgs): void;
|
471
|
+
/** callback when a controller is removed while in a XR session
|
472
|
+
* OR when the component becomes inactive during a running XR session
|
473
|
+
*/
|
474
|
+
onXRControllerRemoved?(args: NeedleXRControllerEventArgs): void;
|
475
|
+
|
476
|
+
|
477
|
+
/* IPointerEventReceiver */
|
478
|
+
/* @inheritdoc */
|
479
|
+
onPointerEnter?(args: PointerEventData);
|
480
|
+
onPointerMove?(args: PointerEventData);
|
481
|
+
onPointerExit?(args: PointerEventData);
|
482
|
+
onPointerDown?(args: PointerEventData);
|
483
|
+
onPointerUp?(args: PointerEventData);
|
484
|
+
onPointerClick?(args: PointerEventData);
|
485
|
+
|
486
|
+
|
487
|
+
/** starts a coroutine (javascript generator function)
|
488
|
+
* `yield` will wait for the next frame:
|
489
|
+
* - Use `yield WaitForSeconds(1)` to wait for 1 second.
|
490
|
+
* - Use `yield WaitForFrames(10)` to wait for 10 frames.
|
491
|
+
* - Use `yield new Promise(...)` to wait for a promise to resolve.
|
492
|
+
* @param routine generator function to start
|
493
|
+
* @param evt event to register the coroutine for (default: FrameEvent.Update). Note that all coroutine FrameEvent callbacks are invoked after the matching regular component callbacks. For example `FrameEvent.Update` will be called after regular component `update()` methods)
|
494
|
+
* @returns the generator function (use it to stop the coroutine with `stopCoroutine`)
|
495
|
+
* @example
|
496
|
+
* ```ts
|
497
|
+
* onEnable() { this.startCoroutine(this.myCoroutine()); }
|
498
|
+
* private *myCoroutine() {
|
499
|
+
* while(this.activeAndEnabled) {
|
500
|
+
* console.log("Hello World", this.context.time.frame);
|
501
|
+
* // wait for 5 frames
|
502
|
+
* for(let i = 0; i < 5; i++) yield;
|
503
|
+
* }
|
504
|
+
* }
|
505
|
+
* ```
|
506
|
+
*/
|
427
507
|
startCoroutine(routine: Generator, evt: FrameEvent = FrameEvent.Update): Generator {
|
428
508
|
return this.context.registerCoroutineUpdate(this, routine, evt);
|
429
509
|
}
|
430
|
-
|
510
|
+
/**
|
511
|
+
* Stop a coroutine that was previously started with `startCoroutine`
|
512
|
+
* @param routine the routine to be stopped
|
513
|
+
* @param evt the frame event to unregister the routine from (default: FrameEvent.Update)
|
514
|
+
*/
|
431
515
|
stopCoroutine(routine: Generator, evt: FrameEvent = FrameEvent.Update): void {
|
432
516
|
this.context.unregisterCoroutineUpdate(routine, evt);
|
433
517
|
}
|
434
518
|
|
519
|
+
/** @returns true if this component was destroyed (`this.destroy()`) or the whole object this component was part of */
|
435
520
|
public get destroyed(): boolean {
|
436
521
|
return this.__destroyed;
|
437
522
|
}
|
438
523
|
|
524
|
+
/**
|
525
|
+
* Destroys this component (and removes it from the object)
|
526
|
+
*/
|
439
527
|
public destroy() {
|
440
528
|
if (this.__destroyed) return;
|
441
529
|
this.__internalDestroy();
|
@@ -464,7 +552,11 @@
|
|
464
552
|
|
465
553
|
/** @internal */
|
466
554
|
constructor() {
|
467
|
-
this.
|
555
|
+
this.__didAwake = false;
|
556
|
+
this.__didStart = false;
|
557
|
+
this.__didEnable = false;
|
558
|
+
this.__isEnabled = undefined;
|
559
|
+
this.__destroyed = false;
|
468
560
|
}
|
469
561
|
|
470
562
|
|
@@ -666,5 +758,6 @@
|
|
666
758
|
}
|
667
759
|
}
|
668
760
|
|
669
|
-
export
|
670
|
-
|
761
|
+
// For legacy reasons we need to export this as well
|
762
|
+
// (and we don't use extend to inherit the component docs)
|
763
|
+
export { Component as Behaviour };
|
@@ -1,3 +1,4 @@
|
|
1
|
+
/* eslint-disable */
|
1
2
|
// Export types
|
2
3
|
export class __Ignore {}
|
3
4
|
export { ActionBuilder } from "../export/usdz/extensions/behavior/BehavioursBuilder.js";
|
@@ -11,11 +12,11 @@
|
|
11
12
|
export { Animator } from "../Animator.js";
|
12
13
|
export { AnimatorController } from "../AnimatorController.js";
|
13
14
|
export { Antialiasing } from "../postprocessing/Effects/Antialiasing.js";
|
14
|
-
export { AttachedObject } from "../webxr/WebXRController.js";
|
15
15
|
export { AudioExtension } from "../export/usdz/extensions/behavior/AudioExtension.js";
|
16
16
|
export { AudioListener } from "../AudioListener.js";
|
17
17
|
export { AudioSource } from "../AudioSource.js";
|
18
18
|
export { AudioTrackHandler } from "../timeline/TimelineTracks.js";
|
19
|
+
export { Avatar } from "../webxr/Avatar.js";
|
19
20
|
export { Avatar_Brain_LookAt } from "../avatar/Avatar_Brain_LookAt.js";
|
20
21
|
export { Avatar_MouthShapes } from "../avatar/Avatar_MouthShapes.js";
|
21
22
|
export { Avatar_MustacheShake } from "../avatar/Avatar_MustacheShake.js";
|
@@ -30,7 +31,6 @@
|
|
30
31
|
export { BasicIKConstraint } from "../BasicIKConstraint.js";
|
31
32
|
export { BehaviorExtension } from "../export/usdz/extensions/behavior/Behaviour.js";
|
32
33
|
export { BehaviorModel } from "../export/usdz/extensions/behavior/BehavioursBuilder.js";
|
33
|
-
export { Behaviour } from "../Component.js";
|
34
34
|
export { Bloom } from "../postprocessing/Effects/Bloom.js";
|
35
35
|
export { BoxCollider } from "../Collider.js";
|
36
36
|
export { BoxGizmo } from "../Gizmos.js";
|
@@ -51,7 +51,6 @@
|
|
51
51
|
export { ColorAdjustments } from "../postprocessing/Effects/ColorAdjustments.js";
|
52
52
|
export { ColorBySpeedModule } from "../ParticleSystemModules.js";
|
53
53
|
export { ColorOverLifetimeModule } from "../ParticleSystemModules.js";
|
54
|
-
export { Component } from "../Component.js";
|
55
54
|
export { ContactShadows } from "../ContactShadows.js";
|
56
55
|
export { ControlTrackHandler } from "../timeline/TimelineTracks.js";
|
57
56
|
export { CustomBranding } from "../export/usdz/USDZExporter.js";
|
@@ -88,7 +87,6 @@
|
|
88
87
|
export { Image } from "../ui/Image.js";
|
89
88
|
export { InheritVelocityModule } from "../ParticleSystemModules.js";
|
90
89
|
export { InputField } from "../ui/InputField.js";
|
91
|
-
export { Interactable } from "../Interactable.js";
|
92
90
|
export { Light } from "../Light.js";
|
93
91
|
export { LimitVelocityOverLifetimeModule } from "../ParticleSystemModules.js";
|
94
92
|
export { LODGroup } from "../LODGroup.js";
|
@@ -102,6 +100,7 @@
|
|
102
100
|
export { MeshRenderer } from "../Renderer.js";
|
103
101
|
export { MinMaxCurve } from "../ParticleSystemModules.js";
|
104
102
|
export { MinMaxGradient } from "../ParticleSystemModules.js";
|
103
|
+
export { NeedleWebXRHtmlElement } from "../webxr/WebXRButtons.js";
|
105
104
|
export { NestedGltf } from "../NestedGltf.js";
|
106
105
|
export { Networking } from "../Networking.js";
|
107
106
|
export { NoiseModule } from "../ParticleSystemModules.js";
|
@@ -125,7 +124,6 @@
|
|
125
124
|
export { PreliminaryAction } from "../export/usdz/extensions/behavior/BehaviourComponents.js";
|
126
125
|
export { PreliminaryTrigger } from "../export/usdz/extensions/behavior/BehaviourComponents.js";
|
127
126
|
export { RawImage } from "../ui/Image.js";
|
128
|
-
export { Raycaster } from "../ui/Raycaster.js";
|
129
127
|
export { Rect } from "../ui/RectTransform.js";
|
130
128
|
export { RectTransform } from "../ui/RectTransform.js";
|
131
129
|
export { ReflectionProbe } from "../ReflectionProbe.js";
|
@@ -153,6 +151,7 @@
|
|
153
151
|
export { SizeOverLifetimeModule } from "../ParticleSystemModules.js";
|
154
152
|
export { SkinnedMeshRenderer } from "../Renderer.js";
|
155
153
|
export { SmoothFollow } from "../SmoothFollow.js";
|
154
|
+
export { SpatialGrabRaycaster } from "../ui/Raycaster.js";
|
156
155
|
export { SpatialHtml } from "../ui/SpatialHtml.js";
|
157
156
|
export { SpatialTrigger } from "../SpatialTrigger.js";
|
158
157
|
export { SpatialTriggerReceiver } from "../SpatialTrigger.js";
|
@@ -167,7 +166,7 @@
|
|
167
166
|
export { SyncedRoom } from "../SyncedRoom.js";
|
168
167
|
export { SyncedTransform } from "../SyncedTransform.js";
|
169
168
|
export { TapGestureTrigger } from "../export/usdz/extensions/behavior/BehaviourComponents.js";
|
170
|
-
export { TeleportTarget } from "../webxr/
|
169
|
+
export { TeleportTarget } from "../webxr/TeleportTarget.js";
|
171
170
|
export { TestRunner } from "../TestRunner.js";
|
172
171
|
export { TestSimulateUserData } from "../TestRunner.js";
|
173
172
|
export { Text } from "../ui/Text.js";
|
@@ -197,20 +196,16 @@
|
|
197
196
|
export { Volume } from "../postprocessing/Volume.js";
|
198
197
|
export { VolumeParameter } from "../postprocessing/VolumeParameter.js";
|
199
198
|
export { VolumeProfile } from "../postprocessing/VolumeProfile.js";
|
200
|
-
export { VRUserState } from "../webxr/WebXRSync.js";
|
201
|
-
export { WebAR } from "../webxr/WebXR.js";
|
202
199
|
export { WebARCameraBackground } from "../webxr/WebARCameraBackground.js";
|
203
200
|
export { WebARSessionRoot } from "../webxr/WebARSessionRoot.js";
|
204
201
|
export { WebXR } from "../webxr/WebXR.js";
|
205
|
-
export { WebXRAvatar } from "../webxr/WebXRAvatar.js";
|
206
|
-
export { WebXRController } from "../webxr/WebXRController.js";
|
207
202
|
export { WebXRImageTracking } from "../webxr/WebXRImageTracking.js";
|
208
203
|
export { WebXRImageTrackingModel } from "../webxr/WebXRImageTracking.js";
|
209
204
|
export { WebXRPlaneTracking } from "../webxr/WebXRPlaneTracking.js";
|
210
|
-
export { WebXRSync } from "../webxr/WebXRSync.js";
|
211
205
|
export { WebXRTrackedImage } from "../webxr/WebXRImageTracking.js";
|
212
|
-
export {
|
213
|
-
export {
|
214
|
-
export {
|
206
|
+
export { XRControllerFollow } from "../webxr/controllers/XRControllerFollow.js";
|
207
|
+
export { XRControllerModel } from "../webxr/controllers/XRControllerModel.js";
|
208
|
+
export { XRControllerMovement } from "../webxr/controllers/XRControllerMovement.js";
|
209
|
+
export { XRFlag } from "../webxr/XRFlag.js";
|
215
210
|
export { XRRig } from "../webxr/WebXRRig.js";
|
216
|
-
export { XRState } from "../XRFlag.js";
|
211
|
+
export { XRState } from "../webxr/XRFlag.js";
|
@@ -1,11 +1,11 @@
|
|
1
|
-
import { Behaviour } from "./Component.js";
|
2
|
-
import { serializable } from "../engine/engine_serialization_decorator.js";
|
3
|
-
|
4
1
|
import { CustomBlending, DoubleSide, Group, Matrix4, MaxEquation, Mesh, MeshBasicMaterial, MeshDepthMaterial, MinEquation, OrthographicCamera, PlaneGeometry, ShaderMaterial, WebGLRenderTarget } from "three";
|
5
2
|
import { HorizontalBlurShader } from 'three/examples/jsm/shaders/HorizontalBlurShader.js';
|
6
3
|
import { VerticalBlurShader } from 'three/examples/jsm/shaders/VerticalBlurShader.js';
|
4
|
+
|
5
|
+
import { serializable } from "../engine/engine_serialization_decorator.js";
|
7
6
|
import { getParam } from "../engine/engine_utils.js"
|
8
7
|
import { setCustomVisibility } from "../engine/js-extensions/Layers.js";
|
8
|
+
import { Behaviour } from "./Component.js";
|
9
9
|
|
10
10
|
const debug = getParam("debugcontactshadows");
|
11
11
|
|
@@ -1,6 +1,7 @@
|
|
1
|
-
import { getErrorCount } from "./debug_overlay.js";
|
2
|
-
import { getParam, isMobileDevice } from "../engine_utils.js";
|
3
1
|
import { isLocalNetwork } from "../engine_networking_utils.js";
|
2
|
+
import { getParam, isMobileDevice, isQuest } from "../engine_utils.js";
|
3
|
+
import { isDevEnvironment } from "./debug.js";
|
4
|
+
import { getErrorCount, makeErrorsVisibleForDevelopment } from "./debug_overlay.js";
|
4
5
|
|
5
6
|
let consoleInstance: any = null;
|
6
7
|
let consoleHtmlElement: HTMLElement | null = null;
|
@@ -22,8 +23,11 @@
|
|
22
23
|
currentUrl.searchParams.set("console", "1");
|
23
24
|
console.log("🌵 Tip: You can add the \"?console\" query parameter to the url to show the debug console (on mobile it will automatically open in the bottom right corner when your get errors during development)", "\nOpen this page console: " + currentUrl.toString());
|
24
25
|
}
|
25
|
-
const isMobile = isMobileDevice();
|
26
|
+
const isMobile = isMobileDevice() || (isQuest() && isDevEnvironment());
|
26
27
|
if (isMobile) {
|
28
|
+
// we need to invoke this here - otherwise we will miss errors that happen after the console is loaded
|
29
|
+
// and calling the method from the root needle-engine.ts import is evaluated later (if we import the method from the toplevel file and then invoke it)
|
30
|
+
makeErrorsVisibleForDevelopment();
|
27
31
|
beginWatchingLogs();
|
28
32
|
createConsole(true);
|
29
33
|
if (isMobile) {
|
@@ -191,7 +195,7 @@
|
|
191
195
|
}
|
192
196
|
`;
|
193
197
|
consoleHtmlElement?.prepend(styles);
|
194
|
-
if (startHidden === true)
|
198
|
+
if (startHidden === true && getErrorCount() <= 0)
|
195
199
|
hideDebugConsole();
|
196
200
|
console.log("🌵 Debug console has loaded");
|
197
201
|
}
|
@@ -1,6 +1,6 @@
|
|
1
|
+
import { ContextRegistry } from "../engine_context_registry.js";
|
2
|
+
import { isLocalNetwork } from "../engine_networking_utils.js";
|
1
3
|
import { getParam } from "../engine_utils.js";
|
2
|
-
import { isLocalNetwork } from "../engine_networking_utils.js";
|
3
|
-
import { ContextRegistry } from "../engine_context_registry.js";
|
4
4
|
|
5
5
|
const debug = getParam("debugdebug");
|
6
6
|
let hide = false;
|
@@ -15,7 +15,7 @@
|
|
15
15
|
}
|
16
16
|
|
17
17
|
export function getErrorCount() {
|
18
|
-
return
|
18
|
+
return _errorCount;
|
19
19
|
}
|
20
20
|
|
21
21
|
const originalConsoleError = console.error;
|
@@ -37,9 +37,10 @@
|
|
37
37
|
if (hide) return;
|
38
38
|
const isLocal = isLocalNetwork();
|
39
39
|
if (debug) console.log("Is this a local network?", isLocal);
|
40
|
-
if (isLocal)
|
40
|
+
if (isLocal)
|
41
|
+
{
|
41
42
|
if (debug)
|
42
|
-
console.
|
43
|
+
console.warn("Patch console", window.location.hostname);
|
43
44
|
console.error = patchedConsoleError;
|
44
45
|
window.addEventListener("error", (event) => {
|
45
46
|
if (hide) return;
|
@@ -66,10 +67,10 @@
|
|
66
67
|
}
|
67
68
|
|
68
69
|
|
69
|
-
let
|
70
|
+
let _errorCount = 0;
|
70
71
|
|
71
72
|
function onReceivedError() {
|
72
|
-
|
73
|
+
_errorCount += 1;
|
73
74
|
}
|
74
75
|
|
75
76
|
function onParseError(args: Array<any>) {
|
@@ -1,10 +1,13 @@
|
|
1
|
+
import { isLocalNetwork } from "../engine_networking_utils.js";
|
2
|
+
import { getParam } from "../engine_utils.js";
|
3
|
+
import { showDebugConsole } from "./debug_console.js";
|
1
4
|
import { addLog, LogType, setAllowOverlayMessages } from "./debug_overlay.js";
|
2
|
-
import { showDebugConsole } from "./debug_console.js";
|
3
|
-
import { isLocalNetwork } from "../engine_networking_utils.js";
|
4
5
|
|
5
6
|
export { showDebugConsole }
|
6
7
|
export { LogType, setAllowOverlayMessages };
|
7
8
|
|
9
|
+
const noDevLogs = getParam("nodevlogs");
|
10
|
+
|
8
11
|
/** Displays a debug message on screen for a certain amount of time */
|
9
12
|
export function showBalloonMessage(text: string, logType: LogType = LogType.Log): void {
|
10
13
|
addLog(logType, text);
|
@@ -22,6 +25,7 @@
|
|
22
25
|
|
23
26
|
/** True when the application runs on a local url */
|
24
27
|
export function isDevEnvironment(): boolean {
|
28
|
+
if (noDevLogs) return false;
|
25
29
|
if (_manuallySetDevEnvironment !== undefined) return _manuallySetDevEnvironment;
|
26
30
|
return isLocalNetwork();
|
27
31
|
}
|
@@ -1,5 +1,6 @@
|
|
1
1
|
|
2
2
|
import * as THREE from "three";
|
3
|
+
|
3
4
|
import { syncDestroy } from "../engine/engine_networking_instantiate.js";
|
4
5
|
import { getParam } from "../engine/engine_utils.js";
|
5
6
|
import { BoxHelperComponent } from "./BoxHelperComponent.js";
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import { DepthOfFieldEffect } from "postprocessing";
|
2
|
+
|
3
|
+
import { Mathf } from "../../../engine/engine_math.js";
|
2
4
|
import { serializable } from "../../../engine/engine_serialization.js";
|
3
|
-
import { Mathf } from "../../../engine/engine_math.js";
|
4
5
|
import { getParam, isMobileDevice } from "../../../engine/engine_utils.js";
|
5
6
|
import { PostProcessingEffect } from "../PostProcessingEffect.js";
|
6
7
|
import { VolumeParameter } from "../VolumeParameter.js";
|
@@ -1,6 +1,6 @@
|
|
1
1
|
|
2
|
+
import { serializable } from "../engine/engine_serialization_decorator.js";
|
2
3
|
import { isMobileDevice } from "../engine/engine_utils.js";
|
3
|
-
import { serializable } from "../engine/engine_serialization_decorator.js";
|
4
4
|
import { Behaviour, GameObject } from "./Component.js";
|
5
5
|
|
6
6
|
|
@@ -1,104 +1,126 @@
|
|
1
|
-
import {
|
2
|
-
|
3
|
-
import
|
1
|
+
import { AxesHelper, Box3, BufferGeometry, Camera, Color, Event, Line, LineBasicMaterial, Matrix3, Matrix4, Mesh, MeshBasicMaterial, Object3D, Plane, PlaneHelper, Quaternion, Ray, Raycaster, SphereGeometry, Vector3 } from "three";
|
2
|
+
|
3
|
+
import { Gizmos } from "../engine/engine_gizmos.js";
|
4
|
+
import { InstancingUtil } from "../engine/engine_instancing.js";
|
5
|
+
import { Mathf } from "../engine/engine_math.js";
|
6
|
+
import { RaycastOptions } from "../engine/engine_physics.js";
|
7
|
+
import { serializable } from "../engine/engine_serialization_decorator.js";
|
4
8
|
import { Context } from "../engine/engine_setup.js";
|
5
|
-
import {
|
6
|
-
import {
|
7
|
-
import {
|
9
|
+
import { getWorldPosition, setWorldPosition } from "../engine/engine_three_utils.js";
|
10
|
+
import { IGameObject } from "../engine/engine_types.js";
|
11
|
+
import { getParam } from "../engine/engine_utils.js";
|
12
|
+
import { NeedleXRSession } from "../engine/engine_xr.js";
|
8
13
|
import { Avatar_POI } from "./avatar/Avatar_Brain_LookAt.js";
|
9
|
-
import {
|
10
|
-
import {
|
11
|
-
import type { KeyCode } from "../engine/engine_input.js";
|
12
|
-
import { nameofFactory } from "../engine/engine_utils.js";
|
13
|
-
import { InstancingUtil } from "../engine/engine_instancing.js";
|
14
|
+
import { Behaviour, GameObject } from "./Component.js";
|
15
|
+
import { UsageMarker } from "./Interactable.js";
|
14
16
|
import { OrbitControls } from "./OrbitControls.js";
|
15
|
-
import {
|
17
|
+
import { Rigidbody } from "./RigidBody.js";
|
18
|
+
import { SyncedTransform } from "./SyncedTransform.js";
|
19
|
+
import type { IPointerEventHandler, PointerEventData } from "./ui/PointerEvents.js";
|
16
20
|
import { ObjectRaycaster } from "./ui/Raycaster.js";
|
17
|
-
import { serializable } from "../engine/engine_serialization_decorator.js";
|
18
21
|
|
19
|
-
const debug =
|
22
|
+
const debug = getParam("debugdrag");
|
20
23
|
|
21
|
-
export enum
|
22
|
-
|
23
|
-
|
24
|
+
export enum DragMode {
|
25
|
+
/** Object stays at the same horizontal plane as it started. Commonly used for objects on the floor */
|
26
|
+
XZPlane = 0,
|
27
|
+
/** Object is dragged as if it was attached to the pointer. In 2D, that means it's dragged along the camera screen plane. In XR, it's dragged by the controller/hand. */
|
28
|
+
Attached = 1,
|
29
|
+
/** Object is dragged along the initial raycast hit normal. */
|
30
|
+
HitNormal = 2,
|
31
|
+
/** Combination of XZ and Screen based on the viewing angle. Low angles result in Screen dragging and higher angles in XZ dragging. */
|
32
|
+
DynamicViewAngle = 3,
|
33
|
+
/** The drag plane is adjusted dynamically while dragging. */
|
34
|
+
SnapToSurfaces = 4,
|
24
35
|
}
|
25
36
|
|
26
|
-
|
27
|
-
selected: Object3D;
|
28
|
-
attached: Object3D | GameObject | null;
|
29
|
-
}
|
37
|
+
export class DragControls extends Behaviour implements IPointerEventHandler {
|
30
38
|
|
39
|
+
// dragPlane (floor, object, view)
|
40
|
+
// snap to surface (snap orientation?)
|
41
|
+
// two-handed drag (scale, rotate, move)
|
42
|
+
// keep upright (no tilt)
|
31
43
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
}
|
44
|
+
/** How and where the object is dragged along. */
|
45
|
+
@serializable()
|
46
|
+
public dragMode: DragMode = DragMode.DynamicViewAngle;
|
36
47
|
|
37
|
-
|
48
|
+
/** Snap dragged objects to a XYZ grid – 0 means: no snapping. */
|
49
|
+
@serializable()
|
50
|
+
public snapGridResolution: number = 0.0;
|
51
|
+
|
52
|
+
/** Keep the original rotation of the dragged object. */
|
53
|
+
@serializable()
|
54
|
+
public keepRotation: boolean = true;
|
55
|
+
|
56
|
+
/** How and where the object is dragged along while dragging in XR. */
|
57
|
+
@serializable()
|
58
|
+
public xrDragMode: DragMode = DragMode.Attached;
|
38
59
|
|
39
|
-
|
40
|
-
|
60
|
+
/** Keep the original rotation of the dragged object while dragging in XR. */
|
61
|
+
@serializable()
|
62
|
+
public xrKeepRotation: boolean = false;
|
41
63
|
|
42
|
-
/**
|
64
|
+
/** Accelerate dragging objects closer / further away when in XR */
|
43
65
|
@serializable()
|
44
|
-
public
|
66
|
+
public xrDistanceDragFactor: number = 1;
|
45
67
|
|
46
|
-
/** When enabled
|
68
|
+
/** When enabled, draws a line from the dragged object downwards to the next raycast hit. */
|
47
69
|
@serializable()
|
48
|
-
public
|
70
|
+
public showGizmo: boolean = false;
|
49
71
|
|
50
|
-
|
51
|
-
//
|
52
|
-
// public targets: Object3D[] | null = null;
|
72
|
+
// future:
|
73
|
+
// constraints?
|
53
74
|
|
54
|
-
|
75
|
+
public static get HasAnySelected(): boolean { return this._active > 0; }
|
76
|
+
private static _active: number = 0;
|
77
|
+
|
78
|
+
/** The object to be dragged – we pass this to handlers when they are created */
|
79
|
+
private targetObject: GameObject | null = null;
|
55
80
|
private orbit: OrbitControls | null = null;
|
81
|
+
private _dragHelper: LegacyDragVisualsHelper | null = null;
|
82
|
+
private static lastHovered: Object3D;
|
83
|
+
private _draggingRigidbodies: Rigidbody[] = [];
|
84
|
+
private _potentialDragStartEvt: PointerEventData | null = null;
|
85
|
+
private _dragHandlers: Map<Object3D, IDragHandler> = new Map();
|
86
|
+
private _totalMovement: Vector3 = new Vector3();
|
87
|
+
/** A marker is attached to components that are currently interacted with, to e.g. prevent them from being deleted. */
|
88
|
+
private _marker: UsageMarker | null = null;
|
89
|
+
private _isDragging: boolean = false;
|
90
|
+
private _didDrag: boolean = false;
|
56
91
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
super();
|
63
|
-
this.selectStartEventListener = [];
|
64
|
-
this.selectEndEventListener = [];
|
65
|
-
this._dragDelta = new Vector2();
|
92
|
+
setTargetObject(obj: Object3D | null) {
|
93
|
+
this.targetObject = obj as GameObject;
|
94
|
+
for (const handler of this._dragHandlers.values()) {
|
95
|
+
handler.setTargetObject(obj);
|
96
|
+
}
|
66
97
|
}
|
67
98
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
}
|
99
|
+
awake() {
|
100
|
+
// initialize all data that may be cloned incorrectly otherwise
|
101
|
+
this._potentialDragStartEvt = null;
|
102
|
+
this._dragHandlers = new Map();
|
103
|
+
this._totalMovement = new Vector3();
|
104
|
+
this._marker = null;
|
105
|
+
this._isDragging = false;
|
106
|
+
this._didDrag = false;
|
107
|
+
this._dragHelper = null;
|
108
|
+
this._draggingRigidbodies = [];
|
79
109
|
}
|
80
110
|
|
81
|
-
|
82
|
-
|
83
111
|
start() {
|
84
112
|
this.orbit = GameObject.findObjectOfType(OrbitControls, this.context);
|
85
|
-
if (!this.gameObject.getComponentInParent(ObjectRaycaster))
|
113
|
+
if (!this.gameObject.getComponentInParent(ObjectRaycaster))
|
86
114
|
this.gameObject.addNewComponent(ObjectRaycaster);
|
87
|
-
}
|
88
115
|
}
|
89
116
|
|
90
|
-
private static lastHovered: Object3D;
|
91
|
-
private _draggingRigidbodies: Rigidbody[] = [];
|
92
|
-
|
93
117
|
private allowEdit(_obj: Object3D | null = null) {
|
94
118
|
return this.context.connection.allowEditing;
|
95
119
|
}
|
96
120
|
|
97
121
|
onPointerEnter(evt: PointerEventData) {
|
98
122
|
if (!this.allowEdit(this.gameObject)) return;
|
99
|
-
if (
|
100
|
-
// const interactable = GameObject.getComponentInParent(evt.object, Interactable);
|
101
|
-
// if (!interactable) return;
|
123
|
+
if (evt.mode !== "screen") return;
|
102
124
|
const dc = GameObject.getComponentInParent(evt.object, DragControls);
|
103
125
|
if (!dc || dc !== this) return;
|
104
126
|
DragControls.lastHovered = evt.object;
|
@@ -107,83 +129,121 @@
|
|
107
129
|
|
108
130
|
onPointerExit(evt: PointerEventData) {
|
109
131
|
if (!this.allowEdit(this.gameObject)) return;
|
110
|
-
if (
|
132
|
+
if (evt.mode !== "screen") return;
|
111
133
|
if (DragControls.lastHovered !== evt.object) return;
|
112
|
-
// const interactable = GameObject.getComponentInParent(evt.object, Interactable);
|
113
|
-
// if (!interactable) return;
|
114
134
|
this.context.domElement.style.cursor = 'auto';
|
115
135
|
}
|
116
136
|
|
117
|
-
private _waitingForDragStart: PointerEventData | null = null;
|
118
|
-
|
119
137
|
onPointerDown(args: PointerEventData) {
|
120
138
|
if (!this.allowEdit(this.gameObject)) return;
|
121
|
-
if (
|
122
|
-
DragControls.
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
139
|
+
if (args.used) return;
|
140
|
+
DragControls.lastHovered = args.object;
|
141
|
+
|
142
|
+
if (args.button === 0) {
|
143
|
+
if (this._dragHandlers.size === 0) {
|
144
|
+
this._didDrag = false;
|
145
|
+
this._totalMovement.set(0, 0, 0);
|
146
|
+
this._potentialDragStartEvt = args;
|
147
|
+
}
|
148
|
+
|
149
|
+
DragControls._active += 1;
|
150
|
+
|
151
|
+
const newDragHandler = new DragPointerHandler(this, this.targetObject || this.gameObject);
|
152
|
+
this._dragHandlers.set(args.event.space, newDragHandler);
|
153
|
+
|
154
|
+
// We need to turn off OrbitControls immediately, otherwise they still get data for a short moment
|
155
|
+
// and they don't properly handle being disabled while already processing data (smoothing happens when enabling again)
|
156
|
+
if (this.orbit) this.orbit.enabled = false;
|
157
|
+
|
158
|
+
newDragHandler.onDragStart(args);
|
159
|
+
|
160
|
+
if (this._dragHandlers.size === 2) {
|
161
|
+
const iterator = this._dragHandlers.values();
|
162
|
+
const a = iterator.next().value;
|
163
|
+
const b = iterator.next().value;
|
164
|
+
const mtHandler = new MultiTouchDragHandler(this, this.targetObject || this.gameObject, a, b);
|
165
|
+
this._dragHandlers.set(this.gameObject, mtHandler);
|
166
|
+
|
167
|
+
mtHandler.onDragStart(args);
|
168
|
+
}
|
169
|
+
|
170
|
+
args.use();
|
171
|
+
}
|
130
172
|
}
|
131
173
|
|
132
174
|
onPointerMove(args: PointerEventData) {
|
133
|
-
if(this._isDragging || this.
|
175
|
+
if (this._isDragging || this._potentialDragStartEvt !== null) args.use();
|
134
176
|
}
|
135
177
|
|
136
178
|
onPointerUp(args: PointerEventData) {
|
137
|
-
|
179
|
+
|
180
|
+
if(debug) Gizmos.DrawLabel(args.point ?? this.gameObject.worldPosition, "POINTERUP:" + args.pointerId + ", " + args.button, .03, 3);
|
181
|
+
|
138
182
|
if (!this.allowEdit(this.gameObject)) return;
|
139
|
-
if (
|
140
|
-
|
141
|
-
|
142
|
-
this.
|
143
|
-
|
144
|
-
if (
|
183
|
+
if (args.button !== 0) return;
|
184
|
+
this._potentialDragStartEvt = null;
|
185
|
+
|
186
|
+
const handler = this._dragHandlers.get(args.event.space);
|
187
|
+
const mtHandler = this._dragHandlers.get(this.gameObject) as MultiTouchDragHandler;
|
188
|
+
if (mtHandler && (mtHandler.handlerA === handler || mtHandler.handlerB === handler)) {
|
189
|
+
// any of the two handlers has been released, so we can remove the multi-touch handler
|
190
|
+
this._dragHandlers.delete(this.gameObject);
|
191
|
+
mtHandler.onDragEnd(args);
|
192
|
+
}
|
193
|
+
|
194
|
+
if (handler) {
|
195
|
+
if (DragControls._active > 0)
|
196
|
+
DragControls._active -= 1;
|
197
|
+
|
198
|
+
if (handler.onDragEnd) handler.onDragEnd(args);
|
199
|
+
this._dragHandlers.delete(args.event.space);
|
200
|
+
|
201
|
+
if (this._dragHandlers.size === 0) {
|
202
|
+
this.onLastDragEnd(args);
|
203
|
+
}
|
204
|
+
args.use();
|
205
|
+
}
|
206
|
+
|
207
|
+
if (DragControls._active === 0) {
|
208
|
+
if (this.orbit) this.orbit.enabled = true;
|
209
|
+
}
|
145
210
|
}
|
146
211
|
|
147
|
-
|
148
212
|
update(): void {
|
149
|
-
if (WebXR.IsInWebXR) return;
|
150
213
|
|
214
|
+
for (const handler of this._dragHandlers.values()) {
|
215
|
+
if (handler.collectMovementInfo) handler.collectMovementInfo();
|
216
|
+
// TODO this doesn't make sense, we should instead just use the max here
|
217
|
+
// or even better, each handler can decide on their own how to handle this
|
218
|
+
if (handler.getTotalMovement) this._totalMovement.add(handler.getTotalMovement());
|
219
|
+
}
|
220
|
+
|
151
221
|
// drag start only after having dragged for some pixels
|
152
|
-
if (this.
|
222
|
+
if (this._potentialDragStartEvt) {
|
153
223
|
if (!this._didDrag) {
|
154
|
-
// this is so we can e.g. process clicks without having a drag change the position
|
155
|
-
//
|
156
|
-
|
157
|
-
if (delta)
|
158
|
-
this._dragDelta.add(delta);
|
159
|
-
if (this._dragDelta.length() > 2)
|
224
|
+
// this is so we can e.g. process clicks without having a drag change the position, e.g. a click to call a method.
|
225
|
+
// TODO probably needs to be treated differently for spatial (3D motion) and screen (2D pixel motion) drags
|
226
|
+
if (this._totalMovement.length() > 0.0003)
|
160
227 |