model_generator/render_material_textures.py
2025-01-31 15:48:40 -06:00

124 lines
3.6 KiB
Python

from dataclasses import dataclass
from generate import renderer
from math import log
from path import texture_path
import sys
from PIL import Image
from parse_material import parse_mtl_file
def render_material_enum(prefix, newmtl_mapkd):
yield f"enum material {{"
for newmtl, mapkd in newmtl_mapkd:
yield f"{prefix}_{newmtl.name},";
yield "};"
def transform_filename(prefix, name):
name = name.replace("/", "_")
return f"model_{prefix}_{name}"
def render_pixel_descriptor(prefix, offset, mapkd, dimensions):
name, _ext = mapkd.name.rsplit('.', maxsplit=1)
pixel_name = f"{transform_filename(prefix, name)}_data"
width, height = dimensions
yield ".pixel = {"
yield f".start = (uint8_t *)&_binary_{pixel_name}_start,"
yield f".size = (int)&_binary_{pixel_name}_size,"
yield f".vram_offset = {offset.pixel},"
yield f".width = {width},"
yield f".height = {height},"
yield "},"
def render_palette_descriptor(offset, mapkd, palette_size):
name, _ext = mapkd.name.rsplit('.', maxsplit=1)
palette_name = f"{name}_data_pal"
yield ".palette = {"
yield f".start = (uint8_t *)&_binary_{palette_name}_start,"
yield f".size = (int)&_binary_{palette_name}_size,"
yield f".vram_offset = {offset.palette},"
yield f".palette_size = {palette_size},"
yield "},"
@dataclass
class Offset:
pixel: int
palette: int
def round_up_colors(name, colors):
assert colors != 0, (name, colors)
if colors <= 4:
return 4
if colors <= 16:
return 16
elif colors <= 256:
return 256
else:
assert False, (name, colors)
def image(mapkd):
path = texture_path(mapkd.name)
im = Image.open(path)
return im
def round_up_n(x, multiple):
return ((x + multiple - 1) // multiple) * multiple
def bytes_per_pixel(palette_size):
bits_per_pixel = int(log(palette_size)/log(2))
return bits_per_pixel / 8
def render_material(prefix, offset, mapkd):
im = image(mapkd)
dimensions = im.size
#colors = len(im.palette.colors)
#palette_size = round_up_colors(mapkd.name, colors)
# pixel descriptor
yield from render_pixel_descriptor(prefix, offset, mapkd, dimensions)
#pixel_size = bytes_per_pixel(palette_size) * dimensions[0] * dimensions[1]
pixel_size = 2 * dimensions[0] * dimensions[1]
assert int(pixel_size) == pixel_size
offset.pixel += round_up_n(int(pixel_size), 8)
# palette descriptor
#yield from render_palette_descriptor(offset, mapkd, palette_size)
#offset.palette += round_up_n(colors * 2, 16)
def render_materials(prefix, newmtl_mapkd):
yield f"const struct material_descriptor {prefix}_material[] = {{"
offset = Offset(0, 0)
for newmtl, mapkd in newmtl_mapkd:
yield f"[{prefix}_{newmtl.name}] = {{"
yield from render_material(prefix, offset, mapkd)
yield "},"
yield "};"
def render_header():
yield "#pragma once"
yield ""
yield "#include <stdint.h>"
yield ""
yield '#include "model/material.h"'
yield ""
if __name__ == "__main__":
prefix = sys.argv[1]
material_filenames = sys.argv[2:]
assert material_filenames
newmtl_mapkd = []
for material_filename in material_filenames:
with open(material_filename) as f:
buf = f.read()
newmtl_mapkd.extend([
(newmtl, mapkd)
for (newmtl, mapkd) in parse_mtl_file(buf)
])
render, out = renderer()
render(render_header())
render(render_material_enum(prefix, newmtl_mapkd))
render(render_materials(prefix, newmtl_mapkd))
sys.stdout.write(out.getvalue())