@needle-tools/engine 4.8.6 → 4.8.7

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.
Files changed (50) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/{gltf-progressive-DXRy9EQz.js → gltf-progressive-BcHT3Nyo.js} +1 -1
  3. package/dist/{gltf-progressive-C-U_onhf.umd.cjs → gltf-progressive-CH3Q4H06.umd.cjs} +1 -1
  4. package/dist/{gltf-progressive-DViD_J_l.min.js → gltf-progressive-DR6HqF_h.min.js} +1 -1
  5. package/dist/{needle-engine.bundle-BTJDRZkJ.js → needle-engine.bundle-B0qaChJt.js} +3481 -3468
  6. package/dist/{needle-engine.bundle-CQIq7Zg-.min.js → needle-engine.bundle-CZBThBDy.min.js} +117 -117
  7. package/dist/{needle-engine.bundle-CaNItSG7.umd.cjs → needle-engine.bundle-lBmpWgFp.umd.cjs} +120 -120
  8. package/dist/needle-engine.js +402 -400
  9. package/dist/needle-engine.min.js +1 -1
  10. package/dist/needle-engine.umd.cjs +1 -1
  11. package/dist/{postprocessing-61aXdqNz.umd.cjs → postprocessing-CVb_x9YY.umd.cjs} +1 -1
  12. package/dist/{postprocessing-D9jDHD0U.js → postprocessing-ORx-0eCx.js} +1 -1
  13. package/dist/{postprocessing-Be9Ds4NK.min.js → postprocessing-Ywv5oKkX.min.js} +1 -1
  14. package/dist/three-examples-BX_Sktc9.min.js +501 -0
  15. package/dist/{three-examples-BihZ_R96.js → three-examples-CNexix3E.js} +2436 -2781
  16. package/dist/{three-examples-Ce6Th3bv.umd.cjs → three-examples-DWxXVnws.umd.cjs} +21 -21
  17. package/dist/{vendor-BRpzuoJE.min.js → vendor-C43vobGc.min.js} +37 -37
  18. package/dist/{vendor-p_xp9KuJ.js → vendor-Z4SPrTcP.js} +2402 -2047
  19. package/dist/vendor-xfQ8tKF3.umd.cjs +1121 -0
  20. package/lib/engine/api.d.ts +2 -0
  21. package/lib/engine/api.js +2 -0
  22. package/lib/engine/api.js.map +1 -1
  23. package/lib/engine/engine_feature_flags.d.ts +3 -0
  24. package/lib/engine/engine_feature_flags.js +6 -0
  25. package/lib/engine/engine_feature_flags.js.map +1 -0
  26. package/lib/engine/engine_gameobject.js +0 -4
  27. package/lib/engine/engine_gameobject.js.map +1 -1
  28. package/lib/engine/engine_mainloop_utils.d.ts +2 -1
  29. package/lib/engine/engine_mainloop_utils.js +18 -6
  30. package/lib/engine/engine_mainloop_utils.js.map +1 -1
  31. package/lib/engine/engine_pmrem.d.ts +6 -0
  32. package/lib/engine/engine_pmrem.js +9 -40
  33. package/lib/engine/engine_pmrem.js.map +1 -1
  34. package/lib/engine/extensions/extensions.js +2 -2
  35. package/lib/engine/extensions/extensions.js.map +1 -1
  36. package/lib/engine/js-extensions/Object3D.js +19 -0
  37. package/lib/engine/js-extensions/Object3D.js.map +1 -1
  38. package/lib/engine-components/Skybox.js +9 -3
  39. package/lib/engine-components/Skybox.js.map +1 -1
  40. package/package.json +3 -2
  41. package/src/engine/api.ts +3 -1
  42. package/src/engine/engine_feature_flags.ts +8 -0
  43. package/src/engine/engine_gameobject.ts +0 -4
  44. package/src/engine/engine_mainloop_utils.ts +24 -8
  45. package/src/engine/engine_pmrem.ts +9 -45
  46. package/src/engine/extensions/extensions.ts +2 -2
  47. package/src/engine/js-extensions/Object3D.ts +25 -2
  48. package/src/engine-components/Skybox.ts +8 -4
  49. package/dist/three-examples-DKY9Nfge.min.js +0 -501
  50. package/dist/vendor-Ja-vKV-a.umd.cjs +0 -1121
package/src/engine/api.ts CHANGED
@@ -33,6 +33,7 @@ export * from "./engine_context.js";
33
33
  export * from "./engine_context_registry.js";
34
34
  export * from "./engine_coroutine.js"
35
35
  export * from "./engine_create_objects.js";
36
+ export * from "./engine_feature_flags.js"
36
37
  export * from "./engine_gameobject.js";
37
38
  export { Gizmos } from "./engine_gizmos.js"
38
39
  export * from "./engine_gltf.js";
@@ -42,7 +43,7 @@ export { InstancingUtil } from "./engine_instancing.js";
42
43
  export { hasCommercialLicense, hasIndieLicense, hasProLicense } from "./engine_license.js";
43
44
  export * from "./engine_lifecycle_api.js";
44
45
  export { NeedleEngineModelLoader } from "./engine_loaders.callbacks.js";
45
- export { loadAsset, loadSync,parseSync } from "./engine_loaders.js";
46
+ export { loadAsset, loadSync, parseSync } from "./engine_loaders.js";
46
47
  export * from "./engine_math.js";
47
48
  export { MODULES as NEEDLE_ENGINE_MODULES } from "./engine_modules.js";
48
49
  export * from "./engine_networking.js";
@@ -59,6 +60,7 @@ export * from "./engine_physics.js";
59
60
  export * from "./engine_physics.types.js";
60
61
  export * from "./engine_physics_rapier.js";
61
62
  export * from "./engine_playerview.js";
63
+ export { loadPMREM } from "./engine_pmrem.js";
62
64
  export * from "./engine_scenelighting.js";
63
65
  export * from "./engine_serialization.js";
64
66
  export { type ISerializable } from "./engine_serialization_core.js";
@@ -0,0 +1,8 @@
1
+
2
+
3
+ export namespace NEEDLE_ENGINE_FEATURE_FLAGS {
4
+
5
+ // eslint-disable-next-line prefer-const
6
+ export let experimentalSmartHierarchyUpdate = false;
7
+
8
+ }
@@ -105,11 +105,7 @@ export class InstantiateOptions implements IInstantiateOptions {
105
105
  // });
106
106
 
107
107
 
108
- const $isActive = Symbol("isActive");
109
108
  export function isActiveSelf(go: Object3D): boolean {
110
- // if (go[$isActive] === undefined) {
111
- // go[$isActive] = true;
112
- // }
113
109
  return go.visible;
114
110
  }
115
111
 
@@ -3,6 +3,7 @@ import { CubeCamera, Object3D, Scene, WebGLCubeRenderTarget } from 'three';
3
3
  import { isDevEnvironment } from "./debug/index.js";
4
4
  import * as constants from "./engine_constants.js";
5
5
  import { ContextRegistry } from "./engine_context_registry.js";
6
+ import { NEEDLE_ENGINE_FEATURE_FLAGS } from './engine_feature_flags.js';
6
7
  import { isActiveSelf } from './engine_gameobject.js';
7
8
  import { safeInvoke } from "./engine_generic_utils.js";
8
9
  import type { IComponent, IContext } from './engine_types.js';
@@ -31,7 +32,7 @@ export function processNewScripts(context: IContext) {
31
32
  if (debug)
32
33
  console.log("Register new components", context.new_scripts.length, [...context.new_scripts], context.alias ? ("element: " + context.alias) : context["hash"], context);
33
34
 
34
-
35
+
35
36
  if (context.new_scripts_pre_setup_callbacks.length > 0) {
36
37
  for (const cb of context.new_scripts_pre_setup_callbacks) {
37
38
  if (!cb) continue;
@@ -39,7 +40,7 @@ export function processNewScripts(context: IContext) {
39
40
  }
40
41
  context.new_scripts_pre_setup_callbacks.length = 0;
41
42
  }
42
-
43
+
43
44
  if (context.new_scripts.length <= 0) return;
44
45
 
45
46
  // TODO: update all the code from above to use this logic
@@ -269,8 +270,22 @@ export function isNeedleXRSessionEventReceiver(script: any, mode: XRSessionMode
269
270
  }
270
271
 
271
272
 
273
+ let needsUpdate = true;
274
+ export function markHierarchyDirty() {
275
+ needsUpdate = true;
276
+ }
277
+
272
278
  /** @internal */
273
- export function updateIsActive(obj?: Object3D) {
279
+ export function updateIsActive(obj?: Object3D, force: boolean = false) {
280
+
281
+ if (NEEDLE_ENGINE_FEATURE_FLAGS.experimentalSmartHierarchyUpdate) {
282
+
283
+ if (!force) {
284
+ if (!needsUpdate) return;
285
+ }
286
+ needsUpdate = false;
287
+ }
288
+
274
289
  if (!obj) obj = ContextRegistry.Current.scene;
275
290
  if (!obj) {
276
291
  console.trace("Invalid call - no current context.");
@@ -295,11 +310,11 @@ function updateIsActiveInHierarchyRecursiveRuntime(go: Object3D, activeInHierarc
295
310
  return false;
296
311
  }
297
312
 
298
- const isActive = isActiveSelf(go);
313
+ const activeSelf = isActiveSelf(go);
299
314
  if (activeInHierarchy) {
300
- activeInHierarchy = isActive;
315
+ activeInHierarchy = activeSelf;
301
316
  // IF we update activeInHierarchy within a disabled hierarchy we need to check the parent
302
- if (activeInHierarchy && go.parent) {
317
+ if (activeInHierarchy && go.parent && level === 0) {
303
318
  const parent = go.parent;
304
319
  activeInHierarchy = parent[constants.activeInHierarchyFieldName];
305
320
  if (activeInHierarchy === undefined) {
@@ -315,12 +330,13 @@ function updateIsActiveInHierarchyRecursiveRuntime(go: Object3D, activeInHierarc
315
330
 
316
331
  const prevActive = go[constants.activeInHierarchyFieldName];
317
332
  const changed = prevActive !== activeInHierarchy;
318
- go[constants.activeInHierarchyFieldName] = activeInHierarchy;
319
333
 
320
334
  // only raise events here if we didnt call enable etc already
321
335
  if (changed) {
336
+ go[constants.activeInHierarchyFieldName] = activeInHierarchy;
337
+
322
338
  if (debugHierarchy)
323
- console.warn("ACTIVE CHANGE", go.name, isActive, go.visible, activeInHierarchy, "changed?" + changed, go);
339
+ console.warn("ACTIVE CHANGE", go.name, activeSelf, go.visible, activeInHierarchy, "changed?" + changed, go);
324
340
  if (allowEventCall) {
325
341
  perComponent(go, comp => {
326
342
  if (activeInHierarchy) {
@@ -4,12 +4,16 @@ import { EXRLoader } from "three/examples/jsm/loaders/EXRLoader";
4
4
  import { KTX2Loader } from "three/examples/jsm/loaders/KTX2Loader";
5
5
  import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader";
6
6
 
7
- import { disposeObjectResources, setDisposable } from "./engine_assetdatabase.js";
8
-
9
7
  const running: Map<string, Promise<Texture | null>> = new Map();
10
8
 
11
9
  // #region api
12
10
 
11
+ /**
12
+ * Loads a PMREM texture from the given URL. This also supports the ultra-fast preprocessed environment maps (PMREM) format.
13
+ * @param url The URL of the PMREM texture to load.
14
+ * @param renderer The WebGLRenderer to use for loading the texture.
15
+ * @returns A promise that resolves to the loaded texture or null if loading failed.
16
+ */
13
17
  export function loadPMREM(url: string, renderer: WebGLRenderer): Promise<Texture | null> {
14
18
  if (running.has(url)) {
15
19
  return running.get(url)!;
@@ -17,47 +21,13 @@ export function loadPMREM(url: string, renderer: WebGLRenderer): Promise<Texture
17
21
  const actualUrl = new URL(url, window.location.href);
18
22
  const promise = internalLoadPMREM(actualUrl, renderer);
19
23
  running.set(url, promise);
24
+ promise.finally(() => {
25
+ running.delete(url);
26
+ });
20
27
  return promise;
21
28
  }
22
29
 
23
30
 
24
-
25
- // #region Cache
26
-
27
- declare type SkyboxCacheEntry = { src: string, texture: Promise<Texture | null> };
28
- function ensureGlobalCache() {
29
- if (!globalThis["NEEDLE_ENGINE_SKYBOX_TEXTURES"])
30
- globalThis["NEEDLE_ENGINE_SKYBOX_TEXTURES"] = new Array<SkyboxCacheEntry>();
31
- return globalThis["NEEDLE_ENGINE_SKYBOX_TEXTURES"] as Array<SkyboxCacheEntry>;
32
- }
33
-
34
- function tryGetPreviouslyLoadedTexture(src: string) {
35
- const cache = ensureGlobalCache();
36
- const found = cache.find(x => x.src === src);
37
- if (found) {
38
- return found.texture;
39
- }
40
- return null;
41
- }
42
- async function disposeCachedTexture(tex: Promise<Texture | null>) {
43
- const texture = await tex;
44
- if (!texture) return;
45
- setDisposable(texture, true);
46
- disposeObjectResources(texture);
47
- }
48
- function registerPromise(src: string, texture: Promise<Texture | null>) {
49
- const cache = ensureGlobalCache();
50
- // Make sure the cache doesnt get too big
51
- while (cache.length > 5) {
52
- const entry = cache.shift();
53
- if (entry) { disposeCachedTexture(entry.texture); }
54
- }
55
- texture.then(t => { return setDisposable(t, false) });
56
- cache.push({ src, texture });
57
- }
58
-
59
-
60
-
61
31
  // #region loading
62
32
 
63
33
 
@@ -67,11 +37,6 @@ async function internalLoadPMREM(url: URL, renderer: WebGLRenderer) {
67
37
  const pathname = url.pathname;
68
38
  const isPMREM_URL: boolean = url.toString().toLowerCase().includes("pmrem") || url.searchParams.get("pmrem") != null;
69
39
 
70
- const cached = tryGetPreviouslyLoadedTexture(pathname);
71
- if (cached) {
72
- const res = await cached;
73
- if (res?.source?.data?.length > 0 || res?.source?.data?.data?.length) return res;
74
- }
75
40
  const isEXR = pathname.endsWith(".exr");
76
41
  const isHdr = pathname.endsWith(".hdr");
77
42
  const isKtx2 = pathname.endsWith(".ktx2");
@@ -110,7 +75,6 @@ async function internalLoadPMREM(url: URL, renderer: WebGLRenderer) {
110
75
  return tex;
111
76
  });
112
77
 
113
- registerPromise(str, promise);
114
78
  const texture = await promise.catch(_err => {
115
79
  console.warn("Failed to load texture from url:", url);
116
80
  return null;
@@ -22,11 +22,11 @@ const debug = getParam("debugextensions");
22
22
 
23
23
  // lazily import the GLTFAnimationPointerExtension in case it doesnt exist (e.g. using vanilla three)
24
24
  let GLTFAnimationPointerExtension: any;
25
- const KHR_ANIMATIONPOINTER_IMPORT = import("three/examples/jsm/loaders/GLTFLoaderAnimationPointer.js").then(async mod => {
25
+ const KHR_ANIMATIONPOINTER_IMPORT = import("@needle-tools/three-animation-pointer").then(async mod => {
26
26
  GLTFAnimationPointerExtension = mod.GLTFAnimationPointerExtension;
27
27
  return GLTFAnimationPointerExtension;
28
28
  }).catch(e => {
29
- console.warn("Failed to import GLTFLoaderAnimationPointer. Please use @needle-tools/three for full KHR_animation support", e);
29
+ console.warn("Failed to import GLTFLoaderAnimationPointer. Please use @needle-tools/three-animationpointer for full KHR_animation support", e);
30
30
  });
31
31
 
32
32
 
@@ -1,7 +1,7 @@
1
1
  import { Object3D, Quaternion, Vector3 } from "three";
2
2
  import { TransformControlsGizmo } from "three/examples/jsm/controls/TransformControls.js";
3
3
 
4
- import { addComponent, addNewComponent, getComponent, getComponentInChildren, getComponentInParent, getComponents, getComponentsInChildren, getComponentsInParent, getOrAddComponent, removeComponent } from "../../engine/engine_components.js";
4
+ import { addComponent, getComponent, getComponentInChildren, getComponentInParent, getComponents, getComponentsInChildren, getComponentsInParent, getOrAddComponent, removeComponent } from "../../engine/engine_components.js";
5
5
  import { destroy, isActiveSelf, setActive } from "../../engine/engine_gameobject.js";
6
6
  import {
7
7
  getTempVector,
@@ -15,7 +15,9 @@ import {
15
15
  setWorldScale
16
16
  }
17
17
  from "../../engine/engine_three_utils.js";
18
- import type { ComponentInit, Constructor, ConstructorConcrete, HideFlags,IComponent as Component, IComponent } from "../../engine/engine_types.js";
18
+ import type { ComponentInit, Constructor, ConstructorConcrete, HideFlags, IComponent as Component, IComponent } from "../../engine/engine_types.js";
19
+ import { NEEDLE_ENGINE_FEATURE_FLAGS } from "../engine_feature_flags.js";
20
+ import { markHierarchyDirty } from "../engine_mainloop_utils.js";
19
21
  import { applyPrototypeExtensions, registerPrototypeExtensions } from "./ExtensionUtils.js";
20
22
 
21
23
 
@@ -150,6 +152,27 @@ export function apply(object: Object3D) {
150
152
  }
151
153
  }
152
154
 
155
+ if (NEEDLE_ENGINE_FEATURE_FLAGS.experimentalSmartHierarchyUpdate) {
156
+
157
+ const addFn = Object3D.prototype.add;
158
+ Object3D.prototype.add = function (...args: any) {
159
+ markHierarchyDirty();
160
+ return addFn.apply(this, args);
161
+ }
162
+
163
+ const attachFn = Object3D.prototype.attach;
164
+ Object3D.prototype.attach = function (...args: any) {
165
+ markHierarchyDirty();
166
+ return attachFn.apply(this, args);
167
+ }
168
+
169
+ const removeFn = Object3D.prototype.remove;
170
+ Object3D.prototype.remove = function (...args: any) {
171
+ markHierarchyDirty();
172
+ return removeFn.apply(this, args);
173
+ }
174
+ }
175
+
153
176
 
154
177
  Object3D.prototype["SetActive"] = function (active: boolean) {
155
178
  this.visible = active;
@@ -217,9 +217,9 @@ export class RemoteSkybox extends Behaviour {
217
217
  if (debug) console.warn("RemoteSkybox: Failed to load texture from url", url);
218
218
  return false;
219
219
  }
220
- // Check if we're still enabled
221
- if (!this.enabled) {
222
- if (debug) console.warn("RemoteSkybox: Component is not enabled, aborting setSkybox");
220
+ // Check if we're not disabled or destroyed
221
+ if (!this.enabled || this.destroyed) {
222
+ if (debug) console.warn("RemoteSkybox: Component is disabled or destroyed");
223
223
  return false;
224
224
  }
225
225
  // Check if the url has changed while loading
@@ -239,7 +239,6 @@ export class RemoteSkybox extends Behaviour {
239
239
  const envMap = this._prevLoadedEnvironment;
240
240
  if (!envMap) return;
241
241
 
242
-
243
242
  if ((envMap instanceof CubeTexture || envMap instanceof CompressedCubeTexture) || envMap.mapping == CubeUVReflectionMapping) {
244
243
  // Nothing to do
245
244
  }
@@ -248,6 +247,11 @@ export class RemoteSkybox extends Behaviour {
248
247
  envMap.needsUpdate = true;
249
248
  }
250
249
 
250
+ if(this.destroyed) return;
251
+ if(!this.context) {
252
+ console.warn("RemoteSkybox: Context is not available - can not apply skybox.");
253
+ return;
254
+ }
251
255
 
252
256
  // capture state
253
257
  if (this.context.scene.background !== envMap)