@needle-tools/engine 2.28.0-pre → 2.30.0-pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/dist/needle-engine.d.ts +232 -139
- package/dist/needle-engine.js +349 -345
- package/dist/needle-engine.js.map +4 -4
- package/dist/needle-engine.min.js +24 -20
- package/dist/needle-engine.min.js.map +4 -4
- package/lib/engine/engine.d.ts +1 -0
- package/lib/engine/engine_input.d.ts +13 -1
- package/lib/engine/engine_input.js +47 -16
- package/lib/engine/engine_input.js.map +1 -1
- package/lib/engine/engine_physics.d.ts +1 -0
- package/lib/engine/engine_physics.js +2 -1
- package/lib/engine/engine_physics.js.map +1 -1
- package/lib/engine/engine_playerview.d.ts +26 -0
- package/lib/engine/engine_playerview.js +65 -0
- package/lib/engine/engine_playerview.js.map +1 -0
- package/lib/engine/engine_serialization.d.ts +1 -0
- package/lib/engine/engine_serialization.js +1 -0
- package/lib/engine/engine_serialization.js.map +1 -1
- package/lib/engine/engine_serialization_core.js +5 -0
- package/lib/engine/engine_serialization_core.js.map +1 -1
- package/lib/engine/engine_setup.d.ts +8 -0
- package/lib/engine/engine_setup.js +23 -0
- package/lib/engine/engine_setup.js.map +1 -1
- package/lib/engine/engine_utils.d.ts +1 -1
- package/lib/engine/engine_utils.js +25 -8
- package/lib/engine/engine_utils.js.map +1 -1
- package/lib/engine/extensions/NEEDLE_deferred_texture.d.ts +1 -1
- package/lib/engine/extensions/NEEDLE_deferred_texture.js +26 -14
- package/lib/engine/extensions/NEEDLE_deferred_texture.js.map +1 -1
- package/lib/engine/extensions/NEEDLE_lighting_settings.js +6 -2
- package/lib/engine/extensions/NEEDLE_lighting_settings.js.map +1 -1
- package/lib/engine/extensions/extension_utils.js +24 -13
- package/lib/engine/extensions/extension_utils.js.map +1 -1
- package/lib/engine/extensions/extensions.js +3 -1
- package/lib/engine/extensions/extensions.js.map +1 -1
- package/lib/engine-components/Camera.js +7 -0
- package/lib/engine-components/Camera.js.map +1 -1
- package/lib/engine-components/Component.d.ts +1 -1
- package/lib/engine-components/Component.js.map +1 -1
- package/lib/engine-components/Light.js +1 -0
- package/lib/engine-components/Light.js.map +1 -1
- package/lib/engine-components/OrbitControls.js +3 -3
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/ParticleSystem.d.ts +0 -1
- package/lib/engine-components/ParticleSystem.js +24 -27
- package/lib/engine-components/ParticleSystem.js.map +1 -1
- package/lib/engine-components/PlayerColor.js +1 -2
- package/lib/engine-components/PlayerColor.js.map +1 -1
- package/lib/engine-components/Renderer.d.ts +1 -0
- package/lib/engine-components/Renderer.js +10 -3
- package/lib/engine-components/Renderer.js.map +1 -1
- package/lib/engine-components/ScreenCapture.d.ts +1 -0
- package/lib/engine-components/ScreenCapture.js +265 -1
- package/lib/engine-components/ScreenCapture.js.map +1 -1
- package/lib/engine-components/SpectatorCamera.d.ts +24 -17
- package/lib/engine-components/SpectatorCamera.js +435 -182
- package/lib/engine-components/SpectatorCamera.js.map +1 -1
- package/lib/engine-components/SyncedCamera.d.ts +8 -4
- package/lib/engine-components/SyncedCamera.js +15 -18
- package/lib/engine-components/SyncedCamera.js.map +1 -1
- package/lib/engine-components/SyncedRoom.js +2 -0
- package/lib/engine-components/SyncedRoom.js.map +1 -1
- package/lib/engine-components/VideoPlayer.d.ts +10 -1
- package/lib/engine-components/VideoPlayer.js +64 -15
- package/lib/engine-components/VideoPlayer.js.map +1 -1
- package/lib/engine-components/Volume.d.ts +4 -0
- package/lib/engine-components/Volume.js +44 -3
- package/lib/engine-components/Volume.js.map +1 -1
- package/lib/engine-components/WebARSessionRoot.d.ts +9 -2
- package/lib/engine-components/WebARSessionRoot.js +69 -24
- package/lib/engine-components/WebARSessionRoot.js.map +1 -1
- package/lib/engine-components/WebXR.d.ts +6 -3
- package/lib/engine-components/WebXR.js +43 -7
- package/lib/engine-components/WebXR.js.map +1 -1
- package/lib/engine-components/WebXRAvatar.d.ts +3 -0
- package/lib/engine-components/WebXRAvatar.js +20 -0
- package/lib/engine-components/WebXRAvatar.js.map +1 -1
- package/lib/engine-components/WebXRController.js +14 -8
- package/lib/engine-components/WebXRController.js.map +1 -1
- package/lib/engine-components/WebXRSync.js +3 -3
- package/lib/engine-components/WebXRSync.js.map +1 -1
- package/lib/engine-components/XRFlag.d.ts +2 -1
- package/lib/engine-components/XRFlag.js +1 -0
- package/lib/engine-components/XRFlag.js.map +1 -1
- package/lib/engine-components/ui/CanvasGroup.d.ts +1 -0
- package/lib/engine-components/ui/CanvasGroup.js +1 -0
- package/lib/engine-components/ui/CanvasGroup.js.map +1 -1
- package/lib/engine-components/ui/EventSystem.js +13 -4
- package/lib/engine-components/ui/EventSystem.js.map +1 -1
- package/lib/engine-components/ui/Graphic.d.ts +1 -0
- package/lib/engine-components/ui/Graphic.js +2 -0
- package/lib/engine-components/ui/Graphic.js.map +1 -1
- package/lib/engine-components/ui/Interfaces.d.ts +2 -0
- package/package.json +2 -2
- package/src/engine/engine_components.js +16 -0
- package/src/engine/engine_input.ts +62 -20
- package/src/engine/engine_physics.ts +2 -1
- package/src/engine/engine_playerview.ts +80 -0
- package/src/engine/engine_serialization.ts +3 -1
- package/src/engine/engine_serialization_core.ts +8 -0
- package/src/engine/engine_setup.ts +24 -0
- package/src/engine/engine_utils.ts +34 -8
- package/src/engine/extensions/NEEDLE_deferred_texture.ts +25 -19
- package/src/engine/extensions/NEEDLE_lighting_settings.ts +4 -2
- package/src/engine/extensions/extension_utils.ts +24 -12
- package/src/engine/extensions/extensions.ts +3 -2
- package/src/engine-components/Camera.ts +9 -1
- package/src/engine-components/Component.ts +1 -1
- package/src/engine-components/Light.ts +3 -0
- package/src/engine-components/OrbitControls.ts +3 -3
- package/src/engine-components/ParticleSystem.ts +25 -26
- package/src/engine-components/PlayerColor.ts +1 -1
- package/src/engine-components/Renderer.ts +11 -3
- package/src/engine-components/ScreenCapture.ts +312 -2
- package/src/engine-components/SpectatorCamera.ts +490 -195
- package/src/engine-components/SyncedCamera.ts +23 -22
- package/src/engine-components/SyncedRoom.ts +1 -0
- package/src/engine-components/VideoPlayer.ts +97 -21
- package/src/engine-components/Volume.ts +47 -4
- package/src/engine-components/WebARSessionRoot.ts +78 -28
- package/src/engine-components/WebXR.ts +51 -15
- package/src/engine-components/WebXRAvatar.ts +27 -2
- package/src/engine-components/WebXRController.ts +21 -15
- package/src/engine-components/WebXRSync.ts +3 -3
- package/src/engine-components/XRFlag.ts +1 -0
- package/src/engine-components/ui/CanvasGroup.ts +2 -0
- package/src/engine-components/ui/EventSystem.ts +21 -15
- package/src/engine-components/ui/Graphic.ts +3 -0
- package/src/engine-components/ui/Interfaces.ts +2 -0
|
@@ -6,6 +6,14 @@ import { getParam } from './engine_utils';
|
|
|
6
6
|
|
|
7
7
|
const debug = getParam("debuggetcomponent");
|
|
8
8
|
|
|
9
|
+
function tryGetObject(obj) {
|
|
10
|
+
if(obj === null || obj === undefined) return obj;
|
|
11
|
+
if(obj.isObject3D) return obj;
|
|
12
|
+
// handle threejs intersection object
|
|
13
|
+
if (obj.object && obj.object.isObject3D) return obj.object;
|
|
14
|
+
return obj;
|
|
15
|
+
}
|
|
16
|
+
|
|
9
17
|
export function registerComponent(script, context) {
|
|
10
18
|
if (!script) return;
|
|
11
19
|
const new_scripts = context?.new_scripts ?? Context.Current.new_scripts;
|
|
@@ -134,6 +142,14 @@ const getComponentsInChildren = function (componentType, obj, arr) {
|
|
|
134
142
|
|
|
135
143
|
const getComponentInParent = function (componentType, obj) {
|
|
136
144
|
if (!obj) return null;
|
|
145
|
+
if (Array.isArray(obj)) {
|
|
146
|
+
for (let i = 0; i < obj.length; i++) {
|
|
147
|
+
const o = tryGetObject(obj[i]);
|
|
148
|
+
const res = getComponentInParent(componentType, o);
|
|
149
|
+
if (res) return res;
|
|
150
|
+
}
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
137
153
|
// console.log(obj);
|
|
138
154
|
const res = getComponent(componentType, obj);
|
|
139
155
|
if (res) return res;
|
|
@@ -1,10 +1,34 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
|
+
import { assign } from './engine_serialization_core';
|
|
2
3
|
import { Context } from './engine_setup';
|
|
3
4
|
|
|
4
|
-
export declare type PointerEventArgs = {
|
|
5
|
+
export declare type PointerEventArgs = {
|
|
6
|
+
button: number;
|
|
7
|
+
clientX: number;
|
|
8
|
+
clientY: number;
|
|
9
|
+
pointerId?: number,
|
|
10
|
+
pointerType: string,
|
|
11
|
+
source?: Event
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export class KeyEventArgs {
|
|
15
|
+
key: string;
|
|
16
|
+
keyType: string;
|
|
17
|
+
source?: Event;
|
|
18
|
+
constructor(evt : KeyboardEvent){
|
|
19
|
+
this.key = evt.key;
|
|
20
|
+
this.keyType = evt.type;
|
|
21
|
+
this.source = evt;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
5
24
|
|
|
6
25
|
export enum InputEvents {
|
|
7
|
-
PointerDown = "
|
|
26
|
+
PointerDown = "pointerdown",
|
|
27
|
+
PointerUp = "pointerup",
|
|
28
|
+
PointerMove = "pointermove",
|
|
29
|
+
KeyDown = "keydown",
|
|
30
|
+
KeyUp = "keyup",
|
|
31
|
+
KeyPressed = "keypress"
|
|
8
32
|
}
|
|
9
33
|
|
|
10
34
|
// export class InputEvent extends Event {
|
|
@@ -244,29 +268,32 @@ export class Input extends EventTarget {
|
|
|
244
268
|
|
|
245
269
|
private keysPressed: { [key: number]: { pressed: boolean, frame: number, startFrame: number, key: string } } = {};
|
|
246
270
|
|
|
247
|
-
private onKeyDown(evt) {
|
|
271
|
+
private onKeyDown(evt: KeyboardEvent) {
|
|
248
272
|
if (!this.context.application.hasFocus)
|
|
249
273
|
return;
|
|
250
|
-
const ex = this.keysPressed[evt.
|
|
274
|
+
const ex = this.keysPressed[evt.key];
|
|
251
275
|
if (ex && ex.pressed) return;
|
|
252
|
-
this.keysPressed[evt.
|
|
276
|
+
this.keysPressed[evt.key] = { pressed: true, frame: this.context.time.frameCount + 1, startFrame: this.context.time.frameCount + 1, key: evt.key };
|
|
277
|
+
this.onDispatchEvent(InputEvents.KeyDown, new KeyEventArgs(evt));
|
|
253
278
|
}
|
|
254
|
-
private onKeyPressed(evt) {
|
|
279
|
+
private onKeyPressed(evt: KeyboardEvent) {
|
|
255
280
|
if (!this.context.application.hasFocus)
|
|
256
281
|
return;
|
|
257
|
-
const p = this.keysPressed[evt.
|
|
282
|
+
const p = this.keysPressed[evt.key];
|
|
258
283
|
if (!p) return;
|
|
259
284
|
p.pressed = true;
|
|
260
285
|
p.frame = this.context.time.frameCount + 1;
|
|
286
|
+
this.onDispatchEvent(InputEvents.KeyPressed, new KeyEventArgs(evt));
|
|
287
|
+
|
|
261
288
|
}
|
|
262
|
-
private onKeyUp(evt) {
|
|
289
|
+
private onKeyUp(evt: KeyboardEvent) {
|
|
263
290
|
if (!this.context.application.hasFocus)
|
|
264
291
|
return;
|
|
265
|
-
const p = this.keysPressed[evt.
|
|
292
|
+
const p = this.keysPressed[evt.key];
|
|
266
293
|
if (!p) return;
|
|
267
294
|
p.pressed = false;
|
|
268
295
|
p.frame = this.context.time.frameCount + 1;
|
|
269
|
-
|
|
296
|
+
this.onDispatchEvent(InputEvents.KeyUp, new KeyEventArgs(evt));
|
|
270
297
|
}
|
|
271
298
|
|
|
272
299
|
private onMouseWheel(_evt) {
|
|
@@ -297,8 +324,8 @@ export class Input extends EventTarget {
|
|
|
297
324
|
private onPointerDown(evt: PointerEvent) {
|
|
298
325
|
if (evt.defaultPrevented) return;
|
|
299
326
|
if (evt.pointerType === undefined && evt.pointerId === undefined) return;
|
|
300
|
-
if (evt.preventDefault)
|
|
301
|
-
|
|
327
|
+
// if (evt.preventDefault)
|
|
328
|
+
// evt.preventDefault();
|
|
302
329
|
let i = evt.pointerType === "mouse" ? evt.button : this.getPointerIndex(evt.pointerId);
|
|
303
330
|
if (evt.pointerId === undefined && evt.button !== undefined) {
|
|
304
331
|
i = evt.button;
|
|
@@ -308,12 +335,12 @@ export class Input extends EventTarget {
|
|
|
308
335
|
// evt.stopPropagation();
|
|
309
336
|
}
|
|
310
337
|
|
|
311
|
-
private onPointerMove(evt: PointerEvent
|
|
338
|
+
private onPointerMove(evt: PointerEvent) {
|
|
312
339
|
// console.log(evt);
|
|
313
340
|
if (evt.defaultPrevented) return;
|
|
314
341
|
if (evt.pointerType === undefined && evt.pointerId === undefined) return;
|
|
315
|
-
if (suppressPreventDefault !== true)
|
|
316
|
-
|
|
342
|
+
// if (suppressPreventDefault !== true)
|
|
343
|
+
// evt.preventDefault();
|
|
317
344
|
let i = evt.pointerType === "mouse" ? evt.button : this.getPointerIndex(evt.pointerId);
|
|
318
345
|
if (evt.pointerId === undefined && evt.button !== undefined) {
|
|
319
346
|
i = evt.button;
|
|
@@ -321,13 +348,14 @@ export class Input extends EventTarget {
|
|
|
321
348
|
if (i < 0) i = 0;
|
|
322
349
|
const args = { button: i, clientX: evt.clientX, clientY: evt.clientY, pointerType: evt.pointerType, source: evt };
|
|
323
350
|
this.onMove(args);
|
|
351
|
+
this.onDispatchEvent(InputEvents.PointerMove, evt);
|
|
324
352
|
}
|
|
325
353
|
|
|
326
|
-
private onPointerUp(evt: PointerEvent
|
|
354
|
+
private onPointerUp(evt: PointerEvent) {
|
|
327
355
|
if (evt.defaultPrevented) return;
|
|
328
356
|
if (evt.pointerType === undefined && evt.pointerId === undefined) return;
|
|
329
|
-
if (suppressPreventDefault !== true)
|
|
330
|
-
|
|
357
|
+
// if (suppressPreventDefault !== true)
|
|
358
|
+
// evt.preventDefault();
|
|
331
359
|
// console.log(evt, this._pointerIds);
|
|
332
360
|
let i = evt.pointerType === "mouse" ? evt.button : this.getPointerIndex(evt.pointerId);
|
|
333
361
|
// console.log("INDEX", i);
|
|
@@ -338,6 +366,7 @@ export class Input extends EventTarget {
|
|
|
338
366
|
this.onUp({ button: i, clientX: evt.clientX, clientY: evt.clientY, pointerType: evt.pointerType, source: evt });
|
|
339
367
|
// console.log(this.getPointerPressedCount());
|
|
340
368
|
// evt.stopPropagation();
|
|
369
|
+
this.onDispatchEvent(InputEvents.PointerUp, evt);
|
|
341
370
|
}
|
|
342
371
|
|
|
343
372
|
// private onMouseDown(evt){
|
|
@@ -385,8 +414,7 @@ export class Input extends EventTarget {
|
|
|
385
414
|
this.updatePointerPosition(evt);
|
|
386
415
|
// console.log("DOWN", this._pointerDown, this.mousePositionRC);
|
|
387
416
|
|
|
388
|
-
|
|
389
|
-
this.dispatchEvent(new Event(InputEvents.PointerDown));
|
|
417
|
+
this.onDispatchEvent(InputEvents.PointerDown, evt);
|
|
390
418
|
}
|
|
391
419
|
// moveEvent?: Event;
|
|
392
420
|
private onMove(evt: PointerEventArgs) {
|
|
@@ -474,6 +502,20 @@ export class Input extends EventTarget {
|
|
|
474
502
|
while (arr.length <= index) arr.push(null as any);
|
|
475
503
|
arr[index] = value;
|
|
476
504
|
}
|
|
505
|
+
|
|
506
|
+
private onDispatchEvent(name: InputEvents, args: PointerEventArgs | KeyEventArgs) {
|
|
507
|
+
const prevContext = Context.Current;
|
|
508
|
+
try {
|
|
509
|
+
|
|
510
|
+
Context.Current = this.context;
|
|
511
|
+
const e = new Event(name);
|
|
512
|
+
assign(e, args);
|
|
513
|
+
this.dispatchEvent(e);
|
|
514
|
+
}
|
|
515
|
+
finally {
|
|
516
|
+
Context.Current = prevContext;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
477
519
|
}
|
|
478
520
|
|
|
479
521
|
|
|
@@ -71,6 +71,7 @@ class CannonCollision {
|
|
|
71
71
|
|
|
72
72
|
export class RaycastOptions {
|
|
73
73
|
ray: THREE.Ray | undefined = undefined;
|
|
74
|
+
cam : THREE.Camera | undefined | null = undefined;
|
|
74
75
|
screenPoint: THREE.Vector2 | undefined = undefined;
|
|
75
76
|
raycaster: THREE.Raycaster | undefined = undefined;
|
|
76
77
|
results: Array<THREE.Intersection> | undefined = undefined;
|
|
@@ -193,7 +194,7 @@ export class Physics {
|
|
|
193
194
|
rc.ray.copy(options.ray);
|
|
194
195
|
}
|
|
195
196
|
else {
|
|
196
|
-
const cam = this.context.mainCamera;
|
|
197
|
+
const cam = options.cam ?? this.context.mainCamera;
|
|
197
198
|
if (!cam) {
|
|
198
199
|
console.error("Can not perform raycast - no main camera found");
|
|
199
200
|
if (this.defaultRaycastOptions.results) this.defaultRaycastOptions.results.length = 0;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { getParam } from "./engine_utils";
|
|
2
|
+
import { Object3D } from "three";
|
|
3
|
+
import { Context } from "./engine_setup";
|
|
4
|
+
|
|
5
|
+
const debug = getParam("debugplayerview");
|
|
6
|
+
|
|
7
|
+
export enum ViewDevice {
|
|
8
|
+
Browser = "browser",
|
|
9
|
+
Headset = "headset",
|
|
10
|
+
Handheld = "handheld",
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class PlayerView {
|
|
14
|
+
readonly userId: string;
|
|
15
|
+
readonly context: Context;
|
|
16
|
+
|
|
17
|
+
viewDevice: ViewDevice = ViewDevice.Browser;
|
|
18
|
+
|
|
19
|
+
get currentObject(): Object3D | undefined | null {
|
|
20
|
+
return this._object;
|
|
21
|
+
}
|
|
22
|
+
set currentObject(obj: Object3D | undefined | null) {
|
|
23
|
+
this._object = obj;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
get isConnected(): boolean {
|
|
27
|
+
return this.context.connection.userIsInRoom(this.userId);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
removed: boolean = false;
|
|
31
|
+
|
|
32
|
+
private _object: undefined | Object3D | null;
|
|
33
|
+
|
|
34
|
+
constructor(userId: string, context: Context) {
|
|
35
|
+
this.userId = userId;
|
|
36
|
+
this.context = context;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export class PlayerViewManager {
|
|
41
|
+
|
|
42
|
+
private readonly context: Context;
|
|
43
|
+
private readonly playerViews = new Map<string, PlayerView>();
|
|
44
|
+
|
|
45
|
+
constructor(context: Context) {
|
|
46
|
+
this.context = context;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
setPlayerView(id: string, obj: Object3D | undefined | null, device: ViewDevice) {
|
|
50
|
+
let view = this.playerViews.get(id);
|
|
51
|
+
if (!view) {
|
|
52
|
+
view = new PlayerView(id, this.context);
|
|
53
|
+
this.playerViews.set(id, view);
|
|
54
|
+
}
|
|
55
|
+
view.viewDevice = device;
|
|
56
|
+
view.currentObject = obj;
|
|
57
|
+
view.removed = false;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
getPlayerView(id: string | null | undefined): PlayerView | undefined {
|
|
61
|
+
if (!id) return undefined;
|
|
62
|
+
if (!this.context.connection.userIsInRoom(id)) {
|
|
63
|
+
this.playerViews.delete(id);
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
const view = this.playerViews.get(id);
|
|
67
|
+
return view;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
removePlayerView(id: string, device: ViewDevice) {
|
|
71
|
+
const view = this.playerViews.get(id);
|
|
72
|
+
if (view?.viewDevice === device) {
|
|
73
|
+
if (debug)
|
|
74
|
+
console.log("REMOVE", id);
|
|
75
|
+
view.removed = true;
|
|
76
|
+
this.playerViews.delete(id);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { serializeObject, deserializeObject } from "./engine_serialization_core";
|
|
2
2
|
import * as builtin from "./engine_serialization_builtin_serializer";
|
|
3
3
|
// export builtin so it will be called and registered
|
|
4
|
-
export { serializeObject, deserializeObject, builtin };
|
|
4
|
+
export { serializeObject, deserializeObject, builtin };
|
|
5
|
+
|
|
6
|
+
export { serializeable } from "./engine_serialization_decorator"
|
|
@@ -248,6 +248,14 @@ export function deserializeObject(obj: ISerializable, serializedData: object, co
|
|
|
248
248
|
for (const key in typeInfo) {
|
|
249
249
|
const serializedEntryInfo = typeInfo[key];
|
|
250
250
|
const data = serializedData[key];
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
if (obj[key] !== undefined && data === undefined) {
|
|
254
|
+
// if a field is marked as serialized and has some default value
|
|
255
|
+
// but no data was serialized do not override the default value with undefined
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
|
|
251
259
|
context.path = key;
|
|
252
260
|
|
|
253
261
|
if (serializedEntryInfo === null) {
|
|
@@ -26,6 +26,7 @@ import { RendererData } from './engine_rendererdata';
|
|
|
26
26
|
import { Addressables } from './engine_addressables';
|
|
27
27
|
import { Application } from './engine_application';
|
|
28
28
|
import { LightDataRegistry, ILightDataRegistry } from './engine_lightdata';
|
|
29
|
+
import { PlayerViewManager } from './engine_playerview';
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
const debug = utils.getParam("debugSetup");
|
|
@@ -71,6 +72,11 @@ export enum FrameEvent {
|
|
|
71
72
|
PhysicsStep = 10,
|
|
72
73
|
}
|
|
73
74
|
|
|
75
|
+
export enum XRSessionMode {
|
|
76
|
+
ImmersiveVR = "immersive-vr",
|
|
77
|
+
ImmersiveAR = "immersive-ar",
|
|
78
|
+
}
|
|
79
|
+
|
|
74
80
|
export declare type OnBeforeRenderCallback = (renderer: THREE.WebGLRenderer, scene: THREE.Scene, camera: THREE.Camera, geometry: THREE.BufferGeometry, material: THREE.Material, group: THREE.Group) => void
|
|
75
81
|
|
|
76
82
|
export class Context {
|
|
@@ -108,6 +114,7 @@ export class Context {
|
|
|
108
114
|
get domX(): number { return this.domElement.offsetLeft; }
|
|
109
115
|
get domY(): number { return this.domElement.offsetTop; }
|
|
110
116
|
get isInXR() { return this.renderer.xr?.isPresenting || false; }
|
|
117
|
+
xrSessionMode : XRSessionMode | undefined = undefined;
|
|
111
118
|
get xrSession() { return this.renderer.xr?.getSession(); }
|
|
112
119
|
get arOverlayElement(): HTMLElement {
|
|
113
120
|
const el = this.domElement as any;
|
|
@@ -165,6 +172,7 @@ export class Context {
|
|
|
165
172
|
rendererData: RendererData;
|
|
166
173
|
addressables: Addressables;
|
|
167
174
|
lightmaps: ILightDataRegistry;
|
|
175
|
+
players : PlayerViewManager;
|
|
168
176
|
|
|
169
177
|
private _sizeChanged: boolean = false;
|
|
170
178
|
private _isCreated: boolean = false;
|
|
@@ -212,6 +220,7 @@ export class Context {
|
|
|
212
220
|
this.rendererData = new RendererData(this);
|
|
213
221
|
this.addressables = new Addressables(this);
|
|
214
222
|
this.lightmaps = new LightDataRegistry(this);
|
|
223
|
+
this.players = new PlayerViewManager(this);
|
|
215
224
|
|
|
216
225
|
window.addEventListener('resize', this.updateSize.bind(this));
|
|
217
226
|
const ro = new ResizeObserver(_ => this._sizeChanged = true);
|
|
@@ -310,6 +319,21 @@ export class Context {
|
|
|
310
319
|
(this.mainCameraComponent as Camera)?.applyClearFlagsIfIsActiveCamera();
|
|
311
320
|
}
|
|
312
321
|
|
|
322
|
+
removeCamera(cam?: Camera | null) {
|
|
323
|
+
if(!cam) return;
|
|
324
|
+
const index = this._cameraStack.indexOf(cam);
|
|
325
|
+
if (index >= 0) this._cameraStack.splice(index, 1);
|
|
326
|
+
|
|
327
|
+
if (this.mainCameraComponent === cam) {
|
|
328
|
+
this.mainCameraComponent = undefined;
|
|
329
|
+
|
|
330
|
+
if (this._cameraStack.length > 0) {
|
|
331
|
+
const last = this._cameraStack[this._cameraStack.length - 1];
|
|
332
|
+
this.setCurrentCamera(last);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
313
337
|
private _onBeforeRenderListeners: { [key: string]: OnBeforeRenderCallback[] } = {};
|
|
314
338
|
|
|
315
339
|
/** use this to subscribe to onBeforeRender events on threejs objects */
|
|
@@ -181,17 +181,43 @@ export function delay(milliseconds: number): Promise<void> {
|
|
|
181
181
|
// if a timeline is exported via menu item the audio clip path is relative to the glb (same folder)
|
|
182
182
|
// we need to detect that here and build the new audio source path relative to the new glb location
|
|
183
183
|
// the same is/might be true for any file that is/will be exported via menu item
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
184
|
+
const debugGetPath = getParam("debugsourcepath");
|
|
185
|
+
export function getPath(source: SourceIdentifier | undefined, uri: string): string {
|
|
186
|
+
if (source === undefined) {
|
|
187
|
+
if (debugGetPath) console.warn("getPath: source is undefined, returning uri", uri);
|
|
188
|
+
return uri;
|
|
189
|
+
}
|
|
190
|
+
if (uri.startsWith("http")) {
|
|
191
|
+
if (debugGetPath) console.warn("getPath: uri is absolute, returning uri", uri);
|
|
192
|
+
return uri;
|
|
193
|
+
}
|
|
194
|
+
const pathIndex = source.lastIndexOf("/");
|
|
195
|
+
if (pathIndex >= 0) {
|
|
196
|
+
let newUri = source.substring(0, pathIndex + 1);
|
|
197
|
+
|
|
198
|
+
const uriDirectoryIndex = uri.lastIndexOf("/");
|
|
199
|
+
if (uriDirectoryIndex >= 0) {
|
|
200
|
+
newUri += uri.substring(uriDirectoryIndex + 1);
|
|
201
|
+
} else {
|
|
202
|
+
newUri += uri;
|
|
191
203
|
}
|
|
204
|
+
if (debugGetPath) console.log("getPath:", source, " - changed uri from\n", uri, "\n→ ", newUri);
|
|
205
|
+
return newUri;
|
|
192
206
|
}
|
|
193
|
-
return
|
|
207
|
+
return uri;
|
|
194
208
|
}
|
|
209
|
+
// export function getPath(glbLocation: SourceIdentifier | undefined, path: string) {
|
|
210
|
+
// if (path && glbLocation && !path.includes("/")) {
|
|
211
|
+
// // get directory of glb and prepend it to the audio file path
|
|
212
|
+
// const pathIndex = glbLocation.lastIndexOf("/");
|
|
213
|
+
// if (pathIndex >= 0) {
|
|
214
|
+
// const newPath = glbLocation.substring(0, pathIndex + 1) + path;
|
|
215
|
+
// return newPath;
|
|
216
|
+
// }
|
|
217
|
+
// }
|
|
218
|
+
// return path;
|
|
219
|
+
// }
|
|
220
|
+
|
|
195
221
|
|
|
196
222
|
export type WriteCallback = (data: any) => void;
|
|
197
223
|
|
|
@@ -3,7 +3,7 @@ import { GLTF, GLTFLoader, GLTFLoaderPlugin, GLTFParser } from "three/examples/j
|
|
|
3
3
|
import { SourceIdentifier } from "../engine_gltf";
|
|
4
4
|
import { Context } from "../engine_setup";
|
|
5
5
|
import { addDracoAndKTX2Loaders } from "../engine_loaders";
|
|
6
|
-
import { getParam } from "../engine_utils";
|
|
6
|
+
import { getParam, getPath } from "../engine_utils";
|
|
7
7
|
|
|
8
8
|
export const EXTENSION_NAME = "NEEDLE_deferred_texture";
|
|
9
9
|
|
|
@@ -11,24 +11,27 @@ const debug = getParam("debugdeferredtextures")
|
|
|
11
11
|
|
|
12
12
|
declare type DeferredTextureModel = {
|
|
13
13
|
uri: string;
|
|
14
|
-
guid
|
|
14
|
+
guid: string;
|
|
15
15
|
usage?: string,
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export class NEEDLE_deferred_texture implements GLTFLoaderPlugin {
|
|
19
19
|
|
|
20
|
-
static assignTextureLOD(context: Context, material: Material, level: number = 0) {
|
|
20
|
+
static assignTextureLOD(context: Context, source : SourceIdentifier | undefined, material: Material, level: number = 0) {
|
|
21
21
|
if (!material) return;
|
|
22
22
|
for (const slot of Object.keys(material)) {
|
|
23
23
|
const val = material[slot];
|
|
24
24
|
if (val?.isTexture === true) {
|
|
25
25
|
if (debug)
|
|
26
|
-
console.log("FIND", slot, val?.name, val?.userData, val);
|
|
27
|
-
NEEDLE_deferred_texture.getOrLoadTexture(context, material, slot, val, level).then(t => {
|
|
26
|
+
console.log("-----------\n", "FIND", material.name, slot, val?.name, val?.userData, val);
|
|
27
|
+
NEEDLE_deferred_texture.getOrLoadTexture(context, source, material, slot, val, level).then(t => {
|
|
28
28
|
if (t?.isTexture === true) {
|
|
29
29
|
t.needsUpdate = true;
|
|
30
|
+
if (debug)
|
|
31
|
+
console.log("Assign LOD", material.name, slot, t.name, t["guid"], material, "Prev:", val, "Now:", t, "\n--------------");
|
|
30
32
|
material[slot] = t;
|
|
31
33
|
material.needsUpdate = true;
|
|
34
|
+
|
|
32
35
|
}
|
|
33
36
|
});
|
|
34
37
|
}
|
|
@@ -67,9 +70,8 @@ export class NEEDLE_deferred_texture implements GLTFLoaderPlugin {
|
|
|
67
70
|
// }
|
|
68
71
|
|
|
69
72
|
afterRoot(gltf: GLTF): null {
|
|
70
|
-
|
|
71
73
|
if (debug)
|
|
72
|
-
console.log("AFTER", gltf);
|
|
74
|
+
console.log("AFTER", this.sourceId, gltf);
|
|
73
75
|
this.parser.json.textures?.forEach((textureInfo, index) => {
|
|
74
76
|
if (textureInfo?.extensions) {
|
|
75
77
|
const ext: DeferredTextureModel = textureInfo?.extensions[EXTENSION_NAME];
|
|
@@ -91,29 +93,31 @@ export class NEEDLE_deferred_texture implements GLTFLoaderPlugin {
|
|
|
91
93
|
private static cache = new Map<string, DeferredTextureModel>();
|
|
92
94
|
private static resolved: { [key: string]: Texture } = {};
|
|
93
95
|
|
|
94
|
-
private static async getOrLoadTexture(context: Context, material: Material, slot: string, current: Texture, _level: number): Promise<Texture | null> {
|
|
96
|
+
private static async getOrLoadTexture(context: Context, source : SourceIdentifier | undefined, material: Material, slot: string, current: Texture, _level: number): Promise<Texture | null> {
|
|
95
97
|
|
|
96
98
|
const key = current.uuid;
|
|
97
|
-
const ext: DeferredTextureModel = NEEDLE_deferred_texture.cache.get(key) || current.userData.deferred;
|
|
99
|
+
const ext: DeferredTextureModel | undefined = NEEDLE_deferred_texture.cache.get(key);// || current.userData.deferred;
|
|
98
100
|
if (ext) {
|
|
99
101
|
if (debug)
|
|
100
102
|
console.log(key, ext.uri, ext.guid);
|
|
101
|
-
const uri = ext.uri;
|
|
103
|
+
const uri = getPath(source, ext.uri);
|
|
102
104
|
if (uri.endsWith(".glb") || uri.endsWith(".gltf")) {
|
|
103
105
|
if (!ext.guid) {
|
|
104
106
|
console.warn("missing pointer for glb/gltf texture", ext);
|
|
105
107
|
return null;
|
|
106
108
|
}
|
|
107
|
-
const resolveKey =
|
|
108
|
-
if (this.resolved[resolveKey])
|
|
109
|
+
const resolveKey = uri + "_" + ext.guid;
|
|
110
|
+
if (this.resolved[resolveKey]) {
|
|
111
|
+
if (debug) console.log("Texture has already been loaded: " + resolveKey, material.name, slot, current.name);
|
|
109
112
|
return this.resolved[resolveKey];
|
|
113
|
+
}
|
|
110
114
|
|
|
111
115
|
const loader = new GLTFLoader();
|
|
112
116
|
addDracoAndKTX2Loaders(loader, context);
|
|
113
|
-
if (debug) console.log("Load " + uri, material.name, slot);
|
|
117
|
+
if (debug) console.log("Load " + uri, material.name, slot, ext.guid);
|
|
114
118
|
const gltf = await loader.loadAsync(uri);
|
|
115
119
|
const parser = gltf.parser;
|
|
116
|
-
|
|
120
|
+
if (debug) console.log("Loading finished " + uri, material.name, slot, ext.guid);
|
|
117
121
|
let index = -1;
|
|
118
122
|
let found = false;
|
|
119
123
|
for (const tex of gltf.parser.json.textures) {
|
|
@@ -137,20 +141,22 @@ export class NEEDLE_deferred_texture implements GLTFLoaderPlugin {
|
|
|
137
141
|
|
|
138
142
|
// const index = Number.parseInt(ext.pointer.substring("textures/".length));
|
|
139
143
|
const tex = await parser.getDependency("texture", index);
|
|
144
|
+
if (tex) {
|
|
145
|
+
tex.guid = ext.guid;
|
|
146
|
+
}
|
|
140
147
|
this.resolved[resolveKey] = tex as Texture;
|
|
141
|
-
|
|
142
148
|
if (debug)
|
|
143
|
-
console.log(material.name, slot, "change \"" + current.name + "\" → \"" + tex.name + "\"", uri, index, tex, material);
|
|
149
|
+
console.log(material.name, slot, "change \"" + current.name + "\" → \"" + tex.name + "\"", uri, index, tex, material, resolveKey);
|
|
144
150
|
return tex;
|
|
145
151
|
}
|
|
146
152
|
else {
|
|
147
|
-
|
|
153
|
+
if (debug) console.log("Load texture from uri: " + uri);
|
|
148
154
|
const loader = new TextureLoader();
|
|
149
|
-
const loaded = await loader.loadAsync(
|
|
155
|
+
const loaded = await loader.loadAsync(uri);
|
|
150
156
|
if (loaded && debug) {
|
|
151
157
|
console.log(ext, loaded);
|
|
152
158
|
}
|
|
153
|
-
else console.warn("failed loading",
|
|
159
|
+
else console.warn("failed loading", uri);
|
|
154
160
|
return loaded;
|
|
155
161
|
}
|
|
156
162
|
// loader.then((h: Texture) => {
|
|
@@ -99,13 +99,14 @@ export class SceneLightSettings extends Behaviour {
|
|
|
99
99
|
onEnable() {
|
|
100
100
|
const isActive = this.context.mainCameraComponent?.sourceId === this.sourceId;
|
|
101
101
|
if (debug)
|
|
102
|
-
console.log("
|
|
102
|
+
console.log("Enable scene lighting", this.sourceId, isActive, this, this.context.mainCameraComponent?.sourceId);
|
|
103
103
|
if (!isActive) {
|
|
104
|
+
if(debug) console.warn("This is no active?!", this.context.mainCameraComponent?.sourceId)
|
|
104
105
|
// this.enabled = false;
|
|
105
106
|
// return;
|
|
106
107
|
}
|
|
107
108
|
if (this.ambientMode == AmbientMode.Flat) {
|
|
108
|
-
if (this.ambientLight) {
|
|
109
|
+
if (this.ambientLight && !this._ambientLightObj) {
|
|
109
110
|
this._ambientLightObj = new AmbientLight(this.ambientLight, Math.PI * this.ambientIntensity);
|
|
110
111
|
}
|
|
111
112
|
if (this._ambientLightObj) {
|
|
@@ -155,6 +156,7 @@ export class SceneLightSettings extends Behaviour {
|
|
|
155
156
|
if (debug)
|
|
156
157
|
console.log("disable", this.sourceId, this);
|
|
157
158
|
if (this._lightProbeObj) this._lightProbeObj.removeFromParent();
|
|
159
|
+
if(this._ambientLightObj) this._ambientLightObj.removeFromParent();
|
|
158
160
|
if (this.sourceId)
|
|
159
161
|
this.context.rendererData.disableReflection();
|
|
160
162
|
}
|
|
@@ -10,13 +10,20 @@ declare type DependencyInfo = {
|
|
|
10
10
|
dependencyName: string,
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
const rootExtensionPrefix = "/extensions/";
|
|
13
|
+
const rootExtensionPrefix = ["/extensions/", "extensions/"];
|
|
14
14
|
const defaultDependencies = [
|
|
15
15
|
{ prefix: "/nodes/", dependencyName: "node" },
|
|
16
16
|
{ prefix: "/meshes/", dependencyName: "mesh" },
|
|
17
17
|
{ prefix: "/materials/", dependencyName: "material" },
|
|
18
18
|
{ prefix: "/textures/", dependencyName: "texture" },
|
|
19
|
-
{ prefix: "/animations/", dependencyName: "animation" }
|
|
19
|
+
{ prefix: "/animations/", dependencyName: "animation" },
|
|
20
|
+
|
|
21
|
+
// legacy support
|
|
22
|
+
{ prefix: "nodes/", dependencyName: "node" },
|
|
23
|
+
{ prefix: "meshes/", dependencyName: "mesh" },
|
|
24
|
+
{ prefix: "materials/", dependencyName: "material" },
|
|
25
|
+
{ prefix: "textures/", dependencyName: "texture" },
|
|
26
|
+
{ prefix: "animations/", dependencyName: "animation" },
|
|
20
27
|
]
|
|
21
28
|
|
|
22
29
|
export async function resolveReferences(parser: GLTFParser, obj) {
|
|
@@ -95,16 +102,21 @@ function internalResolve(paths: DependencyInfo[], parser: GLTFParser, obj, promi
|
|
|
95
102
|
|
|
96
103
|
|
|
97
104
|
function resolveExtension(parser: GLTFParser, str): Promise<void> | null {
|
|
98
|
-
if (parser && parser.plugins && typeof str === "string"
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
if (parser && parser.plugins && typeof str === "string") {
|
|
106
|
+
for (const prefix of rootExtensionPrefix) {
|
|
107
|
+
if (str.startsWith(prefix)) {
|
|
108
|
+
let name = str.substring(prefix.length);
|
|
109
|
+
const endIndex = name.indexOf("/");
|
|
110
|
+
if (endIndex >= 0) name = name.substring(0, endIndex);
|
|
111
|
+
const ext = parser.plugins[name] as IExtensionReferenceResolver;
|
|
112
|
+
if (debugExtension)
|
|
113
|
+
console.log(name, ext);
|
|
114
|
+
if (typeof ext?.resolve === "function") {
|
|
115
|
+
const path = str.substring(prefix.length + name.length + 1);
|
|
116
|
+
return ext.resolve(parser, path);
|
|
117
|
+
}
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
108
120
|
}
|
|
109
121
|
}
|
|
110
122
|
return null;
|
|
@@ -26,8 +26,9 @@ export function registerComponentExtension(loader: GLTFLoader): NEEDLE_component
|
|
|
26
26
|
class PointerResolver {
|
|
27
27
|
resolvePath(path: string) {
|
|
28
28
|
if (path.includes('/extensions/builtin_components/'))
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
return path.replace('/extensions/builtin_components/', '/userData/components/');
|
|
30
|
+
if (path.includes('extensions/builtin_components/'))
|
|
31
|
+
return path.replace('extensions/builtin_components/', '/userData/components/');
|
|
31
32
|
return path;
|
|
32
33
|
}
|
|
33
34
|
}
|