@needle-tools/engine 3.0.1-alpha.5 → 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.
- package/CHANGELOG.md +7 -0
- package/dist/needle-engine.js +24245 -24524
- package/dist/needle-engine.min.js +367 -354
- package/dist/needle-engine.umd.cjs +366 -353
- package/lib/engine/api.d.ts +1 -1
- package/lib/engine/api.js +1 -1
- package/lib/engine/api.js.map +1 -1
- package/lib/engine/codegen/register_types.js +8 -0
- package/lib/engine/codegen/register_types.js.map +1 -1
- package/lib/engine/engine_addressables.d.ts +21 -1
- package/lib/engine/engine_addressables.js +83 -7
- package/lib/engine/engine_addressables.js.map +1 -1
- package/lib/engine/engine_serialization.d.ts +2 -2
- package/lib/engine/engine_serialization.js +2 -3
- package/lib/engine/engine_serialization.js.map +1 -1
- package/lib/engine/engine_serialization_builtin_serializer.d.ts +5 -0
- package/lib/engine/engine_serialization_builtin_serializer.js +16 -0
- package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
- package/lib/engine/engine_serialization_core.d.ts +1 -0
- package/lib/engine/engine_serialization_core.js +26 -20
- package/lib/engine/engine_serialization_core.js.map +1 -1
- package/lib/engine/engine_utils.d.ts +9 -0
- package/lib/engine/engine_utils.js +33 -13
- package/lib/engine/engine_utils.js.map +1 -1
- package/lib/engine/extensions/NEEDLE_animator_controller_model.d.ts +1 -0
- package/lib/engine/extensions/NEEDLE_animator_controller_model.js.map +1 -1
- package/lib/engine/extensions/NEEDLE_progressive.js +2 -2
- package/lib/engine/extensions/NEEDLE_progressive.js.map +1 -1
- package/lib/engine-components/AnimatorController.js +22 -3
- package/lib/engine-components/AnimatorController.js.map +1 -1
- package/lib/engine-components/AudioSource.js +3 -2
- package/lib/engine-components/AudioSource.js.map +1 -1
- package/lib/engine-components/Component.js.map +1 -1
- package/lib/engine-components/ParticleSystem.d.ts +5 -2
- package/lib/engine-components/ParticleSystem.js +34 -4
- package/lib/engine-components/ParticleSystem.js.map +1 -1
- package/lib/engine-components/ParticleSystemModules.d.ts +1 -0
- package/lib/engine-components/ParticleSystemModules.js +1 -1
- package/lib/engine-components/ParticleSystemModules.js.map +1 -1
- package/lib/engine-components/Skybox.js +2 -2
- package/lib/engine-components/Skybox.js.map +1 -1
- package/lib/engine-components/VideoPlayer.d.ts +1 -2
- package/lib/engine-components/VideoPlayer.js +6 -7
- package/lib/engine-components/VideoPlayer.js.map +1 -1
- package/lib/engine-components/WebXR.d.ts +4 -1
- package/lib/engine-components/WebXR.js +10 -2
- package/lib/engine-components/WebXR.js.map +1 -1
- package/lib/engine-components/WebXRController.js +2 -2
- package/lib/engine-components/WebXRController.js.map +1 -1
- package/lib/engine-components/WebXRImageTracking.d.ts +39 -0
- package/lib/engine-components/WebXRImageTracking.js +173 -0
- package/lib/engine-components/WebXRImageTracking.js.map +1 -0
- package/lib/engine-components/codegen/components.d.ts +4 -0
- package/lib/engine-components/codegen/components.js +4 -0
- package/lib/engine-components/codegen/components.js.map +1 -1
- package/lib/engine-components/postprocessing/Effects/DepthOfField.d.ts +1 -0
- package/lib/engine-components/postprocessing/Effects/DepthOfField.js +4 -0
- package/lib/engine-components/postprocessing/Effects/DepthOfField.js.map +1 -1
- package/lib/engine-components/postprocessing/Effects/TiltShiftEffect.d.ts +13 -0
- package/lib/engine-components/postprocessing/Effects/TiltShiftEffect.js +63 -0
- package/lib/engine-components/postprocessing/Effects/TiltShiftEffect.js.map +1 -0
- package/lib/engine-components/timeline/TimelineTracks.js +2 -2
- package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
- package/lib/engine-components/ui/Text.js +7 -7
- package/lib/engine-components/ui/Text.js.map +1 -1
- package/lib/include/three/ARButton.d.ts +1 -1
- package/lib/include/three/ARButton.js +2 -1
- package/lib/include/three/ARButton.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/plugins/vite/config.js +8 -0
- package/plugins/vite/copyfiles.js +12 -3
- package/plugins/vite/drop.js +1 -0
- package/plugins/vite/index.js +2 -0
- package/plugins/vite/transform-codegen.js +45 -0
- package/src/engine/api.ts +1 -1
- package/src/engine/codegen/register_types.js +8 -0
- package/src/engine/engine_addressables.ts +102 -8
- package/src/engine/engine_serialization.ts +5 -4
- package/src/engine/engine_serialization_builtin_serializer.ts +23 -3
- package/src/engine/engine_serialization_core.ts +27 -20
- package/src/engine/engine_utils.ts +35 -14
- package/src/engine/extensions/NEEDLE_animator_controller_model.ts +1 -0
- package/src/engine/extensions/NEEDLE_progressive.ts +2 -2
- package/src/engine-components/AnimatorController.ts +18 -3
- package/src/engine-components/AudioSource.ts +2 -2
- package/src/engine-components/Component.ts +1 -1
- package/src/engine-components/ParticleSystem.ts +34 -4
- package/src/engine-components/ParticleSystemModules.ts +1 -1
- package/src/engine-components/Skybox.ts +2 -2
- package/src/engine-components/VideoPlayer.ts +6 -6
- package/src/engine-components/WebXR.ts +11 -2
- package/src/engine-components/WebXRController.ts +2 -2
- package/src/engine-components/WebXRImageTracking.ts +192 -0
- package/src/engine-components/codegen/components.ts +4 -0
- package/src/engine-components/postprocessing/Effects/DepthOfField.ts +3 -0
- package/src/engine-components/postprocessing/Effects/TiltShiftEffect.ts +56 -0
- package/src/engine-components/timeline/TimelineTracks.ts +2 -2
- package/src/engine-components/ui/Text.ts +7 -7
- package/src/include/three/ARButton.js +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/engine",
|
|
3
|
-
"version": "3.0
|
|
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",
|
package/plugins/vite/config.js
CHANGED
|
@@ -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
|
-
|
|
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,
|
|
47
|
+
const assetsDir = resolve(baseDir, assetsDirName);
|
|
40
48
|
if (existsSync(assetsDir)) {
|
|
41
|
-
console.log(`[${pluginName}] - Copy assets to ${outdirName}
|
|
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);
|
package/plugins/vite/drop.js
CHANGED
|
@@ -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
|
|
package/plugins/vite/index.js
CHANGED
|
@@ -6,6 +6,7 @@ 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";
|
|
9
10
|
import { needleLicense } from "./license.js";
|
|
10
11
|
|
|
11
12
|
export * from "./gzip.js";
|
|
@@ -27,6 +28,7 @@ export const needlePlugins = async (command, config, userSettings) => {
|
|
|
27
28
|
needleReload(command, config, userSettings),
|
|
28
29
|
needleBuild(command, config, userSettings),
|
|
29
30
|
needleCopyFiles(command, config, userSettings),
|
|
31
|
+
needleTransformCodegen(command, config, userSettings),
|
|
30
32
|
needleDrop(command, config, userSettings),
|
|
31
33
|
];
|
|
32
34
|
array.push(await editorConnection(command, config, userSettings, array));
|
|
@@ -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"
|
|
@@ -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,7 +174,10 @@ 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";
|
|
@@ -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);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { getParam,
|
|
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 =
|
|
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.
|
|
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
|
|
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.
|
|
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.
|
|
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();
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { serializeObject, deserializeObject } from "./engine_serialization_core";
|
|
2
|
-
import * as builtin from "./engine_serialization_builtin_serializer";
|
|
3
|
-
// export builtin so it will be called and registered
|
|
4
|
-
export { serializeObject, deserializeObject, builtin };
|
|
5
2
|
|
|
6
|
-
export {
|
|
3
|
+
export { serializeObject, deserializeObject };
|
|
4
|
+
|
|
5
|
+
export { serializable, serializeable } from "./engine_serialization_decorator"
|
|
6
|
+
|
|
7
|
+
export * from "./engine_serialization_builtin_serializer";
|
|
@@ -7,6 +7,7 @@ import { CallInfo, EventList } from "../engine-components/EventList";
|
|
|
7
7
|
import { Color, Object3D, Texture, WebGLRenderTarget } from "three";
|
|
8
8
|
import { RenderTexture } from "./engine_texture";
|
|
9
9
|
import { isDevEnvironment } from "../engine/debug/debug";
|
|
10
|
+
import { resolveUrl } from "./engine_utils";
|
|
10
11
|
|
|
11
12
|
// export class SourcePath {
|
|
12
13
|
// src?:string
|
|
@@ -300,8 +301,8 @@ class EventListSerializer extends TypeSerializer {
|
|
|
300
301
|
return undefined;
|
|
301
302
|
}
|
|
302
303
|
|
|
303
|
-
private createEventMethod(target
|
|
304
|
-
|
|
304
|
+
private createEventMethod(target: object, methodName: string, args?: any): Function | undefined {
|
|
305
|
+
|
|
305
306
|
return (...forwardedArgs) => {
|
|
306
307
|
const method = target[methodName];
|
|
307
308
|
if (typeof method === "function") {
|
|
@@ -339,4 +340,23 @@ export class RenderTextureSerializer extends TypeSerializer {
|
|
|
339
340
|
return undefined;
|
|
340
341
|
}
|
|
341
342
|
}
|
|
342
|
-
new RenderTextureSerializer();
|
|
343
|
+
new RenderTextureSerializer();
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
export class UriSerializer extends TypeSerializer {
|
|
347
|
+
constructor() {
|
|
348
|
+
super([URL]);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
onSerialize(_data: string, _context: SerializationContext) {
|
|
352
|
+
return null;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
onDeserialize(data: string, _context: SerializationContext) {
|
|
356
|
+
if (typeof data === "string") {
|
|
357
|
+
return resolveUrl(_context.gltfId, data);
|
|
358
|
+
}
|
|
359
|
+
return undefined;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
new UriSerializer();
|
|
@@ -173,6 +173,7 @@ export class SerializationContext {
|
|
|
173
173
|
root: THREE.Object3D;
|
|
174
174
|
|
|
175
175
|
gltf?: GLTF;
|
|
176
|
+
/** the url of the glb that is currently being loaded */
|
|
176
177
|
gltfId?: SourceIdentifier;
|
|
177
178
|
object!: THREE.Object3D;
|
|
178
179
|
target?: object;
|
|
@@ -290,16 +291,21 @@ export function deserializeObject(obj: ISerializable, serializedData: object, co
|
|
|
290
291
|
context.type = undefined;
|
|
291
292
|
context.path = key;
|
|
292
293
|
|
|
294
|
+
if (obj.onBeforeDeserializeMember !== undefined) {
|
|
295
|
+
// callback to the instance, if it returns true assume it's done all the things itself
|
|
296
|
+
if (obj.onBeforeDeserializeMember(key, data, context) === true) continue;
|
|
297
|
+
}
|
|
298
|
+
|
|
293
299
|
if (serializedEntryInfo === null) {
|
|
294
300
|
obj[key] = data;
|
|
301
|
+
// if(typeof data === "string"){
|
|
302
|
+
// const serializer = helper.getSerializerForConstructor(String);
|
|
303
|
+
// const res = serializer?.onDeserialize(data, context);
|
|
304
|
+
// if(res !== undefined) obj[key] = res;
|
|
305
|
+
// }
|
|
295
306
|
}
|
|
296
307
|
else {
|
|
297
308
|
|
|
298
|
-
if (obj.onBeforeDeserializeMember !== undefined) {
|
|
299
|
-
// callback to the instance, if it returns true assume it's done all the things itself
|
|
300
|
-
if (obj.onBeforeDeserializeMember(key, data, context) === true) continue;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
309
|
if (Array.isArray(serializedEntryInfo)) {
|
|
304
310
|
for (let i = 0; i < serializedEntryInfo.length; i++) {
|
|
305
311
|
const typeInfoOrConstructor = serializedEntryInfo[i];
|
|
@@ -314,24 +320,25 @@ export function deserializeObject(obj: ISerializable, serializedData: object, co
|
|
|
314
320
|
obj[key] = tryResolve(serializedEntryInfo);
|
|
315
321
|
}
|
|
316
322
|
|
|
317
|
-
function tryResolve(typeInfoOrConstructor) {
|
|
318
|
-
const typeInformationOrConstructor = typeInfoOrConstructor as ITypeInformation;
|
|
319
|
-
// if the entry does specify an object of type ITypeInformation and has the type field set
|
|
320
|
-
const type = typeInformationOrConstructor.type;
|
|
321
|
-
if (type) {
|
|
322
|
-
return deserializeObjectWithType(data, type, context, undefined, obj[key]);
|
|
323
|
-
}
|
|
324
|
-
// it can also just contain a constructor
|
|
325
|
-
else {
|
|
326
|
-
const constructor = typeInfoOrConstructor as Constructor<any>;
|
|
327
|
-
return deserializeObjectWithType(data, constructor, context, undefined, obj[key]);
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
323
|
|
|
331
324
|
buffer.length = 0;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (obj.onAfterDeserializeMember !== undefined) {
|
|
328
|
+
obj.onAfterDeserializeMember(key, data, context);
|
|
329
|
+
}
|
|
332
330
|
|
|
333
|
-
|
|
334
|
-
|
|
331
|
+
function tryResolve(typeInfoOrConstructor) {
|
|
332
|
+
const typeInformationOrConstructor = typeInfoOrConstructor as ITypeInformation;
|
|
333
|
+
// if the entry does specify an object of type ITypeInformation and has the type field set
|
|
334
|
+
const type = typeInformationOrConstructor.type;
|
|
335
|
+
if (type) {
|
|
336
|
+
return deserializeObjectWithType(data, type, context, undefined, obj[key]);
|
|
337
|
+
}
|
|
338
|
+
// it can also just contain a constructor
|
|
339
|
+
else {
|
|
340
|
+
const constructor = typeInfoOrConstructor as Constructor<any>;
|
|
341
|
+
return deserializeObjectWithType(data, constructor, context, undefined, obj[key]);
|
|
335
342
|
}
|
|
336
343
|
}
|
|
337
344
|
}
|
|
@@ -203,30 +203,51 @@ export function delay(milliseconds: number): Promise<void> {
|
|
|
203
203
|
});
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
-
// if a timeline is exported via menu item the audio clip path is relative to the glb (same folder)
|
|
206
|
+
// 1) if a timeline is exported via menu item the audio clip path is relative to the glb (same folder)
|
|
207
207
|
// we need to detect that here and build the new audio source path relative to the new glb location
|
|
208
208
|
// the same is/might be true for any file that is/will be exported via menu item
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
209
|
+
// 2) if the needle.config assetDirectory is modified (from e.g. /assets to /needle/assets) when building a distributable our vite transform and copy plugin will move the files to dist/assets hence we cannot use project-relative paths (because the path changes). What we do instead if make all paths serialized in a glb relative to the glb. The rel: prefix is used to detect urls that need to be resolved.
|
|
210
|
+
const debugGetPath = getParam("debugresolveurl");
|
|
211
|
+
|
|
212
|
+
export const relativePathPrefix = "rel:";
|
|
213
|
+
|
|
214
|
+
/** @deprecated use resolveUrl instead */
|
|
215
|
+
export function getPath(source:SourceIdentifier|undefined, uri:string) : string {
|
|
216
|
+
return resolveUrl(source, uri);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Use to resolve a url serialized in a glTF file
|
|
220
|
+
* @param source The uri of the loading file
|
|
221
|
+
* @param uri The uri of the file to resolve, can be absolute or relative
|
|
222
|
+
* @returns The resolved uri
|
|
223
|
+
*/
|
|
224
|
+
export function resolveUrl(source: SourceIdentifier | undefined, uri: string): string {
|
|
225
|
+
if (uri === undefined) {
|
|
226
|
+
if (debugGetPath) console.warn("getPath: uri is undefined, returning uri", uri);
|
|
227
|
+
return uri;
|
|
228
|
+
}
|
|
229
|
+
if(uri.startsWith("./")) {
|
|
213
230
|
return uri;
|
|
214
231
|
}
|
|
215
232
|
if (uri.startsWith("http")) {
|
|
216
233
|
if (debugGetPath) console.warn("getPath: uri is absolute, returning uri", uri);
|
|
217
234
|
return uri;
|
|
218
235
|
}
|
|
236
|
+
if (source === undefined) {
|
|
237
|
+
if (debugGetPath) console.warn("getPath: source is undefined, returning uri", uri);
|
|
238
|
+
return uri;
|
|
239
|
+
}
|
|
240
|
+
if(uri.startsWith(relativePathPrefix)){
|
|
241
|
+
uri = uri.substring(4);
|
|
242
|
+
}
|
|
219
243
|
const pathIndex = source.lastIndexOf("/");
|
|
220
244
|
if (pathIndex >= 0) {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
newUri += uri;
|
|
228
|
-
}
|
|
229
|
-
if (debugGetPath) console.log("getPath:", source, " - changed uri from\n", uri, "\n→ ", newUri);
|
|
245
|
+
// Take the source uri as the base path
|
|
246
|
+
const basePath = source.substring(0, pathIndex + 1);
|
|
247
|
+
// Append the relative uri
|
|
248
|
+
let newUri = basePath + uri;
|
|
249
|
+
// newUri = new URL(newUri, globalThis.location.href).href;
|
|
250
|
+
if (debugGetPath) console.log("source:", source, "- changed uri \nfrom", uri, "\n→ ", newUri, "\n" + basePath);
|
|
230
251
|
return newUri;
|
|
231
252
|
}
|
|
232
253
|
return uri;
|
|
@@ -3,7 +3,7 @@ import { GLTF, GLTFLoader, GLTFLoaderPlugin, GLTFParser } from "three/examples/j
|
|
|
3
3
|
import { SourceIdentifier } from "../engine_types";
|
|
4
4
|
import { Context } from "../engine_setup";
|
|
5
5
|
import { addDracoAndKTX2Loaders } from "../engine_loaders";
|
|
6
|
-
import { delay, getParam,
|
|
6
|
+
import { delay, getParam, resolveUrl } from "../engine_utils";
|
|
7
7
|
|
|
8
8
|
export const EXTENSION_NAME = "NEEDLE_progressive";
|
|
9
9
|
|
|
@@ -130,7 +130,7 @@ export class NEEDLE_progressive implements GLTFLoaderPlugin {
|
|
|
130
130
|
if (progressiveInfo) {
|
|
131
131
|
if (debug)
|
|
132
132
|
console.log(key, progressiveInfo.uri, progressiveInfo.guid);
|
|
133
|
-
const uri =
|
|
133
|
+
const uri = resolveUrl(source, progressiveInfo.uri);
|
|
134
134
|
if (uri.endsWith(".glb") || uri.endsWith(".gltf")) {
|
|
135
135
|
if (!progressiveInfo.guid) {
|
|
136
136
|
console.warn("missing pointer for glb/gltf texture", progressiveInfo);
|
|
@@ -249,9 +249,16 @@ export class AnimatorController {
|
|
|
249
249
|
|
|
250
250
|
if (action) {
|
|
251
251
|
const dur = state.motion.clip!.duration;
|
|
252
|
-
const normalizedTime = dur <= 0 ? 1 : action.time / dur;
|
|
253
|
-
|
|
254
|
-
|
|
252
|
+
const normalizedTime = dur <= 0 ? 1 : Math.abs(action.time / dur);
|
|
253
|
+
let makeTransition = false;
|
|
254
|
+
if (transition.hasExitTime) {
|
|
255
|
+
if (action.timeScale > 0) makeTransition = normalizedTime >= transition.exitTime;
|
|
256
|
+
// When the animation is playing backwards we need to check exit time inverted
|
|
257
|
+
else if(action.timeScale < 0) makeTransition = 1 - normalizedTime >= transition.exitTime;
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
makeTransition = true;
|
|
261
|
+
}
|
|
255
262
|
if (makeTransition) {
|
|
256
263
|
// if (transition.hasExitTime && transition.exitTime >= .9999)
|
|
257
264
|
action.clampWhenFinished = true;
|
|
@@ -283,6 +290,12 @@ export class AnimatorController {
|
|
|
283
290
|
action.time = 0;
|
|
284
291
|
action.play();
|
|
285
292
|
}
|
|
293
|
+
else if (action.time <= 0 && action.timeScale < 0) {
|
|
294
|
+
didTriggerLooping = true;
|
|
295
|
+
action.reset();
|
|
296
|
+
action.time = action.getClip().duration;
|
|
297
|
+
action.play();
|
|
298
|
+
}
|
|
286
299
|
}
|
|
287
300
|
|
|
288
301
|
// call update state behaviours:
|
|
@@ -367,9 +380,11 @@ export class AnimatorController {
|
|
|
367
380
|
action.stop();
|
|
368
381
|
action.reset();
|
|
369
382
|
action.timeScale = this._speed;
|
|
383
|
+
if (state.speed !== undefined) action.timeScale *= state.speed;
|
|
370
384
|
action.enabled = true;
|
|
371
385
|
const duration = state.motion.clip!.duration;
|
|
372
386
|
action.time = offsetNormalized * duration;
|
|
387
|
+
if(action.timeScale < 0) action.time = duration - action.time;
|
|
373
388
|
action.clampWhenFinished = true;
|
|
374
389
|
action.setLoop(LoopOnce, 0);
|
|
375
390
|
if (durationInSec > 0)
|
|
@@ -82,7 +82,7 @@ export class AudioSource extends Behaviour {
|
|
|
82
82
|
document.addEventListener('touchstart', fn);
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
@serializable()
|
|
85
|
+
@serializable(URL)
|
|
86
86
|
clip: string = "";
|
|
87
87
|
|
|
88
88
|
@serializable()
|
|
@@ -202,7 +202,7 @@ export class AudioSource extends Behaviour {
|
|
|
202
202
|
}
|
|
203
203
|
break;
|
|
204
204
|
case "visible":
|
|
205
|
-
console.log("visible", this.enabled, this.playOnAwake, !this.isPlaying, AudioSource._userInteractionRegistered, this.wasPlaying);
|
|
205
|
+
if (debug) console.log("visible", this.enabled, this.playOnAwake, !this.isPlaying, AudioSource._userInteractionRegistered, this.wasPlaying);
|
|
206
206
|
if (this.enabled && this.playOnAwake && !this.isPlaying && AudioSource._userInteractionRegistered && this.wasPlaying) {
|
|
207
207
|
this.play();
|
|
208
208
|
}
|
|
@@ -9,6 +9,7 @@ import { syncDestroy, syncInstantiate } from "../engine/engine_networking_instan
|
|
|
9
9
|
import { ConstructorConcrete, SourceIdentifier, IComponent, IGameObject, Constructor, GuidsMap, UIDProvider, Collision, ICollider } from "../engine/engine_types";
|
|
10
10
|
import { addNewComponent, destroyComponentInstance, findObjectOfType, findObjectsOfType, getComponent, getComponentInChildren, getComponentInParent, getComponents, getComponentsInChildren, getComponentsInParent, getOrAddComponent, moveComponentInstance, removeComponent } from "../engine/engine_components";
|
|
11
11
|
import { findByGuid, destroy, InstantiateOptions, instantiate, HideFlags, foreachComponent, markAsInstancedRendered, isActiveInHierarchy, isActiveSelf, isUsingInstancing, setActive, isDestroyed } from "../engine/engine_gameobject";
|
|
12
|
+
import { resolveUrl } from "../engine/engine_utils";
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
// export interface ISerializationCallbackReceiver {
|
|
@@ -641,7 +642,6 @@ class Component implements IComponent, EventTarget {
|
|
|
641
642
|
|
|
642
643
|
return false;
|
|
643
644
|
}
|
|
644
|
-
|
|
645
645
|
}
|
|
646
646
|
|
|
647
647
|
class Behaviour extends Component {
|