@@ -4,13 +4,9 @@
|
|
4
4
|
import { serializable } from "../engine/engine_serialization_decorator";
|
5
5
|
import { Networking } from "../engine-components/Networking";
|
6
6
|
import { GLTF } from "three/examples/jsm/loaders/GLTFLoader";
|
7
|
+
import { getParam } from "../engine/engine_utils";
|
7
8
|
|
8
|
-
|
9
|
-
// console.log(res);
|
10
|
-
// const gltf = await parseSync(res);
|
11
|
-
// scene.add(gltf.scene);
|
12
|
-
// console.log("GLTF", gltf);
|
13
|
-
// });
|
9
|
+
const debug = getParam("debugdroplistener");
|
14
10
|
|
15
11
|
export enum DropListenerEvents {
|
16
12
|
ObjectAdded = "object-added",
|
@@ -23,43 +19,29 @@
|
|
23
19
|
filesBackendUrl?: string;
|
24
20
|
|
25
21
|
@serializable()
|
26
|
-
localhost?:string;
|
27
|
-
|
28
|
-
private _dragOver!: (evt: DragEvent) => void;
|
29
|
-
private _drop!: (evt: DragEvent) => void;
|
22
|
+
localhost?: string;
|
30
23
|
|
24
|
+
|
31
25
|
onEnable(): void {
|
32
|
-
this.filesBackendUrl =
|
26
|
+
this.filesBackendUrl = Networking.GetUrl(this.filesBackendUrl, this.localhost) ?? this.filesBackendUrl;
|
27
|
+
if (debug) console.log(this, this.filesBackendUrl);
|
33
28
|
|
34
|
-
this.
|
35
|
-
this.
|
36
|
-
this.context.domElement.addEventListener("dragover", this._dragOver);
|
37
|
-
this.context.domElement.addEventListener("drop", this._drop);
|
29
|
+
this.context.domElement.addEventListener("dragover", this.onDrag);
|
30
|
+
this.context.domElement.addEventListener("drop", this.onDrop);
|
38
31
|
}
|
39
32
|
|
40
33
|
onDisable(): void {
|
41
|
-
this.context.domElement.removeEventListener("dragover", this.
|
42
|
-
this.context.domElement.removeEventListener("drop", this.
|
34
|
+
this.context.domElement.removeEventListener("dragover", this.onDrag);
|
35
|
+
this.context.domElement.removeEventListener("drop", this.onDrop);
|
43
36
|
}
|
44
37
|
|
45
|
-
private onDrag(evt: DragEvent) {
|
38
|
+
private onDrag = (evt: DragEvent) => {
|
46
39
|
// necessary to get drop event
|
47
40
|
evt.preventDefault();
|
48
41
|
}
|
49
42
|
|
50
|
-
async
|
51
|
-
|
52
|
-
if (!file) continue;
|
53
|
-
console.log("Register file " + file.name + " to", this.filesBackendUrl, file);
|
54
|
-
const res = await files.addFile(file, this.context, this.filesBackendUrl);
|
55
|
-
this.dispatchEvent(new CustomEvent(DropListenerEvents.FileDropped, { detail: file }));
|
56
|
-
if (res)
|
57
|
-
this.addObject(undefined, res);
|
58
|
-
}
|
59
|
-
}
|
60
|
-
|
61
|
-
private async onDrop(evt: DragEvent) {
|
62
|
-
console.log(evt);
|
43
|
+
private onDrop = async (evt: DragEvent) => {
|
44
|
+
if (debug) console.log(evt);
|
63
45
|
if (!evt.dataTransfer) return;
|
64
46
|
evt.preventDefault();
|
65
47
|
const items = evt.dataTransfer.items;
|
@@ -70,15 +52,11 @@
|
|
70
52
|
if (it.kind === "file") {
|
71
53
|
const file = it.getAsFile();
|
72
54
|
if (!file) continue;
|
73
|
-
|
74
|
-
const res = await files.addFile(file, this.context, this.filesBackendUrl);
|
75
|
-
this.dispatchEvent(new CustomEvent(DropListenerEvents.FileDropped, { detail: file }));
|
76
|
-
if (res)
|
77
|
-
this.addObject(evt, res);
|
55
|
+
await this.addFiles(file);
|
78
56
|
}
|
79
57
|
else if (it.kind === "string" && it.type == "text/plain") {
|
80
58
|
it.getAsString(async str => {
|
81
|
-
console.log("dropped url", str);
|
59
|
+
if (debug) console.log("dropped url", str);
|
82
60
|
try {
|
83
61
|
const url = new URL(str);
|
84
62
|
if (!url) return;
|
@@ -94,9 +72,24 @@
|
|
94
72
|
}
|
95
73
|
}
|
96
74
|
|
75
|
+
async addFiles(...fileList: Array<File>) {
|
76
|
+
if(debug) console.log("Add files", fileList)
|
77
|
+
if (!Array.isArray(fileList)) return;
|
78
|
+
if (!fileList.length) return;
|
79
|
+
|
80
|
+
for (const file of fileList) {
|
81
|
+
if (!file) continue;
|
82
|
+
if (debug) console.log("Register file " + file.name + " to", this.filesBackendUrl, file);
|
83
|
+
const res = await files.addFile(file, this.context, this.filesBackendUrl);
|
84
|
+
this.dispatchEvent(new CustomEvent(DropListenerEvents.FileDropped, { detail: file }));
|
85
|
+
if (res)
|
86
|
+
this.addObject(undefined, res);
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
97
90
|
private async addObject(evt: DragEvent | undefined, gltf: GLTF) {
|
98
|
-
console.log("Dropped", gltf);
|
99
|
-
|
91
|
+
if (debug) console.log("Dropped", gltf);
|
92
|
+
|
100
93
|
const obj = gltf.scene;
|
101
94
|
if (evt !== undefined) {
|
102
95
|
const opts = new RaycastOptions();
|
@@ -99,9 +99,9 @@
|
|
99
99
|
if (debug)
|
100
100
|
console.warn("BufferAttribute dispose not supported", obj.count);
|
101
101
|
}
|
102
|
-
else if (obj instanceof Array
|
102
|
+
else if (obj instanceof Array) {
|
103
103
|
for (const entry of obj) {
|
104
|
-
if (entry)
|
104
|
+
if (entry instanceof Material)
|
105
105
|
disposeObjectResources(entry);
|
106
106
|
}
|
107
107
|
}
|
@@ -72,8 +72,7 @@
|
|
72
72
|
});
|
73
73
|
}
|
74
74
|
else {
|
75
|
-
console.warn("Unsupported file type: " + name)
|
76
|
-
console.log(file);
|
75
|
+
console.warn("Unsupported file type: " + name, file)
|
77
76
|
}
|
78
77
|
|
79
78
|
return null;
|
@@ -118,7 +117,7 @@
|
|
118
117
|
}
|
119
118
|
if (bin) {
|
120
119
|
const prov = new InstantiateIdProvider(evt.seed);
|
121
|
-
const gltf = await getLoader().parseSync(context, bin,
|
120
|
+
const gltf = await getLoader().parseSync(context, bin, evt.file_name, prov);
|
122
121
|
if (gltf && gltf.scene) {
|
123
122
|
const obj = gltf.scene;
|
124
123
|
def.onDynamicObjectAdded(obj, prov, gltf);
|
@@ -129,7 +128,7 @@
|
|
129
128
|
// add object to proper parent
|
130
129
|
if (evt.parentGuid) {
|
131
130
|
const parent = findByGuid(evt.parentGuid, context.scene) as Object3D;
|
132
|
-
if ("add" in parent) parent.add(obj);
|
131
|
+
if (parent && "add" in parent) parent.add(obj);
|
133
132
|
}
|
134
133
|
if (!obj.parent)
|
135
134
|
context.scene.add(obj);
|
@@ -2,8 +2,6 @@
|
|
2
2
|
// see https://github.com/pvorb/node-md5/issues/52
|
3
3
|
import md5 from "md5";
|
4
4
|
|
5
|
-
// const backend_url = null;// "https://needle-storage-castle-demo.glitch.me";
|
6
|
-
|
7
5
|
export class Upload_Result {
|
8
6
|
success: boolean;
|
9
7
|
filename: string | null;
|
@@ -48,7 +48,7 @@
|
|
48
48
|
}
|
49
49
|
|
50
50
|
|
51
|
-
public static GetUrl(url: string, localhostFallback?: string | null): string {
|
51
|
+
public static GetUrl(url: string | null | undefined, localhostFallback?: string | null): string | null | undefined {
|
52
52
|
|
53
53
|
let result = url;
|
54
54
|
|
@@ -568,5 +568,5 @@
|
|
568
568
|
|
569
569
|
|
570
570
|
const unsupportedStyleNames = [
|
571
|
-
"medium", "mediumitalic", "black", "blackitalic", "thin", "thinitalic", "extrabold", "light", "lightitalic"
|
571
|
+
"medium", "mediumitalic", "black", "blackitalic", "thin", "thinitalic", "extrabold", "light", "lightitalic", "semibold"
|
572
572
|
]
|
@@ -68,7 +68,6 @@
|
|
68
68
|
|
69
69
|
private link!: HTMLAnchorElement;
|
70
70
|
private webxr?: WebXR;
|
71
|
-
private webARSessionRoot: WebARSessionRoot | undefined;
|
72
71
|
|
73
72
|
start() {
|
74
73
|
if (debug) {
|
@@ -107,7 +106,6 @@
|
|
107
106
|
if (debug || (ios && safari)) {
|
108
107
|
if (debug || this.allowCreateQuicklookButton)
|
109
108
|
this.addQuicklookButton();
|
110
|
-
this.webARSessionRoot = GameObject.findObjectOfType(WebARSessionRoot) ?? undefined;
|
111
109
|
this.lastCallback = this.quicklookCallback.bind(this);
|
112
110
|
this.link = ensureQuicklookLinkIsCreated(this.context);
|
113
111
|
this.link.addEventListener('message', this.lastCallback);
|
@@ -144,6 +142,7 @@
|
|
144
142
|
|
145
143
|
// ability to specify a custom USDZ file to be used instead of a dynamic one
|
146
144
|
if (this.customUsdzFile) {
|
145
|
+
if(debug) console.log("Exporting custom usdz", this.customUsdzFile)
|
147
146
|
|
148
147
|
// see https://developer.apple.com/documentation/arkit/adding_an_apple_pay_button_or_a_custom_action_in_ar_quick_look
|
149
148
|
const overlay = this.buildQuicklookOverlay();
|
@@ -153,7 +152,7 @@
|
|
153
152
|
const checkoutSubtitle = overlay.checkoutSubtitle ? encodeURIComponent(overlay.checkoutSubtitle) : "";
|
154
153
|
this.link.href = this.customUsdzFile + `#callToAction=${callToAction}&checkoutTitle=${checkoutTitle}&checkoutSubtitle=${checkoutSubtitle}&callToActionURL=${overlay.callToActionURL}`;
|
155
154
|
|
156
|
-
console.log(this.link.href)
|
155
|
+
if(debug) console.log(this.link.href)
|
157
156
|
|
158
157
|
if (!this.lastCallback) {
|
159
158
|
this.lastCallback = this.quicklookCallback.bind(this)
|
@@ -182,17 +181,10 @@
|
|
182
181
|
}
|
183
182
|
if (debug) showBalloonMessage("Load textures: " + progressiveLoading.length);
|
184
183
|
await Promise.all(progressiveLoading);
|
185
|
-
if(debug) showBalloonMessage("Load textures: done");
|
184
|
+
if (debug) showBalloonMessage("Load textures: done");
|
186
185
|
|
187
186
|
// make sure we apply the AR scale
|
188
|
-
|
189
|
-
const scene = this.webARSessionRoot.gameObject;
|
190
|
-
const scale = 1 / this.webARSessionRoot!.arScale;
|
191
|
-
scene.matrix.makeScale(scale, scale, scale);
|
192
|
-
if (this.webARSessionRoot.invertForward) {
|
193
|
-
scene.matrix.multiply(new Matrix4().makeRotationY(Math.PI));
|
194
|
-
}
|
195
|
-
}
|
187
|
+
this.applyWebARSessionRoot();
|
196
188
|
|
197
189
|
const exporter = new ThreeUSDZExporter();
|
198
190
|
const extensions: any = [...this.extensions]
|
@@ -298,12 +290,15 @@
|
|
298
290
|
obj.checkoutTitle = "🌵 Made with Needle";
|
299
291
|
obj.checkoutSubtitle = "_";
|
300
292
|
}
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
293
|
+
const needsDefaultValues = obj.callToAction?.length || obj.checkoutTitle?.length || obj.checkoutSubtitle?.length;
|
294
|
+
if (needsDefaultValues) {
|
295
|
+
if (!obj.callToAction?.length)
|
296
|
+
obj.callToAction = "\0";
|
297
|
+
if (!obj.checkoutTitle?.length)
|
298
|
+
obj.checkoutTitle = "\0";
|
299
|
+
if (!obj.checkoutSubtitle?.length)
|
300
|
+
obj.checkoutSubtitle = "\0";
|
301
|
+
}
|
307
302
|
// Use the quicklook-overlay event to customize the overlay
|
308
303
|
this.dispatchEvent(new CustomEvent("quicklook-overlay", { detail: obj }));
|
309
304
|
return obj;
|
@@ -378,4 +373,31 @@
|
|
378
373
|
private removeQuicklookButton() {
|
379
374
|
this._quicklookButton?.remove();
|
380
375
|
}
|
376
|
+
|
377
|
+
private applyWebARSessionRoot() {
|
378
|
+
if(debug) console.log("applyWebARSessionRoot")
|
379
|
+
if (!this.objectToExport) return;
|
380
|
+
|
381
|
+
// first check if the sessionroot is in the parent hierarchy
|
382
|
+
// if that's the case we apply the scale to the object being exported
|
383
|
+
let sessionRoot = GameObject.getComponentInParent(this.objectToExport, WebARSessionRoot);
|
384
|
+
const hasSessionRootInParentHierarchy = sessionRoot !== null && sessionRoot !== undefined;
|
385
|
+
// if it's not in the parent hierarchy BUT in the child hierarchy we apply it to the sessionRoot object itself
|
386
|
+
// that#s the case when no objectToExport is explictly assigned and the whole scene is being exported
|
387
|
+
if(!sessionRoot) sessionRoot = GameObject.getComponentInChildren(this.objectToExport, WebARSessionRoot);
|
388
|
+
|
389
|
+
if (!sessionRoot) {
|
390
|
+
if(debug) console.warn("No WebARSessionRoot found in parent hierarchy", this.objectToExport);
|
391
|
+
return;
|
392
|
+
}
|
393
|
+
|
394
|
+
// either apply the scale to the object being exported or to the sessionRoot object itself
|
395
|
+
const target = hasSessionRootInParentHierarchy ? this.objectToExport : sessionRoot.gameObject;
|
396
|
+
const scale = 1 / sessionRoot!.arScale;
|
397
|
+
if(debug) console.log("Scale", scale, target);
|
398
|
+
target.matrix.makeScale(scale, scale, scale);
|
399
|
+
if (sessionRoot.invertForward) {
|
400
|
+
target.matrix.multiply(new Matrix4().makeRotationY(Math.PI));
|
401
|
+
}
|
402
|
+
}
|
381
403
|
}
|