mirror of
https://github.com/syoyo/tinygltf.git
synced 2026-08-13 08:49:35 +00:00
web/ compiles the v3 C runtime with emcc (Emscripten SDK from ~/work/emsdk by default) and ships a simple browser demo that loads glTF/GLB files via drag & drop and renders them with three.js: - loader.c: C bridge exporting flattened primitives, materials, textures (bufferView + data-URI paths) and the scene graph to JS - main.js/index.html/style.css: three.js viewer (OrbitControls, PBR materials, textures, node hierarchy, primitive modes) - gen_sample.py: generates a small self-contained textured Cube.glb sample from tracked assets (no large binaries committed) - Makefile: emcc build (MODULARIZE + ES6, no filesystem), sample generation and local http server targets Verified end-to-end: native bridge tests, Node harness exercising the WASM exports (parse, geometry, images, clear) and HTTP serving.
109 lines
4.0 KiB
Python
109 lines
4.0 KiB
Python
#!/usr/bin/env python3
|
|
"""Generate a small self-contained textured cube GLB (web/Cube.glb).
|
|
|
|
Uses the tracked Cube assets from models/ (Cube.gltf geometry in Cube.bin)
|
|
plus a tiny checkerboard PNG generated with only the standard library, so
|
|
the demo ships without large binary assets.
|
|
"""
|
|
|
|
import base64
|
|
import json
|
|
import struct
|
|
import sys
|
|
import zlib
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
BIN = ROOT / "models" / "Cube" / "Cube.bin"
|
|
OUT = Path(__file__).resolve().parent / "Cube.glb"
|
|
|
|
|
|
def make_png(width=64, height=64, rgb=(230, 140, 60), rgb2=(245, 245, 245)):
|
|
"""Minimal zlib-based RGB PNG writer."""
|
|
def chunk(tag, data):
|
|
c = tag + data
|
|
return struct.pack(">I", len(data)) + c + struct.pack(">I", zlib.crc32(c) & 0xFFFFFFFF)
|
|
|
|
ihdr = struct.pack(">IIBBBBB", width, height, 8, 2, 0, 0, 0) # 8-bit RGB
|
|
raw = bytearray()
|
|
for y in range(height):
|
|
raw.append(0) # filter: none
|
|
for x in range(width):
|
|
c = rgb if (x // 8 + y // 8) % 2 == 0 else rgb2
|
|
raw += bytes(c)
|
|
return (
|
|
b"\x89PNG\r\n\x1a\n"
|
|
+ chunk(b"IHDR", ihdr)
|
|
+ chunk(b"IDAT", zlib.compress(bytes(raw), 9))
|
|
+ chunk(b"IEND", b"")
|
|
)
|
|
|
|
|
|
def main():
|
|
bin_data = BIN.read_bytes()
|
|
|
|
png = make_png()
|
|
total = len(bin_data) + len(png)
|
|
|
|
j = {
|
|
"asset": {"version": "2.0", "generator": "tinygltf web demo (gen_sample.py)"},
|
|
"scene": 0,
|
|
"scenes": [{"nodes": [0]}],
|
|
"nodes": [{"mesh": 0, "name": "Cube"}],
|
|
"meshes": [{
|
|
"primitives": [{
|
|
"attributes": {
|
|
"POSITION": 1, "NORMAL": 2, "TANGENT": 3, "TEXCOORD_0": 4,
|
|
},
|
|
"indices": 0,
|
|
"material": 0,
|
|
}]
|
|
}],
|
|
"materials": [{
|
|
"name": "checker",
|
|
"pbrMetallicRoughness": {
|
|
"baseColorFactor": [1.0, 1.0, 1.0, 1.0],
|
|
"baseColorTexture": {"index": 0},
|
|
"metallicFactor": 0.0,
|
|
"roughnessFactor": 1.0,
|
|
},
|
|
}],
|
|
"textures": [{"source": 0, "sampler": 0}],
|
|
"images": [{"bufferView": 5, "mimeType": "image/png"}],
|
|
"samplers": [{"magFilter": 9729, "minFilter": 9987, "wrapS": 10497, "wrapT": 10497}],
|
|
"buffers": [{"byteLength": total}],
|
|
"bufferViews": [
|
|
{"buffer": 0, "byteOffset": 0, "byteLength": 72, "target": 34963}, # indices
|
|
{"buffer": 0, "byteOffset": 72, "byteLength": 432, "target": 34962}, # positions
|
|
{"buffer": 0, "byteOffset": 504, "byteLength": 432, "target": 34962}, # normals
|
|
{"buffer": 0, "byteOffset": 936, "byteLength": 576, "target": 34962}, # tangents
|
|
{"buffer": 0, "byteOffset": 1512, "byteLength": 288, "target": 34962}, # uvs
|
|
{"buffer": 0, "byteOffset": len(bin_data), "byteLength": len(png)}, # image
|
|
],
|
|
"accessors": [
|
|
{"bufferView": 0, "componentType": 5123, "count": 36, "type": "SCALAR", "min": [0], "max": [35]},
|
|
{"bufferView": 1, "componentType": 5126, "count": 36, "type": "VEC3", "min": [-1, -1, -1], "max": [1, 1, 1]},
|
|
{"bufferView": 2, "componentType": 5126, "count": 36, "type": "VEC3"},
|
|
{"bufferView": 3, "componentType": 5126, "count": 36, "type": "VEC4"},
|
|
{"bufferView": 4, "componentType": 5126, "count": 36, "type": "VEC2"},
|
|
],
|
|
}
|
|
|
|
json_chunk = json.dumps(j, separators=(",", ":")).encode("utf-8")
|
|
json_chunk += b" " * ((4 - len(json_chunk) % 4) % 4)
|
|
bin_chunk = bin_data + png
|
|
bin_chunk += b"\x00" * ((4 - len(bin_chunk) % 4) % 4)
|
|
|
|
total_len = 12 + 8 + len(json_chunk) + 8 + len(bin_chunk)
|
|
glb = struct.pack("<4sII", b"glTF", 2, total_len)
|
|
glb += struct.pack("<II", len(json_chunk), 0x4E4F534A) + json_chunk
|
|
glb += struct.pack("<II", len(bin_chunk), 0x004E4942) + bin_chunk
|
|
|
|
OUT.write_bytes(glb)
|
|
print(f"wrote {OUT} ({len(glb)} bytes, image {len(png)} bytes)")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|