@needle-tools/engine 4.10.0-next.f0ec242 → 4.10.0
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 -3
- package/README.md +2 -1
- package/components.needle.json +1 -1
- package/dist/needle-engine.bundle-BSq-d_16.min.js +1652 -0
- package/dist/{needle-engine.bundle-dgNq9Vsa.umd.cjs → needle-engine.bundle-C2kVfQq6.umd.cjs} +153 -140
- package/dist/{needle-engine.bundle-BC-0Ex9m.js → needle-engine.bundle-CIuhf7-t.js} +7388 -7113
- package/dist/needle-engine.d.ts +15 -15
- package/dist/needle-engine.js +259 -257
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/dist/vendor-CPuBPspY.umd.cjs +1121 -0
- package/dist/vendor-DPCU8cUF.min.js +1121 -0
- package/dist/vendor-MBoqSyFm.js +16240 -0
- package/lib/engine/codegen/register_types.js +2 -0
- package/lib/engine/codegen/register_types.js.map +1 -1
- package/lib/engine/engine_camera.d.ts +7 -1
- package/lib/engine/engine_camera.js +46 -6
- package/lib/engine/engine_camera.js.map +1 -1
- package/lib/engine/engine_context.d.ts +6 -0
- package/lib/engine/engine_context.js +48 -9
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/engine_gizmos.d.ts +11 -10
- package/lib/engine/engine_gizmos.js +24 -10
- package/lib/engine/engine_gizmos.js.map +1 -1
- package/lib/engine/engine_license.js +1 -1
- package/lib/engine/engine_license.js.map +1 -1
- package/lib/engine/engine_lightdata.d.ts +3 -3
- package/lib/engine/engine_lightdata.js +10 -10
- package/lib/engine/engine_lightdata.js.map +1 -1
- package/lib/engine/engine_physics_rapier.js +4 -0
- package/lib/engine/engine_physics_rapier.js.map +1 -1
- package/lib/engine/engine_scenelighting.d.ts +1 -1
- package/lib/engine/engine_scenelighting.js +4 -5
- package/lib/engine/engine_scenelighting.js.map +1 -1
- package/lib/engine/engine_utils.d.ts +3 -1
- package/lib/engine/engine_utils.js +11 -0
- package/lib/engine/engine_utils.js.map +1 -1
- package/lib/engine/extensions/NEEDLE_lightmaps.js +1 -1
- package/lib/engine/extensions/NEEDLE_lightmaps.js.map +1 -1
- package/lib/engine/extensions/extension_utils.js +1 -1
- package/lib/engine/extensions/extension_utils.js.map +1 -1
- package/lib/engine/webcomponents/logo-element.d.ts +1 -1
- package/lib/engine/webcomponents/logo-element.js +29 -5
- package/lib/engine/webcomponents/logo-element.js.map +1 -1
- package/lib/engine/webcomponents/needle menu/needle-menu.js +4 -3
- package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.js +22 -0
- package/lib/engine/webcomponents/needle-engine.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.loading.d.ts +0 -1
- package/lib/engine/webcomponents/needle-engine.loading.js +3 -36
- package/lib/engine/webcomponents/needle-engine.loading.js.map +1 -1
- package/lib/engine/xr/NeedleXRController.d.ts +3 -3
- package/lib/engine/xr/NeedleXRController.js +28 -0
- package/lib/engine/xr/NeedleXRController.js.map +1 -1
- package/lib/engine-components/CameraUtils.js +2 -1
- package/lib/engine-components/CameraUtils.js.map +1 -1
- package/lib/engine-components/Renderer.js +6 -1
- package/lib/engine-components/Renderer.js.map +1 -1
- package/lib/engine-components/Skybox.js +22 -4
- package/lib/engine-components/Skybox.js.map +1 -1
- package/lib/engine-components/codegen/components.d.ts +1 -0
- package/lib/engine-components/codegen/components.js +1 -0
- package/lib/engine-components/codegen/components.js.map +1 -1
- package/lib/engine-components/debug/LogStats.d.ts +1 -0
- package/lib/engine-components/debug/LogStats.js +1 -0
- package/lib/engine-components/debug/LogStats.js.map +1 -1
- package/lib/engine-components/timeline/PlayableDirector.d.ts +7 -0
- package/lib/engine-components/timeline/PlayableDirector.js +8 -1
- package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
- package/lib/engine-components/timeline/TimelineModels.d.ts +11 -1
- package/lib/engine-components/timeline/TimelineTracks.d.ts +2 -1
- package/lib/engine-components/timeline/TimelineTracks.js +30 -25
- package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
- package/lib/engine-components/utils/LookAt.js +5 -1
- package/lib/engine-components/utils/LookAt.js.map +1 -1
- package/lib/engine-components/web/Clickthrough.js +10 -2
- package/lib/engine-components/web/Clickthrough.js.map +1 -1
- package/lib/engine-components/web/ScrollFollow.d.ts +24 -0
- package/lib/engine-components/web/ScrollFollow.js +169 -42
- package/lib/engine-components/web/ScrollFollow.js.map +1 -1
- package/lib/engine-components/web/ViewBox.d.ts +43 -0
- package/lib/engine-components/web/ViewBox.js +258 -0
- package/lib/engine-components/web/ViewBox.js.map +1 -0
- package/lib/engine-components/web/index.d.ts +1 -0
- package/lib/engine-components/web/index.js +1 -0
- package/lib/engine-components/web/index.js.map +1 -1
- package/lib/engine-components-experimental/Presentation.d.ts +1 -0
- package/lib/engine-components-experimental/Presentation.js +1 -0
- package/lib/engine-components-experimental/Presentation.js.map +1 -1
- package/package.json +3 -2
- package/src/engine/codegen/register_types.ts +2 -0
- package/src/engine/engine_camera.ts +61 -9
- package/src/engine/engine_context.ts +50 -10
- package/src/engine/engine_gizmos.ts +37 -23
- package/src/engine/engine_license.ts +1 -1
- package/src/engine/engine_lightdata.ts +11 -11
- package/src/engine/engine_physics_rapier.ts +3 -0
- package/src/engine/engine_scenelighting.ts +5 -6
- package/src/engine/engine_utils.ts +12 -0
- package/src/engine/extensions/NEEDLE_lightmaps.ts +1 -1
- package/src/engine/extensions/extension_utils.ts +1 -1
- package/src/engine/webcomponents/logo-element.ts +29 -4
- package/src/engine/webcomponents/needle menu/needle-menu.ts +4 -3
- package/src/engine/webcomponents/needle-engine.loading.ts +32 -32
- package/src/engine/webcomponents/needle-engine.ts +33 -6
- package/src/engine/xr/NeedleXRController.ts +36 -4
- package/src/engine-components/CameraUtils.ts +1 -1
- package/src/engine-components/Renderer.ts +6 -1
- package/src/engine-components/Skybox.ts +26 -7
- package/src/engine-components/codegen/components.ts +1 -0
- package/src/engine-components/debug/LogStats.ts +1 -0
- package/src/engine-components/timeline/PlayableDirector.ts +10 -1
- package/src/engine-components/timeline/TimelineModels.ts +11 -1
- package/src/engine-components/timeline/TimelineTracks.ts +30 -25
- package/src/engine-components/utils/LookAt.ts +5 -1
- package/src/engine-components/web/Clickthrough.ts +11 -2
- package/src/engine-components/web/ScrollFollow.ts +205 -51
- package/src/engine-components/web/ViewBox.ts +278 -0
- package/src/engine-components/web/index.ts +2 -1
- package/src/engine-components-experimental/Presentation.ts +1 -0
- package/dist/needle-engine.bundle-BSh7dSEx.min.js +0 -1639
- package/dist/vendor-D0Yvltn9.umd.cjs +0 -1121
- package/dist/vendor-DU8tJyl_.js +0 -14366
- package/dist/vendor-JyrX4DVM.min.js +0 -1121
|
@@ -381,6 +381,14 @@ export function resolveUrl(source: SourceIdentifier | undefined, uri: string): s
|
|
|
381
381
|
}
|
|
382
382
|
return uri;
|
|
383
383
|
}
|
|
384
|
+
|
|
385
|
+
export function toSourceId(src: string | null): SourceIdentifier | undefined {
|
|
386
|
+
if (!src) return undefined;
|
|
387
|
+
src = src.trim();
|
|
388
|
+
src = src.split("?")[0]?.split("#")[0];
|
|
389
|
+
return src;
|
|
390
|
+
}
|
|
391
|
+
|
|
384
392
|
// export function getPath(glbLocation: SourceIdentifier | undefined, path: string) {
|
|
385
393
|
// if (path && glbLocation && !path.includes("/")) {
|
|
386
394
|
// // get directory of glb and prepend it to the audio file path
|
|
@@ -793,6 +801,7 @@ const mutationObserverMap = new WeakMap<HTMLElement, HtmlElementExtra>();
|
|
|
793
801
|
/**
|
|
794
802
|
* Register a callback when an {@link HTMLElement} attribute changes.
|
|
795
803
|
* This is used, for example, by the Skybox component to watch for changes to the environment-* and skybox-* attributes.
|
|
804
|
+
* @returns A function that can be used to unregister the callback
|
|
796
805
|
*/
|
|
797
806
|
export function addAttributeChangeCallback(domElement: HTMLElement, name: string, callback: AttributeChangeCallback) {
|
|
798
807
|
if (!mutationObserverMap.get(domElement)) {
|
|
@@ -811,6 +820,9 @@ export function addAttributeChangeCallback(domElement: HTMLElement, name: string
|
|
|
811
820
|
listeners.set(name, []);
|
|
812
821
|
}
|
|
813
822
|
listeners.get(name)!.push(callback);
|
|
823
|
+
return () => {
|
|
824
|
+
removeAttributeChangeCallback(domElement, name, callback);
|
|
825
|
+
}
|
|
814
826
|
};
|
|
815
827
|
|
|
816
828
|
/**
|
|
@@ -107,7 +107,7 @@ export class NEEDLE_lightmaps implements GLTFLoaderPlugin {
|
|
|
107
107
|
|
|
108
108
|
private resolveTexture(entry: LightmapInfo, res: any) {
|
|
109
109
|
const tex: Texture = res as unknown as Texture;
|
|
110
|
-
if (debug) console.log("
|
|
110
|
+
if (debug) console.log("Light Texture loaded:", tex);
|
|
111
111
|
if (tex?.isTexture) {
|
|
112
112
|
if (!this.registry)
|
|
113
113
|
console.log(LightmapType[entry.type], entry.pointer, tex);
|
|
@@ -89,7 +89,7 @@ function internalResolve(paths: DependencyInfo[], parser: GLTFParserWithCache, o
|
|
|
89
89
|
for (let i = 0; i < val.length; i++) {
|
|
90
90
|
const entry = val[i];
|
|
91
91
|
const ext = resolveExtension(parser, entry);
|
|
92
|
-
if (ext !== null) {
|
|
92
|
+
if (ext !== null && ext !== undefined) {
|
|
93
93
|
if (typeof ext.then === "function")
|
|
94
94
|
promises.push(ext.then(res => val[i] = res));
|
|
95
95
|
else val[i] = ext;
|
|
@@ -32,10 +32,22 @@ export class NeedleLogoElement extends HTMLElement {
|
|
|
32
32
|
cursor: pointer;
|
|
33
33
|
}
|
|
34
34
|
img {
|
|
35
|
-
width: 95px;
|
|
36
35
|
height: 100%;
|
|
37
36
|
align-self: end;
|
|
38
37
|
margin-left: 0.6rem;
|
|
38
|
+
transition: transform 0.2s;
|
|
39
|
+
}
|
|
40
|
+
img.with-text {
|
|
41
|
+
width: 11.5ch;
|
|
42
|
+
&:hover {
|
|
43
|
+
transform: scale(1.02);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
img.compact {
|
|
47
|
+
width: 1.7em;
|
|
48
|
+
&:hover {
|
|
49
|
+
transform: scale(1.1);
|
|
50
|
+
}
|
|
39
51
|
}
|
|
40
52
|
span {
|
|
41
53
|
font-size: 1rem;
|
|
@@ -43,12 +55,14 @@ export class NeedleLogoElement extends HTMLElement {
|
|
|
43
55
|
}
|
|
44
56
|
</style>
|
|
45
57
|
<div class="wrapper">
|
|
46
|
-
<img class="logo" src=${needleLogoSVG} />
|
|
58
|
+
<img class="logo with-text" src=${needleLogoSVG} />
|
|
47
59
|
</div>
|
|
48
60
|
`;
|
|
49
61
|
this._root.appendChild(template.content.cloneNode(true));
|
|
50
62
|
this.wrapper = this._root.querySelector(".wrapper") as HTMLDivElement;
|
|
51
63
|
this._root.appendChild(this.wrapper);
|
|
64
|
+
this.logoElement = this._root.querySelector("img.logo") as HTMLImageElement;
|
|
65
|
+
|
|
52
66
|
// this.wrapper.classList.add("wrapper");
|
|
53
67
|
|
|
54
68
|
// this.wrapper.appendChild(this.logoElement);
|
|
@@ -67,13 +81,24 @@ export class NeedleLogoElement extends HTMLElement {
|
|
|
67
81
|
|
|
68
82
|
private readonly _root: ShadowRoot;
|
|
69
83
|
private readonly wrapper: HTMLDivElement;
|
|
70
|
-
private readonly logoElement: HTMLImageElement
|
|
71
|
-
private readonly textElement: HTMLSpanElement = document.createElement("span");
|
|
84
|
+
private readonly logoElement: HTMLImageElement;
|
|
72
85
|
|
|
73
86
|
setLogoVisible(val: boolean) {
|
|
74
87
|
this.logoElement.style.display = val ? "block" : "none";
|
|
75
88
|
}
|
|
76
89
|
|
|
90
|
+
setType(type: "full" | "compact") {
|
|
91
|
+
if (type === "full") {
|
|
92
|
+
this.logoElement.src = needleLogoSVG;
|
|
93
|
+
this.logoElement.classList.remove("with-text");
|
|
94
|
+
this.logoElement.classList.remove("compact");
|
|
95
|
+
} else {
|
|
96
|
+
this.logoElement.src = needleLogoOnlySVG;
|
|
97
|
+
this.logoElement.classList.add("with-text");
|
|
98
|
+
this.logoElement.classList.add("compact");
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
77
102
|
}
|
|
78
103
|
if (!customElements.get(elementName))
|
|
79
104
|
customElements.define(elementName, NeedleLogoElement);
|
|
@@ -459,7 +459,7 @@ export class NeedleMenuElement extends HTMLElement {
|
|
|
459
459
|
|
|
460
460
|
.logo {
|
|
461
461
|
cursor: pointer;
|
|
462
|
-
padding-left: 0.
|
|
462
|
+
padding-left: 0.0rem;
|
|
463
463
|
padding-bottom: .02rem;
|
|
464
464
|
margin-right: 0.5rem;
|
|
465
465
|
}
|
|
@@ -664,8 +664,8 @@ export class NeedleMenuElement extends HTMLElement {
|
|
|
664
664
|
<slot name="end"></slot>
|
|
665
665
|
</div>
|
|
666
666
|
</div>
|
|
667
|
-
<div style="user-select:none" class="logo">
|
|
668
|
-
<span class="madewith notranslate">powered by</span>
|
|
667
|
+
<div style="user-select:none;" class="logo">
|
|
668
|
+
<span class="madewith notranslate" style="display:none;">powered by</span>
|
|
669
669
|
</div>
|
|
670
670
|
</div>
|
|
671
671
|
<button class="compact-menu-button">
|
|
@@ -698,6 +698,7 @@ export class NeedleMenuElement extends HTMLElement {
|
|
|
698
698
|
this.wrapper.classList.add("wrapper");
|
|
699
699
|
|
|
700
700
|
const logo = NeedleLogoElement.create();
|
|
701
|
+
logo.setType("compact");
|
|
701
702
|
logo.style.minHeight = "1rem";
|
|
702
703
|
this.logoContainer.append(logo);
|
|
703
704
|
this.logoContainer.addEventListener("click", () => {
|
|
@@ -374,40 +374,40 @@ export class EngineLoadingView implements ILoadingViewHandler {
|
|
|
374
374
|
// }
|
|
375
375
|
// }
|
|
376
376
|
|
|
377
|
-
this.handleRuntimeLicense(this._loadingElement);
|
|
377
|
+
// this.handleRuntimeLicense(this._loadingElement);
|
|
378
378
|
|
|
379
379
|
return this._loadingElement;
|
|
380
380
|
}
|
|
381
381
|
|
|
382
|
-
private async handleRuntimeLicense(loadingElement: HTMLElement) {
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
}
|
|
382
|
+
// private async handleRuntimeLicense(loadingElement: HTMLElement) {
|
|
383
|
+
// // First check if we have a commercial license
|
|
384
|
+
// let commercialLicense = hasCommercialLicense();
|
|
385
|
+
// // if it's the case then we don't need to perform a runtime check
|
|
386
|
+
// if (commercialLicense) return;
|
|
387
|
+
|
|
388
|
+
// // If we don't have a commercial license, then we need to display our message
|
|
389
|
+
// if (debugLicense) console.log("Loading UI has commercial license?", commercialLicense);
|
|
390
|
+
// const nonCommercialContainer = document.createElement("div");
|
|
391
|
+
// nonCommercialContainer.style.paddingTop = ".6em";
|
|
392
|
+
// nonCommercialContainer.style.fontSize = ".8em";
|
|
393
|
+
// nonCommercialContainer.style.textTransform = "uppercase";
|
|
394
|
+
// nonCommercialContainer.innerText = "NEEDLE ENGINE NON COMMERCIAL VERSION\nCLICK HERE TO GET A LICENSE";
|
|
395
|
+
// nonCommercialContainer.style.cursor = "pointer";
|
|
396
|
+
// nonCommercialContainer.style.userSelect = "none";
|
|
397
|
+
// nonCommercialContainer.style.textAlign = "center";
|
|
398
|
+
// nonCommercialContainer.style.pointerEvents = "all";
|
|
399
|
+
// nonCommercialContainer.addEventListener("click", () => window.open("https://needle.tools/pricing", "_self"));
|
|
400
|
+
// nonCommercialContainer.style.opacity = "0";
|
|
401
|
+
// loadingElement.appendChild(nonCommercialContainer);
|
|
402
|
+
|
|
403
|
+
// // Use the runtime license check
|
|
404
|
+
// if (!isDevEnvironment() && runtimeLicenseCheckPromise) {
|
|
405
|
+
// if (debugLicense) console.log("Waiting for runtime license check");
|
|
406
|
+
// await runtimeLicenseCheckPromise;
|
|
407
|
+
// commercialLicense = hasCommercialLicense();
|
|
408
|
+
// }
|
|
409
|
+
// if (commercialLicense) return;
|
|
410
|
+
// nonCommercialContainer.style.transition = "opacity .5s ease-in-out";
|
|
411
|
+
// nonCommercialContainer.style.opacity = "1";
|
|
412
|
+
// }
|
|
413
413
|
}
|
|
@@ -38,14 +38,18 @@ const observedAttributes = [
|
|
|
38
38
|
"loadstart",
|
|
39
39
|
"progress",
|
|
40
40
|
"loadfinished",
|
|
41
|
+
|
|
41
42
|
"dracoDecoderPath",
|
|
42
43
|
"dracoDecoderType",
|
|
43
44
|
"ktx2DecoderPath",
|
|
45
|
+
|
|
44
46
|
"tone-mapping",
|
|
45
47
|
"tone-mapping-exposure",
|
|
46
48
|
"background-blurriness",
|
|
47
49
|
"background-color",
|
|
48
50
|
"environment-intensity",
|
|
51
|
+
|
|
52
|
+
"focus-rect",
|
|
49
53
|
]
|
|
50
54
|
|
|
51
55
|
// https://developers.google.com/web/fundamentals/web-components/customelements
|
|
@@ -95,7 +99,7 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
95
99
|
if (value === null) this.removeAttribute("camera-controls");
|
|
96
100
|
else this.setAttribute("camera-controls", value ? "true" : "false");
|
|
97
101
|
}
|
|
98
|
-
|
|
102
|
+
|
|
99
103
|
|
|
100
104
|
/**
|
|
101
105
|
* Get the current context for this web component instance. The context is created when the src attribute is set and the loading has finished.
|
|
@@ -331,17 +335,17 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
331
335
|
if (debug) console.log("ktx2DecoderPath", newValue);
|
|
332
336
|
setKtx2TranscoderPath(newValue);
|
|
333
337
|
break;
|
|
334
|
-
|
|
338
|
+
|
|
335
339
|
case "tonemapping":
|
|
336
340
|
case "tone-mapping":
|
|
337
341
|
case "tone-mapping-exposure":
|
|
338
342
|
case "background-blurriness":
|
|
339
343
|
case "background-color":
|
|
340
344
|
case "environment-intensity":
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
+
{
|
|
346
|
+
this.applyAttributes();
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
345
349
|
case "public-key": {
|
|
346
350
|
if (newValue != PUBLIC_KEY)
|
|
347
351
|
this.setPublicKey();
|
|
@@ -352,6 +356,25 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
352
356
|
this.setVersion();
|
|
353
357
|
break;
|
|
354
358
|
}
|
|
359
|
+
|
|
360
|
+
case "focus-rect":
|
|
361
|
+
{
|
|
362
|
+
const focus_rect = this.getAttribute("focus-rect") as HTMLElement | string | null;
|
|
363
|
+
if (focus_rect && this._context) {
|
|
364
|
+
if (focus_rect === null) {
|
|
365
|
+
this._context.setCameraFocusRect(null);
|
|
366
|
+
}
|
|
367
|
+
else if (typeof focus_rect === "string" && focus_rect.length > 0) {
|
|
368
|
+
const element = document.querySelector(focus_rect);
|
|
369
|
+
this._context.setCameraFocusRect(element instanceof HTMLElement ? element : null);
|
|
370
|
+
}
|
|
371
|
+
else if (focus_rect instanceof HTMLElement) {
|
|
372
|
+
this._context.setCameraFocusRect(focus_rect);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
break;
|
|
355
378
|
}
|
|
356
379
|
}
|
|
357
380
|
|
|
@@ -570,6 +593,10 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
570
593
|
this._context.renderer.setClearColor(rgbaColor, rgbaColor.alpha);
|
|
571
594
|
this.context.scene.background = null;
|
|
572
595
|
}
|
|
596
|
+
// HACK: if we set background-color to a color and then back to null we want the background-image attribute to re-apply
|
|
597
|
+
else if (this.getAttribute("background-image")) {
|
|
598
|
+
this.setAttribute("background-image", this.getAttribute("background-image")!);
|
|
599
|
+
}
|
|
573
600
|
}
|
|
574
601
|
}
|
|
575
602
|
|
|
@@ -23,10 +23,10 @@ const debugCustomGesture = getParam("debugcustomgesture");
|
|
|
23
23
|
// let _didReceiveSelectStartEvent = false;
|
|
24
24
|
|
|
25
25
|
// https://github.com/immersive-web/webxr-input-profiles/blob/4484a05e30bcd43fe86bb4e06b7a707861a26796/packages/registry/profiles/meta/meta-quest-touch-plus.json
|
|
26
|
-
declare type ControllerAxes = "xr-standard-thumbstick";
|
|
27
|
-
declare type StickName = "xr-standard-thumbstick";
|
|
26
|
+
declare type ControllerAxes = "xr-standard-thumbstick" | "xr-standard-touchpad";
|
|
27
|
+
declare type StickName = "xr-standard-thumbstick" | "xr-standard-touchpad";
|
|
28
28
|
declare type Mapping = "xr-standard";
|
|
29
|
-
declare type ComponentType = "button" | "thumbstick" | "squeeze";
|
|
29
|
+
declare type ComponentType = "button" | "thumbstick" | "squeeze" | "touchpad";
|
|
30
30
|
declare type GamepadKey = "button" | "xAxis" | "yAxis";
|
|
31
31
|
|
|
32
32
|
declare type NeedleXRControllerButtonName = ButtonName | "primary-button" | "primary";
|
|
@@ -407,6 +407,16 @@ C:${this.connected ? "x" : "-"} T:${this.isTracking ? "x" : "-"} Hand:${this.inp
|
|
|
407
407
|
gamepadStr += "\n[axes " + gp.axes.length + "]: " + gp.axes.map(a => a.toPrecision(1)).join(",");
|
|
408
408
|
debugStr += "\n" + gamepadStr;
|
|
409
409
|
}
|
|
410
|
+
if (this._layout) {
|
|
411
|
+
debugStr += "\nLayout: ";
|
|
412
|
+
for (const component of Object.keys(this._layout.components || {})) {
|
|
413
|
+
const val = this.getStick(component as StickName);
|
|
414
|
+
const indices = this._layout.components[component]?.gamepadIndices;
|
|
415
|
+
const indicesAsString = indices ? Object.entries(indices).map(e => e[0][0].toUpperCase() + e[0].slice(1) + "=" + e[1]).join(",") : "";
|
|
416
|
+
debugStr += `\n ${component}: ${this._layout.components[component]?.type} [${indicesAsString}] (${val.x.toPrecision(2)},${val.y.toPrecision(2)})`;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
410
420
|
Gizmos.DrawLabel(debugLabelPosition, debugStr, .006);
|
|
411
421
|
}
|
|
412
422
|
|
|
@@ -730,6 +740,7 @@ C:${this.connected ? "x" : "-"} T:${this.isTracking ? "x" : "-"} Hand:${this.inp
|
|
|
730
740
|
if (componentModel?.gamepadIndices) {
|
|
731
741
|
switch (componentModel.type) {
|
|
732
742
|
case "thumbstick":
|
|
743
|
+
case "touchpad":
|
|
733
744
|
if (this.inputSource.gamepad) {
|
|
734
745
|
const xIndex = componentModel.gamepadIndices!.xAxis!;
|
|
735
746
|
const yIndex = componentModel.gamepadIndices!.yAxis!;
|
|
@@ -760,7 +771,11 @@ C:${this.connected ? "x" : "-"} T:${this.isTracking ? "x" : "-"} Hand:${this.inp
|
|
|
760
771
|
this._isMetaQuestTouchController = this.profiles.includes("meta-quest-touch-plus") || this.profiles.includes("oculus-touch-v3");
|
|
761
772
|
|
|
762
773
|
// Proper profile starting with v69 and browser 35.1
|
|
763
|
-
this._isMxInk = this.profiles.includes("logitech-mx-ink")
|
|
774
|
+
this._isMxInk = this.profiles.includes("logitech-mx-ink");
|
|
775
|
+
|
|
776
|
+
// For debugging to see ALL available profiles
|
|
777
|
+
/** @ts-ignore */
|
|
778
|
+
// fetchProfilesList(DEFAULT_PROFILES_PATH).then(list => console.log("Available controller profiles", list));
|
|
764
779
|
|
|
765
780
|
if (!this._layout) {
|
|
766
781
|
// Ignore transient-pointer since we likely don't want to spawn a controller visual just for a temporary pointer.
|
|
@@ -780,6 +795,8 @@ C:${this.connected ? "x" : "-"} T:${this.isTracking ? "x" : "-"} Hand:${this.inp
|
|
|
780
795
|
res.assetPath || ""
|
|
781
796
|
);
|
|
782
797
|
|
|
798
|
+
// const overrideProfile = await fetch(DEFAULT_PROFILES_PATH + "/htc-vive-focus-3/profile.json").then(r => r.json());
|
|
799
|
+
|
|
783
800
|
const profile = res.profile as InputDeviceProfile;
|
|
784
801
|
const layout = profile.layouts[this.inputSource.handedness];
|
|
785
802
|
this._layout = layout;
|
|
@@ -791,6 +808,21 @@ C:${this.connected ? "x" : "-"} T:${this.isTracking ? "x" : "-"} Hand:${this.inp
|
|
|
791
808
|
this._layout.gamepad[component.gamepadIndices!.button!] = key as XRControllerButtonName;
|
|
792
809
|
}
|
|
793
810
|
}
|
|
811
|
+
|
|
812
|
+
// If we have 4 axes and no thumbstick defined, we define thumbstick for axis 3+4
|
|
813
|
+
// This is a workaround for HTC Vive Focus 3 controllers, which have the profile for Vive Focus Plus...
|
|
814
|
+
// This workaround fixes it for HTC Vive Focus 3 but does not change anything for Vive Focus Plus controllers
|
|
815
|
+
if (this.profiles.length >= 1 && this.profiles[0] === "htc-vive-focus-plus") {
|
|
816
|
+
if (this.inputSource.gamepad && this.inputSource.gamepad.axes.length === 4 && !this._layout.components["xr-standard-thumbstick"]) {
|
|
817
|
+
this._layout.components["xr-standard-thumbstick"] = {
|
|
818
|
+
type: "thumbstick",
|
|
819
|
+
gamepadIndices: {
|
|
820
|
+
xAxis: 2,
|
|
821
|
+
yAxis: 3,
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
}
|
|
794
826
|
}
|
|
795
827
|
// if (debug) console.log(this._layout, this.inputSource);
|
|
796
828
|
// debugger;
|
|
@@ -122,7 +122,7 @@ function createDefaultCameraControls(context: IContext, cam?: ICamera) {
|
|
|
122
122
|
orbit.autoRotate = autoRotate != "0" && autoRotate?.toLowerCase() != "false";
|
|
123
123
|
const autoRotateSpeed = Number.parseFloat(autoRotate || ".5");
|
|
124
124
|
orbit.autoRotateSpeed = !isNaN(autoRotateSpeed) ? autoRotateSpeed : .5;
|
|
125
|
-
console.log("Auto-rotate", orbit.autoRotate, "speed:", orbit.autoRotateSpeed);
|
|
125
|
+
if(debug) console.log("Auto-rotate", orbit.autoRotate, "speed:", orbit.autoRotateSpeed);
|
|
126
126
|
const autoFit = context.domElement.getAttribute("auto-fit");
|
|
127
127
|
orbit.autoFit = autoFit !== "0" && autoFit?.toLowerCase() != "false";
|
|
128
128
|
orbit.autoTarget = true;
|
|
@@ -358,8 +358,11 @@ export class Renderer extends Behaviour implements IRenderer {
|
|
|
358
358
|
//@ts-ignore
|
|
359
359
|
get sharedMaterials(): SharedMaterialArray {
|
|
360
360
|
|
|
361
|
+
// @ts-ignore (original materials will be set during deserialization)
|
|
362
|
+
if(this._originalMaterials === undefined) return null;
|
|
363
|
+
|
|
361
364
|
// @ts-ignore during deserialization code might access this property *before* the setter and then create an empty array
|
|
362
|
-
if (
|
|
365
|
+
if (this.__isDeserializing === true) return null;
|
|
363
366
|
|
|
364
367
|
if (!this._sharedMaterials || !this._sharedMaterials.is(this)) {
|
|
365
368
|
if (!this._originalMaterials) this._originalMaterials = [];
|
|
@@ -725,6 +728,8 @@ export class Renderer extends Behaviour implements IRenderer {
|
|
|
725
728
|
// If the material has a envMap and is NOT using a reflection probe we set the envMap to the scene environment
|
|
726
729
|
if (mat && "envMap" in mat && "envMapIntensity" in mat && !ReflectionProbe.isUsingReflectionProbe(mat)) {
|
|
727
730
|
mat.envMap = this.context.scene.environment;
|
|
731
|
+
mat.envMapIntensity = this.context.scene.environmentIntensity;
|
|
732
|
+
mat.envMapRotation = this.context.scene.environmentRotation;
|
|
728
733
|
}
|
|
729
734
|
}
|
|
730
735
|
}
|
|
@@ -8,7 +8,7 @@ import { syncField } from "../engine/engine_networking_auto.js";
|
|
|
8
8
|
import { loadPMREM } from "../engine/engine_pmrem.js";
|
|
9
9
|
import { serializable } from "../engine/engine_serialization_decorator.js";
|
|
10
10
|
import { type IContext } from "../engine/engine_types.js";
|
|
11
|
-
import { addAttributeChangeCallback, getParam, PromiseAllWithErrors, removeAttributeChangeCallback } from "../engine/engine_utils.js";
|
|
11
|
+
import { addAttributeChangeCallback, getParam, PromiseAllWithErrors, removeAttributeChangeCallback, toSourceId } from "../engine/engine_utils.js";
|
|
12
12
|
import { registerObservableAttribute } from "../engine/webcomponents/needle-engine.extras.js";
|
|
13
13
|
import { Camera, ClearFlags } from "./Camera.js";
|
|
14
14
|
import { Behaviour, GameObject } from "./Component.js";
|
|
@@ -27,15 +27,34 @@ function createRemoteSkyboxComponent(context: IContext, url: string, skybox: boo
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
const remote = new RemoteSkybox();
|
|
30
|
+
remote.sourceId = toSourceId(url);
|
|
30
31
|
remote.allowDrop = false;
|
|
31
32
|
remote.allowNetworking = false;
|
|
32
33
|
remote.background = skybox;
|
|
33
34
|
remote.environment = environment;
|
|
34
35
|
GameObject.addComponent(context.scene, remote);
|
|
35
36
|
const urlChanged = newValue => {
|
|
36
|
-
if (
|
|
37
|
-
if (
|
|
38
|
-
|
|
37
|
+
if (debug) console.log(attribute, "CHANGED TO", newValue);
|
|
38
|
+
if (newValue) {
|
|
39
|
+
if (typeof newValue !== "string") {
|
|
40
|
+
console.warn("Invalid attribute value for " + attribute);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
remote.setSkybox(newValue);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
if (remote.sourceId) {
|
|
47
|
+
if (environment) {
|
|
48
|
+
if (!context.sceneLighting.internalEnableReflection(remote.sourceId)) {
|
|
49
|
+
context.scene.environment = null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (skybox) {
|
|
53
|
+
const skybox = context.lightmaps.tryGetSkybox(remote.sourceId);
|
|
54
|
+
context.scene.background = skybox;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
39
58
|
};
|
|
40
59
|
addAttributeChangeCallback(context.domElement, attribute, urlChanged);
|
|
41
60
|
remote.addEventListener("destroy", () => {
|
|
@@ -50,7 +69,7 @@ ContextRegistry.registerCallback(ContextEvent.ContextCreationStart, (args) => {
|
|
|
50
69
|
const context = args.context;
|
|
51
70
|
const backgroundImage = context.domElement.getAttribute("background-image");
|
|
52
71
|
const environmentImage = context.domElement.getAttribute("environment-image");
|
|
53
|
-
|
|
72
|
+
|
|
54
73
|
if (backgroundImage) {
|
|
55
74
|
if (debug) console.log("Creating RemoteSkybox to load background " + backgroundImage);
|
|
56
75
|
// if the user is loading a GLB without a camera then the CameraUtils (which creates the default camera)
|
|
@@ -246,8 +265,8 @@ export class RemoteSkybox extends Behaviour {
|
|
|
246
265
|
envMap.needsUpdate = true;
|
|
247
266
|
}
|
|
248
267
|
|
|
249
|
-
if(this.destroyed) return;
|
|
250
|
-
if(!this.context) {
|
|
268
|
+
if (this.destroyed) return;
|
|
269
|
+
if (!this.context) {
|
|
251
270
|
console.warn("RemoteSkybox: Context is not available - can not apply skybox.");
|
|
252
271
|
return;
|
|
253
272
|
}
|
|
@@ -208,6 +208,7 @@ export { ClickThrough } from "../web/Clickthrough.js";
|
|
|
208
208
|
export { CursorFollow } from "../web/CursorFollow.js";
|
|
209
209
|
export { HoverAnimation } from "../web/HoverAnimation.js";
|
|
210
210
|
export { ScrollFollow } from "../web/ScrollFollow.js";
|
|
211
|
+
export { ViewBox } from "../web/ViewBox.js";
|
|
211
212
|
export { Avatar } from "../webxr/Avatar.js";
|
|
212
213
|
export { XRControllerFollow } from "../webxr/controllers/XRControllerFollow.js";
|
|
213
214
|
export { XRControllerModel } from "../webxr/controllers/XRControllerModel.js";
|
|
@@ -66,10 +66,19 @@ export class PlayableDirector extends Behaviour {
|
|
|
66
66
|
this.createTrackFunctions[type] = fn;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
/**
|
|
70
|
+
* The timeline asset that is played by this director.
|
|
71
|
+
*/
|
|
69
72
|
playableAsset?: Models.TimelineAssetModel;
|
|
73
|
+
|
|
70
74
|
/** Set to true to start playing the timeline when the scene starts */
|
|
71
75
|
@serializable()
|
|
72
76
|
playOnAwake?: boolean;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Determines how the timeline behaves when it reaches the end of its duration.
|
|
80
|
+
* @default DirectorWrapMode.Loop
|
|
81
|
+
*/
|
|
73
82
|
@serializable()
|
|
74
83
|
extrapolationMode: DirectorWrapMode = DirectorWrapMode.Loop;
|
|
75
84
|
|
|
@@ -106,7 +115,7 @@ export class PlayableDirector extends Behaviour {
|
|
|
106
115
|
/** @internal */
|
|
107
116
|
awake(): void {
|
|
108
117
|
if (debug)
|
|
109
|
-
console.log(this, this.playableAsset
|
|
118
|
+
console.log(this, this.playableAsset);
|
|
110
119
|
|
|
111
120
|
this.rebuildGraph();
|
|
112
121
|
|
|
@@ -92,4 +92,14 @@ export declare class SignalMarkerModel extends MarkerModel {
|
|
|
92
92
|
asset: string;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
/**
|
|
96
|
+
* Marker with a name, used for scroll-driven timelines. It is used together with elements in your HTML to define what time in the timeline should be active when the element is in the scroll view.
|
|
97
|
+
*
|
|
98
|
+
* @example Mark html elements to define scroll positions
|
|
99
|
+
* ```html
|
|
100
|
+
* <div data-timeline-marker>...</div>
|
|
101
|
+
* ```
|
|
102
|
+
*
|
|
103
|
+
* @link [Example Project using ScrollMarker](https://scrollytelling-bike-z23hmxb2gnu5a.needle.run/)
|
|
104
|
+
*/
|
|
105
|
+
export type ScrollMarkerModel = MarkerModel & { name: string };
|