@@ -25,6 +25,9 @@
|
|
25
25
|
'md5': null,
|
26
26
|
}
|
27
27
|
|
28
|
+
/**
|
29
|
+
* @param {import('../types').userSettings} userSettings
|
30
|
+
*/
|
28
31
|
export const needleViteAlias = (command, config, userSettings) => {
|
29
32
|
|
30
33
|
if (config?.noAlias === true || userSettings?.noAlias === true)
|
@@ -17,7 +17,9 @@
|
|
17
17
|
if (existsSync(path)) {
|
18
18
|
const text = readFileSync(path, 'utf8');
|
19
19
|
if (!text) return null;
|
20
|
-
|
20
|
+
/**@type {import("../types/needleConfig").needleConfig} */
|
21
|
+
const meta = JSON.parse(text);
|
22
|
+
return meta;
|
21
23
|
}
|
22
24
|
else console.error("Could not find config file at " + path);
|
23
25
|
return null;
|
@@ -51,7 +53,7 @@
|
|
51
53
|
|
52
54
|
|
53
55
|
/** "assets" -> the directory name inside the output directory to put e.g. glb files into */
|
54
|
-
export function builtAssetsDirectory(){
|
56
|
+
export function builtAssetsDirectory() {
|
55
57
|
return "assets";
|
56
58
|
}
|
57
59
|
|
@@ -4,7 +4,9 @@
|
|
4
4
|
import { builtAssetsDirectory, tryLoadProjectConfig } from './config.js';
|
5
5
|
|
6
6
|
|
7
|
-
/** copy files on build from assets to dist
|
7
|
+
/** copy files on build from assets to dist
|
8
|
+
* @param {import('../types').userSettings} userSettings
|
9
|
+
*/
|
8
10
|
export const needleCopyFiles = (command, config, userSettings) => {
|
9
11
|
|
10
12
|
if (config?.noCopy === true || userSettings?.noCopy === true) {
|
@@ -9,6 +9,9 @@
|
|
9
9
|
|
10
10
|
// https://vitejs.dev/config/#using-environment-variables-in-config
|
11
11
|
|
12
|
+
/**
|
13
|
+
* @param {import('../types').userSettings} userSettings
|
14
|
+
*/
|
12
15
|
export const needleDefines = (command, needleEngineConfig, userSettings) => {
|
13
16
|
|
14
17
|
if (!userSettings) userSettings = {};
|
@@ -8,6 +8,9 @@
|
|
8
8
|
console.log(prefix, ...msg)
|
9
9
|
}
|
10
10
|
|
11
|
+
/**
|
12
|
+
* @param {import('../types').userSettings} userSettings
|
13
|
+
*/
|
11
14
|
export const needleDependencyWatcher = (command, config, userSettings) => {
|
12
15
|
if (command === "build") return;
|
13
16
|
|
@@ -12,6 +12,9 @@
|
|
12
12
|
*/
|
13
13
|
let editorSyncEnabled = false;
|
14
14
|
|
15
|
+
/**
|
16
|
+
* @param {import('../types').userSettings} userSettings
|
17
|
+
*/
|
15
18
|
export const editorConnection = async (command, config, userSettings, pluginsArray) => {
|
16
19
|
if (command === "build") return;
|
17
20
|
|
@@ -20,7 +20,11 @@
|
|
20
20
|
allowHotReload: true,
|
21
21
|
}
|
22
22
|
|
23
|
+
/**
|
24
|
+
* @param {import('../types').userSettings} userSettings
|
25
|
+
*/
|
23
26
|
export const needlePlugins = async (command, config, userSettings) => {
|
27
|
+
|
24
28
|
// ensure we have user settings initialized with defaults
|
25
29
|
userSettings = { ...defaultUserSettings, ...userSettings }
|
26
30
|
const array = [
|
@@ -3,6 +3,9 @@
|
|
3
3
|
import { getPosterPath } from './poster.js';
|
4
4
|
import { tryGetNeedleEngineVersion } from './utils.js';
|
5
5
|
|
6
|
+
/**
|
7
|
+
* @param {import('../types').userSettings} userSettings
|
8
|
+
*/
|
6
9
|
export const needleMeta = (command, config, userSettings) => {
|
7
10
|
|
8
11
|
// we can check if this is a build
|
@@ -3,6 +3,9 @@
|
|
3
3
|
window.global = window;
|
4
4
|
var parcelRequire;`
|
5
5
|
|
6
|
+
/**
|
7
|
+
* @param {import('../types').userSettings} userSettings
|
8
|
+
*/
|
6
9
|
export const needlePeerjs = (command, config, userSettings) => {
|
7
10
|
|
8
11
|
if (userSettings.noPeer === true) return;
|
@@ -11,6 +11,9 @@
|
|
11
11
|
const filesUsingHotReload = new Set();
|
12
12
|
let assetsDirectory = "";
|
13
13
|
|
14
|
+
/**
|
15
|
+
* @param {import('../types').userSettings} userSettings
|
16
|
+
*/
|
14
17
|
export const needleReload = (command, config, userSettings) => {
|
15
18
|
if (command === "build") return;
|
16
19
|
|
@@ -3,6 +3,7 @@
|
|
3
3
|
/**
|
4
4
|
* modify the glb load path in codegen files
|
5
5
|
* this is necessary if the assets directory is not the default (changed by the user in needle.config.json)
|
6
|
+
* @param {import('../types').userSettings} userSettings
|
6
7
|
*/
|
7
8
|
export const needleTransformCodegen = (command, config, userSettings) => {
|
8
9
|
|
@@ -110,6 +110,7 @@
|
|
110
110
|
targetId?: string | Target;
|
111
111
|
tokenId?: string;
|
112
112
|
type?: string;
|
113
|
+
distance?: number;
|
113
114
|
|
114
115
|
constructor(targetId?: string | Target, id?: string) {
|
115
116
|
if (targetId) this.targetId = targetId;
|
@@ -127,6 +128,8 @@
|
|
127
128
|
writer.appendLine(`token info:id = "${this.tokenId}"`);
|
128
129
|
if (this.type)
|
129
130
|
writer.appendLine(`token type = "${this.type}"`);
|
131
|
+
if (typeof this.distance === "number")
|
132
|
+
writer.appendLine(`double distance = ${this.distance}`);
|
130
133
|
writer.closeBlock();
|
131
134
|
}
|
132
135
|
}
|
@@ -150,6 +153,13 @@
|
|
150
153
|
static isTapTrigger(trigger?: TriggerModel) {
|
151
154
|
return trigger?.tokenId === "TapGesture";
|
152
155
|
}
|
156
|
+
|
157
|
+
static proximityToCameraTrigger(targetObject: Target, distance: number): TriggerModel {
|
158
|
+
const trigger = new TriggerModel(targetObject);
|
159
|
+
trigger.tokenId = "ProximityToCamera";
|
160
|
+
trigger.distance = distance;
|
161
|
+
return trigger;
|
162
|
+
}
|
153
163
|
}
|
154
164
|
|
155
165
|
export class GroupActionModel implements IBehaviorElement {
|
@@ -178,7 +178,7 @@
|
|
178
178
|
|
179
179
|
const hasLicense = hasProLicense();
|
180
180
|
if (!existing) {
|
181
|
-
this._loadingElement.style.position = "
|
181
|
+
this._loadingElement.style.position = "absolute";
|
182
182
|
this._loadingElement.style.width = "100%";
|
183
183
|
this._loadingElement.style.height = "100%";
|
184
184
|
this._loadingElement.style.left = "0";
|
@@ -1,1 +1,3 @@
|
|
1
|
-
export { USDZExporter } from "./USDZExporter"
|
1
|
+
export { USDZExporter } from "./USDZExporter";
|
2
|
+
export { USDObject } from "./ThreeUSDZExporter";
|
3
|
+
export { type UsdzBehaviour } from "./extensions/behavior/Behaviour";
|
@@ -55,8 +55,9 @@
|
|
55
55
|
|
56
56
|
// rotate by 90° - counter-rotation on the parent makes sure
|
57
57
|
// that without Preliminary Behaviours it still looks right
|
58
|
-
|
59
|
-
|
58
|
+
const flip = this.invertForward ? -1 : 1;
|
59
|
+
parent.matrix.multiply(new Matrix4().makeRotationZ(Math.PI / 2 * flip));
|
60
|
+
model.matrix.multiply(new Matrix4().makeRotationZ(-Math.PI / 2 * flip));
|
60
61
|
}
|
61
62
|
|
62
63
|
const lookAt = new BehaviorModel("lookat " + this.name,
|
@@ -66,6 +66,13 @@
|
|
66
66
|
|
67
67
|
}
|
68
68
|
|
69
|
+
static createEmpty() {
|
70
|
+
|
71
|
+
const empty = new USDObject( MathUtils.generateUUID(), 'Empty_' + ( USDObject.USDObject_export_id ++ ), new Matrix4() );
|
72
|
+
empty.isDynamic = true;
|
73
|
+
return empty;
|
74
|
+
}
|
75
|
+
|
69
76
|
constructor( id, name, matrix, mesh: BufferGeometry | null = null, material: Material | null = null, camera: Camera | null = null ) {
|
70
77
|
|
71
78
|
this.uuid = id;
|
@@ -443,7 +450,7 @@
|
|
443
450
|
|
444
451
|
await invokeAll( context, 'onAfterSerialize' );
|
445
452
|
|
446
|
-
context.output += buildMaterials( materials, textures );
|
453
|
+
context.output += buildMaterials( materials, textures, options.quickLookCompatible );
|
447
454
|
|
448
455
|
const header = context.document.buildHeader();
|
449
456
|
const final = header + '\n' + context.output;
|
@@ -1100,7 +1107,7 @@
|
|
1100
1107
|
|
1101
1108
|
// Materials
|
1102
1109
|
|
1103
|
-
function buildMaterials( materials, textures ) {
|
1110
|
+
function buildMaterials( materials, textures, quickLookCompatible = false ) {
|
1104
1111
|
|
1105
1112
|
const array: Array<string> = [];
|
1106
1113
|
|
@@ -1108,7 +1115,7 @@
|
|
1108
1115
|
|
1109
1116
|
const material = materials[ uuid ];
|
1110
1117
|
|
1111
|
-
array.push( buildMaterial( material, textures ) );
|
1118
|
+
array.push( buildMaterial( material, textures, quickLookCompatible ) );
|
1112
1119
|
|
1113
1120
|
}
|
1114
1121
|
|
@@ -1121,14 +1128,13 @@
|
|
1121
1128
|
|
1122
1129
|
}
|
1123
1130
|
|
1124
|
-
function buildMaterial( material: MeshStandardMaterial, textures ) {
|
1131
|
+
function buildMaterial( material: MeshStandardMaterial, textures, quickLookCompatible = false ) {
|
1125
1132
|
|
1126
1133
|
// https://graphics.pixar.com/usd/docs/UsdPreviewSurface-Proposal.html
|
1127
1134
|
|
1128
1135
|
const pad = ' ';
|
1129
1136
|
const inputs: Array<string> = [];
|
1130
1137
|
const samplers: Array<string> = [];
|
1131
|
-
const exportForQuickLook = false;
|
1132
1138
|
|
1133
1139
|
function buildTexture( texture, mapType, color: Color | undefined = undefined, opacity: number | undefined = undefined ) {
|
1134
1140
|
|
@@ -1151,7 +1157,7 @@
|
|
1151
1157
|
|
1152
1158
|
// turns out QuickLook is buggy and interprets texture repeat inverted.
|
1153
1159
|
// Apple Feedback: FB10036297 and FB11442287
|
1154
|
-
if (
|
1160
|
+
if ( quickLookCompatible ) {
|
1155
1161
|
|
1156
1162
|
// This is NOT correct yet in QuickLook, but comes close for a range of models.
|
1157
1163
|
// It becomes more incorrect the bigger the offset is
|
@@ -0,0 +1,15 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
|
4
|
+
module.exports.getMeta = function () {
|
5
|
+
const workingDirectory = process.cwd();
|
6
|
+
const needleConfig = require(workingDirectory + "/needle.config.json");
|
7
|
+
if (needleConfig.codegenDirectory) {
|
8
|
+
const metaPath = workingDirectory + "/" + needleConfig.codegenDirectory + "/meta.json";
|
9
|
+
|
10
|
+
/**@type {import("../types").needleConfig} */
|
11
|
+
const meta = require(metaPath);
|
12
|
+
return meta;
|
13
|
+
}
|
14
|
+
return null;
|
15
|
+
}
|
@@ -0,0 +1,31 @@
|
|
1
|
+
const { getMeta } = require("./config.cjs");
|
2
|
+
|
3
|
+
/**
|
4
|
+
* @param {string} code
|
5
|
+
* @param {string | null | undefined} licenseType
|
6
|
+
*/
|
7
|
+
module.exports.replaceLicense = function (code, licenseType) {
|
8
|
+
|
9
|
+
if (!licenseType) {
|
10
|
+
const meta = getMeta();
|
11
|
+
if (meta) {
|
12
|
+
licenseType = meta.license;
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
|
17
|
+
if (!licenseType) {
|
18
|
+
return code;
|
19
|
+
}
|
20
|
+
|
21
|
+
const index = code.indexOf("NEEDLE_ENGINE_LICENSE_TYPE");
|
22
|
+
if (index >= 0) {
|
23
|
+
const end = code.indexOf(";", index);
|
24
|
+
if (end >= 0) {
|
25
|
+
const line = code.substring(index, end);
|
26
|
+
const replaced = "NEEDLE_ENGINE_LICENSE_TYPE = \"" + licenseType + "\"";
|
27
|
+
code = code.replace(line, replaced);
|
28
|
+
return code;
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
@@ -0,0 +1,5 @@
|
|
1
|
+
const { replaceLicense } = require("../common/license.cjs");
|
2
|
+
|
3
|
+
module.exports = function (source, _map) {
|
4
|
+
return replaceLicense(source);
|
5
|
+
};
|
@@ -0,0 +1,1 @@
|
|
1
|
+
export * from "./next.js"
|
@@ -0,0 +1,64 @@
|
|
1
|
+
import { fileURLToPath } from 'url';
|
2
|
+
import { dirname, resolve } from 'path';
|
3
|
+
// import { ApplyLicensePlugin } from './license.js';
|
4
|
+
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
6
|
+
const __dirname = dirname(__filename);
|
7
|
+
|
8
|
+
|
9
|
+
/** Pass a nextConfig object in to add the needle specific settings.
|
10
|
+
* Optionally omit nextConfig and it will be created for you.
|
11
|
+
* @param {import('next').NextConfig} nextConfig
|
12
|
+
* @param {import('@needle-tools/engine/plugins/types').userSettings} userSettings
|
13
|
+
* @returns {import('next').NextConfig}
|
14
|
+
*/
|
15
|
+
export const needleNext = (nextConfig, userSettings) => {
|
16
|
+
if (!nextConfig) nextConfig = {
|
17
|
+
reactStrictMode: true,
|
18
|
+
};
|
19
|
+
|
20
|
+
// add transpile packages
|
21
|
+
if (!nextConfig.transpilePackages) {
|
22
|
+
nextConfig.transpilePackages = [];
|
23
|
+
}
|
24
|
+
nextConfig.transpilePackages.push("three", "peerjs", "@needle-tools/engine", "three-mesh-ui");
|
25
|
+
|
26
|
+
// add webpack config
|
27
|
+
if (!nextConfig.webpack) nextConfig.webpack = nextWebPack;
|
28
|
+
else {
|
29
|
+
const webpackFn = nextConfig.webpack;
|
30
|
+
nextConfig.webpack = (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
|
31
|
+
nextWebPack(config, { buildId, dev, isServer, defaultLoaders, webpack });
|
32
|
+
return webpackFn(config, { buildId, dev, isServer, defaultLoaders, webpack });
|
33
|
+
}
|
34
|
+
}
|
35
|
+
/** @param {import ('next').NextConfig config } */
|
36
|
+
function nextWebPack(config, { buildId, dev, isServer, defaultLoaders, webpack }) {
|
37
|
+
// add defines
|
38
|
+
const webpackModule = userSettings.modules?.webpack;
|
39
|
+
const definePlugin = webpackModule && new webpackModule.DefinePlugin({
|
40
|
+
NEEDLE_ENGINE_META: {},
|
41
|
+
NEEDLE_USE_RAPIER: true,
|
42
|
+
parcelRequire: undefined,
|
43
|
+
});
|
44
|
+
if (!definePlugin) console.log("WARN: no define plugin provided. Did you miss adding the webpack module to the next config? You can pass it to the Needle plugins via `nextConfig.modules = { webpack };`");
|
45
|
+
else
|
46
|
+
config.plugins.push(definePlugin);
|
47
|
+
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
if (!config.module) config.module = {};
|
52
|
+
if (!config.module.rules) config.module.rules = [];
|
53
|
+
// add license plugin
|
54
|
+
config.module.rules.push({
|
55
|
+
test: /engine_license\.(ts|js)$/,
|
56
|
+
loader: resolve(__dirname, 'license.cjs')
|
57
|
+
});
|
58
|
+
|
59
|
+
return config;
|
60
|
+
}
|
61
|
+
|
62
|
+
|
63
|
+
return nextConfig;
|
64
|
+
};
|
@@ -0,0 +1,2 @@
|
|
1
|
+
export * from './userconfig';
|
2
|
+
export * from "./needleConfig";
|
@@ -0,0 +1,12 @@
|
|
1
|
+
export type needleConfig = {
|
2
|
+
needleEditor: string | null,
|
3
|
+
meta: string | null;
|
4
|
+
absolutePath: string | null,
|
5
|
+
sceneName: string | null,
|
6
|
+
deployOnly: boolean,
|
7
|
+
generator: string | null,
|
8
|
+
gzip: boolean,
|
9
|
+
allowHotReload: boolean,
|
10
|
+
license: string | null,
|
11
|
+
useRapier: boolean,
|
12
|
+
}
|
File without changes
|
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
export type needleModules = {
|
4
|
+
webpack: object | undefined
|
5
|
+
}
|
6
|
+
|
7
|
+
export type userSettings = {
|
8
|
+
/** disable vite.alias modification */
|
9
|
+
noAlias: boolean;
|
10
|
+
/** disable automatic copying of files to include and output directory (dist) */
|
11
|
+
noCopy: boolean;
|
12
|
+
/** set to false to tree-shake rapier physics engine to the reduce bundle size */
|
13
|
+
useRapier: boolean;
|
14
|
+
noDependencyWatcher: boolean;
|
15
|
+
/** set to false to suppress editor-sync package installation and connection */
|
16
|
+
dontInstallEditor: boolean;
|
17
|
+
/** set to false to prevent meta.html modifications (vite only) */
|
18
|
+
allowMetaPlugin: boolean;
|
19
|
+
/** set to true to prevent injecting peerjs `parcelRequire` global variable declaration */
|
20
|
+
noPeer: boolean;
|
21
|
+
/** set to true to disable reload plugin */
|
22
|
+
noReload: boolean;
|
23
|
+
noCodegenTransform: boolean;
|
24
|
+
|
25
|
+
/** used by nextjs config to forward the webpack module */
|
26
|
+
modules: needleModules
|
27
|
+
}
|