37 lines
1.6 KiB
Python
37 lines
1.6 KiB
Python
# Packs a .gltf with external buffers and images into one self-contained .glb, which is the only
|
|
# model format Singe loads. Usage: python3 util/packGlb.py Model.gltf Model.glb
|
|
import json, os, struct, sys
|
|
src, out = sys.argv[1], sys.argv[2]
|
|
base = os.path.dirname(src)
|
|
g = json.load(open(src))
|
|
binary = bytearray()
|
|
views = g.setdefault('bufferViews', [])
|
|
def add(data):
|
|
while len(binary) % 4: binary.append(0)
|
|
off = len(binary); binary.extend(data)
|
|
return off
|
|
# Buffers: concatenate, remapping views.
|
|
offsets = []
|
|
for b in g.get('buffers', []):
|
|
data = open(os.path.join(base, b['uri']), 'rb').read()
|
|
offsets.append(add(data))
|
|
for v in views:
|
|
v['byteOffset'] = v.get('byteOffset', 0) + offsets[v.get('buffer', 0)]
|
|
v['buffer'] = 0
|
|
# Images: each becomes a buffer view with a mime type.
|
|
for img in g.get('images', []):
|
|
uri = img.pop('uri')
|
|
data = open(os.path.join(base, uri), 'rb').read()
|
|
ext = uri.lower().rsplit('.', 1)[-1]
|
|
views.append({'buffer': 0, 'byteOffset': add(data), 'byteLength': len(data)})
|
|
img['bufferView'] = len(views) - 1
|
|
img['mimeType'] = 'image/png' if ext == 'png' else 'image/jpeg'
|
|
while len(binary) % 4: binary.append(0)
|
|
g['buffers'] = [{'byteLength': len(binary)}]
|
|
js = json.dumps(g, separators=(',', ':')).encode()
|
|
while len(js) % 4: js += b' '
|
|
with open(out, 'wb') as f:
|
|
f.write(struct.pack('<4sII', b'glTF', 2, 12 + 8 + len(js) + 8 + len(binary)))
|
|
f.write(struct.pack('<II', len(js), 0x4E4F534A)); f.write(js)
|
|
f.write(struct.pack('<II', len(binary), 0x004E4942)); f.write(binary)
|
|
print(out, os.path.getsize(out), 'bytes')
|