Needle Engine

Changes between version 3.47.6 and 3.47.7
Files changed (4) hide show
  1. src/engine/engine_element.ts +16 -17
  2. src/engine/engine_scenetools.ts +2 -1
  3. src/engine/engine_utils_format.ts +27 -5
  4. src/engine/webcomponents/needle menu/needle-menu.ts +2 -0
src/engine/engine_element.ts CHANGED
@@ -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
- const isNumber = c >= '0' && c <= '9';
778
- if (isFirstCharacter == false && c === c.toUpperCase() && !isNumber) {
779
- displayName += " " + c;
777
+
778
+ if (isFirstCharacter) {
779
+ c = c.toUpperCase();
780
780
  }
781
- else {
782
- if (isFirstCharacter) {
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
- if (debug) console.log("displayName", name, displayName);
797
- return displayName;
795
+ console.debug("Generated display name: \"" + name + "\" → \"" + displayName + "\"");
796
+ return displayName.trim();
798
797
  }
799
- if (debug) console.log("displayName", name);
798
+ console.debug("Loading: use default name", name);
800
799
  return name;
801
800
  }
src/engine/engine_scenetools.ts CHANGED
@@ -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();
src/engine/engine_utils_format.ts CHANGED
@@ -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 lazy 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
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, lazy: boolean = true): Promise<FileType> {
22
+ export async function tryDetermineFileTypeFromURL(url: string, useExtension: boolean = true): Promise<FileType> {
23
23
 
24
- if (lazy) {
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
- // const text = new TextDecoder().decode(data.slice(0, 9));
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")) {
src/engine/webcomponents/needle menu/needle-menu.ts CHANGED
@@ -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;