@@ -758,7 +758,7 @@
|
|
758
758
|
|
759
759
|
const extension = name.split(".").pop();
|
760
760
|
const extensions = ["glb", "gltf", "usdz", "usd", "fbx", "obj", "mtl"];
|
761
|
-
const matchedIndex = !extension ? -1 : extensions.indexOf(extension);
|
761
|
+
const matchedIndex = !extension ? -1 : extensions.indexOf(extension.toLowerCase());
|
762
762
|
if (extension && matchedIndex >= 0) {
|
763
763
|
name = name.substring(0, name.length - extension.length - 1);
|
764
764
|
}
|
@@ -774,28 +774,27 @@
|
|
774
774
|
const isIgnored = ignoredCharacters.includes(c);
|
775
775
|
if (isIgnored) continue;
|
776
776
|
const isFirstCharacter = displayName.length === 0;
|
777
|
-
|
778
|
-
if (isFirstCharacter
|
779
|
-
|
777
|
+
|
778
|
+
if (isFirstCharacter) {
|
779
|
+
c = c.toUpperCase();
|
780
780
|
}
|
781
|
-
|
782
|
-
|
783
|
-
c = c.toUpperCase();
|
784
|
-
}
|
785
|
-
if (lastCharacterWasSpace && c === " ") continue;
|
786
|
-
if (lastCharacterWasSpace) {
|
787
|
-
c = c.toUpperCase();
|
788
|
-
}
|
789
|
-
lastCharacterWasSpace = false;
|
790
|
-
displayName += c;
|
781
|
+
if (lastCharacterWasSpace && c === " ") {
|
782
|
+
continue;
|
791
783
|
}
|
784
|
+
if (lastCharacterWasSpace) {
|
785
|
+
c = c.toUpperCase();
|
786
|
+
}
|
787
|
+
|
788
|
+
lastCharacterWasSpace = false;
|
789
|
+
displayName += c;
|
790
|
+
|
792
791
|
if (c === " ") {
|
793
792
|
lastCharacterWasSpace = true;
|
794
793
|
}
|
795
794
|
}
|
796
|
-
|
797
|
-
return displayName;
|
795
|
+
console.debug("Generated display name: \"" + name + "\" → \"" + displayName + "\"");
|
796
|
+
return displayName.trim();
|
798
797
|
}
|
799
|
-
|
798
|
+
console.debug("Loading: use default name", name);
|
800
799
|
return name;
|
801
800
|
}
|
@@ -100,10 +100,11 @@
|
|
100
100
|
export async function createLoader(url: string, context: Context): Promise<GLTFLoader | FBXLoader | USDZLoader | OBJLoader | null> {
|
101
101
|
|
102
102
|
const type = await tryDetermineFileTypeFromURL(url) || "unknown";
|
103
|
+
console.debug("Determined file type: " + type + " for url", url);
|
103
104
|
|
104
105
|
switch (type) {
|
105
106
|
case "unknown":
|
106
|
-
console.warn("Unknown file type:", url);
|
107
|
+
console.warn("Unknown file type. Assuming glTF:", url);
|
107
108
|
return new GLTFLoader();
|
108
109
|
case "fbx":
|
109
110
|
return new FBXLoader();
|
@@ -12,16 +12,16 @@
|
|
12
12
|
* This method does perform a range request to the server to get the first few bytes of the file
|
13
13
|
* If the file type can not be determined it will return "unknown"
|
14
14
|
* @param url The URL of the file
|
15
|
-
* @param
|
15
|
+
* @param useExtension If true the file type will be determined by the file extension first - if the file extension is not known it will then check the header
|
16
16
|
* @example
|
17
17
|
* ```typescript
|
18
18
|
* const url = "https://example.com/model.glb";
|
19
19
|
* const fileType = await tryDetermineFileTypeFromURL(url);
|
20
20
|
* console.log(fileType); // "glb"
|
21
21
|
*/
|
22
|
-
export async function tryDetermineFileTypeFromURL(url: string,
|
22
|
+
export async function tryDetermineFileTypeFromURL(url: string, useExtension: boolean = true): Promise<FileType> {
|
23
23
|
|
24
|
-
if (
|
24
|
+
if (useExtension) {
|
25
25
|
// We want to save on requests so we first check the file extension if there's any
|
26
26
|
// In some scenarios we might not have one (e.g. if we're dealing with blob: files or if the URL doesn't contain the filename)
|
27
27
|
// In that case we need to check the header
|
@@ -37,6 +37,7 @@
|
|
37
37
|
if (!ext?.length) {
|
38
38
|
ext = urlobj.pathname.split(".").pop()?.toUpperCase();
|
39
39
|
}
|
40
|
+
console.debug("Use file extension to determine type: " + ext);
|
40
41
|
switch (ext) {
|
41
42
|
case "GLTF":
|
42
43
|
return "gltf";
|
@@ -52,6 +53,8 @@
|
|
52
53
|
return "usda";
|
53
54
|
case "USDZ":
|
54
55
|
return "usdz";
|
56
|
+
case "OBJ":
|
57
|
+
return "obj";
|
55
58
|
}
|
56
59
|
}
|
57
60
|
|
@@ -94,29 +97,48 @@
|
|
94
97
|
|
95
98
|
// GLTF or GLB
|
96
99
|
if (bytes[0] == 103 && bytes[1] == 108 && bytes[2] == 84 && bytes[3] == 70) {
|
100
|
+
console.debug("GLTF detected");
|
97
101
|
return "glb";
|
98
102
|
}
|
99
103
|
// USDZ
|
100
104
|
if (bytes[0] == 80 && bytes[1] == 75 && bytes[2] == 3 && bytes[3] == 4) {
|
105
|
+
console.debug("USDZ detected");
|
101
106
|
return "usdz";
|
102
107
|
}
|
103
108
|
// USD
|
104
109
|
if (bytes[0] == 80 && bytes[1] == 88 && bytes[2] == 82 && bytes[3] == 45 && bytes[4] == 85 && bytes[5] == 83 && bytes[6] == 68 && bytes[7] == 67) {
|
110
|
+
console.debug("Binary USD detected");
|
105
111
|
return "usd";
|
106
112
|
}
|
107
113
|
// USDA: check if the file starts with #usda
|
108
|
-
else if(bytes[0] == 35 && bytes[1] == 117 && bytes[2] == 115 && bytes[3] == 100 && bytes[4] == 97) {
|
114
|
+
else if (bytes[0] == 35 && bytes[1] == 117 && bytes[2] == 115 && bytes[3] == 100 && bytes[4] == 97) {
|
115
|
+
console.debug("ASCII USD detected");
|
109
116
|
return "usda";
|
110
117
|
}
|
111
118
|
// FBX
|
112
119
|
if (bytes[0] == 75 && bytes[1] == 97 && bytes[2] == 121 && bytes[3] == 100 && bytes[4] == 97 && bytes[5] == 114 && bytes[6] == 97 && bytes[7] == 32) {
|
120
|
+
console.debug("Binary FBX detected");
|
113
121
|
return "fbx";
|
114
122
|
}
|
123
|
+
// ASCII FBX
|
124
|
+
else if (bytes[0] == 59 && bytes[1] == 32 && bytes[2] == 70 && bytes[3] == 66 && bytes[4] == 88 && bytes[5] == 32) {
|
125
|
+
console.debug("ASCII FBX detected");
|
126
|
+
return "fbx";
|
127
|
+
}
|
115
128
|
// OBJ - in this case exported from blender it starts with "# Blender" - we only check the first 10 bytes, technically it could still be a different file so we should do this check at the end
|
116
129
|
else if (bytes[0] == 35 && bytes[1] == 32 && bytes[2] == 66 && bytes[3] == 108 && bytes[4] == 101 && bytes[5] == 110 && bytes[6] == 100 && bytes[7] == 101 && bytes[8] == 114 && bytes[9] == 32) {
|
117
|
-
|
130
|
+
console.debug("OBJ detected");
|
118
131
|
return "obj";
|
119
132
|
}
|
133
|
+
// Check if it starts "# Alias OBJ"
|
134
|
+
else if (bytes[0] == 35 && bytes[1] == 32 && bytes[2] == 65 && bytes[3] == 108 && bytes[4] == 105 && bytes[5] == 97 && bytes[6] == 115 && bytes[7] == 32 && bytes[8] == 79 && bytes[9] == 66 && bytes[10] == 74) {
|
135
|
+
console.debug("OBJ detected");
|
136
|
+
return "obj";
|
137
|
+
}
|
138
|
+
else {
|
139
|
+
// const text = new TextDecoder().decode(data.slice(0, 9));
|
140
|
+
console.debug("Could not determine file type from binary data", bytes);
|
141
|
+
}
|
120
142
|
|
121
143
|
// const text = new TextDecoder().decode(data);
|
122
144
|
// if (text.startsWith("Kaydara FBX")) {
|
@@ -487,6 +487,7 @@
|
|
487
487
|
}
|
488
488
|
.compact .options {
|
489
489
|
flex-wrap: wrap;
|
490
|
+
gap: .3rem;
|
490
491
|
}
|
491
492
|
.compact .top .options {
|
492
493
|
height: auto;
|
@@ -550,6 +551,7 @@
|
|
550
551
|
.compact .options > button {
|
551
552
|
display: flex;
|
552
553
|
flex-basis: 100%;
|
554
|
+
min-height: 3rem;
|
553
555
|
}
|
554
556
|
.compact .options > button.row2 {
|
555
557
|
//border: 1px solid red !important;
|