@needle-tools/engine 5.0.5 → 5.0.6-next.bb467e1
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/components.needle.json +1 -1
- package/dist/{needle-engine.bundle-CwycbG-K.umd.cjs → needle-engine.bundle-BPvphEEJ.umd.cjs} +75 -75
- package/dist/{needle-engine.bundle-DLNQOFNZ.js → needle-engine.bundle-CNoLozgc.js} +1744 -1703
- package/dist/{needle-engine.bundle-yYWZqy6w.min.js → needle-engine.bundle-DNW6Q7aB.min.js} +83 -83
- package/dist/needle-engine.d.ts +14 -1
- package/dist/needle-engine.js +2 -2
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/lib/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js +1 -1
- package/lib/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js.map +1 -1
- package/lib/engine-components/DragControls.d.ts +7 -0
- package/lib/engine-components/DragControls.js +19 -0
- package/lib/engine-components/DragControls.js.map +1 -1
- package/lib/engine-components/OrbitControls.js +16 -11
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/ui/Text.d.ts +8 -1
- package/lib/engine-components/ui/Text.js +29 -14
- package/lib/engine-components/ui/Text.js.map +1 -1
- package/lib/engine-components/web/CursorFollow.js +21 -12
- package/lib/engine-components/web/CursorFollow.js.map +1 -1
- package/package.json +2 -2
- package/plugins/common/worker.js +9 -4
- package/plugins/vite/asap.js +17 -8
- package/plugins/vite/dependencies.js +29 -0
- package/plugins/vite/local-files-core.js +3 -3
- package/plugins/vite/local-files-utils.d.ts +3 -1
- package/plugins/vite/local-files-utils.js +29 -5
- package/src/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js +1 -1
- package/src/engine-components/DragControls.ts +18 -2
- package/src/engine-components/OrbitControls.ts +18 -9
- package/src/engine-components/ui/Text.ts +43 -18
- package/src/engine-components/web/CursorFollow.ts +21 -13
|
@@ -266,19 +266,28 @@ export class CursorFollow extends Behaviour {
|
|
|
266
266
|
this.gameObject.worldPosition = newPosition;
|
|
267
267
|
}
|
|
268
268
|
if (this.snapToSurface) {
|
|
269
|
-
ray.origin =
|
|
270
|
-
ray.direction = rayDirection
|
|
271
|
-
const hits = this.context.physics.raycastFromRay(ray
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
if (this.damping > 0) {
|
|
275
|
-
this.gameObject.worldPosition = _position.lerp(hit.point, this.context.time.deltaTime / this.damping);
|
|
276
|
-
}
|
|
277
|
-
else {
|
|
278
|
-
this.gameObject.worldPosition = hit.point;
|
|
269
|
+
ray.origin = cameraPosition;
|
|
270
|
+
ray.direction = rayDirection;
|
|
271
|
+
const hits = this.context.physics.raycastFromRay(ray, {
|
|
272
|
+
testObject: obj => {
|
|
273
|
+
return obj !== this.gameObject && !this.gameObject.contains(obj) ? true : false;
|
|
279
274
|
}
|
|
280
|
-
|
|
281
|
-
|
|
275
|
+
});
|
|
276
|
+
if (hits?.length) {
|
|
277
|
+
// Get the first hit that is not a child of *this* object. Because we do not want to lerp to a surface that is part of the object itself, since that would result in *this* object moving closer and closer to the camera as it tries to snap to itself
|
|
278
|
+
const hit = hits[0]; //.find(h => !this.gameObject.contains(h.object));
|
|
279
|
+
if (hit) {
|
|
280
|
+
if (this.damping > 0) {
|
|
281
|
+
this.gameObject.worldPosition = _position.lerp(hit.point, this.context.time.deltaTime / this.damping);
|
|
282
|
+
// this._distance = this.gameObject.worldPosition.distanceTo(cameraPosition);
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
this.gameObject.worldPosition = hit.point;
|
|
286
|
+
// this._distance = hit.point.distanceTo(cameraPosition);
|
|
287
|
+
}
|
|
288
|
+
if (debug) {
|
|
289
|
+
Gizmos.DrawLine(hit.point, hit.normal.add(hit.point), 0x00FF00);
|
|
290
|
+
}
|
|
282
291
|
}
|
|
283
292
|
}
|
|
284
293
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CursorFollow.js","sourceRoot":"","sources":["../../../src/engine-components/web/CursorFollow.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"CursorFollow.js","sourceRoot":"","sources":["../../../src/engine-components/web/CursorFollow.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/engine",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.6-next.bb467e1",
|
|
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.min.js",
|
|
6
6
|
"exports": {
|
|
@@ -204,4 +204,4 @@
|
|
|
204
204
|
"module": "lib/needle-engine.js",
|
|
205
205
|
"typings": "lib/needle-engine.d.ts",
|
|
206
206
|
"types": "lib/needle-engine.d.ts"
|
|
207
|
-
}
|
|
207
|
+
}
|
package/plugins/common/worker.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import path from 'path';
|
|
1
2
|
import { needleLog } from '../vite/logging.js';
|
|
2
3
|
|
|
3
4
|
|
|
@@ -53,13 +54,17 @@ export function rollupFixWorkerImport(opts = { logFail: true }) {
|
|
|
53
54
|
// console.log("WORKER?", url)
|
|
54
55
|
if (url?.startsWith("/")) {
|
|
55
56
|
needleLog("rollup", `Rewrite worker import in ${chunk.fileName}`, "log", { leadingNewline: true, dimBody: false });
|
|
56
|
-
//
|
|
57
|
-
|
|
57
|
+
// Compute the relative path from the chunk's directory to the worker file.
|
|
58
|
+
// url is absolute from build root (e.g. "/assets/worker.js") and the chunk
|
|
59
|
+
// may itself be inside assets/ — using path.posix.relative avoids producing
|
|
60
|
+
// a double "assets/assets/" path.
|
|
61
|
+
const workerPath = url.replace(/^\//, "");
|
|
62
|
+
const chunkDir = path.posix.dirname(chunk.fileName);
|
|
63
|
+
const relativeUrl = path.posix.relative(chunkDir, workerPath) || workerPath;
|
|
58
64
|
// For CORS issues we need to use importScripts: https://linear.app/needle/issue/NE-6572#comment-ea5dc65e
|
|
59
|
-
const output = `/* new-worker */ new Worker(URL.createObjectURL(new Blob(["import '" + \`\${new URL('./${
|
|
65
|
+
const output = `/* new-worker */ new Worker(URL.createObjectURL(new Blob(["import '" + \`\${new URL('./${relativeUrl}', import.meta.url).toString()}\` + "';"], { type: 'text/javascript' }))`;
|
|
60
66
|
needleLog("rollup", "Did rewrite worker output to: " + output, "log", { leadingNewline: true });
|
|
61
67
|
return output;
|
|
62
|
-
// return `new Worker(new URL("./${newUrl}", import.meta.url)`;
|
|
63
68
|
}
|
|
64
69
|
return match;
|
|
65
70
|
});
|
package/plugins/vite/asap.js
CHANGED
|
@@ -50,7 +50,7 @@ export async function needleAsap(command, config, userSettings) {
|
|
|
50
50
|
const tags = [];
|
|
51
51
|
|
|
52
52
|
try {
|
|
53
|
-
generateGltfPreloadLinks(config, html, tags);
|
|
53
|
+
generateGltfPreloadLinks(config, html, tags, viteConfig?.base);
|
|
54
54
|
}
|
|
55
55
|
catch (err) {
|
|
56
56
|
console.error("Error generating gltf preload links", err);
|
|
@@ -173,18 +173,21 @@ function fixMainTs() {
|
|
|
173
173
|
* @param {import('vite').ResolvedConfig} _config
|
|
174
174
|
* @param {import('vite').HtmlTagDescriptor[]} tags
|
|
175
175
|
*/
|
|
176
|
-
function generateScriptPreloadLinks(
|
|
176
|
+
function generateScriptPreloadLinks(config, tags) {
|
|
177
177
|
try {
|
|
178
|
+
const base = config.base || '/';
|
|
178
179
|
const chunks = preloadScriptPaths;
|
|
179
180
|
// console.log("ASAP", chunks)
|
|
180
181
|
if (chunks.length > 0) {
|
|
181
182
|
for (const chunk of chunks) {
|
|
183
|
+
// Apply base path so preload hrefs resolve correctly under SPA routing
|
|
184
|
+
const href = chunk.startsWith('./') ? base + chunk.slice(2) : chunk;
|
|
182
185
|
tags.push({
|
|
183
186
|
tag: 'link',
|
|
184
187
|
attrs: {
|
|
185
188
|
rel: "modulepreload",
|
|
186
189
|
as: "script",
|
|
187
|
-
href:
|
|
190
|
+
href: href,
|
|
188
191
|
}
|
|
189
192
|
});
|
|
190
193
|
}
|
|
@@ -203,15 +206,16 @@ const codegenRegex = /\"(?<gltf>.+(.glb|.gltf)(\?.*)?)\"/gm;
|
|
|
203
206
|
/**
|
|
204
207
|
* @param {import('../types').needleConfig} config
|
|
205
208
|
* @param {string} html
|
|
206
|
-
* @param {import('vite').HtmlTagDescriptor[]} tags
|
|
209
|
+
* @param {import('vite').HtmlTagDescriptor[]} tags
|
|
210
|
+
* @param {string} [base]
|
|
207
211
|
**/
|
|
208
|
-
function generateGltfPreloadLinks(config, html, tags) {
|
|
212
|
+
function generateGltfPreloadLinks(config, html, tags, base) {
|
|
209
213
|
|
|
210
214
|
// TODO: try to get the <needle-engine src> element src attribute and preload that
|
|
211
215
|
const needleEngineMatches = tryParseNeedleEngineSrcAttributeFromHtml(html);
|
|
212
216
|
if (needleEngineMatches?.length) {
|
|
213
217
|
for (const item of needleEngineMatches) {
|
|
214
|
-
insertPreloadLink(tags, item, "model/gltf+json");
|
|
218
|
+
insertPreloadLink(tags, item, "model/gltf+json", base);
|
|
215
219
|
}
|
|
216
220
|
}
|
|
217
221
|
|
|
@@ -246,7 +250,7 @@ function generateGltfPreloadLinks(config, html, tags) {
|
|
|
246
250
|
}
|
|
247
251
|
}
|
|
248
252
|
needleLog("needle:asap", `Insert glTF preload link: ${value}`);
|
|
249
|
-
insertPreloadLink(tags, value, "model/gltf+json");
|
|
253
|
+
insertPreloadLink(tags, value, "model/gltf+json", base);
|
|
250
254
|
}
|
|
251
255
|
}
|
|
252
256
|
}
|
|
@@ -258,9 +262,14 @@ function generateGltfPreloadLinks(config, html, tags) {
|
|
|
258
262
|
* @param {import('vite').HtmlTagDescriptor[]} tags
|
|
259
263
|
* @param {string} href
|
|
260
264
|
* @param {string} type
|
|
265
|
+
* @param {string} [base]
|
|
261
266
|
*/
|
|
262
|
-
function insertPreloadLink(tags, href, type) {
|
|
267
|
+
function insertPreloadLink(tags, href, type, base) {
|
|
263
268
|
if (!href) return;
|
|
269
|
+
// Apply base path so preload hrefs resolve correctly under SPA routing
|
|
270
|
+
if (base && !href.startsWith('http') && !href.startsWith('/')) {
|
|
271
|
+
href = base + (href.startsWith('./') ? href.slice(2) : href);
|
|
272
|
+
}
|
|
264
273
|
tags.push({
|
|
265
274
|
tag: 'link',
|
|
266
275
|
attrs: {
|
|
@@ -61,6 +61,35 @@ export function needleDependencies(command, config, userSettings) {
|
|
|
61
61
|
}
|
|
62
62
|
},
|
|
63
63
|
},
|
|
64
|
+
// Vite 8's optimizer rebases `new URL(specifier, import.meta.url)` paths
|
|
65
|
+
// inside pre-bundled dependencies (PR #21434), but only handles truly relative
|
|
66
|
+
// paths (./ ../). Bare-specifier paths like `three-mesh-bvh/src/workers/...`
|
|
67
|
+
// are treated as relative to the *source file* that contained the `new URL()`
|
|
68
|
+
// call, producing a wrong URL such as:
|
|
69
|
+
// /node_modules/@needle-tools/engine/.../three-mesh-bvh/src/workers/generateMeshBVH.worker.js
|
|
70
|
+
// This middleware rewrites those broken URLs so the dev server finds the file at
|
|
71
|
+
// its real location in node_modules.
|
|
72
|
+
{
|
|
73
|
+
name: 'needle:worker-url-rewrite',
|
|
74
|
+
configureServer(server) {
|
|
75
|
+
const rewritePackages = ['three-mesh-bvh'];
|
|
76
|
+
server.middlewares.use((req, _res, next) => {
|
|
77
|
+
if (req.url) {
|
|
78
|
+
for (const pkg of rewritePackages) {
|
|
79
|
+
const marker = `/${pkg}/`;
|
|
80
|
+
if (req.url.includes(marker) && !req.url.startsWith(`/node_modules/${pkg}/`)) {
|
|
81
|
+
const idx = req.url.indexOf(marker);
|
|
82
|
+
const rewritten = '/node_modules' + req.url.slice(idx);
|
|
83
|
+
needleLog('needle-dependencies', `Rewriting worker URL → ${rewritten}`);
|
|
84
|
+
req.url = rewritten;
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
next();
|
|
90
|
+
});
|
|
91
|
+
},
|
|
92
|
+
},
|
|
64
93
|
]
|
|
65
94
|
}
|
|
66
95
|
|
|
@@ -291,7 +291,7 @@ export function needleMakeFilesLocal(command, _config, userSettings) {
|
|
|
291
291
|
failedDownloads,
|
|
292
292
|
localizationStats,
|
|
293
293
|
}, activeHandlers);
|
|
294
|
-
src = fixRelativeNewURL(src);
|
|
294
|
+
src = fixRelativeNewURL(src, viteConfig?.base);
|
|
295
295
|
}
|
|
296
296
|
catch (err) {
|
|
297
297
|
needleLog("needle:local-files", "Error in transform: " + getErrMessage(err), "error");
|
|
@@ -303,7 +303,7 @@ export function needleMakeFilesLocal(command, _config, userSettings) {
|
|
|
303
303
|
},
|
|
304
304
|
renderChunk(code, chunk) {
|
|
305
305
|
if (!chunk.fileName?.endsWith(".js")) return null;
|
|
306
|
-
const fixed = fixRelativeNewURL(code);
|
|
306
|
+
const fixed = fixRelativeNewURL(code, viteConfig?.base);
|
|
307
307
|
if (fixed === code) return null;
|
|
308
308
|
return {
|
|
309
309
|
code: fixed,
|
|
@@ -314,7 +314,7 @@ export function needleMakeFilesLocal(command, _config, userSettings) {
|
|
|
314
314
|
for (const output of Object.values(bundle)) {
|
|
315
315
|
if (output.type !== "chunk") continue;
|
|
316
316
|
if (!output.fileName?.endsWith(".js")) continue;
|
|
317
|
-
const fixed = fixRelativeNewURL(output.code);
|
|
317
|
+
const fixed = fixRelativeNewURL(output.code, viteConfig?.base);
|
|
318
318
|
if (fixed !== output.code) output.code = fixed;
|
|
319
319
|
}
|
|
320
320
|
},
|
|
@@ -24,9 +24,11 @@ export function normalizeWebPath(path: string): string;
|
|
|
24
24
|
export function ensureTrailingSlash(path: string): string;
|
|
25
25
|
/**
|
|
26
26
|
* @param {string} src
|
|
27
|
+
* @param {string} [base] - Vite base path (e.g. "/" or "/app/"). When provided,
|
|
28
|
+
* ext/ paths are made absolute so they resolve correctly under SPA routing.
|
|
27
29
|
* @returns {string}
|
|
28
30
|
*/
|
|
29
|
-
export function fixRelativeNewURL(src: string): string;
|
|
31
|
+
export function fixRelativeNewURL(src: string, base?: string): string;
|
|
30
32
|
/**
|
|
31
33
|
* @param {string} src
|
|
32
34
|
* @returns {string}
|
|
@@ -113,25 +113,49 @@ export function ensureTrailingSlash(path) {
|
|
|
113
113
|
|
|
114
114
|
/**
|
|
115
115
|
* @param {string} src
|
|
116
|
+
* @param {string} [base] - Vite base path (e.g. "/" or "/app/"). When provided,
|
|
117
|
+
* ext/ paths are made absolute so they resolve correctly under SPA routing.
|
|
116
118
|
* @returns {string}
|
|
117
119
|
*/
|
|
118
|
-
export function fixRelativeNewURL(src) {
|
|
120
|
+
export function fixRelativeNewURL(src, base) {
|
|
121
|
+
/** @param {string} path */
|
|
122
|
+
function makeAbsolute(path) {
|
|
123
|
+
// Strip any leading ./ ../ or / prefix to get the clean ext/... path
|
|
124
|
+
const clean = path.replace(/^(?:\.\.?\/)+/, '').replace(/^\//, '');
|
|
125
|
+
if (base) return base.replace(/\/+$/, '') + '/' + clean;
|
|
126
|
+
return clean;
|
|
127
|
+
}
|
|
128
|
+
|
|
119
129
|
src = src.replace(
|
|
120
130
|
/(?<==\s*)(["'])((?:(?:\.{1,2}\/)|\/)?ext\/[^"']*\/)\1/g,
|
|
121
131
|
(/** @type {string} */ _match, /** @type {string} */ quote, /** @type {string} */ path) => {
|
|
122
|
-
const
|
|
123
|
-
return `new URL(${quote}${
|
|
132
|
+
const resolved = makeAbsolute(path);
|
|
133
|
+
return `new URL(${quote}${resolved}${quote}, self.location?.href || ${quote}${quote}).href`;
|
|
124
134
|
}
|
|
125
135
|
);
|
|
126
136
|
|
|
127
137
|
src = src.replace(
|
|
128
138
|
/new\s+URL\s*\(\s*(["'`])((?:(?:\.{1,2}\/)|\/)?ext\/[^"'`]+)\1\s*\)/g,
|
|
129
139
|
(/** @type {string} */ _match, /** @type {string} */ quote, /** @type {string} */ path) => {
|
|
130
|
-
const
|
|
131
|
-
return `new URL(${quote}${
|
|
140
|
+
const resolved = makeAbsolute(path);
|
|
141
|
+
return `new URL(${quote}${resolved}${quote}, self.location?.href)`;
|
|
132
142
|
}
|
|
133
143
|
);
|
|
134
144
|
|
|
145
|
+
// Make remaining ext/ string literals absolute (e.g. font paths passed as
|
|
146
|
+
// function arguments like addVariant("normal","normal","ext/fonts/...")).
|
|
147
|
+
// The regexes above already consumed paths inside new URL() calls and
|
|
148
|
+
// assignment-based patterns, so this only catches leftover bare strings.
|
|
149
|
+
if (base) {
|
|
150
|
+
src = src.replace(
|
|
151
|
+
/(["'`])((?:\.{1,2}\/)?ext\/[^"'`]+)\1/g,
|
|
152
|
+
(/** @type {string} */ _match, /** @type {string} */ quote, /** @type {string} */ path) => {
|
|
153
|
+
const resolved = makeAbsolute(path);
|
|
154
|
+
return `${quote}${resolved}${quote}`;
|
|
155
|
+
}
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
135
159
|
return src;
|
|
136
160
|
}
|
|
137
161
|
|
|
@@ -35,7 +35,7 @@ export class GenerateMeshBVHWorker extends WorkerBase {
|
|
|
35
35
|
|
|
36
36
|
worker.onerror = e => {
|
|
37
37
|
|
|
38
|
-
reject(new Error(`[GenerateMeshBVHWorker] ${e.message || "
|
|
38
|
+
reject(new Error(`[GenerateMeshBVHWorker] ${e.message || "Could not load worker."}`));
|
|
39
39
|
|
|
40
40
|
};
|
|
41
41
|
|
|
@@ -12,6 +12,7 @@ import { getParam } from "../engine/engine_utils.js";
|
|
|
12
12
|
import { NeedleXRSession } from "../engine/engine_xr.js";
|
|
13
13
|
import { Avatar_POI } from "./avatar/Avatar_Brain_LookAt.js";
|
|
14
14
|
import { Behaviour, GameObject } from "./Component.js";
|
|
15
|
+
import { EventList } from "./EventList.js";
|
|
15
16
|
import { UsageMarker } from "./Interactable.js";
|
|
16
17
|
import { Rigidbody } from "./RigidBody.js";
|
|
17
18
|
import { SyncedTransform } from "./SyncedTransform.js";
|
|
@@ -155,7 +156,19 @@ export class DragControls extends Behaviour implements IPointerEventHandler {
|
|
|
155
156
|
@serializable()
|
|
156
157
|
public showGizmo: boolean = false;
|
|
157
158
|
|
|
158
|
-
/**
|
|
159
|
+
/** Invoked once when a drag begins (after the minimum drag distance threshold is met). */
|
|
160
|
+
@serializable(EventList)
|
|
161
|
+
dragStarted: EventList = new EventList();
|
|
162
|
+
|
|
163
|
+
/** Invoked every frame while the object is being dragged. */
|
|
164
|
+
@serializable(EventList)
|
|
165
|
+
dragUpdated: EventList = new EventList();
|
|
166
|
+
|
|
167
|
+
/** Invoked once when the last pointer is released and the drag ends. */
|
|
168
|
+
@serializable(EventList)
|
|
169
|
+
dragEnded: EventList = new EventList();
|
|
170
|
+
|
|
171
|
+
/**
|
|
159
172
|
* Returns the object currently being dragged by this DragControls component, if any.
|
|
160
173
|
* @returns The object being dragged or null if no object is currently dragged
|
|
161
174
|
*/
|
|
@@ -457,6 +470,7 @@ export class DragControls extends Behaviour implements IPointerEventHandler {
|
|
|
457
470
|
if (!object) return;
|
|
458
471
|
|
|
459
472
|
this._isDragging = true;
|
|
473
|
+
this.dragStarted?.invoke();
|
|
460
474
|
|
|
461
475
|
const sync = GameObject.getComponentInChildren(object, SyncedTransform);
|
|
462
476
|
if (debug) console.log("DRAG START", sync, object);
|
|
@@ -497,9 +511,10 @@ export class DragControls extends Behaviour implements IPointerEventHandler {
|
|
|
497
511
|
const object = this._targetObject || this.gameObject;
|
|
498
512
|
|
|
499
513
|
InstancingUtil.markDirty(object);
|
|
514
|
+
this.dragUpdated?.invoke();
|
|
500
515
|
}
|
|
501
516
|
|
|
502
|
-
/**
|
|
517
|
+
/**
|
|
503
518
|
* Called when the last pointer has been removed from this object.
|
|
504
519
|
* Cleans up drag state and applies final velocities to rigidbodies.
|
|
505
520
|
* @param evt Pointer event data for the last pointer that was lifted
|
|
@@ -507,6 +522,7 @@ export class DragControls extends Behaviour implements IPointerEventHandler {
|
|
|
507
522
|
private onLastDragEnd(evt: PointerEventData | null) {
|
|
508
523
|
if (!this || !this._isDragging) return;
|
|
509
524
|
this._isDragging = false;
|
|
525
|
+
this.dragEnded?.invoke();
|
|
510
526
|
for (const rb of this._draggingRigidbodies) {
|
|
511
527
|
rb.setVelocity(rb.smoothedVelocity.multiplyScalar(this.context.time.deltaTime));
|
|
512
528
|
}
|
|
@@ -758,19 +758,26 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
758
758
|
|
|
759
759
|
if (this.targetBounds) {
|
|
760
760
|
// #region target bounds
|
|
761
|
-
const targetVector = this._controls.target;
|
|
762
761
|
const boundsCenter = this.targetBounds.worldPosition;
|
|
763
762
|
const boundsHalfSize = getTempVector(this.targetBounds.worldScale).multiplyScalar(0.5);
|
|
764
763
|
const min = getTempVector(boundsCenter).sub(boundsHalfSize);
|
|
765
764
|
const max = getTempVector(boundsCenter).add(boundsHalfSize);
|
|
766
|
-
|
|
767
|
-
const duration = .1;
|
|
768
|
-
if (duration <= 0) targetVector.copy(newTarget);
|
|
769
|
-
else targetVector.lerp(newTarget, this.context.time.deltaTime / duration);
|
|
765
|
+
|
|
770
766
|
if (this._lookTargetLerpActive) {
|
|
771
|
-
|
|
772
|
-
|
|
767
|
+
// During a programmatic transition (fitCamera / setLookTargetPosition with immediate: false),
|
|
768
|
+
// only clamp the destination. The look-target lerp (above) handles moving _controls.target
|
|
769
|
+
// towards the endpoint — we must not fight it by also lerping _controls.target here.
|
|
770
|
+
this._lookTargetEndPosition.clamp(min, max);
|
|
771
|
+
}
|
|
772
|
+
else {
|
|
773
|
+
// Interactive use (pan/orbit): smoothly push the target back into bounds
|
|
774
|
+
const targetVector = this._controls.target;
|
|
775
|
+
const newTarget = getTempVector(targetVector).clamp(min, max);
|
|
776
|
+
const duration = .1;
|
|
777
|
+
if (duration <= 0) targetVector.copy(newTarget);
|
|
778
|
+
else targetVector.lerp(newTarget, Math.min(1, this.context.time.deltaTime / duration));
|
|
773
779
|
}
|
|
780
|
+
|
|
774
781
|
if (debug) {
|
|
775
782
|
Gizmos.DrawWireBox(boundsCenter, boundsHalfSize.multiplyScalar(2), 0xffaa00);
|
|
776
783
|
}
|
|
@@ -847,7 +854,8 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
847
854
|
this._controls.update(this.context.time.deltaTime);
|
|
848
855
|
|
|
849
856
|
if (debug) {
|
|
850
|
-
|
|
857
|
+
const distance = this._controls.getDistance();
|
|
858
|
+
Gizmos.DrawWireSphere(this._controls.target, 0.01 * distance, 0x00ff00);
|
|
851
859
|
}
|
|
852
860
|
}
|
|
853
861
|
}
|
|
@@ -1022,7 +1030,8 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
1022
1030
|
|
|
1023
1031
|
if (debug) {
|
|
1024
1032
|
console.warn("OrbitControls: setLookTargetPosition", position, immediateOrDuration);
|
|
1025
|
-
|
|
1033
|
+
const distance = this._controls.getDistance();
|
|
1034
|
+
Gizmos.DrawWireSphere(this._lookTargetEndPosition, 0.01 * distance, 0xff5500, 2);
|
|
1026
1035
|
}
|
|
1027
1036
|
|
|
1028
1037
|
if (immediateOrDuration === true) {
|
|
@@ -81,7 +81,24 @@ export class Text extends Graphic implements IHasAlphaFactor, ICanvasEventReceiv
|
|
|
81
81
|
@serializable()
|
|
82
82
|
supportRichText: boolean = false;
|
|
83
83
|
@serializable(URL)
|
|
84
|
-
font
|
|
84
|
+
set font(val: string | null) {
|
|
85
|
+
if (val !== this._font) {
|
|
86
|
+
this._font = val;
|
|
87
|
+
// If the font is assigned during deserialization it means the font URL MUST be resolved with the style suffix. If it's assigned at runtime by a user invocation and is absolute then we assume the user is prividing a full path to the font asset json or png
|
|
88
|
+
this._assignedAtRuntime = this.__didAwake;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
get font(): string | null {
|
|
92
|
+
return this._font;
|
|
93
|
+
}
|
|
94
|
+
private _font: string | null = null;
|
|
95
|
+
private _assignedAtRuntime: boolean = true;
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Whether to support basic rich text tags in the `text` property. Supported tags include `<b>`, `<i>`, and `<color=hex>`. For example: `Hello <b>World</b>` or `Score: <color=#ff0000>100</color>`
|
|
100
|
+
* @default false
|
|
101
|
+
*/
|
|
85
102
|
@serializable()
|
|
86
103
|
fontStyle: FontStyle = FontStyle.Normal;
|
|
87
104
|
|
|
@@ -224,8 +241,15 @@ export class Text extends Graphic implements IHasAlphaFactor, ICanvasEventReceiv
|
|
|
224
241
|
// fontSize /= this.canvas?.scaleFactor;
|
|
225
242
|
// }
|
|
226
243
|
|
|
227
|
-
|
|
228
|
-
|
|
244
|
+
const textOpts: {
|
|
245
|
+
color: Color,
|
|
246
|
+
fontOpacity: number,
|
|
247
|
+
fontSize: number,
|
|
248
|
+
fontKerning: string,
|
|
249
|
+
whiteSpace?: string,
|
|
250
|
+
overflow?: string,
|
|
251
|
+
lineHeight?: number
|
|
252
|
+
} = {
|
|
229
253
|
color: this.color,
|
|
230
254
|
fontOpacity: this.color.alpha,
|
|
231
255
|
fontSize: fontSize,
|
|
@@ -486,15 +510,16 @@ export class Text extends Graphic implements IHasAlphaFactor, ICanvasEventReceiv
|
|
|
486
510
|
* @private
|
|
487
511
|
*/
|
|
488
512
|
private setFont(opts: ThreeMeshUIEveryOptions, fontStyle: FontStyle) {
|
|
513
|
+
|
|
514
|
+
if (!this.font) {
|
|
515
|
+
if(debug) console.warn("No font set for Text component, skipping font setup");
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
489
518
|
|
|
490
|
-
// @TODO : THH could be useful to uniformize font family name :
|
|
491
|
-
// This would ease possible html/vr matching
|
|
492
|
-
// - Arial instead of assets/arial
|
|
493
|
-
// - Arial should stay Arial instead of arial
|
|
494
|
-
if (!this.font) return;
|
|
495
519
|
const fontName = this.font;
|
|
496
520
|
const familyName = this.getFamilyNameWithCorrectSuffix(fontName, fontStyle);
|
|
497
|
-
|
|
521
|
+
|
|
522
|
+
if (debug) console.log("Selected font family:" + familyName, this.font);
|
|
498
523
|
|
|
499
524
|
// ensure a font family is register under this name
|
|
500
525
|
let fontFamily = ThreeMeshUI.FontLibrary.getFontFamily(familyName as string);
|
|
@@ -527,9 +552,7 @@ export class Text extends Graphic implements IHasAlphaFactor, ICanvasEventReceiv
|
|
|
527
552
|
opts.fontWeight = 400;
|
|
528
553
|
}
|
|
529
554
|
|
|
530
|
-
|
|
531
555
|
// Ensure a fontVariant is registered
|
|
532
|
-
//@TODO: @swingingtom add type for fontWeight
|
|
533
556
|
let fontVariant = fontFamily.getVariant(opts.fontWeight as any as string, opts.fontStyle);
|
|
534
557
|
if (!fontVariant) {
|
|
535
558
|
let jsonPath = familyName;
|
|
@@ -550,13 +573,7 @@ export class Text extends Graphic implements IHasAlphaFactor, ICanvasEventReceiv
|
|
|
550
573
|
|
|
551
574
|
private getFamilyNameWithCorrectSuffix(familyName: string, style: FontStyle): string {
|
|
552
575
|
|
|
553
|
-
|
|
554
|
-
// the URL decorator resolves the URL to absolute URLs - we need to remove the domain part since we're only interested in the path
|
|
555
|
-
if (familyName.startsWith("https:") || familyName.startsWith("http:")) {
|
|
556
|
-
const url = new URL(familyName);
|
|
557
|
-
familyName = url.pathname;
|
|
558
|
-
}
|
|
559
|
-
|
|
576
|
+
const isAbsolute = familyName.startsWith("https:") || familyName.startsWith("http:");
|
|
560
577
|
|
|
561
578
|
// we can only change the style for the family if the name has a suffix (e.g. Arial-Bold)
|
|
562
579
|
const styleSeparator = familyName.lastIndexOf('-');
|
|
@@ -580,8 +597,16 @@ export class Text extends Graphic implements IHasAlphaFactor, ICanvasEventReceiv
|
|
|
580
597
|
}
|
|
581
598
|
const isUpperCase = fontBaseName[0] === fontBaseName[0].toUpperCase();
|
|
582
599
|
const fontNameWithoutSuffix = familyName.substring(0, styleSeparator > pathSeparatorIndex ? styleSeparator : familyName.length);
|
|
600
|
+
|
|
583
601
|
if (debug) console.log("Select font: ", familyName, FontStyle[style], fontBaseName, isUpperCase, fontNameWithoutSuffix);
|
|
584
602
|
|
|
603
|
+
/**
|
|
604
|
+
* If a user provides a font with an absolute URL AND the font name does not end with "-msdf.json" or ".png" (e.g. "https://example.com/fonts/Arial-Bold"), we will assume that the user is providing the full path to the font files and we will not try to modify the font name based on the style. This allows users to have more control over the font files they are using, especially if they are hosting their own fonts or using a custom font provider that does not follow the same naming conventions as our default fonts.
|
|
605
|
+
*/
|
|
606
|
+
if (isAbsolute && this._assignedAtRuntime && !(familyName.endsWith("-msdf.json") || familyName.endsWith(".png"))) {
|
|
607
|
+
return fontNameWithoutSuffix;
|
|
608
|
+
}
|
|
609
|
+
|
|
585
610
|
switch (style) {
|
|
586
611
|
case FontStyle.Normal:
|
|
587
612
|
if (isUpperCase) return fontNameWithoutSuffix + "-Regular";
|
|
@@ -289,20 +289,28 @@ export class CursorFollow extends Behaviour {
|
|
|
289
289
|
|
|
290
290
|
|
|
291
291
|
if (this.snapToSurface) {
|
|
292
|
-
ray.origin =
|
|
293
|
-
ray.direction = rayDirection
|
|
294
|
-
const hits = this.context.physics.raycastFromRay(ray
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
if (this.damping > 0) {
|
|
298
|
-
this.gameObject.worldPosition = _position.lerp(hit.point, this.context.time.deltaTime / this.damping);
|
|
299
|
-
}
|
|
300
|
-
else {
|
|
301
|
-
this.gameObject.worldPosition = hit.point;
|
|
292
|
+
ray.origin = cameraPosition;
|
|
293
|
+
ray.direction = rayDirection;
|
|
294
|
+
const hits = this.context.physics.raycastFromRay(ray, {
|
|
295
|
+
testObject: obj => {
|
|
296
|
+
return obj !== this.gameObject && !this.gameObject.contains(obj) ? true : false
|
|
302
297
|
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
298
|
+
});
|
|
299
|
+
if (hits?.length) {
|
|
300
|
+
// Get the first hit that is not a child of *this* object. Because we do not want to lerp to a surface that is part of the object itself, since that would result in *this* object moving closer and closer to the camera as it tries to snap to itself
|
|
301
|
+
const hit = hits[0];//.find(h => !this.gameObject.contains(h.object));
|
|
302
|
+
if (hit) {
|
|
303
|
+
if (this.damping > 0) {
|
|
304
|
+
this.gameObject.worldPosition = _position.lerp(hit.point, this.context.time.deltaTime / this.damping);
|
|
305
|
+
// this._distance = this.gameObject.worldPosition.distanceTo(cameraPosition);
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
this.gameObject.worldPosition = hit.point;
|
|
309
|
+
// this._distance = hit.point.distanceTo(cameraPosition);
|
|
310
|
+
}
|
|
311
|
+
if (debug) {
|
|
312
|
+
Gizmos.DrawLine(hit.point, hit.normal!.add(hit.point), 0x00FF00);
|
|
313
|
+
}
|
|
306
314
|
}
|
|
307
315
|
}
|
|
308
316
|
}
|