129 lines
3.4 KiB
Python
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
|