From d14c32eb01c9af012dfddef22b23339f5e464b2d Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Tue, 18 Feb 2025 17:55:54 -0600 Subject: [PATCH] x: initial generator --- x/gen.py | 170 +++++++++++++++++++++++++++++++++++++++++++++++++ x/generate.py | 35 ++++++++++ x/parse.py | 61 ++++++++++-------- x/templates.py | 112 ++++++++++++++++---------------- x/x.h | 109 ------------------------------- x/x.hpp | 137 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 435 insertions(+), 189 deletions(-) create mode 100644 x/gen.py create mode 100644 x/generate.py delete mode 100644 x/x.h create mode 100644 x/x.hpp diff --git a/x/gen.py b/x/gen.py new file mode 100644 index 0000000..8ac99d6 --- /dev/null +++ b/x/gen.py @@ -0,0 +1,170 @@ +import generate +from parse import parse_all, TokenReader +import templates +import dataclasses +from collections import Counter + +from pprint import pprint +import sys + +def obj_value(obj): + if type(obj) is tuple: + assert len(obj) == 2, obj + assert type(obj[0]) == bytes, obj + return obj[1] + else: + return obj + +def obj_type(obj): + return type(obj_value(obj)) + +def visit_objects(func, obj): + print("vo", func) + yield func(obj) + for o in obj_value(obj).objects: + yield func(o) + +def visit_self(func, obj): + print("vs", func) + yield func(obj) + +visitors = { + templates.ColorRGBA : visit_self, + templates.ColorRGB : visit_self, + templates.Matrix4x4 : visit_self, + templates.Vector : visit_self, + templates.MeshFace : visit_self, + templates.Coords2D : visit_self, + templates.Reference : visit_self, + templates.FloatKeys : visit_self, + templates.TimedFloatKeys : visit_self, + + templates.Header : visit_self, + templates.Material : visit_objects, + templates.TextureFilename : visit_self, + templates.Frame : visit_objects, + templates.FrameTransformMatrix : visit_self, + templates.Mesh : visit_objects, + templates.MeshMaterialList : visit_objects, + templates.MeshNormals : visit_self, + templates.MeshTextureCoords : visit_self, + templates.AnimationKey : visit_self, + templates.AnimationOptions : visit_self, + templates.Animation : visit_objects, + templates.AnimationSet : visit_objects, +} + +type_map = { + templates.ColorRGBA : "vec4", + templates.ColorRGB : "vec3", + templates.Matrix4x4 : "mat4x4", + templates.Vector : "vec3", + templates.MeshFace : "mesh_face", + templates.Coords2D : "vec2", + #templates.Reference : None, + templates.FloatKeys : "float_keys", + templates.TimedFloatKeys : "time_float_keys", + + templates.Header : "header", + templates.Material : "material", + templates.TextureFilename : "texture_filename", + templates.Frame : "frame", + templates.FrameTransformMatrix : "frame_transform_matrix", + templates.Mesh : "mesh", + templates.MeshMaterialList : "mesh_material_list", + templates.MeshNormals : "mesh_normals", + templates.MeshTextureCoords : "mesh_texture_coords", + templates.AnimationKey : "animation_key", + templates.AnimationOptions : "animation_options", + templates.Animation : "animation", + templates.AnimationSet : "animation_set", +} + +type_counter = Counter() +def name_gen(obj): + global type_counter + assert type(obj) is not tuple + i = type_counter[type(obj)] + type_counter[type(obj)] += 1 + return i + +name_map = {} +def add_name_map(obj): + if type(obj) is not tuple: + return + + name, obj = obj + assert name not in name_map, name + name_map[name] = obj + yield None + +def type_declaration(obj): + type_name = type_map[obj_type(obj)] + if type(obj) is tuple: + name, _ = obj + string_name = name.decode('utf-8') + else: + string_name = name_gen(obj) + return f"const {type_name} {type_name}_{string_name}" + +def generate_predeclaration(obj): + if type(obj) is not tuple: + return + + yield f"{type_declaration(obj)};" + +def generate_header(obj): + yield f"{type_declaration(obj)} {{" + yield "};" + +def generate_definition(obj): + if obj_type(obj) is templates.Header: + yield from generate_header(obj) + elif obj_type(obj) is templates.Material: + yield from generate_material(obj) + elif obj_type(obj) is templates.TextureFilename: + yield from generate_texture_filename(obj) + elif obj_type(obj) is templates.Frame: + yield from generate_frame(obj) + elif obj_type(obj) is templates.FrameTransformMatrix: + yield from generate_frame_transform_matrix(obj) + elif obj_type(obj) is templates.Mesh: + yield from generate_mesh(obj) + elif obj_type(obj) is templates.MeshMaterialList: + yield from generate_mesh_material_list(obj) + elif obj_type(obj) is templates.MeshNormals: + yield from generate_mesh_normals(obj) + elif obj_type(obj) is templates.MeshTextureCoords: + yield from generate_mesh_texture_coords(obj) + elif obj_type(obj) is templates.AnimationKey: + yield from generate_animation_key(obj) + elif obj_type(obj) is templates.AnimationOptions: + yield from generate_animation_options(obj) + elif obj_type(obj) is templates.Animation: + yield from generate_animation(obj) + elif obj_type(obj) is templates.AnimationSet: + yield from generate_animation_set(obj) + else: + assert False, (type(obj), obj) + +def visit(func, obj): + yield from visitors[obj_type(obj)](func, obj) + +def visit_all(func, objects): + for obj in objects: + yield from visit(func, obj) + +def gen(objects): + yield from visit_all(generate_predeclaration, objects) + yield from visit_all(generate_definition, objects) + +with open(sys.argv[1], "rb") as f: + buf = f.read() +objects = list(parse_all(TokenReader(buf))) + +_ = list(visit_all(add_name_map, objects)) + +render, out = generate.renderer() +for i in gen(objects): + print("line", i) +print(out.getvalue()) diff --git a/x/generate.py b/x/generate.py new file mode 100644 index 0000000..2871189 --- /dev/null +++ b/x/generate.py @@ -0,0 +1,35 @@ +import io + +def should_autonewline(line): + return ( + "static_assert" not in line + and "extern" not in line + and (len(line.split()) < 2 or line.split()[1] != '=') # hacky; meh + ) + +def _render(out, lines): + indent = " " + level = 0 + for l in lines: + if l and (l[0] == "}" or l[0] == ")"): + level -= 2 + assert level >= 0, out.getvalue() + + if len(l) == 0: + out.write("\n") + else: + out.write(indent * level + l + "\n") + + if l and (l[-1] == "{" or l[-1] == "("): + level += 2 + + if level == 0 and l and l[-1] == ";": + if should_autonewline(l): + out.write("\n") + return out + +def renderer(): + out = io.StringIO() + def render(lines): + return _render(out, lines) + return render, out diff --git a/x/parse.py b/x/parse.py index 6eeb5de..4b8d517 100644 --- a/x/parse.py +++ b/x/parse.py @@ -1,15 +1,9 @@ -from pprint import pprint -import sys - import lex import templates -with open(sys.argv[1], "rb") as f: - buf = f.read() -mem = memoryview(buf) - class TokenReader: - def __init__(self, mem): + def __init__(self, buf): + mem = memoryview(buf) self.tokens = list(lex.lex_all(mem, 0)) self.ix = 0 @@ -262,6 +256,18 @@ def parse_mesh_texture_coords(r): textureCoords ) +def parse_animation(r): + r.consume(b"Animation") + name = r.consume_type(bytes) + r.consume(lex.TOKEN_LBRACKET) + objects = [] + while not r.match(lex.TOKEN_RBRACKET): + objects.append(parse_one_ref(r, {b"AnimationKey", b"AnimationOptions"})) + + return name, templates.Animation( + objects + ) + def parse_animation_set(r): r.consume(b"AnimationSet") name = r.consume_type(bytes) @@ -274,16 +280,12 @@ def parse_animation_set(r): objects ) -def parse_animation(r): - r.consume(b"Animation") - name = r.consume_type(bytes) - r.consume(lex.TOKEN_LBRACKET) - objects = [] - while not r.match(lex.TOKEN_RBRACKET): - objects.append(parse_one_ref(r, {b"AnimationKey", b"AnimationOptions"})) - - return name, templates.Animation( - objects +def parse_animation_options(r): + openClosed = parse_int(r) + positionQuality = parse_int(r) + return templates.AnimationOptions( + openClosed, + positionQuality ) def parse_float_keys(r): @@ -341,12 +343,14 @@ def parse_one(r, peek_token=None): return parse_mesh_normals(r) elif token == b"MeshTextureCoords": return parse_mesh_texture_coords(r) - elif token == b"AnimationSet": - return parse_animation_set(r) - elif token == b"Animation": - return parse_animation(r) elif token == b"AnimationKey": return parse_animation_key(r) + elif token == b"AnimationOptions": + return parse_animation_options(r) + elif token == b"Animation": + return parse_animation(r) + elif token == b"AnimationSet": + return parse_animation_set(r) else: assert False, token @@ -365,6 +369,13 @@ def parse_all(r): while not r.eof(): yield parse_one_ref(r) -r = TokenReader(mem) -for i in parse_all(r): - pprint(i) +if __name__ == "__main__": + from pprint import pprint + import sys + + with open(sys.argv[1], "rb") as f: + buf = f.read() + + r = TokenReader(buf) + for i in parse_all(r): + pprint(i) diff --git a/x/templates.py b/x/templates.py index 1bbc97e..2505bf9 100644 --- a/x/templates.py +++ b/x/templates.py @@ -1,11 +1,7 @@ from typing import Any, Union from dataclasses import dataclass -@dataclass -class Header: - major: int - minor: int - flags: int +# untagged objects @dataclass class ColorRGBA: @@ -24,23 +20,6 @@ class ColorRGB: class Matrix4x4: v: list[float] -@dataclass -class Material: - faceColor: ColorRGBA - power: float - specularColor: ColorRGB - emissiveColor: ColorRGB - - objects: list[Any] - -@dataclass -class Frame: - objects: list[Any] - -@dataclass -class FrameTransformMatrix: - frameMatrix: Matrix4x4 - @dataclass class Vector: x: float @@ -52,44 +31,11 @@ class MeshFace: nFaceVertexIndices: int faceVertexIndices: list[int] -@dataclass -class Mesh: - nVertices: int - vertices: list[Vector] - nFaces: int - faces: list[MeshFace] - - objects: list[Any] - -@dataclass -class MeshMaterialList: - nMaterials: int - nFaceIndices: int - faceIndices: list[int] - - objects: list[Material] - -@dataclass -class MeshNormals: - nNormals: int - normals: list[Vector] - nFaceNormals: int - faceNormals: list[MeshFace] - @dataclass class Coords2D: u: float v: float -@dataclass -class MeshTextureCoords: - nTextureCoords: int - textureCoords: list[Coords2D] - -@dataclass -class TextureFilename: - filename: str - @dataclass class Reference: name: bytes @@ -104,6 +50,62 @@ class TimedFloatKeys: time: int tfkeys: FloatKeys +# tagged objects + +@dataclass +class Header: + major: int + minor: int + flags: int + +@dataclass +class Material: + faceColor: ColorRGBA + power: float + specularColor: ColorRGB + emissiveColor: ColorRGB + + objects: list[Any] + +@dataclass +class TextureFilename: + filename: str + +@dataclass +class Frame: + objects: list[Any] + +@dataclass +class FrameTransformMatrix: + frameMatrix: Matrix4x4 + +@dataclass +class Mesh: + nVertices: int + vertices: list[Vector] + nFaces: int + faces: list[MeshFace] + objects: list[Any] + +@dataclass +class MeshMaterialList: + nMaterials: int + nFaceIndices: int + faceIndices: list[int] + objects: list[Material] + +@dataclass +class MeshNormals: + nNormals: int + normals: list[Vector] + nFaceNormals: int + faceNormals: list[MeshFace] + +@dataclass +class MeshTextureCoords: + nTextureCoords: int + textureCoords: list[Coords2D] + @dataclass class AnimationKey: keyType: int diff --git a/x/x.h b/x/x.h deleted file mode 100644 index 74628a8..0000000 --- a/x/x.h +++ /dev/null @@ -1,109 +0,0 @@ -struct header { - int tag; - int major; - int minor; - int flags; -}; - -struct color_rgba { - float r; - float g; - float b; - float a; -}; - -struct color_rgb { - float r; - float g; - float b; -}; - -struct material { - int tag; - x_color_rgba facecolor; - float power; - x_color_rgb specularcolor; - x_color_rgb emissivecolor; - void * objects[]; -}; - -struct frame { - int tag; - void * objects[]; -}; - -struct frame_transform_matrix { - int tag; - mat4x4 framematrix; -}; - -struct mesh_face { - int nfacevertexindices; - int facevertexindices[]; -}; - -struct mesh { - int nvertices; - vec3 * vertices; - int nfaces; - mesh_face * faces; - void * objects[]; -}; - -struct mesh_material_list { - int n_materials; - int n_face_indices; - int * face_indices; - void * objects[]; -}; - -struct mesh_normals { - int tag; - int n_normals; - vec3 * normals; - int n_face_normals; - mesh_face * face_normals; -}; - -struct mesh_texture_coords { - int tag; - int n_texture_coords; - vec2 texture_coords[]; -}; - -struct texture_filename { - const char * filename; -}; - -struct float_keys { - int nvalues; - float values; -}; - -struct timed_float_keys { - int time; - float_keys tfkeys; -}; - -struct animation_key { - int tag; - int key_type; - int n_keys; - timed_float_keys keys[]; -}; - -struct animation_options { - int tag; - int open_closed; - int position_quality; -}; - -struct animation { - int tag; - void * objects[]; -}; - -struct animation_set { - int tag; - void * objects[]; -} diff --git a/x/x.hpp b/x/x.hpp new file mode 100644 index 0000000..635e44a --- /dev/null +++ b/x/x.hpp @@ -0,0 +1,137 @@ +/* primitives */ +struct mesh_face { + int nfacevertexindices; + int facevertexindices[]; +}; + +struct float_keys { + int nvalues; + float values; +}; + +struct timed_float_keys { + int time; + struct float_keys tfkeys; +}; + +/* data objects */ +struct data_object; + +enum struct tag : int { + header, + material, + texture_filename, + frame, + frame_transform_matrix, + mesh, + mesh_material_list, + mesh_normals, + mesh_texture_coords, + animation_key, + animation_options, + animation, + animation_set, +}; + +struct header { + enum tag tag; + int major; + int minor; + int flags; +}; + +struct material { + enum tag tag; + vec4 facecolor; + float power; + vec3 specularcolor; + vec3 emissivecolor; + struct data_object * objects[]; +}; + +struct texture_filename { + enum tag tag; + const char * filename; +}; + +struct frame { + enum tag tag; + struct data_object * objects[]; +}; + +struct frame_transform_matrix { + enum tag tag; + mat4x4 framematrix; +}; + +struct mesh { + enum tag tag; + int nvertices; + vec3 * vertices; + int nfaces; + struct mesh_face * faces; + struct data_object * objects[]; +}; + +struct mesh_material_list { + enum tag tag; + int n_materials; + int n_face_indices; + int * face_indices; + struct data_object * objects[]; +}; + +struct mesh_normals { + enum tag tag; + int n_normals; + vec3 * normals; + int n_face_normals; + struct mesh_face * face_normals; +}; + +struct mesh_texture_coords { + enum tag tag; + int n_texture_coords; + vec2 texture_coords[]; +}; + +struct animation_key { + enum tag tag; + int key_type; + int n_keys; + struct timed_float_keys keys[]; +}; + +struct animation_options { + enum tag tag; + int open_closed; + int position_quality; +}; + +struct animation { + enum tag tag; + struct data_object * objects[]; +}; + +struct animation_set { + enum tag tag; + struct data_object * objects[]; +}; + +struct data_object { + union { + enum tag tag; + struct header header; + struct material material; + struct texture_filename texture_filename; + struct frame frame; + struct frame_transform_matrix frame_transform_matrix; + struct mesh mesh; + struct mesh_material_list mesh_material_list; + struct mesh_normals mesh_normals; + struct mesh_texture_coords mesh_texture_coords; + struct animation_set animation_set; + struct animation animation; + struct animation_key animation_key; + }; +};