(bytes: &[u8])
| 158 | const CHUNK_BIN: u32 = 0x004E4942; // "BIN\0" |
| 159 | |
| 160 | fn parse_glb(bytes: &[u8]) -> Option<Model> { |
| 161 | if bytes.len() < 12 { return None; } |
| 162 | if u32_le(bytes, 0) != GLB_MAGIC { return None; } |
| 163 | let _version = u32_le(bytes, 4); |
| 164 | let _total_len = u32_le(bytes, 8); |
| 165 | |
| 166 | // Walk chunks. Expect JSON first, then BIN. |
| 167 | let mut off = 12usize; |
| 168 | let mut json_bytes: &[u8] = &[]; |
| 169 | let mut bin_bytes: &[u8] = &[]; |
| 170 | while off + 8 <= bytes.len() { |
| 171 | let chunk_len = u32_le(bytes, off) as usize; |
| 172 | let chunk_type = u32_le(bytes, off + 4); |
| 173 | let data_start = off + 8; |
| 174 | let data_end = data_start + chunk_len; |
| 175 | if data_end > bytes.len() { break; } |
| 176 | let data = &bytes[data_start..data_end]; |
| 177 | match chunk_type { |
| 178 | CHUNK_JSON => json_bytes = data, |
| 179 | CHUNK_BIN => bin_bytes = data, |
| 180 | _ => {} |
| 181 | } |
| 182 | off = data_end; |
| 183 | } |
| 184 | if json_bytes.is_empty() { return None; } |
| 185 | |
| 186 | let json = std::str::from_utf8(json_bytes).ok()?; |
| 187 | let root = json_parse(json)?; |
| 188 | |
| 189 | let meshes_js = root.get("meshes")?.arr()?; |
| 190 | let accessors = root.get("accessors")?.arr()?; |
| 191 | let buf_views = root.get("bufferViews")?.arr()?; |
| 192 | |
| 193 | let mut meshes: Vec<Mesh> = Vec::with_capacity(meshes_js.len()); |
| 194 | for mesh_js in meshes_js { |
| 195 | let prims_js = match mesh_js.get("primitives").and_then(|v| v.arr()) { |
| 196 | Some(p) => p, |
| 197 | None => continue, |
| 198 | }; |
| 199 | let mut primitives: Vec<Primitive> = Vec::with_capacity(prims_js.len()); |
| 200 | for prim in prims_js { |
| 201 | if let Some(p) = parse_primitive(prim, &root, accessors, buf_views, bin_bytes) { |
| 202 | primitives.push(p); |
| 203 | } |
| 204 | } |
| 205 | meshes.push(Mesh { primitives }); |
| 206 | } |
| 207 | if meshes.is_empty() { return None; } |
| 208 | |
| 209 | // Parse nodes + scenes (glTF hierarchy). |
| 210 | let mut nodes: Vec<Node> = Vec::new(); |
| 211 | if let Some(nodes_js) = root.get("nodes").and_then(|v| v.arr()) { |
| 212 | nodes.reserve(nodes_js.len()); |
| 213 | for n in nodes_js { |
| 214 | nodes.push(parse_node(n)); |
| 215 | } |
| 216 | } |
| 217 | let mut scene_roots: Vec<usize> = Vec::new(); |
no test coverage detected