2026-07-16 15:21:09 -05:00

129 lines
3.4 KiB
Python

import sys
import struct
from itertools import chain
from dataclasses import dataclass
from obj import tangent
with open(sys.argv[1], 'r') as f:
lines = f.read().split('\n')
position = []
texture = []
normal = []
faces = []
def parse_vertex(prefix, s):
return s.removeprefix(prefix).strip().split()
def float_vector(l, n):
v = list(map(float, l))
assert len(v) == n
return v
vertex_types = [
("v ", position, 3),
("vn ", normal, 3),
("vt ", texture, 2),
]
ignore_prefixes = ["#", "mtllib ", "usemtl ", "o ", "s "]
def parse_line(line):
if not line.strip():
return
for prefix in ignore_prefixes:
if line.startswith(prefix):
return
for prefix, out, n in vertex_types:
if line.startswith(prefix):
out.append(float_vector(parse_vertex(prefix, line), n))
return
if line.startswith("f "):
vertices = [
tuple(int(i)-1 for i in vertex.split("/"))
for vertex in parse_vertex("f ", line)
]
assert len(vertices) == 3, vertices # is not triangle
faces.append(vertices)
return
assert False, repr(line) # unhandled line prefix
for line in lines:
parse_line(line)
vertex_buffer_keys = dict()
vertex_buffer = []
index_buffer = []
for face in faces:
for vertex in face:
if vertex not in vertex_buffer_keys:
vertex_buffer_keys[vertex] = len(vertex_buffer)
vertex_buffer.append(tuple(chain(
position[vertex[0]],
texture[vertex[1]],
normal[vertex[2]],
)))
index_buffer.append(vertex_buffer_keys[vertex])
def render_vertex(f, vertex, tangent):
# extra padding zero for normal R16G16B16A16
# position texture normal tangent
stride = struct.pack("<" + "fff" + "ff" + "eeee" + "eeee", *vertex, 0, *tangent)
print(vertex, tangent)
#print(len(stride))
f.write(stride)
minv = [0, 0, 0]
maxv = [0, 0, 0]
for v in vertex_buffer:
for i in range(3):
if v[i] > maxv[i]:
maxv[i] = v[i]
if v[i] < minv[i]:
minv[i] = v[i]
with open(sys.argv[2], 'wb') as f:
header_size = 4 * 5 + 4 * 6
index_size = 2 * 1
index_buffer_size = index_size * len(index_buffer)
vertex_size = (4 * 3) + (4 * 2) + (2 * 4) + (2 * 4)
vertex_buffer_size = vertex_size * len(vertex_buffer)
index_count = len(index_buffer)
index_buffer_offset = header_size
vertex_buffer_offset = header_size + index_buffer_size
tangents = tangent.generate_tangents(vertex_buffer, index_buffer)
header = struct.pack("<IIIIIffffff",
index_count,
index_buffer_offset,
index_buffer_size,
vertex_buffer_offset,
vertex_buffer_size,
*minv,
*maxv)
f.write(header)
assert f.tell() == index_buffer_offset
for index in index_buffer:
print(index, vertex_buffer[index])
f.write(struct.pack("<H", index))
assert f.tell() == vertex_buffer_offset
for vertex, tangent in zip(vertex_buffer, tangents):
render_vertex(f, vertex, tangent)
assert f.tell() == vertex_buffer_offset + vertex_buffer_size