81 lines
1.8 KiB
Python

from dataclasses import dataclass
def ignore(state, line):
pass
def normalize_float(s):
f = float(s)
if f == -0.0:
return 0.0
return f
def parse_float_components(s, length):
components = s.split()
assert len(components) == length
return tuple(map(normalize_float, components))
def parse_position(state, line):
position = parse_float_components(line, 3)
state.position.append(position)
def parse_normal(state, line):
normal = parse_float_components(line, 3)
state.normal.append(normal)
def parse_texture(state, line):
texture = parse_float_components(line, 2)
state.texture.append(texture)
def parse_ptn(s):
ptn = tuple(int(i) - 1 for i in s.split("/"))
assert all(c >= 0 for c in ptn), ptn
assert len(ptn) == 3, ptn
return ptn
def parse_triangle(state, line):
indices = line.split()
assert len(indices) == 3, line
triangle = tuple(map(parse_ptn, indices))
state.triangle.append(triangle)
prefixes = [
("#", ignore),
("o ", ignore),
("s ", ignore),
("v ", parse_position),
("vn ", parse_normal),
("vt ", parse_texture),
("f ", parse_triangle),
]
@dataclass
class ObjState:
position: list
normal: list
texture: list
triangle: list
def __init__(self):
self.position = []
self.normal = []
self.texture = []
self.triangle = []
def parse_obj(s):
state = ObjState()
lines = s.strip().split("\n")
for line in lines:
for prefix, func in prefixes:
if line.startswith(prefix):
line = line.removeprefix(prefix)
func(state, line)
break
else:
assert False, line
return state
def parse_obj_from_filename(filename):
with open(filename, "r") as f:
buf = f.read()
return parse_obj(buf)