add combine_obj

This commit is contained in:
Zack Buhman 2025-04-02 12:54:43 -05:00
parent 0b4d41f42e
commit 3c775a0f86
3 changed files with 116 additions and 27 deletions

83
combine_obj.py Normal file
View File

@ -0,0 +1,83 @@
from collections import defaultdict
import sys
from obj import parse_obj_file
from obj import VertexPosition
from obj import VertexNormal
from obj import VertexTexture
from obj import ObjFile
from obj import Object
from obj import Face
from obj import FacePTN
from generate import renderer
from generate_cpp import generate_obj_file
global_vertex = {
VertexPosition: {},
VertexNormal: {},
VertexTexture: {},
}
global_names = defaultdict(int)
def merge_vertex(vertex, type):
d = global_vertex[type]
if vertex not in d:
d[vertex] = len(d)
def merge_vertices(vertices, type):
for vertex in vertices:
merge_vertex(vertex, type)
def rewrite_ptn(obj_file, ptn):
return FacePTN(
position=global_vertex[VertexPosition][obj_file.position[ptn.position]],
normal=global_vertex[VertexNormal][obj_file.normal[ptn.normal]],
texture=global_vertex[VertexTexture][obj_file.texture[ptn.texture]],
)
def rewrite_face(obj_file, face):
return Face(
ptn=[rewrite_ptn(obj_file, face_ptn) for face_ptn in face.ptn]
)
def rewrite_object(obj_file, object):
global global_names
global_names[object.name] += 1
name_suffix = global_names[object.name]
return Object(
name=f"{object.name}_{name_suffix}",
faces=[rewrite_face(obj_file, face) for face in object.faces],
material=object.material,
)
def rewrite_objects(obj_files):
for obj_file in obj_files:
for object in obj_file.objects:
yield rewrite_object(obj_file, object)
def reorder_vertices(type):
d = global_vertex[type]
dd = {v: k for k, v in d.items()}
for i in range(len(dd)):
yield dd[i]
def rewrite_obj_file(obj_files):
for obj_file in obj_files:
merge_vertices(obj_file.position, VertexPosition)
merge_vertices(obj_file.normal, VertexNormal)
merge_vertices(obj_file.texture, VertexTexture)
return ObjFile(
position=reorder_vertices(VertexPosition),
normal=reorder_vertices(VertexNormal),
texture=reorder_vertices(VertexTexture),
objects=list(rewrite_objects(obj_files))
)
if __name__ == "__main__":
filenames = sys.argv[2:]
obj_files = [parse_obj_file(fn) for fn in filenames]
obj_file = rewrite_obj_file(obj_files)
render, out = renderer(indent_length=4)
render(generate_obj_file(sys.argv[1], obj_file))
sys.stdout.write(out.getvalue())

View File

@ -4,11 +4,11 @@ import sys
def generate_vec3(vs):
for v in vs:
yield f"{{{v.x:.6f}f, {v.y:.6f}f, {v.z:.6f}f}},"
yield f"{{{v.x.to_string()}f, {v.y.to_string()}f, {v.z.to_string()}f}},"
def generate_vec2(vs):
for v in vs:
yield f"{{{v.x:.6f}f, {v.y:.6f}f}},"
yield f"{{{v.x.to_string()}f, {v.y.to_string()}f}},"
def generate_vec(name, type, func, vs):
yield f"const vertex_{type} {name}_{type}[] = {{"

56
obj.py
View File

@ -2,23 +2,36 @@ from dataclasses import dataclass
import sys
import os
@dataclass(frozen=True)
class FixedPoint:
s: int # sign
w: int # whole
f: int # fraction
b: int # base
def to_string(self):
s_s = "-" if self.s < 0 else ""
w_s = f"{self.w}"
f_s = f"{self.f}".rjust(self.b, '0')
return f"{s_s}{w_s}.{f_s}"
@dataclass(frozen=True)
class VertexPosition:
x: float
y: float
z: float
x: FixedPoint
y: FixedPoint
z: FixedPoint
@dataclass(frozen=True)
class VertexNormal:
x: float
y: float
z: float
x: FixedPoint
y: FixedPoint
z: FixedPoint
@dataclass(frozen=True)
class VertexTexture:
x: float
y: float
z: float
x: FixedPoint
y: FixedPoint
z: FixedPoint
@dataclass(frozen=True)
class ObjectEvent:
@ -44,10 +57,10 @@ class Object:
faces: list[Face]
material: Material
def __init__(self, name):
def __init__(self, name, faces=None, material=None):
self.name = name
self.faces = []
self.material = None
self.faces = [] if faces is None else faces
self.material = material
@dataclass
class ObjFile:
@ -56,11 +69,11 @@ class ObjFile:
texture: list[VertexTexture]
objects: list[Object]
def __init__(self):
self.position = []
self.normal = []
self.texture = []
self.objects = []
def __init__(self, position=None, normal=None, texture=None, objects=None):
self.position = [] if position is None else position
self.normal = [] if normal is None else normal
self.texture = [] if texture is None else texture
self.objects = [] if objects is None else objects
def parse_float(s):
sign = -1 if s.startswith("-") else 1
@ -72,14 +85,7 @@ def parse_float(s):
i = int(i, 10)
f = int(f, 10)
if 'ROUND_PRECISION' in os.environ:
max_digits = 4
if f_digits > max_digits:
f = int(f / (f_digits - max_digits))
f_digits = max_digits
f_10 = (f / 10 ** f_digits)
return sign * (i + f_10)
return FixedPoint(sign, i, f, f_digits)
def parse_vertex(line, n, type):
assert len(line) == n