@needle-tools/engine 2.62.1-pre → 2.63.0-pre
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 +20 -0
- package/dist/needle-engine.js +9983 -9692
- package/dist/needle-engine.umd.cjs +306 -223
- package/lib/engine/api.d.ts +1 -0
- package/lib/engine/api.js +1 -0
- package/lib/engine/api.js.map +1 -1
- package/lib/engine/codegen/license.d.ts +1 -0
- package/lib/engine/codegen/license.js +2 -0
- package/lib/engine/codegen/license.js.map +1 -0
- package/lib/engine/engine.js +0 -2
- package/lib/engine/engine.js.map +1 -1
- package/lib/engine/engine_camera.d.ts +4 -0
- package/lib/engine/engine_camera.js +13 -0
- package/lib/engine/engine_camera.js.map +1 -0
- package/lib/engine/engine_element.d.ts +1 -0
- package/lib/engine/engine_element.js +18 -2
- package/lib/engine/engine_element.js.map +1 -1
- package/lib/engine/engine_element_loading.js +28 -4
- package/lib/engine/engine_element_loading.js.map +1 -1
- package/lib/engine/engine_input.d.ts +2 -0
- package/lib/engine/engine_input.js +14 -0
- package/lib/engine/engine_input.js.map +1 -1
- package/lib/engine/engine_license.d.ts +1 -0
- package/lib/engine/engine_license.js +199 -0
- package/lib/engine/engine_license.js.map +1 -0
- package/lib/engine/engine_physics.d.ts +3 -0
- package/lib/engine/engine_physics.js +13 -2
- package/lib/engine/engine_physics.js.map +1 -1
- package/lib/engine/engine_setup.js +1 -1
- package/lib/engine/engine_setup.js.map +1 -1
- package/lib/engine/engine_types.d.ts +4 -0
- package/lib/engine/engine_types.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/js-extensions/Camera.d.ts +1 -0
- package/lib/engine/js-extensions/Camera.js +37 -0
- package/lib/engine/js-extensions/Camera.js.map +1 -0
- package/lib/engine/js-extensions/Layers.js +1 -0
- package/lib/engine/js-extensions/Layers.js.map +1 -1
- package/lib/engine/js-extensions/index.d.ts +2 -0
- package/lib/engine/js-extensions/index.js +3 -0
- package/lib/engine/js-extensions/index.js.map +1 -0
- package/lib/engine-components/CameraUtils.d.ts +1 -3
- package/lib/engine-components/CameraUtils.js +34 -17
- package/lib/engine-components/CameraUtils.js.map +1 -1
- package/lib/engine-components/Light.d.ts +4 -1
- package/lib/engine-components/Light.js +17 -2
- package/lib/engine-components/Light.js.map +1 -1
- package/lib/engine-components/OrbitControls.d.ts +4 -1
- package/lib/engine-components/OrbitControls.js +13 -2
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/ScreenCapture.d.ts +2 -2
- package/lib/engine-components/ScreenCapture.js +3 -1
- package/lib/engine-components/ScreenCapture.js.map +1 -1
- package/lib/engine-components/VideoPlayer.d.ts +2 -1
- package/lib/engine-components/VideoPlayer.js +9 -6
- package/lib/engine-components/VideoPlayer.js.map +1 -1
- package/lib/engine-components/timeline/TimelineTracks.js +7 -1
- package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
- package/lib/engine-components/ui/BaseUIComponent.d.ts +3 -0
- package/lib/engine-components/ui/BaseUIComponent.js +20 -10
- package/lib/engine-components/ui/BaseUIComponent.js.map +1 -1
- package/lib/engine-components/ui/Button.js +7 -3
- package/lib/engine-components/ui/Button.js.map +1 -1
- package/lib/engine-components/ui/EventSystem.js +21 -42
- package/lib/engine-components/ui/EventSystem.js.map +1 -1
- package/lib/engine-components/ui/Graphic.d.ts +1 -0
- package/lib/engine-components/ui/Graphic.js +7 -0
- package/lib/engine-components/ui/Graphic.js.map +1 -1
- package/lib/engine-components/ui/Interfaces.d.ts +2 -1
- package/lib/engine-components/ui/RaycastUtils.js +2 -0
- package/lib/engine-components/ui/RaycastUtils.js.map +1 -1
- package/lib/engine-components/ui/Text.js +10 -1
- package/lib/engine-components/ui/Text.js.map +1 -1
- package/lib/needle-engine.d.ts +2 -0
- package/lib/needle-engine.js +2 -2
- package/lib/needle-engine.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/engine/api.ts +2 -1
- package/src/engine/assets/logo.svg +1 -0
- package/src/engine/codegen/license.js +1 -0
- package/src/engine/engine.ts +0 -3
- package/src/engine/engine_camera.ts +18 -0
- package/src/engine/engine_element.ts +18 -2
- package/src/engine/engine_element_loading.ts +33 -8
- package/src/engine/engine_input.ts +17 -5
- package/src/engine/engine_license.ts +216 -0
- package/src/engine/engine_physics.ts +16 -2
- package/src/engine/engine_setup.ts +2 -1
- package/src/engine/engine_types.ts +9 -4
- package/src/engine/extensions/extension_utils.ts +1 -1
- package/src/engine/js-extensions/Camera.ts +35 -0
- package/src/engine/js-extensions/Layers.ts +2 -1
- package/src/engine/js-extensions/index.ts +2 -0
- package/src/engine-components/CameraUtils.ts +42 -20
- package/src/engine-components/Light.ts +16 -3
- package/src/engine-components/OrbitControls.ts +18 -6
- package/src/engine-components/ScreenCapture.ts +3 -2
- package/src/engine-components/VideoPlayer.ts +10 -6
- package/src/engine-components/timeline/TimelineTracks.ts +9 -3
- package/src/engine-components/ui/BaseUIComponent.ts +21 -11
- package/src/engine-components/ui/Button.ts +7 -3
- package/src/engine-components/ui/EventSystem.ts +20 -42
- package/src/engine-components/ui/Graphic.ts +7 -0
- package/src/engine-components/ui/Interfaces.ts +3 -1
- package/src/engine-components/ui/RaycastUtils.ts +2 -1
- package/src/engine-components/ui/Text.ts +11 -2
- package/src/needle-engine.ts +6 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/engine",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.63.0-pre",
|
|
4
4
|
"description": "Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally.",
|
|
5
5
|
"main": "dist/needle-engine.umd.cjs",
|
|
6
6
|
"module": "dist/needle-engine.js",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"@needle-tools/needle-component-compiler": "1.9.3",
|
|
61
61
|
"@needle-tools/helper": "^0.2.1-pre",
|
|
62
62
|
"@types/three": "0.146.0",
|
|
63
|
-
"copy-files-from-to": "^3.
|
|
63
|
+
"copy-files-from-to": "^3.7.0",
|
|
64
64
|
"esbuild": "^0.15.10",
|
|
65
65
|
"esbuild-node-externals": "^1.5.0",
|
|
66
66
|
"jsdoc-babel": "^0.5.0",
|
package/src/engine/api.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?><svg id="Ebene_3" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 160 187.74"><defs><style>.cls-1{fill:url(#Unbenannter_Verlauf_122);}.cls-2{fill:#f3e600;}.cls-3{fill:url(#Unbenannter_Verlauf_113);}.cls-4{fill:url(#gradient-6);}.cls-5{fill:url(#Unbenannter_Verlauf_110);}.cls-6{fill:url(#Unbenannter_Verlauf_101);}.cls-7{fill:#9c3;}.cls-8{fill:#ffe113;}.cls-9{fill:url(#gradient-5);}</style><linearGradient id="Unbenannter_Verlauf_113" x1="89.64" y1="184.81" x2="90.48" y2="21.85" gradientTransform="matrix(1, 0, 0, 1, 0, 0)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#62d399"/><stop offset=".51" stop-color="#acd842"/><stop offset=".9" stop-color="#d7db0a"/></linearGradient><linearGradient id="Unbenannter_Verlauf_110" x1="69.68" y1="178.9" x2="68.08" y2="16.77" gradientTransform="matrix(1, 0, 0, 1, 0, 0)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#0ba398"/><stop offset=".5" stop-color="#4ca352"/><stop offset="1" stop-color="#76a30a"/></linearGradient><linearGradient id="Unbenannter_Verlauf_101" x1="36.6" y1="152.17" x2="34.7" y2="84.19" gradientTransform="matrix(1, 0, 0, 1, 0, 0)" gradientUnits="userSpaceOnUse"><stop offset=".19" stop-color="#36a382"/><stop offset=".54" stop-color="#49a459"/><stop offset="1" stop-color="#76a30b"/></linearGradient><linearGradient id="Unbenannter_Verlauf_122" x1="15.82" y1="153.24" x2="18" y2="90.86" gradientTransform="matrix(1, 0, 0, 1, 0, 0)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#267880"/><stop offset=".51" stop-color="#457a5c"/><stop offset="1" stop-color="#717516"/></linearGradient><linearGradient id="gradient-6" x1="135.08" y1="135.43" x2="148.93" y2="63.47" gradientTransform="matrix(1, 0, 0, 1, 0, 0)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#b0d939"/><stop offset="1" stop-color="#eadb04"/></linearGradient><linearGradient id="gradient-5" x1="-4163.25" y1="2285.12" x2="-4160.81" y2="2215.34" gradientTransform="translate(4801.15 -595.25) rotate(20)" gradientUnits="userSpaceOnUse"><stop offset=".17" stop-color="#74af52"/><stop offset=".48" stop-color="#99be32"/><stop offset="1" stop-color="#c0c40a"/></linearGradient><symbol id="needle-icon" viewBox="0 0 160 187.74"><g><polygon class="cls-3" points="79.32 36.98 79.32 187.74 95 174.54 101.59 18.23 79.32 36.98"/><polygon class="cls-5" points="79.32 36.98 57.05 18.23 63.64 174.54 79.32 187.74 79.32 36.98"/><polygon class="cls-6" points="25.19 104.83 33.82 153.87 46.32 138.92 43.86 82.5 25.19 104.83"/><polygon class="cls-1" points="25.19 104.83 0 90.24 16.97 144.1 33.82 153.87 25.19 104.83"/><polygon class="cls-7" points="43.86 82.5 18.69 67.98 0 90.24 25.18 104.83 43.86 82.5"/><polygon class="cls-4" points="134.82 78.69 124.85 135.19 140.43 126.15 160 64.1 134.82 78.69"/><polygon class="cls-9" points="134.82 78.69 116.14 56.36 113.28 121.36 124.85 135.19 134.82 78.69"/><polygon class="cls-8" points="160 64.1 141.31 41.84 116.14 56.36 134.81 78.69 160 64.1"/><polygon class="cls-2" points="101.59 18.23 79.32 0 57.05 18.23 79.32 36.98 101.59 18.23"/></g></symbol></defs><use width="160" height="187.74" xlink:href="#needle-icon"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const hasLicense = false;
|
package/src/engine/engine.ts
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ICameraController } from "./engine_types";
|
|
2
|
+
import { Camera } from "three";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
const $cameraController = Symbol("cameraController");
|
|
6
|
+
|
|
7
|
+
export function getCameraController(cam: Camera): ICameraController | null {
|
|
8
|
+
return cam[$cameraController];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function setCameraController(cam: Camera, cameraController: ICameraController, active: boolean) {
|
|
12
|
+
if (active)
|
|
13
|
+
cam[$cameraController] = cameraController;
|
|
14
|
+
else{
|
|
15
|
+
if(cam[$cameraController] === cameraController)
|
|
16
|
+
cam[$cameraController] = null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -79,6 +79,12 @@ export class EngineElement extends HTMLElement implements INeedleEngineComponent
|
|
|
79
79
|
public get loadingProgress01(): number { return this._loadingProgress01; }
|
|
80
80
|
public get loadingFinished(): boolean { return this.loadingProgress01 > .999; }
|
|
81
81
|
|
|
82
|
+
public get cameraControls(): boolean {
|
|
83
|
+
const attr = this.getAttribute("camera-controls");
|
|
84
|
+
if(attr === null || attr === "False" || attr === "false" || attr === "0") return false;
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
|
|
82
88
|
public getContext(): Promise<Context> {
|
|
83
89
|
return new Promise((res, _rej) => {
|
|
84
90
|
if (this._context && this.loadingFinished) {
|
|
@@ -208,7 +214,7 @@ export class EngineElement extends HTMLElement implements INeedleEngineComponent
|
|
|
208
214
|
}
|
|
209
215
|
this._loadingProgress01 = 1;
|
|
210
216
|
if (useDefaultLoading)
|
|
211
|
-
this._loadingView?.onLoadingFinished("
|
|
217
|
+
this._loadingView?.onLoadingFinished("creating scene");
|
|
212
218
|
this.classList.remove("loading");
|
|
213
219
|
this.classList.add("loading-finished");
|
|
214
220
|
if (debug)
|
|
@@ -237,7 +243,17 @@ export class EngineElement extends HTMLElement implements INeedleEngineComponent
|
|
|
237
243
|
}
|
|
238
244
|
|
|
239
245
|
static get observedAttributes() {
|
|
240
|
-
return [
|
|
246
|
+
return [
|
|
247
|
+
"hash",
|
|
248
|
+
"src",
|
|
249
|
+
"camera-controls",
|
|
250
|
+
"loadstart",
|
|
251
|
+
"progress",
|
|
252
|
+
"loadfinished",
|
|
253
|
+
"dracoDecoderPath",
|
|
254
|
+
"dracoDecoderType",
|
|
255
|
+
"ktx2DecoderPath"
|
|
256
|
+
];
|
|
241
257
|
}
|
|
242
258
|
|
|
243
259
|
attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
|
|
@@ -64,13 +64,13 @@ export class EngineLoadingView implements ILoadingViewHandler {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
onLoadingBegin(message?: string) {
|
|
67
|
-
if(debug) console.log("Begin Loading")
|
|
67
|
+
if (debug) console.log("Begin Loading")
|
|
68
68
|
if (!this._loadingElement) {
|
|
69
69
|
for (let i = 0; i < this.container.children.length; i++) {
|
|
70
70
|
const el = this.container.children[i] as HTMLElement;
|
|
71
71
|
if (el.classList.contains(EngineLoadingView.LoadingContainerClassName)) {
|
|
72
72
|
if (!this._allowCustomLoadingElement) {
|
|
73
|
-
if(debug) console.warn("Remove custom loading container")
|
|
73
|
+
if (debug) console.warn("Remove custom loading container")
|
|
74
74
|
this.container.removeChild(el);
|
|
75
75
|
continue;
|
|
76
76
|
}
|
|
@@ -102,7 +102,7 @@ export class EngineLoadingView implements ILoadingViewHandler {
|
|
|
102
102
|
if ("index" in progress)
|
|
103
103
|
total01 = calculateProgress01(progress);
|
|
104
104
|
if (!message && "name" in progress)
|
|
105
|
-
this.setMessage(progress.name);
|
|
105
|
+
this.setMessage("loading " + progress.name);
|
|
106
106
|
}
|
|
107
107
|
this.loadingProgress = total01;
|
|
108
108
|
if (message) this.setMessage(message);
|
|
@@ -125,11 +125,14 @@ export class EngineLoadingView implements ILoadingViewHandler {
|
|
|
125
125
|
if (this._progressLoop) return;
|
|
126
126
|
let dt = 1 / 12;
|
|
127
127
|
const max = 1 - .05;
|
|
128
|
-
if(debugRendering)
|
|
128
|
+
if (debugRendering) {
|
|
129
|
+
dt = 1 / 500;
|
|
130
|
+
if (typeof debugRendering === "number") dt *= debugRendering;
|
|
131
|
+
}
|
|
129
132
|
this._progressLoop = setInterval(() => {
|
|
130
133
|
if (this.loadingProgress >= 1 && this._progress >= max) {
|
|
131
134
|
if (this._loadingElement) {
|
|
132
|
-
if(debug) console.log("Hiding loading element");
|
|
135
|
+
if (debug) console.log("Hiding loading element");
|
|
133
136
|
this._loadingElement.style.display = "none";
|
|
134
137
|
this._loadingElement.remove();
|
|
135
138
|
}
|
|
@@ -154,7 +157,7 @@ export class EngineLoadingView implements ILoadingViewHandler {
|
|
|
154
157
|
}
|
|
155
158
|
|
|
156
159
|
private createLoadingElement(existing?: HTMLElement): HTMLElement {
|
|
157
|
-
|
|
160
|
+
if (debug && !existing) console.log("Creating loading element");
|
|
158
161
|
this._loadingElement = existing || document.createElement("div");
|
|
159
162
|
if (!existing) {
|
|
160
163
|
this._loadingElement.style.position = "fixed";
|
|
@@ -186,9 +189,29 @@ export class EngineLoadingView implements ILoadingViewHandler {
|
|
|
186
189
|
loadingBarContainer.style.display = "flex";
|
|
187
190
|
loadingBarContainer.style.width = maxWidth + "%";
|
|
188
191
|
loadingBarContainer.style.height = "2px";
|
|
189
|
-
loadingBarContainer.style.background = "rgba(255,255,255,.
|
|
192
|
+
loadingBarContainer.style.background = "rgba(255,255,255,.2)"
|
|
193
|
+
// loadingBarContainer.style.alignItems = "center";
|
|
190
194
|
this._loadingElement.appendChild(loadingBarContainer);
|
|
191
195
|
|
|
196
|
+
const needleLogo = document.createElement("img");
|
|
197
|
+
loadingBarContainer.appendChild(needleLogo);
|
|
198
|
+
const logoSize = 64;
|
|
199
|
+
needleLogo.style.width = `${logoSize}px`;
|
|
200
|
+
needleLogo.style.height = `${logoSize}px`;
|
|
201
|
+
needleLogo.style.position = "absolute";
|
|
202
|
+
needleLogo.style.left = "50%";
|
|
203
|
+
needleLogo.style.transform = `translate(-${logoSize * .5}px, -${logoSize + 32}px)`;
|
|
204
|
+
needleLogo.addEventListener("click", () => window.open("https://needle.tools", "_blank"));
|
|
205
|
+
needleLogo.style.cursor = "pointer";
|
|
206
|
+
needleLogo.style.pointerEvents = "all";
|
|
207
|
+
try {
|
|
208
|
+
//@ts-ignore
|
|
209
|
+
import("./assets/logo.svg").then(res => {
|
|
210
|
+
needleLogo.src = res.default;
|
|
211
|
+
})
|
|
212
|
+
}
|
|
213
|
+
catch { }
|
|
214
|
+
|
|
192
215
|
this._loadingBar = document.createElement("div");
|
|
193
216
|
loadingBarContainer.appendChild(this._loadingBar);
|
|
194
217
|
const getGradientPos = function (t: number): string {
|
|
@@ -203,7 +226,7 @@ export class EngineLoadingView implements ILoadingViewHandler {
|
|
|
203
226
|
this._loadingTextContainer = document.createElement("div");
|
|
204
227
|
this._loadingTextContainer.style.display = "flex";
|
|
205
228
|
this._loadingTextContainer.style.justifyContent = "center";
|
|
206
|
-
this._loadingTextContainer.style.marginTop = ".
|
|
229
|
+
this._loadingTextContainer.style.marginTop = "1.2em";
|
|
207
230
|
this._loadingElement.appendChild(this._loadingTextContainer);
|
|
208
231
|
|
|
209
232
|
const messageContainer = document.createElement("div");
|
|
@@ -212,6 +235,8 @@ export class EngineLoadingView implements ILoadingViewHandler {
|
|
|
212
235
|
messageContainer.style.fontSize = ".8em";
|
|
213
236
|
messageContainer.style.paddingTop = ".5em";
|
|
214
237
|
messageContainer.style.color = "rgba(255,255,255,.5)";
|
|
238
|
+
messageContainer.style.fontWeight = "200";
|
|
239
|
+
messageContainer.style.fontFamily = "Roboto, sans-serif";
|
|
215
240
|
// messageContainer.style.border = "1px solid rgba(255,255,255,.1)";
|
|
216
241
|
messageContainer.style.justifyContent = "center";
|
|
217
242
|
this._loadingElement.appendChild(messageContainer);
|
|
@@ -220,6 +220,7 @@ export class Input extends EventTarget {
|
|
|
220
220
|
private _pointerPositionDown: THREE.Vector2[] = [new THREE.Vector2()];
|
|
221
221
|
private _pointerDownTime: number[] = [];
|
|
222
222
|
private _pointerUpTime: number[] = [];
|
|
223
|
+
private _pointerUpTimestamp: number[] = [];
|
|
223
224
|
private _pointerIds: number[] = [];
|
|
224
225
|
private _pointerTypes: string[] = [""];
|
|
225
226
|
private _mouseWheelChanged: boolean[] = [false];
|
|
@@ -411,13 +412,15 @@ export class Input extends EventTarget {
|
|
|
411
412
|
}
|
|
412
413
|
}
|
|
413
414
|
|
|
414
|
-
private onTouchUp(evt) {
|
|
415
|
+
private onTouchUp(evt: TouchEvent) {
|
|
415
416
|
if (evt.changedTouches.length <= 0) return;
|
|
416
417
|
for (let i = 0; i < evt.changedTouches.length; i++) {
|
|
417
418
|
const touch = evt.changedTouches[i];
|
|
418
|
-
const id = this.getPointerIndex(touch.identifier)
|
|
419
|
-
|
|
420
|
-
|
|
419
|
+
const id = this.getPointerIndex(touch.identifier);
|
|
420
|
+
|
|
421
|
+
if (!this.isNewEvent(evt.timeStamp, id, this._pointerUpTimestamp)) continue;
|
|
422
|
+
|
|
423
|
+
if (debug) showBalloonMessage(`touch up #${id}, identifier:${touch.identifier}`);
|
|
421
424
|
const args: PointerEventArgs = { button: id, clientX: touch.clientX, clientY: touch.clientY, pointerType: PointerType.Touch, source: evt };
|
|
422
425
|
this.onUp(args);
|
|
423
426
|
}
|
|
@@ -440,11 +443,20 @@ export class Input extends EventTarget {
|
|
|
440
443
|
private onMouseUp(evt: MouseEvent) {
|
|
441
444
|
if (evt.defaultPrevented) return;
|
|
442
445
|
let i = evt.button;
|
|
446
|
+
if (!this.isNewEvent(evt.timeStamp, i, this._pointerUpTimestamp)) return;
|
|
443
447
|
this.onUp({ button: i, clientX: evt.clientX, clientY: evt.clientY, pointerType: PointerType.Mouse, source: evt });
|
|
444
448
|
}
|
|
445
449
|
|
|
450
|
+
// Prevent the same event being handled twice (e.g. on touch we get a mouseUp and touchUp evt with the same timestamp)
|
|
451
|
+
private isNewEvent(timestamp: number, index: number, arr: number[]): boolean {
|
|
452
|
+
while (arr.length <= index) arr.push(-1);
|
|
453
|
+
if (timestamp === arr[index]) return false;
|
|
454
|
+
arr[index] = timestamp;
|
|
455
|
+
return true;
|
|
456
|
+
}
|
|
457
|
+
|
|
446
458
|
private isInRect(e: { clientX: number, clientY: number }): boolean {
|
|
447
|
-
if(this.context.isInXR) return true;
|
|
459
|
+
if (this.context.isInXR) return true;
|
|
448
460
|
const rect = this.context.domElement.getBoundingClientRect();
|
|
449
461
|
const px = e.clientX;
|
|
450
462
|
const py = e.clientY;
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { getParam } from "./engine_utils";
|
|
2
|
+
import { ContextEvent, ContextRegistry } from "./engine_context_registry";
|
|
3
|
+
import { IContext } from "./engine_types";
|
|
4
|
+
|
|
5
|
+
const debug = getParam("debuglicense");
|
|
6
|
+
|
|
7
|
+
ContextRegistry.registerCallback(ContextEvent.ContextCreated, evt => {
|
|
8
|
+
showLicenseInfo(evt.context);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
async function showLicenseInfo(ctx: IContext) {
|
|
12
|
+
try {
|
|
13
|
+
const res = await import(/* @vite-ignore */ "./codegen/license");
|
|
14
|
+
//@ts-ignore
|
|
15
|
+
if (!res || res.hasLicense !== true || debug) return onNonCommercialVersionDetected(ctx);
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
if (debug) console.log("License check failed", err)
|
|
19
|
+
return onNonCommercialVersionDetected(ctx)
|
|
20
|
+
}
|
|
21
|
+
if (debug) onNonCommercialVersionDetected(ctx)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
const _licenseText = "🌵 <span class=\"text\">Made with <a href=\"https://needle.tools\" target=\"_blank\">Needle</a></span>";
|
|
26
|
+
const licenseElementClass = "needle-license-element";
|
|
27
|
+
const licenseDuration = 30000;
|
|
28
|
+
const licenseDelay = 600;
|
|
29
|
+
|
|
30
|
+
function onNonCommercialVersionDetected(ctx: IContext) {
|
|
31
|
+
insertNonCommercialUseHint(ctx);
|
|
32
|
+
sendNonCommercialUsageMessageToAnalyticsBackend();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function insertNonCommercialUseHint(ctx: IContext) {
|
|
36
|
+
|
|
37
|
+
let licenseText = _licenseText;
|
|
38
|
+
const licenseElement = createLicenseElement();
|
|
39
|
+
licenseElement.innerHTML = licenseText;
|
|
40
|
+
|
|
41
|
+
const style = createLicenseStyle();
|
|
42
|
+
|
|
43
|
+
const interval = setInterval(() => {
|
|
44
|
+
if (!licenseElement) return;
|
|
45
|
+
if (licenseElement.parentElement !== ctx.domElement) {
|
|
46
|
+
ctx.domElement.appendChild(licenseElement);
|
|
47
|
+
if (style) ctx.domElement.appendChild(style);
|
|
48
|
+
}
|
|
49
|
+
}, 100);
|
|
50
|
+
|
|
51
|
+
logNonCommercialUse();
|
|
52
|
+
|
|
53
|
+
//@ts-ignore
|
|
54
|
+
import("./assets/logo.svg").then(res => {
|
|
55
|
+
const svgContent = res.default;
|
|
56
|
+
let svg = `<img class="logo" src="${svgContent}" style="width: 40px; height: 40px; margin-right: 2px; vertical-align: middle; margin-bottom: 2px;"/>`;
|
|
57
|
+
svg = "<a href=\"https://needle.tools\" target=\"_blank\">" + svg + "</a>";
|
|
58
|
+
licenseText = svg; //licenseText.replace("🌵", svg);
|
|
59
|
+
licenseElement.innerHTML = licenseText;
|
|
60
|
+
}).catch(err => {
|
|
61
|
+
if (debug) console.log("Failed to load logo", err);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const removeDelay = licenseDuration + licenseDelay;
|
|
65
|
+
setTimeout(() => {
|
|
66
|
+
clearInterval(interval);
|
|
67
|
+
licenseElement?.remove();
|
|
68
|
+
}, removeDelay);
|
|
69
|
+
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function logNonCommercialUse(_logo?: string) {
|
|
73
|
+
const logo = "data:image/webp;base64,UklGRrABAABXRUJQVlA4WAoAAAAQAAAAHwAAHwAAQUxQSKEAAAARN6CmbSM4WR7vdARON11EBDq3fLiNbVtVzpMCPlKAEzsx0Y/x+Ovuv4dn0EFE/ydAvz6YggXzgh5sVgXM/zOC/4sii7qgGvB5N7hmuQYwkvazWAu1JPW41FXSHq6pnaQWvqYH18Fc0j1hO/BFTtIeSBlJi5w6qIIO7IOrwhFsB2Yxukif0FTRLpXswHR8MxbslKe9VZsn/Ub5C7YFOpqSTABWUDgg6AAAAFAGAJ0BKiAAIAA+7VyoTqmkpCI3+qgBMB2JbACdMt69DwMIQBLhkTO6XwY00UEDK6cNIDnuNibPf0EgAP7Y1myuiQHLDsF/0h5unrGh6WAbv7aegg2ZMd3uRKfT/3SJztcaujYfTvMXspfCTmYcoO6a+vhC3ss4M8uM58t4siiu59I4aOl59e9Sr6xoxYlHf2v+NnBNpJYeJf8jABQAId/PXuBkLEFkiCucgSGEcfhvajql/j3reCGl0M5/9gQWy7ayNPs+wlvIxFnNfSlfuND4CZOCyxOHhRqOmHN4ULHo3tCSrUNvgAA=";
|
|
74
|
+
const style = `
|
|
75
|
+
font-size:18px;
|
|
76
|
+
background-size: contain;
|
|
77
|
+
background-position: left center;
|
|
78
|
+
background-repeat:no-repeat;
|
|
79
|
+
background-image:url('${logo}')
|
|
80
|
+
`;
|
|
81
|
+
let licenseText = "Needle Engine — non commercial version";
|
|
82
|
+
console.log("%c " + licenseText, style)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function createLicenseElement() {
|
|
86
|
+
const licenseElement = document.createElement("div");
|
|
87
|
+
licenseElement.classList.add(licenseElementClass);
|
|
88
|
+
licenseElement.setAttribute("data-needle_engine_license_element", "");
|
|
89
|
+
licenseElement.style.position = "fixed";
|
|
90
|
+
licenseElement.style.bottom = "12px";
|
|
91
|
+
licenseElement.style.right = "15px";
|
|
92
|
+
|
|
93
|
+
// licenseElement.style.textShadow = "0 0 2px rgba(200,200,200, 1)";
|
|
94
|
+
const maxPossibleZIndex = 2147483647;
|
|
95
|
+
licenseElement.style.zIndex = `${maxPossibleZIndex}`;
|
|
96
|
+
return licenseElement;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function createLicenseStyle() {
|
|
100
|
+
const licenseStyle = document.createElement("style");
|
|
101
|
+
const selector = "." + licenseElementClass;
|
|
102
|
+
licenseStyle.innerHTML = `
|
|
103
|
+
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;500&display=swap');
|
|
104
|
+
|
|
105
|
+
${selector} {
|
|
106
|
+
font-family: 'Roboto', sans-serif !important;
|
|
107
|
+
font-weight: 300;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
${selector} a {
|
|
111
|
+
color: black;
|
|
112
|
+
text-decoration: none;
|
|
113
|
+
font-weight: 500;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
@keyframes append-animate {
|
|
117
|
+
0% {
|
|
118
|
+
transform: translate(0px, 10px);
|
|
119
|
+
opacity: 0;
|
|
120
|
+
pointer-events: none;
|
|
121
|
+
}
|
|
122
|
+
1% {
|
|
123
|
+
transform: translate(0, -5px);
|
|
124
|
+
opacity: .9;
|
|
125
|
+
}
|
|
126
|
+
2% {
|
|
127
|
+
transform: translate(0, 3px);
|
|
128
|
+
}
|
|
129
|
+
6% {
|
|
130
|
+
transform: translate(0, 0px);
|
|
131
|
+
pointer-events: all;
|
|
132
|
+
opacity: 1;
|
|
133
|
+
}
|
|
134
|
+
50% {
|
|
135
|
+
transform: scale(1)
|
|
136
|
+
}
|
|
137
|
+
51% {
|
|
138
|
+
transform: scale(1.2)
|
|
139
|
+
}
|
|
140
|
+
53% {
|
|
141
|
+
transform: scale(1)
|
|
142
|
+
}
|
|
143
|
+
90% {
|
|
144
|
+
opacity: 1;
|
|
145
|
+
pointer-events: all;
|
|
146
|
+
transform: scale(1)
|
|
147
|
+
}
|
|
148
|
+
100% {
|
|
149
|
+
opacity: 0;
|
|
150
|
+
pointer-events: none;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
${selector} {
|
|
154
|
+
opacity: 0;
|
|
155
|
+
pointer-events: none;
|
|
156
|
+
animation: append-animate;
|
|
157
|
+
animation-iteration-count: 1;
|
|
158
|
+
animation-duration: ${(licenseDuration / 1000)}s;
|
|
159
|
+
animation-delay: ${licenseDelay / 1000}s;
|
|
160
|
+
animation-easing: ease-in-out;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
${selector} .text, ${selector} a {
|
|
164
|
+
color: rgb(255, 0, 0);
|
|
165
|
+
mix-blend-mode: difference;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
${selector} .logo {
|
|
169
|
+
border-radius: 50%;
|
|
170
|
+
background-color: transparent;
|
|
171
|
+
padding: 5px;
|
|
172
|
+
transition: all 0.1s ease-in-out;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
${selector} .logo:hover {
|
|
176
|
+
transform: scale(1.3);
|
|
177
|
+
cursor: pointer;
|
|
178
|
+
}
|
|
179
|
+
`
|
|
180
|
+
return licenseStyle;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
async function sendNonCommercialUsageMessageToAnalyticsBackend() {
|
|
185
|
+
try {
|
|
186
|
+
const analyticsBackendUrlForward = "https://urls.needle.tools/analytics-endpoint";
|
|
187
|
+
const res = await fetch(analyticsBackendUrlForward);
|
|
188
|
+
let analyticsUrl = await res.text();
|
|
189
|
+
if (analyticsUrl) {
|
|
190
|
+
if (debug) console.log("Analytics backend url", analyticsUrl);
|
|
191
|
+
|
|
192
|
+
// analyticsUrl = "http://localhost:3000/";
|
|
193
|
+
|
|
194
|
+
const currentUrl = window.location.href;
|
|
195
|
+
|
|
196
|
+
let endpoint = "api/v1/register/web-request";
|
|
197
|
+
if (!analyticsUrl.endsWith("/")) endpoint = "/" + endpoint;
|
|
198
|
+
const finalUrl = `${analyticsUrl}${endpoint}?type=non-commercial&url=${encodeURIComponent(currentUrl)}&hostname=${encodeURIComponent(window.location.hostname)}&pathname=${encodeURIComponent(window.location.pathname)}&search=${encodeURIComponent(window.location.search)}&hash=${encodeURIComponent(window.location.hash)}`;
|
|
199
|
+
if (debug) console.log("Sending non-commercial usage message to analytics backend", finalUrl);
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
fetch(finalUrl,
|
|
203
|
+
{
|
|
204
|
+
mode: "no-cors"
|
|
205
|
+
})
|
|
206
|
+
.catch(err => {
|
|
207
|
+
if (debug)
|
|
208
|
+
console.log("Failed to send non-commercial usage message to analytics backend", err);
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
catch (err) {
|
|
213
|
+
if (debug)
|
|
214
|
+
console.log("Failed to send non-commercial usage message to analytics backend", err);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
@@ -324,8 +324,22 @@ export class Physics {
|
|
|
324
324
|
await RAPIER.init().then(() => RAPIER)
|
|
325
325
|
Physics._didLoadPhysicsEngine = true;
|
|
326
326
|
}
|
|
327
|
-
|
|
328
|
-
|
|
327
|
+
this.world = new World(this._gravity);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
private _gravity = { x: 0.0, y: -9.81, z: 0.0 };
|
|
331
|
+
|
|
332
|
+
get gravity() {
|
|
333
|
+
return this.world?.gravity ?? this._gravity;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
set gravity(value: Vec3) {
|
|
337
|
+
if (this.world) {
|
|
338
|
+
this.world.gravity = value;
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
this._gravity = value;
|
|
342
|
+
}
|
|
329
343
|
}
|
|
330
344
|
|
|
331
345
|
clearCaches() {
|
|
@@ -504,7 +504,6 @@ export class Context implements IContext {
|
|
|
504
504
|
this.domElement.prepend(this.renderer.domElement);
|
|
505
505
|
|
|
506
506
|
Context._current = this;
|
|
507
|
-
ContextRegistry.dispatchCallback(ContextEvent.ContextCreated, this);
|
|
508
507
|
|
|
509
508
|
// Setup
|
|
510
509
|
Context._current = this;
|
|
@@ -591,6 +590,8 @@ export class Context implements IContext {
|
|
|
591
590
|
|
|
592
591
|
if (debug)
|
|
593
592
|
logHierarchy(this.scene, true);
|
|
593
|
+
|
|
594
|
+
ContextRegistry.dispatchCallback(ContextEvent.ContextCreated, this);
|
|
594
595
|
}
|
|
595
596
|
|
|
596
597
|
private render(_, frame) {
|
|
@@ -30,10 +30,11 @@ export declare type CoroutineData = {
|
|
|
30
30
|
export interface IContext {
|
|
31
31
|
alias?: string | null;
|
|
32
32
|
|
|
33
|
-
scene
|
|
34
|
-
renderer
|
|
35
|
-
mainCamera
|
|
36
|
-
|
|
33
|
+
scene: Scene;
|
|
34
|
+
renderer: WebGLRenderer;
|
|
35
|
+
mainCamera: Camera | null;
|
|
36
|
+
mainCameraComponent: ICamera | undefined;
|
|
37
|
+
domElement: HTMLElement;
|
|
37
38
|
|
|
38
39
|
scripts: IComponent[];
|
|
39
40
|
scripts_pausedChanged: IComponent[];
|
|
@@ -158,6 +159,10 @@ export declare interface ICamera extends IComponent {
|
|
|
158
159
|
screenPointToRay(x: number, y: number, ray?: Ray): Ray;
|
|
159
160
|
}
|
|
160
161
|
|
|
162
|
+
export declare interface ICameraController {
|
|
163
|
+
get isCameraController(): boolean;
|
|
164
|
+
}
|
|
165
|
+
|
|
161
166
|
export declare interface ILight extends IComponent {
|
|
162
167
|
intensity: number;
|
|
163
168
|
color: Color;
|
|
@@ -43,7 +43,7 @@ function internalResolve(paths: DependencyInfo[], parser: GLTFParser, obj, promi
|
|
|
43
43
|
// handle json pointer in string variable
|
|
44
44
|
if (typeof val === "string") {
|
|
45
45
|
const ext = resolveExtension(parser, val);
|
|
46
|
-
if (ext !== null) {
|
|
46
|
+
if (ext !== null && ext !== undefined) {
|
|
47
47
|
if (typeof ext.then === "function")
|
|
48
48
|
promises.push(ext.then(res => obj[key] = res));
|
|
49
49
|
else obj[key] = ext;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { PerspectiveCamera } from "three";
|
|
2
|
+
|
|
3
|
+
// Wrap camera FOV to allow animation of fov
|
|
4
|
+
Object.defineProperty(PerspectiveCamera.prototype, "fov", {
|
|
5
|
+
get: function () {
|
|
6
|
+
return this._fov;;
|
|
7
|
+
},
|
|
8
|
+
set: function (val) {
|
|
9
|
+
const changed = val !== this._fov;
|
|
10
|
+
this._fov = val;
|
|
11
|
+
if (changed && this.view !== undefined) this.updateProjectionMatrix();
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
Object.defineProperty(PerspectiveCamera.prototype, "near", {
|
|
16
|
+
get: function () {
|
|
17
|
+
return this._near;
|
|
18
|
+
},
|
|
19
|
+
set: function (val) {
|
|
20
|
+
const changed = val !== this._near;
|
|
21
|
+
this._near = val;
|
|
22
|
+
if (changed && this.view !== undefined) this.updateProjectionMatrix();
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
Object.defineProperty(PerspectiveCamera.prototype, "far", {
|
|
27
|
+
get: function () {
|
|
28
|
+
return this._far;
|
|
29
|
+
},
|
|
30
|
+
set: function (val) {
|
|
31
|
+
const changed = val !== this._far;
|
|
32
|
+
this._far = val;
|
|
33
|
+
if (changed && this.view !== undefined) this.updateProjectionMatrix();
|
|
34
|
+
}
|
|
35
|
+
});
|