@needle-tools/engine 2.61.0-pre → 2.62.1-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 +11 -0
- package/dist/needle-engine.js +24479 -24329
- package/dist/needle-engine.umd.cjs +230 -232
- package/lib/engine/debug/debug_overlay.js +9 -9
- package/lib/engine/debug/debug_overlay.js.map +1 -1
- package/lib/engine/engine_addressables.js +16 -5
- package/lib/engine/engine_addressables.js.map +1 -1
- package/lib/engine/engine_loaders.d.ts +1 -0
- package/lib/engine/engine_loaders.js +12 -0
- package/lib/engine/engine_loaders.js.map +1 -1
- package/lib/engine-components/Animation.js +12 -3
- package/lib/engine-components/Animation.js.map +1 -1
- package/lib/engine-components/timeline/PlayableDirector.js +27 -17
- package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
- package/lib/engine-components/ui/EventSystem.js +3 -1
- package/lib/engine-components/ui/EventSystem.js.map +1 -1
- package/lib/engine-components/ui/Text.js +1 -0
- package/lib/engine-components/ui/Text.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/engine/debug/debug_overlay.ts +9 -9
- package/src/engine/engine_addressables.ts +13 -5
- package/src/engine/engine_loaders.ts +13 -0
- package/src/engine-components/Animation.ts +11 -3
- package/src/engine-components/timeline/PlayableDirector.ts +25 -17
- package/src/engine-components/ui/EventSystem.ts +3 -1
- package/src/engine-components/ui/Text.ts +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/engine",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.62.1-pre",
|
|
4
4
|
"description": "Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally.",
|
|
5
5
|
"main": "dist/needle-engine.umd.cjs",
|
|
6
6
|
"module": "dist/needle-engine.js",
|
|
@@ -115,39 +115,37 @@ const logsContainerStyles = `
|
|
|
115
115
|
|
|
116
116
|
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
|
|
117
117
|
|
|
118
|
-
|
|
119
|
-
div {
|
|
118
|
+
div[data-needle_engine_debug_overlay] {
|
|
120
119
|
font-family: 'Roboto', sans-serif;
|
|
121
120
|
font-weight: 400;
|
|
122
121
|
}
|
|
123
122
|
|
|
124
|
-
strong {
|
|
123
|
+
div[data-needle_engine_debug_overlay] strong {
|
|
125
124
|
font-weight: 700;
|
|
126
125
|
}
|
|
127
126
|
|
|
128
|
-
a {
|
|
127
|
+
div[data-needle_engine_debug_overlay] a {
|
|
129
128
|
color: white;
|
|
130
129
|
text-decoration: none;
|
|
131
130
|
border-bottom: 1px solid rgba(255, 255, 255, 0.3);
|
|
132
131
|
}
|
|
133
132
|
|
|
134
|
-
a:hover {
|
|
133
|
+
div[data-needle_engine_debug_overlay] a:hover {
|
|
135
134
|
text-decoration: none;
|
|
136
135
|
border: none;
|
|
137
136
|
}
|
|
138
137
|
|
|
139
|
-
.log strong {
|
|
138
|
+
div[data-needle_engine_debug_overlay] .log strong {
|
|
140
139
|
color: rgba(200,200,200,.9);
|
|
141
140
|
}
|
|
142
141
|
|
|
143
|
-
.warn strong {
|
|
142
|
+
div[data-needle_engine_debug_overlay] .warn strong {
|
|
144
143
|
color: rgba(255,255,230, 1);
|
|
145
144
|
}
|
|
146
145
|
|
|
147
|
-
.error strong {
|
|
146
|
+
div[data-needle_engine_debug_overlay] .error strong {
|
|
148
147
|
color: rgba(255,100,120, 1);
|
|
149
148
|
}
|
|
150
|
-
|
|
151
149
|
`;
|
|
152
150
|
|
|
153
151
|
function getLogsContainer(domElement: HTMLElement): HTMLElement {
|
|
@@ -155,6 +153,7 @@ function getLogsContainer(domElement: HTMLElement): HTMLElement {
|
|
|
155
153
|
return errorContainer.get(domElement)!;
|
|
156
154
|
} else {
|
|
157
155
|
const container = document.createElement("div");
|
|
156
|
+
container.setAttribute("data-needle_engine_debug_overlay", "");
|
|
158
157
|
container.classList.add(arContainerClassName);
|
|
159
158
|
container.classList.add("desktop");
|
|
160
159
|
container.classList.add("debug-container");
|
|
@@ -206,6 +205,7 @@ function getMessageContainer(type: LogType, msg: string): HTMLElement {
|
|
|
206
205
|
}
|
|
207
206
|
}
|
|
208
207
|
const element = document.createElement("div");
|
|
208
|
+
element.setAttribute("data-id", "__needle_engine_debug_overlay");
|
|
209
209
|
element.style.marginRight = "5px";
|
|
210
210
|
element.style.padding = ".5em";
|
|
211
211
|
element.style.backgroundColor = "rgba(0,0,0,.9)";
|
|
@@ -60,7 +60,7 @@ export class AssetReference {
|
|
|
60
60
|
return ref;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
private static currentlyInstantiating: string
|
|
63
|
+
private static currentlyInstantiating: Map<string, number> = new Map<string, number>();
|
|
64
64
|
|
|
65
65
|
get asset(): any {
|
|
66
66
|
return this._glbRoot ?? this._asset;
|
|
@@ -236,12 +236,16 @@ export class AssetReference {
|
|
|
236
236
|
}
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
-
|
|
240
|
-
|
|
239
|
+
let count = AssetReference.currentlyInstantiating.get(this.uri);
|
|
240
|
+
// allow up to 100 instantiations of the same prefab in the same frame
|
|
241
|
+
if (count !== undefined && count >= 100) {
|
|
242
|
+
console.error("Recursive or too many instantiations of " + this.uri + " in the same frame (" + count + ")");
|
|
241
243
|
return null;
|
|
242
244
|
}
|
|
243
245
|
try {
|
|
244
|
-
|
|
246
|
+
if (count === undefined) count = 0;
|
|
247
|
+
count += 1;
|
|
248
|
+
AssetReference.currentlyInstantiating.set(this.uri, count);
|
|
245
249
|
if (networked) {
|
|
246
250
|
options.context = context;
|
|
247
251
|
const prefab = this.asset;
|
|
@@ -259,7 +263,11 @@ export class AssetReference {
|
|
|
259
263
|
}
|
|
260
264
|
}
|
|
261
265
|
finally {
|
|
262
|
-
context.post_render_callbacks.push(() =>
|
|
266
|
+
context.post_render_callbacks.push(() => {
|
|
267
|
+
if (count === undefined || count < 0) count = 0;
|
|
268
|
+
else count -= 1;
|
|
269
|
+
AssetReference.currentlyInstantiating.set(this.uri, count)
|
|
270
|
+
});
|
|
263
271
|
}
|
|
264
272
|
|
|
265
273
|
}
|
|
@@ -3,6 +3,8 @@ import { Context } from "./engine_setup"
|
|
|
3
3
|
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
|
|
4
4
|
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
|
5
5
|
import { KTX2Loader } from 'three/examples/jsm/loaders/KTX2Loader.js';
|
|
6
|
+
import { MeshoptDecoder } from 'three/examples/jsm/libs/meshopt_decoder.module.js';
|
|
7
|
+
|
|
6
8
|
import { getParam } from "./engine_utils";
|
|
7
9
|
|
|
8
10
|
const debug = getParam("debugdecoders");
|
|
@@ -11,6 +13,7 @@ const DEFAULT_DRACO_DECODER_LOCATION ='https://www.gstatic.com/draco/versioned/d
|
|
|
11
13
|
const DEFAULT_KTX2_TRANSCODER_LOCATION ='https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/';
|
|
12
14
|
|
|
13
15
|
let dracoLoader: DRACOLoader;
|
|
16
|
+
let meshoptDecoder: MeshoptDecoder;
|
|
14
17
|
let ktx2Loader: KTX2Loader;
|
|
15
18
|
|
|
16
19
|
export function setDracoDecoderPath(path: string | undefined) {
|
|
@@ -40,6 +43,11 @@ export function setKtx2TranscoderPath(path: string) {
|
|
|
40
43
|
}
|
|
41
44
|
}
|
|
42
45
|
|
|
46
|
+
export function setMeshoptDecoder(_meshoptDecoder: any) {
|
|
47
|
+
if (_meshoptDecoder !== undefined)
|
|
48
|
+
meshoptDecoder = _meshoptDecoder;
|
|
49
|
+
}
|
|
50
|
+
|
|
43
51
|
export function addDracoAndKTX2Loaders(loader: GLTFLoader, context: Context) {
|
|
44
52
|
if (!dracoLoader) {
|
|
45
53
|
dracoLoader = new DRACOLoader();
|
|
@@ -54,7 +62,12 @@ export function addDracoAndKTX2Loaders(loader: GLTFLoader, context: Context) {
|
|
|
54
62
|
if (context.renderer)
|
|
55
63
|
ktx2Loader.detectSupport(context.renderer);
|
|
56
64
|
}
|
|
65
|
+
if (!meshoptDecoder) {
|
|
66
|
+
meshoptDecoder = MeshoptDecoder;
|
|
67
|
+
if (debug) console.log("Using the default meshopt decoder");
|
|
68
|
+
}
|
|
57
69
|
|
|
58
70
|
loader.setDRACOLoader(dracoLoader);
|
|
59
71
|
loader.setKTX2Loader(ktx2Loader);
|
|
72
|
+
loader.setMeshoptDecoder(meshoptDecoder);
|
|
60
73
|
}
|
|
@@ -145,12 +145,19 @@ export class Animation extends Behaviour {
|
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
play(clipOrNumber: AnimationClip | number | string | undefined, options?: PlayOptions): Promise<AnimationAction> | void {
|
|
148
|
+
if (debug) console.log("PLAY", clipOrNumber)
|
|
148
149
|
this.init();
|
|
149
|
-
if (!this.mixer)
|
|
150
|
+
if (!this.mixer) {
|
|
151
|
+
if (debug) console.warn("Missing mixer", this);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
150
154
|
if (clipOrNumber === undefined) clipOrNumber = 0;
|
|
151
155
|
let clip: AnimationClip | undefined = clipOrNumber as AnimationClip;
|
|
152
156
|
if (typeof clipOrNumber === 'number') {
|
|
153
|
-
if (clipOrNumber >= this.animations.length)
|
|
157
|
+
if (clipOrNumber >= this.animations.length) {
|
|
158
|
+
if (debug) console.log("No animation at index", clipOrNumber)
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
154
161
|
clip = this.animations[clipOrNumber];
|
|
155
162
|
}
|
|
156
163
|
else if (typeof clipOrNumber === "string") {
|
|
@@ -205,7 +212,8 @@ export class Animation extends Behaviour {
|
|
|
205
212
|
action.loop = options.loop ? THREE.LoopRepeat : THREE.LoopOnce;
|
|
206
213
|
else action.loop = THREE.LoopOnce;
|
|
207
214
|
action.play();
|
|
208
|
-
|
|
215
|
+
if (debug)
|
|
216
|
+
console.log("PLAY", action.getClip().name, action)
|
|
209
217
|
|
|
210
218
|
const handle = new AnimationHandle(action, this.mixer!, options, _ => {
|
|
211
219
|
this._handles.splice(this._handles.indexOf(handle), 1);
|
|
@@ -149,7 +149,11 @@ export class PlayableDirector extends Behaviour {
|
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
pause() {
|
|
152
|
+
if (!this.isValid()) return;
|
|
153
|
+
this._isPlaying = false;
|
|
154
|
+
if (this._isPaused) return;
|
|
152
155
|
this._isPaused = true;
|
|
156
|
+
this.evaluate();
|
|
153
157
|
}
|
|
154
158
|
|
|
155
159
|
stop() {
|
|
@@ -267,8 +271,10 @@ export class PlayableDirector extends Behaviour {
|
|
|
267
271
|
for (const handler of this._animationTracks) {
|
|
268
272
|
handler.evaluate(time);
|
|
269
273
|
}
|
|
270
|
-
|
|
271
|
-
handler.
|
|
274
|
+
if (AudioSource.userInteractionRegistered) {
|
|
275
|
+
for (const handler of this._audioTracks) {
|
|
276
|
+
handler.evaluate(time);
|
|
277
|
+
}
|
|
272
278
|
}
|
|
273
279
|
for (const sig of this._signalTracks) {
|
|
274
280
|
sig.evaluate(time);
|
|
@@ -279,7 +285,6 @@ export class PlayableDirector extends Behaviour {
|
|
|
279
285
|
for (const cust of this._customTracks) {
|
|
280
286
|
cust.evaluate(time);
|
|
281
287
|
}
|
|
282
|
-
|
|
283
288
|
}
|
|
284
289
|
|
|
285
290
|
private resolveBindings() {
|
|
@@ -358,6 +363,7 @@ export class PlayableDirector extends Behaviour {
|
|
|
358
363
|
|
|
359
364
|
if (!this.playableAsset) return;
|
|
360
365
|
const audioTracks: Array<Models.TrackModel> = [];
|
|
366
|
+
const audioAllowedCallbacks : any = [];
|
|
361
367
|
for (const track of this.playableAsset!.tracks) {
|
|
362
368
|
const type = track.type;
|
|
363
369
|
const registered = PlayableDirector.createTrackFunctions[type];
|
|
@@ -425,7 +431,20 @@ export class PlayableDirector extends Behaviour {
|
|
|
425
431
|
}
|
|
426
432
|
else if (track.type === Models.TrackType.Audio) {
|
|
427
433
|
if (track.clips.length <= 0) continue;
|
|
428
|
-
|
|
434
|
+
const audio = new Tracks.AudioTrackHandler();
|
|
435
|
+
audio.director = this;
|
|
436
|
+
audio.track = track;
|
|
437
|
+
this._audioTracks.push(audio);
|
|
438
|
+
|
|
439
|
+
audioAllowedCallbacks.push(() => {
|
|
440
|
+
const listener = GameObject.findObjectOfType(AudioListener, this.context) as AudioListener;
|
|
441
|
+
if (!listener) return;
|
|
442
|
+
audio.listener = listener.listener;
|
|
443
|
+
for (let i = 0; i < track.clips.length; i++) {
|
|
444
|
+
const clipModel = track.clips[i];
|
|
445
|
+
audio.addModel(clipModel);
|
|
446
|
+
}
|
|
447
|
+
});
|
|
429
448
|
}
|
|
430
449
|
else if (track.type === Models.TrackType.Marker) {
|
|
431
450
|
const signalHandler: Tracks.SignalTrackHandler = new Tracks.SignalTrackHandler();
|
|
@@ -473,19 +492,8 @@ export class PlayableDirector extends Behaviour {
|
|
|
473
492
|
}
|
|
474
493
|
|
|
475
494
|
AudioSource.registerWaitForAllowAudio(() => {
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
for (const track of audioTracks) {
|
|
479
|
-
const audio = new Tracks.AudioTrackHandler();
|
|
480
|
-
audio.director = this;
|
|
481
|
-
audio.track = track;
|
|
482
|
-
audio.listener = listener.listener;
|
|
483
|
-
for (let i = 0; i < track.clips.length; i++) {
|
|
484
|
-
const clipModel = track.clips[i];
|
|
485
|
-
audio.addModel(clipModel);
|
|
486
|
-
}
|
|
487
|
-
this._audioTracks.push(audio);
|
|
488
|
-
}
|
|
495
|
+
audioAllowedCallbacks.forEach((cb: any) => cb());
|
|
496
|
+
audioAllowedCallbacks.length = 0;
|
|
489
497
|
});
|
|
490
498
|
}
|
|
491
499
|
|
|
@@ -500,7 +500,9 @@ class MeshUIHelper {
|
|
|
500
500
|
if (lu.context === context) {
|
|
501
501
|
if (context.time.frameCount === lu.frame) return;
|
|
502
502
|
lu.frame = context.time.frameCount;
|
|
503
|
-
if (this.needsUpdate || context.time.frameCount <
|
|
503
|
+
if (this.needsUpdate || context.time.frameCount < 1) {
|
|
504
|
+
if (debug)
|
|
505
|
+
console.log("Update threemeshui");
|
|
504
506
|
this.needsUpdate = false;
|
|
505
507
|
threeMeshUI.update();
|
|
506
508
|
}
|
|
@@ -187,6 +187,8 @@ export class Text extends Graphic {
|
|
|
187
187
|
// @ts-ignore
|
|
188
188
|
this.uiObject.onAfterUpdate = this.updateWidth.bind(this);
|
|
189
189
|
}
|
|
190
|
+
|
|
191
|
+
setTimeout(()=> this.markDirty(), 10);
|
|
190
192
|
}
|
|
191
193
|
|
|
192
194
|
private createBlock(rt: RectTransform, hideOverflow: boolean, content: THREE.Object3D | Array<THREE.Object3D> | null, isTextIntermediate: boolean = false): ThreeMeshUI.Block | null {
|