@needle-tools/engine 3.0.0-alpha.1 → 3.0.1-alpha

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 (68) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/dist/needle-engine.js +9914 -9823
  3. package/dist/needle-engine.min.js +4812 -0
  4. package/dist/needle-engine.umd.cjs +283 -283
  5. package/lib/engine/engine_addressables.js +1 -1
  6. package/lib/engine/engine_addressables.js.map +1 -1
  7. package/lib/engine/engine_context.d.ts +0 -1
  8. package/lib/engine/engine_context.js +15 -17
  9. package/lib/engine/engine_context.js.map +1 -1
  10. package/lib/engine/engine_context_registry.d.ts +2 -1
  11. package/lib/engine/engine_context_registry.js +6 -1
  12. package/lib/engine/engine_context_registry.js.map +1 -1
  13. package/lib/engine/engine_element.js +1 -1
  14. package/lib/engine/engine_element.js.map +1 -1
  15. package/lib/engine/engine_gltf.d.ts +2 -2
  16. package/lib/engine/engine_mainloop_utils.js +13 -11
  17. package/lib/engine/engine_mainloop_utils.js.map +1 -1
  18. package/lib/engine/engine_networking_files.js +4 -3
  19. package/lib/engine/engine_networking_files.js.map +1 -1
  20. package/lib/engine/engine_scenetools.d.ts +4 -4
  21. package/lib/engine/engine_scenetools.js +5 -5
  22. package/lib/engine/engine_scenetools.js.map +1 -1
  23. package/lib/engine/engine_time.d.ts +2 -1
  24. package/lib/engine/engine_time.js.map +1 -1
  25. package/lib/engine/engine_types.d.ts +5 -0
  26. package/lib/engine/engine_types.js.map +1 -1
  27. package/lib/engine-components/Animation.d.ts +1 -1
  28. package/lib/engine-components/Animation.js +3 -3
  29. package/lib/engine-components/Animation.js.map +1 -1
  30. package/lib/engine-components/Renderer.d.ts +1 -1
  31. package/lib/engine-components/Renderer.js +15 -4
  32. package/lib/engine-components/Renderer.js.map +1 -1
  33. package/lib/engine-components/api.d.ts +1 -0
  34. package/lib/engine-components/api.js +2 -0
  35. package/lib/engine-components/api.js.map +1 -0
  36. package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusion.d.ts +2 -0
  37. package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusion.js +18 -1
  38. package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusion.js.map +1 -1
  39. package/lib/engine-components/postprocessing/PostProcessingHandler.d.ts +3 -0
  40. package/lib/engine-components/postprocessing/PostProcessingHandler.js +1 -1
  41. package/lib/engine-components/postprocessing/PostProcessingHandler.js.map +1 -1
  42. package/lib/engine-components/ui/Text.d.ts +1 -1
  43. package/lib/engine-components/ui/Text.js +42 -17
  44. package/lib/engine-components/ui/Text.js.map +1 -1
  45. package/lib/needle-engine.d.ts +1 -0
  46. package/lib/needle-engine.js +1 -0
  47. package/lib/needle-engine.js.map +1 -1
  48. package/lib/tsconfig.tsbuildinfo +1 -1
  49. package/package.json +3 -4
  50. package/plugins/vite/copyfiles.js +37 -10
  51. package/plugins/vite/reload.js +2 -1
  52. package/src/engine/engine_addressables.ts +1 -1
  53. package/src/engine/engine_context.ts +15 -18
  54. package/src/engine/engine_context_registry.ts +7 -1
  55. package/src/engine/engine_element.ts +1 -1
  56. package/src/engine/engine_gltf.ts +2 -2
  57. package/src/engine/engine_mainloop_utils.ts +12 -10
  58. package/src/engine/engine_networking_files.ts +5 -4
  59. package/src/engine/engine_scenetools.ts +7 -7
  60. package/src/engine/engine_time.ts +2 -1
  61. package/src/engine/engine_types.ts +6 -0
  62. package/src/engine-components/Animation.ts +3 -3
  63. package/src/engine-components/Renderer.ts +19 -5
  64. package/src/engine-components/api.ts +1 -0
  65. package/src/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusion.ts +15 -1
  66. package/src/engine-components/postprocessing/PostProcessingHandler.ts +1 -1
  67. package/src/engine-components/ui/Text.ts +41 -17
  68. package/src/needle-engine.ts +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/engine",
3
- "version": "3.0.0-alpha.1",
3
+ "version": "3.0.1-alpha",
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": "lib/needle-engine.js",
@@ -57,8 +57,8 @@
57
57
  "flatbuffers": "2.0.4",
58
58
  "md5": "^2.3.0",
59
59
  "peerjs": "1.3.2",
60
- "simplex-noise": "^4.0.1",
61
60
  "postprocessing": "^6.30.1",
61
+ "simplex-noise": "^4.0.1",
62
62
  "stats.js": "^0.17.0",
63
63
  "three": "npm:@needle-tools/three@^0.146.6",
64
64
  "three-mesh-ui": "^6.4.5",
@@ -72,10 +72,9 @@
72
72
  "@needle-tools/helper": "^0.4.5",
73
73
  "@needle-tools/needle-component-compiler": "1.9.3",
74
74
  "@types/three": "0.146.0",
75
- "copy-files-from-to": "^3.7.0",
76
75
  "esbuild": "^0.15.10",
77
76
  "esbuild-node-externals": "^1.5.0",
78
- "fs-extra": "^11.1.0",
77
+ "fs-extra": "^11.1.1",
79
78
  "jsdoc-babel": "^0.5.0",
80
79
  "jsdoc-to-markdown": "^7.1.1",
81
80
  "madge": "^5.0.1",
@@ -1,7 +1,6 @@
1
1
 
2
- import { copy } from 'fs-extra'
3
- import { resolve } from 'path'
4
- import { existsSync } from 'fs';
2
+ import { resolve, join } from 'path'
3
+ import { existsSync, statSync, mkdirSync, readdirSync, copyFileSync, mkdir } from 'fs';
5
4
 
6
5
 
7
6
  /** copy files on build from assets to dist */
@@ -11,32 +10,60 @@ export const needleCopyFiles = (command, config, userSettings) => {
11
10
  return;
12
11
  }
13
12
 
13
+ const copyIncludesFromEngine = config?.copyIncludesFromEngine ?? true;
14
+
14
15
  return {
15
16
  name: 'needle-copy-files',
16
17
  apply: 'build',
17
18
  async closeBundle() {
18
19
  const baseDir = process.cwd();
20
+ const pluginName = "needle-copy-files";
19
21
 
20
22
  const outdirName = "dist";
21
23
  const outDir = resolve(baseDir, outdirName);
22
24
  if (!existsSync(outDir)) {
23
- console.log(`No ${outdirName} folder found, skipping copy files: ${outDir}`);
24
- return;
25
+ mkdirSync(outDir);
26
+ }
27
+
28
+ if (copyIncludesFromEngine !== false) {
29
+ // copy include from engine
30
+ const engineIncludeDir = resolve(baseDir, 'node_modules', '@needle-tools', 'engine', 'src', 'include');
31
+ if (existsSync(engineIncludeDir)) {
32
+ console.log(`[${pluginName}] - Copy engine include to ${baseDir}/include`)
33
+ const targetDir = resolve(baseDir, 'include');
34
+ copyRecursiveSync(engineIncludeDir, targetDir);
35
+ }
25
36
  }
37
+
26
38
  // copy assets dir
27
39
  const assetsDir = resolve(baseDir, 'assets');
28
40
  if (existsSync(assetsDir)) {
29
- console.log(`Copy assets to ${outdirName}/assets`)
41
+ console.log(`[${pluginName}] - Copy assets to ${outdirName}/assets`)
30
42
  const targetDir = resolve(outDir, 'assets');
31
- await copy(assetsDir, targetDir, { overwrite: true });
43
+ copyRecursiveSync(assetsDir, targetDir);
32
44
  }
33
45
  // copy include dir
34
46
  const includeDir = resolve(baseDir, 'include');
35
47
  if (existsSync(includeDir)) {
36
- console.log(`Copy include to ${outdirName}/include`)
48
+ console.log(`[${pluginName}] - Copy include to ${outdirName}/include`)
37
49
  const targetDir = resolve(outDir, 'include');
38
- await copy(includeDir, targetDir, { overwrite: true });
50
+ copyRecursiveSync(includeDir, targetDir);
39
51
  }
40
52
  }
41
53
  }
42
- }
54
+ }
55
+
56
+ function copyRecursiveSync(src, dest) {
57
+ var exists = existsSync(src);
58
+ var stats = exists && statSync(src);
59
+ var isDirectory = exists && stats.isDirectory();
60
+ if (isDirectory) {
61
+ if (!existsSync(dest))
62
+ mkdirSync(dest);
63
+ readdirSync(src).forEach(function (childItemName) {
64
+ copyRecursiveSync(join(src, childItemName), join(dest, childItemName));
65
+ });
66
+ } else {
67
+ copyFileSync(src, dest);
68
+ }
69
+ };
@@ -43,7 +43,8 @@ export const needleReload = (command, config, userSettings) => {
43
43
  else if (!config.server.watch.ignored) config.server.watch.ignored = [];
44
44
  for (const pattern of ignorePatterns)
45
45
  config.server.watch.ignored.push(pattern);
46
- setTimeout(() => console.log("Updated server ignore patterns: ", config.server.watch.ignored), 100);
46
+ if(config?.debug === true || userSettings?.debug === true)
47
+ setTimeout(() => console.log("Updated server ignore patterns: ", config.server.watch.ignored), 100);
47
48
  },
48
49
  handleHotUpdate(args) {
49
50
  args.buildDirectory = buildDirectory;
@@ -163,7 +163,7 @@ export class AssetReference {
163
163
  }
164
164
  else {
165
165
  if (debug) console.log("Load async", this.uri);
166
- this._loading = getLoader().loadSync(context, this._hashedUri, null, true, prog => {
166
+ this._loading = getLoader().loadSync(context, this._hashedUri, this.uri, null, prog => {
167
167
  this.raiseProgressEvent(prog);
168
168
  });
169
169
  }
@@ -87,15 +87,12 @@ export function registerComponent(script: IComponent, context?: Context) {
87
87
 
88
88
  export class Context implements IContext {
89
89
 
90
- private static _current: Context;
91
-
92
90
  static get Current(): Context {
93
- return this._current;
91
+ return ContextRegistry.Current as Context;
94
92
  }
95
93
 
96
94
  static set Current(context: Context) {
97
95
  ContextRegistry.Current = context;
98
- this._current = context;
99
96
  }
100
97
 
101
98
  name: string;
@@ -307,7 +304,7 @@ export class Context implements IContext {
307
304
  // private _requestSizeUpdate : boolean = false;
308
305
 
309
306
  updateSize() {
310
- if (!this.isManagedExternally && !this.renderer.xr.isPresenting) {
307
+ if (!this.isManagedExternally && this.renderer.xr?.isPresenting === false) {
311
308
  this._sizeChanged = false;
312
309
  const scaleFactor = this.resolutionScaleFactor;
313
310
  const width = this.domWidth * scaleFactor;
@@ -516,10 +513,10 @@ export class Context implements IContext {
516
513
  if (!this.isManagedExternally)
517
514
  this.domElement.prepend(this.renderer.domElement);
518
515
 
519
- Context._current = this;
516
+ Context.Current = this;
520
517
 
521
518
  // Setup
522
- Context._current = this;
519
+ Context.Current = this;
523
520
  for (let i = 0; i < this.new_scripts.length; i++) {
524
521
  const script = this.new_scripts[i];
525
522
  if (script.gameObject !== undefined && script.gameObject !== null) {
@@ -546,13 +543,13 @@ export class Context implements IContext {
546
543
  // resolve post setup callbacks (things that rely on threejs objects having references to components)
547
544
  if (this.post_setup_callbacks) {
548
545
  for (let i = 0; i < this.post_setup_callbacks.length; i++) {
549
- Context._current = this;
546
+ Context.Current = this;
550
547
  await this.post_setup_callbacks[i](this);
551
548
  }
552
549
  }
553
550
 
554
551
  if (!this.mainCamera) {
555
- Context._current = this;
552
+ Context.Current = this;
556
553
  let camera: ICamera | null = null;
557
554
  foreachComponent(this.scene, comp => {
558
555
  const cam = comp as ICamera;
@@ -577,7 +574,7 @@ export class Context implements IContext {
577
574
  }
578
575
  }
579
576
 
580
- Context._current = this;
577
+ Context.Current = this;
581
578
  looputils.processNewScripts(this);
582
579
 
583
580
  // const mainCam = this.mainCameraComponent as Camera;
@@ -624,10 +621,10 @@ export class Context implements IContext {
624
621
 
625
622
  this._stats?.begin();
626
623
 
627
- Context._current = this;
624
+ Context.Current = this;
628
625
  if (this.onHandlePaused()) return;
629
626
 
630
- Context._current = this;
627
+ Context.Current = this;
631
628
  this.time.update();
632
629
  if (debugframerate)
633
630
  console.log("FPS", (this.time.smoothedFps).toFixed(0));
@@ -655,7 +652,7 @@ export class Context implements IContext {
655
652
  const script = this.scripts_earlyUpdate[i];
656
653
  if (!script.activeAndEnabled) continue;
657
654
  if (script.earlyUpdate !== undefined) {
658
- Context._current = this;
655
+ Context.Current = this;
659
656
  script.earlyUpdate();
660
657
  }
661
658
  }
@@ -668,7 +665,7 @@ export class Context implements IContext {
668
665
  const script = this.scripts_update[i];
669
666
  if (!script.activeAndEnabled) continue;
670
667
  if (script.update !== undefined) {
671
- Context._current = this;
668
+ Context.Current = this;
672
669
  script.update();
673
670
  }
674
671
  }
@@ -681,7 +678,7 @@ export class Context implements IContext {
681
678
  const script = this.scripts_lateUpdate[i];
682
679
  if (!script.activeAndEnabled) continue;
683
680
  if (script.lateUpdate !== undefined) {
684
- Context._current = this;
681
+ Context.Current = this;
685
682
  script.lateUpdate();
686
683
  }
687
684
  }
@@ -712,7 +709,7 @@ export class Context implements IContext {
712
709
  if (!script.activeAndEnabled) continue;
713
710
  // if(script.isActiveAndEnabled === false) continue;
714
711
  if (script.onBeforeRender !== undefined) {
715
- Context._current = this;
712
+ Context.Current = this;
716
713
  script.onBeforeRender(frame);
717
714
  }
718
715
  }
@@ -741,7 +738,7 @@ export class Context implements IContext {
741
738
  const script = this.scripts_onAfterRender[i];
742
739
  if (!script.activeAndEnabled) continue;
743
740
  if (script.onAfterRender !== undefined) {
744
- Context._current = this;
741
+ Context.Current = this;
745
742
  script.onAfterRender();
746
743
  }
747
744
  }
@@ -798,7 +795,7 @@ export class Context implements IContext {
798
795
  const script = this.scripts_pausedChanged[i];
799
796
  if (!script.activeAndEnabled) continue;
800
797
  if (script.onPausedChanged !== undefined) {
801
- Context._current = this;
798
+ Context.Current = this;
802
799
  script.onPausedChanged(paused, this._wasPaused);
803
800
  }
804
801
  }
@@ -14,7 +14,13 @@ export type ContextEventArgs = {
14
14
  export type ContextCallback = (evt: ContextEventArgs) => void;
15
15
 
16
16
  export class ContextRegistry {
17
- static Current: IContext;
17
+
18
+ static get Current(): IContext{
19
+ return globalThis["NeedleEngine.Context.Current"]
20
+ }
21
+ static set Current(ctx: IContext) {
22
+ globalThis["NeedleEngine.Context.Current"] = ctx;
23
+ }
18
24
 
19
25
  static Registered: IContext[] = [];
20
26
 
@@ -240,7 +240,7 @@ export class EngineElement extends HTMLElement implements INeedleEngineComponent
240
240
  totalProgress01: this._loadingProgress01
241
241
  }
242
242
  }
243
- const res = await loader.loadSync(ctx, url, hash, false, prog => {
243
+ const res = await loader.loadSync(ctx, url, url, hash, prog => {
244
244
  // Calc progress
245
245
  progress.progress = prog;
246
246
  this._loadingProgress01 = calculateProgress01(progress);
@@ -8,8 +8,8 @@ import { GLTF } from 'three/examples/jsm/loaders/GLTFLoader.js'
8
8
  export interface INeedleGltfLoader {
9
9
  createBuiltinComponents(context: Context, gltfId: SourceIdentifier, gltf, seed: number | null | UIDProvider, extension?: NEEDLE_components): Promise<void>
10
10
  writeBuiltinComponentData(comp: object, context: SerializationContext);
11
- parseSync(context: Context, data, path: string, seed: number | UIDProvider | null): Promise<GLTF | undefined>;
12
- loadSync(context: Context, url: string, seed: number | UIDProvider | null, _allowAddingAnimator: boolean, prog?: (prog : ProgressEvent) => void): Promise<GLTF | undefined>
11
+ parseSync(context: Context, data : string | ArrayBuffer, path: string, seed: number | UIDProvider | null): Promise<GLTF | undefined>;
12
+ loadSync(context: Context, url: string, sourceId:string, seed: number | UIDProvider | null, prog?: (prog : ProgressEvent) => void): Promise<GLTF | undefined>
13
13
  }
14
14
 
15
15
  let gltfLoader: INeedleGltfLoader;
@@ -370,17 +370,19 @@ export function runPrewarm(context: IContext) {
370
370
  if (cam) {
371
371
  if (debugPrewarm) console.log("prewarm", list.length, "objects", [...list]);
372
372
  const renderer = context.renderer;
373
- const scene = context.scene;
374
- renderer.compile(scene, cam!)
375
- prewarmTarget ??= new WebGLCubeRenderTarget(64)
376
- prewarmCamera ??= new CubeCamera(0.001, 9999999, prewarmTarget);
377
- prewarmCamera.update(renderer, scene);
378
- for (const obj of list) {
379
- obj[$prewarmedFlag] = true;
380
- obj[$waitingForPrewarm] = false;
373
+ if (renderer.compile) {
374
+ const scene = context.scene;
375
+ renderer.compile(scene, cam!)
376
+ prewarmTarget ??= new WebGLCubeRenderTarget(64)
377
+ prewarmCamera ??= new CubeCamera(0.001, 9999999, prewarmTarget);
378
+ prewarmCamera.update(renderer, scene);
379
+ for (const obj of list) {
380
+ obj[$prewarmedFlag] = true;
381
+ obj[$waitingForPrewarm] = false;
382
+ }
383
+ list.length = 0;
384
+ if (debugPrewarm) console.log("prewarm done");
381
385
  }
382
- list.length = 0;
383
- if (debugPrewarm) console.log("prewarm done");
384
386
  }
385
387
  }
386
388
 
@@ -48,13 +48,13 @@ export async function addFile(file: File, context: Context, backendUrl?: string)
48
48
  if (name.endsWith(".gltf") || name.endsWith(".glb")) {
49
49
  return new Promise((resolve, _reject) => {
50
50
  const reader = new FileReader()
51
- reader.readAsDataURL(file);
51
+ reader.readAsArrayBuffer(file);
52
52
  reader.onloadend = async (_ev: ProgressEvent<FileReader>) => {
53
- const content = reader.result as string;
53
+ const content = reader.result as ArrayBuffer;
54
54
  // first load it locally
55
55
  const seed = generateSeed();
56
56
  const prov = new InstantiateIdProvider(seed);
57
- const gltf: GLTF = await getLoader().loadSync(context, content, prov, true) as GLTF;
57
+ const gltf: GLTF = await getLoader().parseSync(context, content, file.name, prov) as GLTF;
58
58
  if (gltf && gltf.scene) {
59
59
  const obj = gltf.scene as unknown as IGameObject;
60
60
  // if we dont have a guid yet (because components guids are actually created in a callback a bit later)
@@ -85,7 +85,8 @@ export async function addFileFromUrl(url: URL, context: Context): Promise<GLTF |
85
85
  return new Promise(async (resolve, _reject) => {
86
86
  const seed = generateSeed();
87
87
  const prov = new InstantiateIdProvider(seed);
88
- const gltf: GLTF = await getLoader().loadSync(context, url.toString(), prov, true) as GLTF;
88
+ const urlStr = url.toString();
89
+ const gltf: GLTF = await getLoader().loadSync(context, urlStr, urlStr, prov) as GLTF;
89
90
  if (gltf && gltf.scene) {
90
91
  const obj = gltf.scene as unknown as IGameObject;
91
92
  // handleUpload(context.connection, file, seed, obj); // TODO needs to upload the URL only and store that
@@ -24,11 +24,11 @@ export class NeedleGltfLoader implements INeedleGltfLoader {
24
24
  return writeBuiltinComponentData(comp, context);
25
25
  }
26
26
 
27
- parseSync(context: Context, data, path: string, seed: number | UIDProvider | null): Promise<GLTF | undefined> {
27
+ parseSync(context: Context, data : string | ArrayBuffer, path: string, seed: number | UIDProvider | null): Promise<GLTF | undefined> {
28
28
  return parseSync(context, data, path, seed);
29
29
  }
30
- loadSync(context: Context, url: string, seed: number | UIDProvider | null, _allowAddingAnimator: boolean, prog?: ((ProgressEvent: any) => void) | undefined): Promise<GLTF | undefined> {
31
- return loadSync(context, url, seed, _allowAddingAnimator, prog);
30
+ loadSync(context: Context, url: string, sourceId:string, seed: number | UIDProvider | null, prog?: ((ProgressEvent: any) => void) | undefined): Promise<GLTF | undefined> {
31
+ return loadSync(context, url, sourceId, seed, prog);
32
32
  }
33
33
  }
34
34
 
@@ -87,7 +87,7 @@ function invokeEvents(type: GltfLoadEventType, event: GltfLoadEvent) {
87
87
 
88
88
  async function handleLoadedGltf(context: Context, gltfId: string, gltf, seed: number | null | UIDProvider, componentsExtension) {
89
89
  if (printGltf)
90
- console.log(gltf);
90
+ console.warn("glTF", gltfId, gltf);
91
91
  await getLoader().createBuiltinComponents(context, gltfId, gltf, seed, componentsExtension);
92
92
 
93
93
  // load and assign animation
@@ -102,7 +102,7 @@ export function createGLTFLoader(url: string, context: Context) {
102
102
  return loader;
103
103
  }
104
104
 
105
- export function parseSync(context: Context, data, path: string, seed: number | UIDProvider | null): Promise<GLTF | undefined> {
105
+ export function parseSync(context: Context, data : string | ArrayBuffer, path: string, seed: number | UIDProvider | null): Promise<GLTF | undefined> {
106
106
  if (typeof path !== "string") {
107
107
  console.warn("Parse gltf binary without path, this might lead to errors in resolving extensions. Please provide the source path of the gltf/glb file", path, typeof path);
108
108
  }
@@ -131,7 +131,7 @@ export function parseSync(context: Context, data, path: string, seed: number | U
131
131
  });
132
132
  }
133
133
 
134
- export function loadSync(context: Context, url: string, seed: number | UIDProvider | null, _allowAddingAnimator: boolean = false, prog?: (ProgressEvent) => void): Promise<GLTF | undefined> {
134
+ export function loadSync(context: Context, url: string, sourceId:string, seed: number | UIDProvider | null, prog?: (ProgressEvent) => void): Promise<GLTF | undefined> {
135
135
  // better to create new loaders every time
136
136
  // (maybe we can cache them...)
137
137
  // but due to the async nature and potentially triggering multiple loads at the same time
@@ -145,7 +145,7 @@ export function loadSync(context: Context, url: string, seed: number | UIDProvid
145
145
  invokeEvents(GltfLoadEventType.BeforeLoad, new GltfLoadEvent(context, url, loader));
146
146
  loader.load(url, async data => {
147
147
  invokeEvents(GltfLoadEventType.AfterLoaded, new GltfLoadEvent(context, url, loader, data));
148
- await handleLoadedGltf(context, url, data, seed, componentsExtension);
148
+ await handleLoadedGltf(context, sourceId, data, seed, componentsExtension);
149
149
  invokeEvents(GltfLoadEventType.FinishedSetup, new GltfLoadEvent(context, url, loader, data));
150
150
  registerPrewarmObject(data.scene, context);
151
151
  resolve(data);
@@ -1,11 +1,12 @@
1
1
  import { Clock } from 'three'
2
2
  import { getParam } from './engine_utils';
3
+ import { ITime } from './engine_types';
3
4
 
4
5
  const timescaleUrl = getParam("timescale");
5
6
  let timeScale = 1;
6
7
  if (typeof timescaleUrl === "number") timeScale = timescaleUrl;
7
8
 
8
- export class Time {
9
+ export class Time implements ITime {
9
10
 
10
11
  deltaTime = 0;
11
12
  time = 0;
@@ -27,9 +27,13 @@ export declare type CoroutineData = {
27
27
  chained?: Array<Generator>
28
28
  }
29
29
 
30
+ export interface ITime {
31
+ get time(): number;
32
+ }
30
33
 
31
34
  export interface IContext {
32
35
  alias?: string | null;
36
+ hash?:string;
33
37
 
34
38
  scene: Scene;
35
39
  renderer: WebGLRenderer;
@@ -37,6 +41,8 @@ export interface IContext {
37
41
  mainCameraComponent: ICamera | undefined;
38
42
  domElement: HTMLElement;
39
43
 
44
+ time: ITime;
45
+
40
46
  scripts: IComponent[];
41
47
  scripts_pausedChanged: IComponent[];
42
48
  // scripts with update event
@@ -145,7 +145,7 @@ export class Animation extends Behaviour {
145
145
  return false;
146
146
  }
147
147
 
148
- play(clipOrNumber: AnimationClip | number | string | undefined, options?: PlayOptions): Promise<AnimationAction> | void {
148
+ play(clipOrNumber: AnimationClip | number | string | undefined = 0, options?: PlayOptions): Promise<AnimationAction> | void {
149
149
  if (debug) console.log("PLAY", clipOrNumber)
150
150
  this.init();
151
151
  if (!this.mixer) {
@@ -171,8 +171,8 @@ export class Animation extends Behaviour {
171
171
  if (!options) options = {};
172
172
  if (!options.minMaxOffsetNormalized) options.minMaxOffsetNormalized = this.minMaxOffsetNormalized;
173
173
  if (!options.minMaxSpeed) options.minMaxSpeed = this.minMaxSpeed;
174
- if (!options.loop) options.loop = this.loop;
175
- if (!options.clampWhenFinished) options.clampWhenFinished = this.clampWhenFinished;
174
+ if (options.loop === undefined) options.loop = this.loop;
175
+ if (options.clampWhenFinished === undefined) options.clampWhenFinished = this.clampWhenFinished;
176
176
  for (const act of this.actions) {
177
177
  if (act.getClip() === clip) {
178
178
  return this.internalOnPlay(act, options);
@@ -639,7 +639,7 @@ export class Renderer extends Behaviour implements IRenderer {
639
639
  }
640
640
  }
641
641
 
642
- private applySettings(go: THREE.Object3D) {
642
+ applySettings(go: THREE.Object3D) {
643
643
  go.receiveShadow = this.receiveShadows;
644
644
  if (this.shadowCastingMode == ShadowCastingMode.On) {
645
645
  go.castShadow = true;
@@ -734,15 +734,16 @@ class InstancingHandler {
734
734
  public setup(renderer: Renderer, obj: THREE.Object3D, context: Context, handlesArray: InstanceHandle[] | null, args: InstancingSetupArgs, level: number = 0)
735
735
  : InstanceHandle[] | null {
736
736
 
737
+ // make sure setting casting settings are applied so when we add the mesh to the InstancedMesh we can ask for the correct cast shadow setting
738
+ renderer.applySettings(obj);
737
739
  const res = this.tryCreateOrAddInstance(obj, context, args);
738
740
  if (res) {
739
741
  renderer.loadProgressiveTextures(res.instancer.material);
740
742
  if (handlesArray === null) handlesArray = [];
741
743
  handlesArray.push(res);
742
- return handlesArray;
743
744
  }
744
745
 
745
- if (level <= 0 && obj.type !== "Mesh") {
746
+ else if (level <= 0 && obj.type !== "Mesh") {
746
747
  const nextLevel = level + 1;
747
748
  for (const ch of obj.children) {
748
749
  handlesArray = this.setup(renderer, ch, context, handlesArray, args, nextLevel);
@@ -799,10 +800,8 @@ class InstancingHandler {
799
800
  let previousMatrix: THREE.Matrix4 = obj.matrixWorld.clone();
800
801
  const matrixChangeWrapper = (a: Matrix4, b: Matrix4) => {
801
802
  const newMatrixWorld = original(a, b);
802
- // console.warn("MULT", obj.matrixWorldNeedsUpdate);
803
803
  if (obj[NEED_UPDATE_INSTANCE_KEY] || previousMatrix.equals(newMatrixWorld) === false) {
804
804
  previousMatrix.copy(newMatrixWorld)
805
- // handle.setMatrix(newMatrixWorld);
806
805
  obj[NEED_UPDATE_INSTANCE_KEY] = true;
807
806
  }
808
807
  return newMatrixWorld;
@@ -865,6 +864,13 @@ class InstanceHandle {
865
864
 
866
865
  class InstancedMeshRenderer {
867
866
 
867
+ set castShadow(val: boolean) {
868
+ this.inst.castShadow = val;
869
+ }
870
+ set receiveShadow(val: boolean) {
871
+ this.inst.receiveShadow = val;
872
+ }
873
+
868
874
  public name: string = "";
869
875
  public geo: THREE.BufferGeometry;
870
876
  public material: THREE.Material;
@@ -915,6 +921,14 @@ class InstancedMeshRenderer {
915
921
  return null;
916
922
  }
917
923
  const handle = new InstanceHandle(-1, obj, this);
924
+
925
+ if (obj.castShadow === true && this.inst.castShadow === false) {
926
+ this.inst.castShadow = true;
927
+ }
928
+ if (obj.receiveShadow === true && this.inst.receiveShadow === false) {
929
+ this.inst.receiveShadow = true;
930
+ }
931
+
918
932
  this.add(handle);
919
933
  return handle;
920
934
  }
@@ -0,0 +1 @@
1
+ export * from "./ui/PointerEvents"
@@ -1,5 +1,5 @@
1
1
  import { BlendFunction, DepthDownsamplingPass, Effect, NormalPass, SSAOEffect } from "postprocessing";
2
- import { NeverDepth, PerspectiveCamera } from "three";
2
+ import { Color, NeverDepth, PerspectiveCamera } from "three";
3
3
  import { serializable } from "../../../engine/engine_serialization";
4
4
  import { EffectProviderResult, PostProcessingEffect } from "../PostProcessingEffect";
5
5
  import { VolumeParameter } from "../VolumeParameter";
@@ -21,6 +21,12 @@ export class ScreenSpaceAmbientOcclusion extends PostProcessingEffect {
21
21
  @serializable(VolumeParameter)
22
22
  samples!: VolumeParameter;
23
23
 
24
+ @serializable(VolumeParameter)
25
+ color!: VolumeParameter;
26
+
27
+ @serializable(VolumeParameter)
28
+ luminanceInfluence!: VolumeParameter;
29
+
24
30
  onBeforeRender() {
25
31
  if (this._ssao && this.context.mainCamera instanceof PerspectiveCamera) {
26
32
  const fadeDistance = this.context.mainCamera.far - this.context.mainCamera.near;
@@ -48,6 +54,7 @@ export class ScreenSpaceAmbientOcclusion extends PostProcessingEffect {
48
54
  worldProximityFalloff: 2,
49
55
  intensity: 1,
50
56
  blendFunction: BlendFunction.MULTIPLY,
57
+ luminanceInfluence: .5,
51
58
  });
52
59
 
53
60
  this.intensity.onValueChanged = newValue => {
@@ -59,6 +66,13 @@ export class ScreenSpaceAmbientOcclusion extends PostProcessingEffect {
59
66
  this.samples.onValueChanged = newValue => {
60
67
  ssao.samples = newValue;
61
68
  }
69
+ this.color.onValueChanged = newValue => {
70
+ if (!ssao.color) ssao.color = new Color();
71
+ ssao.color.copy(newValue);
72
+ }
73
+ this.luminanceInfluence.onValueChanged = newValue => {
74
+ ssao.luminanceInfluence = newValue;
75
+ }
62
76
 
63
77
  const arr = new Array();
64
78
  arr.push(normalPass);
@@ -193,7 +193,7 @@ export class PostProcessingHandler {
193
193
  }
194
194
 
195
195
 
196
- const effectsOrder: Array<Constructor<Effect | Pass>> = [
196
+ export const effectsOrder: Array<Constructor<Effect | Pass>> = [
197
197
  NormalPass,
198
198
  DepthDownsamplingPass,
199
199
  SSAOEffect,