182 lines
5.6 KiB
Python
182 lines
5.6 KiB
Python
from dataclasses import astuple
|
|
import sys
|
|
from generate import renderer
|
|
|
|
from parse_obj_fixed_point import parse_obj_file
|
|
from parse_obj_fixed_point import VertexPosition
|
|
from parse_obj_fixed_point import VertexNormal
|
|
from parse_obj_fixed_point import VertexTexture
|
|
from parse_obj_fixed_point import Triangle
|
|
from parse_obj_fixed_point import Quadrilateral
|
|
|
|
from parse_material import parse_mtl_file
|
|
|
|
vertex_position_fraction_bits = 6 # 4.6
|
|
vertex_normal_fraction_bits = 9 # s.9
|
|
vertex_texture_fraction_bits = 14 # s.15
|
|
|
|
def convert_fixed_point(fp, fraction_bits):
|
|
point = 2 ** fraction_bits
|
|
sign = -1 if fp.negative else 1
|
|
n0 = sign * (fp.integer * fp.point + fp.fraction)
|
|
n1 = n0 * point // fp.point
|
|
return n1
|
|
|
|
def render_index_vtn(index_vtn):
|
|
s = ", ".join(map(str, index_vtn))
|
|
yield f"{{{s}}},"
|
|
|
|
def render_face(face):
|
|
yield "{"
|
|
for index_vtn in astuple(face):
|
|
yield from render_index_vtn(index_vtn)
|
|
yield "},"
|
|
|
|
def render_faces(prefix, name, faces):
|
|
yield f"struct {name} {prefix}_{name}[] = {{"
|
|
for face in faces:
|
|
yield from render_face(face)
|
|
yield "};"
|
|
|
|
def render_triangles(prefix, faces):
|
|
yield from render_faces(prefix, "triangle", faces)
|
|
|
|
def render_quadrilateral(prefix, faces):
|
|
yield from render_faces(prefix, "quadrilateral", faces)
|
|
|
|
def xyz(vec):
|
|
return (vec.x, vec.y, vec.z)
|
|
|
|
def uv(vec):
|
|
return (vec.u, vec.v)
|
|
|
|
def render_vertex(vertex_tuple, fraction_bits):
|
|
s = ", ".join(
|
|
str(convert_fixed_point(fp, fraction_bits))
|
|
for fp in vertex_tuple
|
|
)
|
|
yield f"{{{s}}},"
|
|
|
|
def render_vertices(prefix, name, vertices, fraction_bits):
|
|
yield f"// .{fraction_bits} fixed-point"
|
|
yield f"struct vertex_{name} {prefix}_{name}[] = {{"
|
|
for vertex in vertices:
|
|
yield from render_vertex(vertex, fraction_bits)
|
|
yield "};"
|
|
|
|
def render_vertex_positions(prefix, vertex_positions):
|
|
yield from render_vertices(prefix,
|
|
"position",
|
|
map(xyz, vertex_positions),
|
|
vertex_position_fraction_bits)
|
|
|
|
def render_vertex_normals(prefix, vertex_normals):
|
|
yield from render_vertices(prefix,
|
|
"normal",
|
|
map(xyz, vertex_normals),
|
|
vertex_normal_fraction_bits)
|
|
|
|
def render_vertex_texture(prefix, vertex_textures):
|
|
yield from render_vertices(prefix,
|
|
"texture",
|
|
map(uv, vertex_textures),
|
|
vertex_texture_fraction_bits)
|
|
|
|
def render_object(prefix, object_name, d, material):
|
|
yield f"struct object {prefix}_{object_name} = {{"
|
|
|
|
triangle_count = len(d[Triangle]) if Triangle in d else 0
|
|
quadrilateral_count = len(d[Quadrilateral]) if Quadrilateral in d else 0
|
|
|
|
if triangle_count > 0:
|
|
yield f".triangle = &{prefix}_{object_name}_triangle[0],"
|
|
else:
|
|
yield f".triangle = NULL,"
|
|
|
|
if quadrilateral_count > 0:
|
|
yield f".quadrilateral = &{prefix}_{object_name}_quadrilateral[0],"
|
|
else:
|
|
yield f".quadrilateral = NULL,"
|
|
|
|
yield f".triangle_count = {triangle_count},"
|
|
yield f".quadrilateral_count = {quadrilateral_count},"
|
|
|
|
if material is None:
|
|
yield f".material = -1,",
|
|
else:
|
|
yield f".material = {material.name},"
|
|
|
|
yield "};"
|
|
|
|
def render_pixel_palette(prefix, newmtl, mapkd):
|
|
name, _ext = mapkd.name.rsplit('.', maxsplit=1)
|
|
pixel_name = f"{name}_data"
|
|
palette_name = f"{name}_data_pal"
|
|
|
|
yield f"[{newmtl.name}] = {{"
|
|
yield ".pixel = {"
|
|
yield f".start = (uint8_t *)&_binary_{pixel_name}_start,"
|
|
yield f".end = (uint8_t *)&_binary_{pixel_name}_end,"
|
|
yield f".size = (int)&_binary_{pixel_name}_size,"
|
|
yield "},"
|
|
yield ".palette = {"
|
|
yield f".start = (uint8_t *)&_binary_{palette_name}_start,"
|
|
yield f".end = (uint8_t *)&_binary_{palette_name}_end,"
|
|
yield f".size = (int)&_binary_{palette_name}_size,"
|
|
yield "},"
|
|
yield "},"
|
|
|
|
def render_materials(prefix, newmtl_mapkd):
|
|
yield f"enum {prefix}_material {{"
|
|
for newmtl, mapkd in newmtl_mapkd:
|
|
yield f"{newmtl.name},";
|
|
yield "};"
|
|
|
|
yield f"struct pixel_palette {prefix}_pixel_palette[] = {{"
|
|
for newmtl, mapkd in newmtl_mapkd:
|
|
yield from render_pixel_palette(prefix, newmtl, mapkd)
|
|
yield "};"
|
|
|
|
def render_header():
|
|
yield '#include "model.h"'
|
|
yield ""
|
|
|
|
with open(sys.argv[1]) as f:
|
|
buf = f.read()
|
|
|
|
prefix = sys.argv[2]
|
|
vertices, faces, materials = parse_obj_file(buf)
|
|
render, out = renderer()
|
|
render(render_header())
|
|
render(render_vertex_positions(prefix, vertices[VertexPosition]))
|
|
render(render_vertex_texture(prefix, vertices[VertexTexture]))
|
|
render(render_vertex_normals(prefix, vertices[VertexNormal]))
|
|
|
|
materials_by_lib_name = set((m.lib, m.name) for m in materials.values())
|
|
material_names = set()
|
|
for _, name in materials_by_lib_name:
|
|
assert name not in material_names
|
|
material_names.add(name)
|
|
material_libs = set(lib for lib, _ in materials_by_lib_name)
|
|
for material_lib in material_libs:
|
|
with open(material_lib) as f:
|
|
buf = f.read()
|
|
newmtl_mapkd = [
|
|
(newmtl, mapkd)
|
|
for (newmtl, mapkd) in parse_mtl_file(buf)
|
|
if newmtl.name in material_names
|
|
]
|
|
render(render_materials(prefix, newmtl_mapkd))
|
|
|
|
for object_name, d in faces.items():
|
|
object_prefix = '_'.join((prefix, object_name))
|
|
|
|
if Triangle in d:
|
|
render(render_triangles(object_prefix, d[Triangle]))
|
|
if Quadrilateral in d:
|
|
render(render_quadrilateral(object_prefix, d[Quadrilateral]))
|
|
|
|
render(render_object(prefix, object_name, d, materials.get(object_name)));
|
|
|
|
sys.stdout.write(out.getvalue())
|