@needle-tools/engine 3.0.1-alpha.4 → 3.1.0-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 (146) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/dist/needle-engine.js +13110 -12429
  3. package/dist/needle-engine.min.js +378 -365
  4. package/dist/needle-engine.umd.cjs +366 -353
  5. package/lib/engine/api.d.ts +2 -1
  6. package/lib/engine/api.js +2 -1
  7. package/lib/engine/api.js.map +1 -1
  8. package/lib/engine/codegen/register_types.js +8 -0
  9. package/lib/engine/codegen/register_types.js.map +1 -1
  10. package/lib/engine/debug/debug_overlay.js +3 -0
  11. package/lib/engine/debug/debug_overlay.js.map +1 -1
  12. package/lib/engine/engine_addressables.d.ts +21 -1
  13. package/lib/engine/engine_addressables.js +83 -7
  14. package/lib/engine/engine_addressables.js.map +1 -1
  15. package/lib/engine/engine_context.d.ts +2 -0
  16. package/lib/engine/engine_context.js +3 -0
  17. package/lib/engine/engine_context.js.map +1 -1
  18. package/lib/engine/engine_element.d.ts +1 -1
  19. package/lib/engine/engine_element.js +2 -2
  20. package/lib/engine/engine_element.js.map +1 -1
  21. package/lib/engine/engine_element_loading.d.ts +7 -2
  22. package/lib/engine/engine_element_loading.js +67 -22
  23. package/lib/engine/engine_element_loading.js.map +1 -1
  24. package/lib/engine/engine_license.d.ts +1 -1
  25. package/lib/engine/engine_license.js +6 -19
  26. package/lib/engine/engine_license.js.map +1 -1
  27. package/lib/engine/engine_networking.d.ts +1 -0
  28. package/lib/engine/engine_networking.js +3 -0
  29. package/lib/engine/engine_networking.js.map +1 -1
  30. package/lib/engine/engine_serialization.d.ts +2 -2
  31. package/lib/engine/engine_serialization.js +2 -3
  32. package/lib/engine/engine_serialization.js.map +1 -1
  33. package/lib/engine/engine_serialization_builtin_serializer.d.ts +5 -0
  34. package/lib/engine/engine_serialization_builtin_serializer.js +16 -0
  35. package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
  36. package/lib/engine/engine_serialization_core.d.ts +1 -0
  37. package/lib/engine/engine_serialization_core.js +26 -20
  38. package/lib/engine/engine_serialization_core.js.map +1 -1
  39. package/lib/engine/engine_utils.d.ts +9 -0
  40. package/lib/engine/engine_utils.js +33 -13
  41. package/lib/engine/engine_utils.js.map +1 -1
  42. package/lib/engine/extensions/NEEDLE_animator_controller_model.d.ts +1 -0
  43. package/lib/engine/extensions/NEEDLE_animator_controller_model.js.map +1 -1
  44. package/lib/engine/extensions/NEEDLE_progressive.js +2 -2
  45. package/lib/engine/extensions/NEEDLE_progressive.js.map +1 -1
  46. package/lib/engine-components/AnimatorController.js +22 -3
  47. package/lib/engine-components/AnimatorController.js.map +1 -1
  48. package/lib/engine-components/AudioSource.d.ts +2 -3
  49. package/lib/engine-components/AudioSource.js +28 -32
  50. package/lib/engine-components/AudioSource.js.map +1 -1
  51. package/lib/engine-components/CameraUtils.js.map +1 -1
  52. package/lib/engine-components/Component.js.map +1 -1
  53. package/lib/engine-components/ParticleSystem.d.ts +5 -2
  54. package/lib/engine-components/ParticleSystem.js +49 -10
  55. package/lib/engine-components/ParticleSystem.js.map +1 -1
  56. package/lib/engine-components/ParticleSystemModules.d.ts +2 -0
  57. package/lib/engine-components/ParticleSystemModules.js +23 -12
  58. package/lib/engine-components/ParticleSystemModules.js.map +1 -1
  59. package/lib/engine-components/ScreenCapture.d.ts +1 -0
  60. package/lib/engine-components/ScreenCapture.js +145 -46
  61. package/lib/engine-components/ScreenCapture.js.map +1 -1
  62. package/lib/engine-components/Skybox.js +2 -2
  63. package/lib/engine-components/Skybox.js.map +1 -1
  64. package/lib/engine-components/SyncedRoom.js +1 -2
  65. package/lib/engine-components/SyncedRoom.js.map +1 -1
  66. package/lib/engine-components/VideoPlayer.d.ts +4 -2
  67. package/lib/engine-components/VideoPlayer.js +35 -12
  68. package/lib/engine-components/VideoPlayer.js.map +1 -1
  69. package/lib/engine-components/WebXR.d.ts +4 -1
  70. package/lib/engine-components/WebXR.js +10 -2
  71. package/lib/engine-components/WebXR.js.map +1 -1
  72. package/lib/engine-components/WebXRController.js +2 -2
  73. package/lib/engine-components/WebXRController.js.map +1 -1
  74. package/lib/engine-components/WebXRImageTracking.d.ts +39 -0
  75. package/lib/engine-components/WebXRImageTracking.js +173 -0
  76. package/lib/engine-components/WebXRImageTracking.js.map +1 -0
  77. package/lib/engine-components/codegen/components.d.ts +4 -0
  78. package/lib/engine-components/codegen/components.js +4 -0
  79. package/lib/engine-components/codegen/components.js.map +1 -1
  80. package/lib/engine-components/postprocessing/Effects/DepthOfField.d.ts +2 -0
  81. package/lib/engine-components/postprocessing/Effects/DepthOfField.js +19 -1
  82. package/lib/engine-components/postprocessing/Effects/DepthOfField.js.map +1 -1
  83. package/lib/engine-components/postprocessing/Effects/TiltShiftEffect.d.ts +13 -0
  84. package/lib/engine-components/postprocessing/Effects/TiltShiftEffect.js +63 -0
  85. package/lib/engine-components/postprocessing/Effects/TiltShiftEffect.js.map +1 -0
  86. package/lib/engine-components/postprocessing/VolumeParameter.d.ts +1 -0
  87. package/lib/engine-components/postprocessing/VolumeParameter.js +4 -0
  88. package/lib/engine-components/postprocessing/VolumeParameter.js.map +1 -1
  89. package/lib/engine-components/timeline/PlayableDirector.d.ts +3 -1
  90. package/lib/engine-components/timeline/PlayableDirector.js +40 -2
  91. package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
  92. package/lib/engine-components/timeline/TimelineTracks.d.ts +2 -2
  93. package/lib/engine-components/timeline/TimelineTracks.js +14 -16
  94. package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
  95. package/lib/engine-components/ui/Text.js +7 -8
  96. package/lib/engine-components/ui/Text.js.map +1 -1
  97. package/lib/include/three/ARButton.d.ts +1 -1
  98. package/lib/include/three/ARButton.js +2 -1
  99. package/lib/include/three/ARButton.js.map +1 -1
  100. package/lib/tsconfig.tsbuildinfo +1 -1
  101. package/package.json +3 -4
  102. package/plugins/vite/config.js +8 -0
  103. package/plugins/vite/copyfiles.js +12 -3
  104. package/plugins/vite/drop.js +1 -0
  105. package/plugins/vite/index.js +4 -0
  106. package/plugins/vite/license.js +24 -0
  107. package/plugins/vite/transform-codegen.js +45 -0
  108. package/src/engine/api.ts +2 -2
  109. package/src/engine/codegen/register_types.js +10 -2
  110. package/src/engine/debug/debug_overlay.ts +2 -0
  111. package/src/engine/engine_addressables.ts +102 -8
  112. package/src/engine/engine_context.ts +4 -1
  113. package/src/engine/engine_element.ts +2 -2
  114. package/src/engine/engine_element_loading.ts +68 -22
  115. package/src/engine/engine_license.ts +6 -17
  116. package/src/engine/engine_networking.ts +4 -0
  117. package/src/engine/engine_serialization.ts +5 -4
  118. package/src/engine/engine_serialization_builtin_serializer.ts +23 -3
  119. package/src/engine/engine_serialization_core.ts +27 -20
  120. package/src/engine/engine_utils.ts +35 -14
  121. package/src/engine/extensions/NEEDLE_animator_controller_model.ts +1 -0
  122. package/src/engine/extensions/NEEDLE_progressive.ts +2 -2
  123. package/src/engine-components/AnimatorController.ts +18 -3
  124. package/src/engine-components/AudioSource.ts +29 -38
  125. package/src/engine-components/CameraUtils.ts +2 -2
  126. package/src/engine-components/Component.ts +1 -1
  127. package/src/engine-components/ParticleSystem.ts +52 -10
  128. package/src/engine-components/ParticleSystemModules.ts +24 -12
  129. package/src/engine-components/ScreenCapture.ts +149 -49
  130. package/src/engine-components/Skybox.ts +2 -2
  131. package/src/engine-components/SyncedRoom.ts +1 -2
  132. package/src/engine-components/VideoPlayer.ts +33 -11
  133. package/src/engine-components/WebXR.ts +11 -2
  134. package/src/engine-components/WebXRController.ts +2 -2
  135. package/src/engine-components/WebXRImageTracking.ts +192 -0
  136. package/src/engine-components/codegen/components.ts +4 -0
  137. package/src/engine-components/postprocessing/Effects/DepthOfField.ts +21 -6
  138. package/src/engine-components/postprocessing/Effects/TiltShiftEffect.ts +56 -0
  139. package/src/engine-components/postprocessing/VolumeParameter.ts +5 -0
  140. package/src/engine-components/timeline/PlayableDirector.ts +38 -2
  141. package/src/engine-components/timeline/TimelineTracks.ts +15 -18
  142. package/src/engine-components/ui/Text.ts +7 -8
  143. package/src/include/three/ARButton.js +2 -2
  144. package/lib/engine/codegen/license.json +0 -1
  145. package/license-2447137e.js +0 -4
  146. package/src/engine/codegen/license.json +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/engine",
3
- "version": "3.0.1-alpha.4",
3
+ "version": "3.1.0-alpha",
4
4
  "description": "Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in",
5
5
  "main": "dist/needle-engine.umd.cjs",
6
6
  "type": "module",
@@ -35,8 +35,7 @@
35
35
  "src",
36
36
  "dist",
37
37
  "lib",
38
- "plugins",
39
- "license-2447137e.js"
38
+ "plugins"
40
39
  ],
41
40
  "keywords": [
42
41
  "needle",
@@ -58,7 +57,7 @@
58
57
  "@dimforge/rapier3d-compat": "^0.9.0",
59
58
  "flatbuffers": "2.0.4",
60
59
  "md5": "^2.3.0",
61
- "peerjs": "1.3.2",
60
+ "peerjs": "1.4.7",
62
61
  "postprocessing": "^6.30.1",
63
62
  "simplex-noise": "^4.0.1",
64
63
  "stats.js": "^0.17.0",
@@ -1,5 +1,6 @@
1
1
  import { existsSync, readFileSync } from 'fs';
2
2
 
3
+ /** the codegen meta file */
3
4
  export async function loadConfig(path) {
4
5
  try {
5
6
  // First try to get the path from the config
@@ -28,6 +29,7 @@ export async function loadConfig(path) {
28
29
  }
29
30
  }
30
31
 
32
+ /** get the needle.config.json */
31
33
  export function tryLoadProjectConfig() {
32
34
  try {
33
35
  const root = process.cwd();
@@ -45,4 +47,10 @@ export function tryLoadProjectConfig() {
45
47
  }
46
48
 
47
49
  return null;
50
+ }
51
+
52
+
53
+ /** "assets" -> the directory name inside the output directory to put e.g. glb files into */
54
+ export function builtAssetsDirectory(){
55
+ return "assets";
48
56
  }
@@ -1,6 +1,7 @@
1
1
 
2
2
  import { resolve, join } from 'path'
3
3
  import { existsSync, statSync, mkdirSync, readdirSync, copyFileSync, mkdir } from 'fs';
4
+ import { builtAssetsDirectory, tryLoadProjectConfig } from './config.js';
4
5
 
5
6
 
6
7
  /** copy files on build from assets to dist */
@@ -19,7 +20,14 @@ export const needleCopyFiles = (command, config, userSettings) => {
19
20
  const baseDir = process.cwd();
20
21
  const pluginName = "needle-copy-files";
21
22
 
22
- const outdirName = "dist";
23
+ let assetsDirName = "assets";
24
+ let outdirName = "dist";
25
+
26
+ const needleConfig = tryLoadProjectConfig();
27
+ if(needleConfig){
28
+ assetsDirName = needleConfig.assetsDirectory;
29
+ }
30
+
23
31
  const outDir = resolve(baseDir, outdirName);
24
32
  if (!existsSync(outDir)) {
25
33
  mkdirSync(outDir);
@@ -36,9 +44,9 @@ export const needleCopyFiles = (command, config, userSettings) => {
36
44
  }
37
45
 
38
46
  // copy assets dir
39
- const assetsDir = resolve(baseDir, 'assets');
47
+ const assetsDir = resolve(baseDir, assetsDirName);
40
48
  if (existsSync(assetsDir)) {
41
- console.log(`[${pluginName}] - Copy assets to ${outdirName}/assets`)
49
+ console.log(`[${pluginName}] - Copy assets to ${outdirName}/${builtAssetsDirectory()}`)
42
50
  const targetDir = resolve(outDir, 'assets');
43
51
  copyRecursiveSync(assetsDir, targetDir);
44
52
  }
@@ -53,6 +61,7 @@ export const needleCopyFiles = (command, config, userSettings) => {
53
61
  }
54
62
  }
55
63
 
64
+
56
65
  function copyRecursiveSync(src, dest) {
57
66
  var exists = existsSync(src);
58
67
  var stats = exists && statSync(src);
@@ -6,6 +6,7 @@ import { fileURLToPath } from 'url';
6
6
  const __filename = fileURLToPath(import.meta.url);
7
7
  const __dirname = path.dirname(__filename);
8
8
 
9
+ /** experimental, allow dropping files from Unity into the running scene */
9
10
  export const needleDrop = (command, config, userSettings) => {
10
11
  if (command === "build") return;
11
12
 
@@ -6,6 +6,8 @@ import { needleDrop } from "./drop.js";
6
6
  import { editorConnection } from "./editor-connection.js";
7
7
  import { needleCopyFiles } from "./copyfiles.js";
8
8
  import { needleViteAlias } from "./alias.js";
9
+ import { needleTransformCodegen } from "./transform-codegen.js";
10
+ import { needleLicense } from "./license.js";
9
11
 
10
12
  export * from "./gzip.js";
11
13
  export * from "./config.js";
@@ -19,12 +21,14 @@ export const needlePlugins = async (command, config, userSettings) => {
19
21
  // ensure we have user settings initialized with defaults
20
22
  userSettings = { ...defaultUserSettings, ...userSettings }
21
23
  const array = [
24
+ needleLicense(command, config, userSettings),
22
25
  needleViteAlias(command, config, userSettings),
23
26
  needleMeta(command, config, userSettings),
24
27
  needlePoster(command),
25
28
  needleReload(command, config, userSettings),
26
29
  needleBuild(command, config, userSettings),
27
30
  needleCopyFiles(command, config, userSettings),
31
+ needleTransformCodegen(command, config, userSettings),
28
32
  needleDrop(command, config, userSettings),
29
33
  ];
30
34
  array.push(await editorConnection(command, config, userSettings, array));
@@ -0,0 +1,24 @@
1
+ import { loadConfig } from './config.js';
2
+
3
+
4
+ export const needleLicense = (command, config, userSettings) => {
5
+
6
+ return {
7
+ name: "needle-license",
8
+ enforce: 'pre',
9
+ async transform(src, id) {
10
+ if (id.includes("engine/engine_license.ts")) {
11
+ const needleConfig = await loadConfig();
12
+ if (needleConfig) {
13
+ if (needleConfig.hasProLicense !== undefined && typeof needleConfig.hasProLicense === "boolean") {
14
+ src = src.replace("const HAS_LICENSE = false;", "const HAS_LICENSE = " + needleConfig.hasProLicense + ";");
15
+ return { code: src, map: null }
16
+ }
17
+ }
18
+ else {
19
+ console.log("No config found - can not apply license");
20
+ }
21
+ }
22
+ }
23
+ }
24
+ };
@@ -0,0 +1,45 @@
1
+ import { builtAssetsDirectory, tryLoadProjectConfig } from './config.js';
2
+
3
+ /**
4
+ * modify the glb load path in codegen files
5
+ * this is necessary if the assets directory is not the default (changed by the user in needle.config.json)
6
+ */
7
+ export const needleTransformCodegen = (command, config, userSettings) => {
8
+
9
+ if (config?.noCodegenTransform === true || userSettings?.noCodegenTransform === true) {
10
+ return;
11
+ }
12
+
13
+ let codegenDirectory = "src/generated";
14
+ const needleConfig = tryLoadProjectConfig();
15
+ if (needleConfig?.codegenDirectory?.length)
16
+ codegenDirectory = needleConfig.codegenDirectory;
17
+
18
+ let configuredAssetsDirectory = "assets";
19
+ if (needleConfig?.assetsDirectory?.length)
20
+ configuredAssetsDirectory = needleConfig.assetsDirectory;
21
+
22
+ // https://regex101.com/r/Y05z9P/1
23
+ // const matchCodegenFilePaths = /\"(.+)\/.+?\.(glb|gltf)/g;
24
+
25
+ return [
26
+ {
27
+ name: 'needle-transform-files',
28
+ apply: 'build',
29
+ transform(src, id) {
30
+ if (id.endsWith(codegenDirectory + "/gen.js")) {
31
+ const assetsDir = builtAssetsDirectory();
32
+ if (assetsDir !== configuredAssetsDirectory) {
33
+ console.log(`[needle-transform-files] - Transform codegen paths \"${configuredAssetsDirectory}\" → \"${assetsDir}\"`)
34
+ // replace codegen paths
35
+ src = src.replaceAll(configuredAssetsDirectory, assetsDir);
36
+ return {
37
+ code: src,
38
+ map: null
39
+ }
40
+ }
41
+ }
42
+ }
43
+ }
44
+ ];
45
+ }
package/src/engine/api.ts CHANGED
@@ -6,7 +6,7 @@ export { InstancingUtil } from "./engine_instancing";
6
6
  export * from "./engine_gameobject";
7
7
  export * from "./engine_components";
8
8
  export * from "./engine_components_internal";
9
- export { AssetReference } from "./engine_addressables";
9
+ export { AssetReference, ImageReference } from "./engine_addressables";
10
10
  export { Context, FrameEvent } from "./engine_setup";
11
11
  export * from "./debug/debug";
12
12
  export { validate } from "./engine_util_decorator"
@@ -14,7 +14,7 @@ export { Gizmos } from "./engine_gizmos"
14
14
  export * from "./engine_scenetools";
15
15
  export * from "./engine_math"
16
16
  export * from "./js-extensions"
17
-
17
+ export { hasProLicense } from "./engine_license"
18
18
 
19
19
  export {
20
20
  // url params
@@ -1,5 +1,5 @@
1
1
  import { TypeStore } from "./../engine_typestore"
2
-
2
+
3
3
  // Import types
4
4
  import { __Ignore } from "../../engine-components/codegen/components";
5
5
  import { AlignmentConstraint } from "../../engine-components/AlignmentConstraint";
@@ -150,6 +150,7 @@ import { TestRunner } from "../../engine-components/TestRunner";
150
150
  import { TestSimulateUserData } from "../../engine-components/TestRunner";
151
151
  import { Text } from "../../engine-components/ui/Text";
152
152
  import { TextureSheetAnimationModule } from "../../engine-components/ParticleSystemModules";
153
+ import { TiltShiftEffect } from "../../engine-components/postprocessing/Effects/TiltShiftEffect";
153
154
  import { ToneMapping } from "../../engine-components/postprocessing/Effects/Tonemapping";
154
155
  import { TrailModule } from "../../engine-components/ParticleSystemModules";
155
156
  import { TransformData } from "../../engine-components/export/usdz/extensions/Animation";
@@ -173,13 +174,16 @@ import { WebARSessionRoot } from "../../engine-components/WebARSessionRoot";
173
174
  import { WebXR } from "../../engine-components/WebXR";
174
175
  import { WebXRAvatar } from "../../engine-components/WebXRAvatar";
175
176
  import { WebXRController } from "../../engine-components/WebXRController";
177
+ import { WebXRImageTracking } from "../../engine-components/WebXRImageTracking";
178
+ import { WebXRImageTrackingModel } from "../../engine-components/WebXRImageTracking";
176
179
  import { WebXRSync } from "../../engine-components/WebXRSync";
180
+ import { WebXRTrackedImage } from "../../engine-components/WebXRImageTracking";
177
181
  import { XRFlag } from "../../engine-components/XRFlag";
178
182
  import { XRGrabModel } from "../../engine-components/WebXRGrabRendering";
179
183
  import { XRGrabRendering } from "../../engine-components/WebXRGrabRendering";
180
184
  import { XRRig } from "../../engine-components/WebXRRig";
181
185
  import { XRState } from "../../engine-components/XRFlag";
182
-
186
+
183
187
  // Register types
184
188
  TypeStore.add("__Ignore", __Ignore);
185
189
  TypeStore.add("AlignmentConstraint", AlignmentConstraint);
@@ -330,6 +334,7 @@ TypeStore.add("TestRunner", TestRunner);
330
334
  TypeStore.add("TestSimulateUserData", TestSimulateUserData);
331
335
  TypeStore.add("Text", Text);
332
336
  TypeStore.add("TextureSheetAnimationModule", TextureSheetAnimationModule);
337
+ TypeStore.add("TiltShiftEffect", TiltShiftEffect);
333
338
  TypeStore.add("ToneMapping", ToneMapping);
334
339
  TypeStore.add("TrailModule", TrailModule);
335
340
  TypeStore.add("TransformData", TransformData);
@@ -353,7 +358,10 @@ TypeStore.add("WebARSessionRoot", WebARSessionRoot);
353
358
  TypeStore.add("WebXR", WebXR);
354
359
  TypeStore.add("WebXRAvatar", WebXRAvatar);
355
360
  TypeStore.add("WebXRController", WebXRController);
361
+ TypeStore.add("WebXRImageTracking", WebXRImageTracking);
362
+ TypeStore.add("WebXRImageTrackingModel", WebXRImageTrackingModel);
356
363
  TypeStore.add("WebXRSync", WebXRSync);
364
+ TypeStore.add("WebXRTrackedImage", WebXRTrackedImage);
357
365
  TypeStore.add("XRFlag", XRFlag);
358
366
  TypeStore.add("XRGrabModel", XRGrabModel);
359
367
  TypeStore.add("XRGrabRendering", XRGrabRendering);
@@ -108,6 +108,8 @@ function showMessage(type: LogType, element: HTMLElement, msg: string) {
108
108
  if (container.childElementCount >= 20) {
109
109
  return;
110
110
  }
111
+ // truncate long messages before they go into the cache/set
112
+ if(msg.length > 300) msg = msg.substring(0, 300) + "...";
111
113
  if (currentMessages.has(msg)) return;
112
114
  currentMessages.add(msg);
113
115
  const msgcontainer = getMessageContainer(type, msg);
@@ -1,8 +1,8 @@
1
- import { getParam, getPath } from "../engine/engine_utils";
1
+ import { getParam, resolveUrl } from "../engine/engine_utils";
2
2
  // import { loadSync, parseSync } from "./engine_scenetools";
3
3
  import { SerializationContext, TypeSerializer } from "./engine_serialization_core";
4
4
  import { Context } from "./engine_setup";
5
- import { Group, Object3D, Scene } from "three";
5
+ import { Group, Object3D, Scene, Texture } from "three";
6
6
  import { processNewScripts } from "./engine_mainloop_utils";
7
7
  import { registerPrefabProvider, syncInstantiate } from "./engine_networking_instantiate";
8
8
  import { download, hash } from "./engine_web_api";
@@ -50,7 +50,7 @@ export type ProgressCallback = (asset: AssetReference, prog: ProgressEvent) => v
50
50
  export class AssetReference {
51
51
 
52
52
  static getOrCreate(sourceId: SourceIdentifier, uri: string, context: Context): AssetReference {
53
- const fullPath = getPath(sourceId, uri);
53
+ const fullPath = resolveUrl(sourceId, uri);
54
54
  if (debug) console.log("GetOrCreate Addressable from", sourceId, uri, "FinalPath=", fullPath);
55
55
  const addressables = context.addressables;
56
56
  const existing = addressables.findAssetReference(fullPath);
@@ -72,15 +72,16 @@ export class AssetReference {
72
72
 
73
73
  private _loading?: PromiseLike<any>;
74
74
 
75
+ // TODO: rename to url
75
76
  get uri(): string {
76
- return this._uri;
77
+ return this._url;
77
78
  }
78
79
 
79
80
  get rawAsset(): any { return this._asset; }
80
81
 
81
82
  private _asset: any;
82
83
  private _glbRoot?: Object3D | null;
83
- private _uri: string;
84
+ private _url: string;
84
85
  private _progressListeners: ProgressCallback[] = [];
85
86
 
86
87
  private _hash?: string;
@@ -90,14 +91,14 @@ export class AssetReference {
90
91
  private _rawBinary?: ArrayBuffer | null;
91
92
 
92
93
  constructor(uri: string, hash?: string) {
93
- this._uri = uri;
94
+ this._url = uri;
94
95
  this._hash = hash;
95
96
  if (uri.includes("?v="))
96
97
  this._hashedUri = uri;
97
98
  else
98
99
  this._hashedUri = hash ? uri + "?v=" + hash : uri;
99
100
 
100
- registerPrefabProvider(this._uri, this.onResolvePrefab.bind(this));
101
+ registerPrefabProvider(this._url, this.onResolvePrefab.bind(this));
101
102
  }
102
103
 
103
104
  private async onResolvePrefab(uri: string): Promise<IGameObject | null> {
@@ -330,4 +331,97 @@ class AddressableSerializer extends TypeSerializer {
330
331
  }
331
332
 
332
333
  }
333
- new AddressableSerializer();
334
+ new AddressableSerializer();
335
+
336
+
337
+
338
+
339
+
340
+
341
+ export class ImageReference {
342
+
343
+ private static imageReferences = new Map<string, ImageReference>();
344
+
345
+ static getOrCreate(url: string) {
346
+ let ref = ImageReference.imageReferences.get(url);
347
+ if (!ref) {
348
+ ref = new ImageReference(url);
349
+ ImageReference.imageReferences.set(url, ref);
350
+ }
351
+ return ref;
352
+ }
353
+
354
+ constructor(url: string) {
355
+ this.url = url;
356
+ }
357
+
358
+ readonly url!: string;
359
+
360
+ private _bitmap?: Promise<ImageBitmap | null>;
361
+ private _bitmapObject?: ImageBitmap;
362
+
363
+ dispose() {
364
+ if (this._bitmapObject) {
365
+ this._bitmapObject.close();
366
+ }
367
+ this._bitmap = undefined;
368
+ }
369
+
370
+ createHTMLImage(): HTMLImageElement {
371
+ const img = new Image();
372
+ img.src = this.url;
373
+ return img;
374
+ }
375
+
376
+ createTexture(): Promise<Texture | null> {
377
+ return this.getBitmap().then((bitmap) => {
378
+ if (bitmap) {
379
+ const texture = new Texture(bitmap);
380
+ texture.needsUpdate = true;
381
+ return texture;
382
+ }
383
+ return null;
384
+ });
385
+ }
386
+
387
+ /** Loads the bitmap data of the image */
388
+ getBitmap(): Promise<ImageBitmap | null> {
389
+ if (this._bitmap) return this._bitmap;
390
+ this._bitmap = new Promise((res, _) => {
391
+ const imageElement = document.createElement("img") as HTMLImageElement;
392
+ imageElement.addEventListener("load", () => {
393
+ this._bitmap = createImageBitmap(imageElement).then((bitmap) => {
394
+ this._bitmapObject = bitmap;
395
+ res(bitmap);
396
+ return bitmap;
397
+ })
398
+ });
399
+ imageElement.addEventListener("error", err => {
400
+ console.error("Failed to load image:" + this.url, err);
401
+ res(null);
402
+ });
403
+ imageElement.src = this.url;
404
+ });
405
+ return this._bitmap;
406
+ }
407
+ }
408
+
409
+
410
+ export class ImageReferenceSerializer extends TypeSerializer {
411
+ constructor() {
412
+ super([ImageReference]);
413
+ }
414
+
415
+ onSerialize(_data: string, _context: SerializationContext) {
416
+ return null;
417
+ }
418
+
419
+ onDeserialize(data: string, _context: SerializationContext) {
420
+ if (typeof data === "string") {
421
+ const url = resolveUrl(_context.gltfId, data)
422
+ return ImageReference.getOrCreate(url);
423
+ }
424
+ return undefined;
425
+ }
426
+ }
427
+ new ImageReferenceSerializer();
@@ -161,6 +161,8 @@ export class Context implements IContext {
161
161
  get isInVR() { return this.xrSessionMode === XRSessionMode.ImmersiveVR; }
162
162
  get isInAR() { return this.xrSessionMode === XRSessionMode.ImmersiveAR; }
163
163
  get xrSession() { return this.renderer.xr?.getSession(); }
164
+ get xrFrame() { return this._xrFrame }
165
+ private _xrFrame: XRFrame | null = null;
164
166
  get arOverlayElement(): HTMLElement {
165
167
  const el = this.domElement as any;
166
168
  if (typeof el.getAROverlayContainer === "function")
@@ -607,7 +609,8 @@ export class Context implements IContext {
607
609
  private _accumulatedTime = 0;
608
610
  private _framerateClock = new Clock();
609
611
 
610
- private render(_, frame) {
612
+ private render(_, frame : XRFrame) {
613
+ this._xrFrame = frame;
611
614
 
612
615
  this._currentFrameEvent = FrameEvent.Undefined;
613
616
 
@@ -24,7 +24,7 @@ const arSessionActiveClassName = "ar-session-active";
24
24
  const desktopSessionActiveClassName = "desktop-session-active";
25
25
 
26
26
  // https://developers.google.com/web/fundamentals/web-components/customelements
27
- export class EngineElement extends HTMLElement implements INeedleEngineComponent {
27
+ export class NeedleEngineHTMLElement extends HTMLElement implements INeedleEngineComponent {
28
28
 
29
29
  public get loadingProgress01(): number { return this._loadingProgress01; }
30
30
  public get loadingFinished(): boolean { return this.loadingProgress01 > .999; }
@@ -424,7 +424,7 @@ export class EngineElement extends HTMLElement implements INeedleEngineComponent
424
424
  }
425
425
 
426
426
  if (!window.customElements.get(htmlTagName))
427
- window.customElements.define(htmlTagName, EngineElement);
427
+ window.customElements.define(htmlTagName, NeedleEngineHTMLElement);
428
428
 
429
429
 
430
430
 
@@ -3,6 +3,7 @@ import { Mathf } from "./engine_math";
3
3
  import { LoadingProgressArgs } from "./engine_setup";
4
4
  import { getParam } from "./engine_utils";
5
5
  import { logoSVG } from "./assets"
6
+ import { hasProLicense } from "./engine_license";
6
7
 
7
8
  const debug = getParam("debugloadingbar");
8
9
  const debugRendering = getParam("debugloadingbarrendering");
@@ -50,7 +51,8 @@ export class EngineLoadingView implements ILoadingViewHandler {
50
51
  // the raw progress
51
52
  loadingProgress: number = 0;
52
53
 
53
- private container: HTMLElement;
54
+ /** Usually the NeedleEngineHTMLElement */
55
+ private _element: HTMLElement;
54
56
  private _progress: number = 0;
55
57
  private _allowCustomLoadingElement: boolean = true;
56
58
  private _loadingElement?: HTMLElement;
@@ -59,20 +61,24 @@ export class EngineLoadingView implements ILoadingViewHandler {
59
61
  private _messageContainer: HTMLElement | null = null;
60
62
  private _loadingElementOptions?: LoadingElementOptions;
61
63
 
62
- constructor(container: HTMLElement, opts?: LoadingElementOptions) {
63
- this.container = container;
64
+ /**
65
+ * Creates a new loading view
66
+ * @param owner the element that will contain the loading view (should be the NeedleEngineHTMLElement)
67
+ */
68
+ constructor(owner: HTMLElement, opts?: LoadingElementOptions) {
69
+ this._element = owner;
64
70
  this._loadingElementOptions = opts;
65
71
  }
66
72
 
67
73
  onLoadingBegin(message?: string) {
68
74
  if (debug) console.log("Begin Loading")
69
75
  if (!this._loadingElement) {
70
- for (let i = 0; i < this.container.children.length; i++) {
71
- const el = this.container.children[i] as HTMLElement;
76
+ for (let i = 0; i < this._element.children.length; i++) {
77
+ const el = this._element.children[i] as HTMLElement;
72
78
  if (el.classList.contains(EngineLoadingView.LoadingContainerClassName)) {
73
79
  if (!this._allowCustomLoadingElement) {
74
80
  if (debug) console.warn("Remove custom loading container")
75
- this.container.removeChild(el);
81
+ this._element.removeChild(el);
76
82
  continue;
77
83
  }
78
84
  this._loadingElement = this.createLoadingElement(el);
@@ -84,7 +90,7 @@ export class EngineLoadingView implements ILoadingViewHandler {
84
90
  this._progress = 0;
85
91
  this.loadingProgress = 0;
86
92
  this._loadingElement.style.display = "flex";
87
- this.container.appendChild(this._loadingElement);
93
+ this._element.appendChild(this._loadingElement);
88
94
  this.smoothProgressLoop();
89
95
  this.setMessage(message ?? "");
90
96
  }
@@ -113,8 +119,10 @@ export class EngineLoadingView implements ILoadingViewHandler {
113
119
  onLoadingFinished() {
114
120
  if (debug)
115
121
  console.warn("Finished Loading");
116
- this.loadingProgress = 1;
117
- this.onDoneLoading();
122
+ if (!debugRendering) {
123
+ this.loadingProgress = 1;
124
+ this.onDoneLoading();
125
+ }
118
126
  }
119
127
 
120
128
  setMessage(message: string) {
@@ -133,7 +141,7 @@ export class EngineLoadingView implements ILoadingViewHandler {
133
141
  }
134
142
  this._progressLoop = setInterval(() => {
135
143
  // increate loading speed when almost done
136
- if (this.loadingProgress >= .95) dt = .9;
144
+ if (this.loadingProgress >= .95 && !debugRendering) dt = .9;
137
145
  this._progress = Mathf.lerp(this._progress, this.loadingProgress, dt * this.loadingProgress);
138
146
  this.updateDisplay();
139
147
  }, dt);
@@ -164,6 +172,7 @@ export class EngineLoadingView implements ILoadingViewHandler {
164
172
  private createLoadingElement(existing?: HTMLElement): HTMLElement {
165
173
  if (debug && !existing) console.log("Creating loading element");
166
174
  this._loadingElement = existing || document.createElement("div");
175
+ const hasLicense = hasProLicense();
167
176
  if (!existing) {
168
177
  this._loadingElement.style.position = "fixed";
169
178
  this._loadingElement.style.width = "100%";
@@ -178,6 +187,16 @@ export class EngineLoadingView implements ILoadingViewHandler {
178
187
  this._loadingElement.style.flexDirection = "column";
179
188
  this._loadingElement.style.pointerEvents = "none";
180
189
  this._loadingElement.style.color = "white";
190
+ if (hasLicense && this._element) {
191
+ const loadingBackgroundColor = this._element.getAttribute("loading-background-color");
192
+ if (loadingBackgroundColor) {
193
+ this._loadingElement.style.backgroundColor = loadingBackgroundColor;
194
+ }
195
+ const textColor = this._element.getAttribute("loading-text-color");
196
+ if (textColor) {
197
+ this._loadingElement.style.color = textColor;
198
+ }
199
+ }
181
200
  }
182
201
 
183
202
  const className = this._loadingElementOptions?.className ?? EngineLoadingView.LoadingContainerClassName;
@@ -198,19 +217,26 @@ export class EngineLoadingView implements ILoadingViewHandler {
198
217
  // loadingBarContainer.style.alignItems = "center";
199
218
  this._loadingElement.appendChild(loadingBarContainer);
200
219
 
201
- const needleLogo = document.createElement("img");
220
+ const logo = document.createElement("img");
202
221
  const logoSize = 64;
203
- needleLogo.style.width = `${logoSize}px`;
204
- needleLogo.style.height = `${logoSize}px`;
205
- needleLogo.style.position = "absolute";
206
- needleLogo.style.left = "50%";
207
- needleLogo.style.transform = `translate(-${logoSize * .5}px, -${logoSize + 32}px)`;
208
- needleLogo.addEventListener("click", () => window.open("https://needle.tools", "_blank"));
209
- needleLogo.style.cursor = "pointer";
210
- needleLogo.style.userSelect = "none";
211
- needleLogo.style.pointerEvents = "all";
212
- needleLogo.src = logoSVG;
213
- loadingBarContainer.appendChild(needleLogo);
222
+ logo.style.width = `${logoSize}px`;
223
+ logo.style.height = `${logoSize}px`;
224
+ logo.style.position = "absolute";
225
+ logo.style.left = "50%";
226
+ logo.style.transform = `translate(-${logoSize * .5}px, -${logoSize + 32}px)`;
227
+ logo.addEventListener("click", () => window.open("https://needle.tools", "_blank"));
228
+ logo.style.cursor = "pointer";
229
+ logo.style.userSelect = "none";
230
+ logo.style.pointerEvents = "all";
231
+ logo.style.objectFit = "contain";
232
+ logo.src = logoSVG;
233
+ if (hasLicense && this._element) {
234
+ const customLogo = this._element.getAttribute("loading-logo-src");
235
+ if (customLogo) {
236
+ logo.src = customLogo;
237
+ }
238
+ }
239
+ loadingBarContainer.appendChild(logo);
214
240
 
215
241
  this._loadingBar = document.createElement("div");
216
242
  loadingBarContainer.appendChild(this._loadingBar);
@@ -222,6 +248,19 @@ export class EngineLoadingView implements ILoadingViewHandler {
222
248
  this._loadingBar.style.backgroundAttachment = "fixed";
223
249
  this._loadingBar.style.width = "0%";
224
250
  this._loadingBar.style.height = "100%";
251
+ if(hasLicense && this._element){
252
+ const primaryColor = this._element.getAttribute("primary-color");
253
+ const secondaryColor = this._element.getAttribute("secondary-color");
254
+ if(primaryColor && secondaryColor){
255
+ this._loadingBar.style.background = `linear-gradient(90deg, ${primaryColor} ${getGradientPos(0)}, ${secondaryColor} ${getGradientPos(1)})`;
256
+ }
257
+ else if(primaryColor){
258
+ this._loadingBar.style.background = primaryColor;
259
+ }
260
+ else if(secondaryColor){
261
+ this._loadingBar.style.background = secondaryColor;
262
+ }
263
+ }
225
264
 
226
265
  this._loadingTextContainer = document.createElement("div");
227
266
  this._loadingTextContainer.style.display = "flex";
@@ -241,6 +280,13 @@ export class EngineLoadingView implements ILoadingViewHandler {
241
280
  messageContainer.style.justifyContent = "center";
242
281
  this._loadingElement.appendChild(messageContainer);
243
282
 
283
+ if(hasLicense && this._element){
284
+ const loadingTextColor = this._element.getAttribute("loading-text-color");
285
+ if(loadingTextColor){
286
+ messageContainer.style.color = loadingTextColor;
287
+ }
288
+ }
289
+
244
290
  return this._loadingElement;
245
291
  }
246
292
  }