Produce a Blender-friendly copy of the bistro glTF. Bloom's bistro.gltf lists every texture twice: once as `foo.png` (the original source from FBX2glTF) and once as `foo.dds` via the `MSFT_texture_dds` extension. The `.png` files were removed after `etcpak.sh` converted them to BC7
(src_path)
| 184 | |
| 185 | |
| 186 | def sanitize_gltf_for_blender(src_path): |
| 187 | """Produce a Blender-friendly copy of the bistro glTF. |
| 188 | |
| 189 | Bloom's bistro.gltf lists every texture twice: once as `foo.png` (the |
| 190 | original source from FBX2glTF) and once as `foo.dds` via the |
| 191 | `MSFT_texture_dds` extension. The `.png` files were removed after |
| 192 | `etcpak.sh` converted them to BC7 DDS, so Blender's glTF importer |
| 193 | crashes trying to pack the missing PNGs. |
| 194 | |
| 195 | Blender 5.0 can load DDS natively, so we generate a patched copy with |
| 196 | every missing `.png` URI rewritten to its existing `.dds` sibling and |
| 197 | the MSFT_texture_dds extension stripped from textures. The patched |
| 198 | file is cached next to the original so we only do this once. |
| 199 | """ |
| 200 | base_dir = os.path.dirname(src_path) |
| 201 | out_path = os.path.join(base_dir, "bistro_blender.gltf") |
| 202 | |
| 203 | # Regenerate if missing or older than source |
| 204 | if (os.path.isfile(out_path) |
| 205 | and os.path.getmtime(out_path) >= os.path.getmtime(src_path)): |
| 206 | return out_path |
| 207 | |
| 208 | with open(src_path, "r") as f: |
| 209 | g = json.load(f) |
| 210 | |
| 211 | patched = 0 |
| 212 | for im in g.get("images", []): |
| 213 | uri = im.get("uri", "") |
| 214 | if not uri: |
| 215 | continue |
| 216 | full = os.path.join(base_dir, uri) |
| 217 | if os.path.exists(full): |
| 218 | continue |
| 219 | if uri.lower().endswith(".png"): |
| 220 | dds = uri[:-4] + ".dds" |
| 221 | if os.path.exists(os.path.join(base_dir, dds)): |
| 222 | im["uri"] = dds |
| 223 | patched += 1 |
| 224 | |
| 225 | # Strip MSFT_texture_dds extension from textures — each texture now |
| 226 | # resolves directly to the DDS source (or an untouched real PNG). |
| 227 | for tex in g.get("textures", []): |
| 228 | exts = tex.get("extensions") |
| 229 | if exts and "MSFT_texture_dds" in exts: |
| 230 | del exts["MSFT_texture_dds"] |
| 231 | if not exts: |
| 232 | del tex["extensions"] |
| 233 | used = g.get("extensionsUsed", []) |
| 234 | if "MSFT_texture_dds" in used: |
| 235 | used.remove("MSFT_texture_dds") |
| 236 | |
| 237 | with open(out_path, "w") as f: |
| 238 | json.dump(g, f) |
| 239 | print(f"[cycles_reference] wrote sanitized gltf ({patched} png->dds URIs): {out_path}") |
| 240 | return out_path |
| 241 | |
| 242 | |
| 243 | def import_scene_gltf(): |
no test coverage detected