diff --git a/combine_obj.py b/combine_obj.py new file mode 100644 index 0000000..b02b523 --- /dev/null +++ b/combine_obj.py @@ -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()) diff --git a/generate_cpp.py b/generate_cpp.py index 5b728fb..9bd1e75 100644 --- a/generate_cpp.py +++ b/generate_cpp.py @@ -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}[] = {{" diff --git a/obj.py b/obj.py index 49089c7..f805a3c 100644 --- a/obj.py +++ b/obj.py @@ -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