mirror of
https://github.com/buhman/nds.git
synced 2025-06-18 06:25:40 -04:00
gen: move to separate repository
This commit is contained in:
parent
ed46a806b7
commit
7e1c251a22
@ -22,6 +22,7 @@ SECTIONS
|
||||
.text.arm9 ALIGN(4) :
|
||||
{
|
||||
KEEP(*(.data.arm9*.bin))
|
||||
. = ALIGN(32);
|
||||
} AT>rom
|
||||
|
||||
. = 0x02000000 + 0x390000;
|
||||
@ -31,6 +32,7 @@ SECTIONS
|
||||
.text.arm7 ALIGN(4) :
|
||||
{
|
||||
KEEP(*(.data.arm7*.bin))
|
||||
. = ALIGN(32);
|
||||
} AT>rom
|
||||
|
||||
/DISCARD/ :
|
||||
|
@ -1,78 +0,0 @@
|
||||
import struct
|
||||
import sys
|
||||
|
||||
from PIL import Image
|
||||
|
||||
def round_up_palette_size(palette_size):
|
||||
assert palette_size != 0, (name, palette_size)
|
||||
if palette_size <= 4:
|
||||
return 4
|
||||
elif palette_size <= 16:
|
||||
return 16
|
||||
elif palette_size <= 256:
|
||||
return 256
|
||||
else:
|
||||
assert False, palette_size
|
||||
|
||||
def pixels_per_byte(palette_size):
|
||||
if palette_size == 4:
|
||||
return 4
|
||||
elif palette_size == 16:
|
||||
return 2
|
||||
elif palette_size == 256:
|
||||
return 1
|
||||
else:
|
||||
assert False, palette_size
|
||||
|
||||
def pack_one_byte(pixels, index, colors, palette_size):
|
||||
color_count = len(colors)
|
||||
num = pixels_per_byte(palette_size)
|
||||
shift = 8 // num
|
||||
byte = 0
|
||||
i = 0
|
||||
while num > 0:
|
||||
px, alpha = pixels[index]
|
||||
if alpha == 0 and color_count < palette_size:
|
||||
px = color_count
|
||||
assert px < palette_size
|
||||
byte |= px << (shift * i)
|
||||
index += 1
|
||||
i += 1
|
||||
num -= 1
|
||||
return [byte], index
|
||||
|
||||
def pack_one_texel(pixels, index, colors, palette_size):
|
||||
px, alpha = pixels[index]
|
||||
return
|
||||
|
||||
def pack_pixels(pixels, width, height, colors, palette_size):
|
||||
index = 0
|
||||
with open(sys.argv[2], 'wb') as f:
|
||||
while index < (width * height):
|
||||
byte_list, index = pack_texel(pixels, index, colors, palette_size)
|
||||
f.write(bytes(byte))
|
||||
|
||||
def pack_palette(colors, palette_size):
|
||||
with open(sys.argv[2], 'wb') as f:
|
||||
for color in colors:
|
||||
out = argb1555(255, *color)
|
||||
f.write(struct.pack('<H', out))
|
||||
if len(colors) < palette_size:
|
||||
# transparent color
|
||||
print('pack transparency at ix', len(colors))
|
||||
out = argb1555(0, 0, 0, 0)
|
||||
f.write(struct.pack('<H', out))
|
||||
|
||||
with Image.open(sys.argv[1]) as im:
|
||||
assert im.mode == "P"
|
||||
width, height = im.size
|
||||
colors = list(im.palette.colors)
|
||||
pixels = list(im.convert("PA").getdata())
|
||||
|
||||
palette_size = round_up_palette_size(len(colors))
|
||||
if sys.argv[2].endswith('.data'):
|
||||
pack_pixels(pixels, width, height, len(colors), palette_size)
|
||||
elif sys.argv[2].endswith('.pal'):
|
||||
pack_palette(colors, palette_size)
|
||||
else:
|
||||
assert False, sys.argv[2]
|
@ -1,92 +0,0 @@
|
||||
import struct
|
||||
import sys
|
||||
|
||||
from PIL import Image
|
||||
|
||||
class color_format:
|
||||
def gbgr1555(r, g, b, a): # nintendo ds
|
||||
r5 = (r >> 3) & 31
|
||||
g6 = (g >> 3) & 31
|
||||
g6_l = (g >> 2) & 1
|
||||
b5 = (b >> 3) & 31
|
||||
return (g6_l << 15) | (b5 << 10) | (g6 << 5) | (r5 << 0)
|
||||
|
||||
def argb4444(r, g, b, a):
|
||||
a4 = (a >> 4) & 15
|
||||
r4 = (r >> 4) & 15
|
||||
g4 = (g >> 4) & 15
|
||||
b4 = (b >> 4) & 15
|
||||
return (a4 << 12) | (r4 << 8) | (g4 << 4) | (b4 << 0)
|
||||
|
||||
def argb1555(r, g, b, a):
|
||||
a1 = (a >> 7) & 1
|
||||
r5 = (r >> 3) & 31
|
||||
g5 = (g >> 3) & 31
|
||||
b5 = (b >> 3) & 31
|
||||
return (a1 << 15) | (r5 << 10) | (g5 << 5) | (b5 << 0)
|
||||
|
||||
def rgb565(r, g, b, a):
|
||||
r5 = (r >> 3) & 31
|
||||
g6 = (g >> 2) & 63
|
||||
b5 = (b >> 3) & 31
|
||||
return (r5 << 11) | (g5 << 5) | (b5 << 0)
|
||||
|
||||
def from_string(s):
|
||||
return dict([
|
||||
("gbgr1555", color_format.gbgr1555),
|
||||
("argb4444", color_format.argb4444),
|
||||
("argb1555", color_format.argb1555),
|
||||
("rgb565", color_format.rgb565),
|
||||
])[s]
|
||||
|
||||
in_file = sys.argv[1]
|
||||
format = sys.argv[2]
|
||||
out_file = sys.argv[3]
|
||||
|
||||
palette = None
|
||||
|
||||
with Image.open(in_file) as im:
|
||||
width, height = im.size
|
||||
if not im.palette:
|
||||
pixels = list(im.convert("RGBA").getdata())
|
||||
else:
|
||||
pixels = list(im.convert("P").getdata())
|
||||
palette = list(im.palette.colors)
|
||||
|
||||
has_alpha = False
|
||||
convert = color_format.from_string(format)
|
||||
|
||||
def convert_colors(f, colors):
|
||||
for color in colors:
|
||||
value = convert(*color)
|
||||
f.write(struct.pack("<H", value))
|
||||
|
||||
if palette is None:
|
||||
with open(out_file, 'wb') as f:
|
||||
convert_colors(f, pixels)
|
||||
else:
|
||||
with open(out_file, 'wb') as f:
|
||||
if len(palette) <= 4:
|
||||
for i in range(len(pixels) // 4):
|
||||
a = pixels[i * 4 + 0]
|
||||
b = pixels[i * 4 + 1]
|
||||
c = pixels[i * 4 + 2]
|
||||
d = pixels[i * 4 + 3]
|
||||
assert a <= 3 and b <= 3 and c <= 3 and d <= 3, (a, b, c, d)
|
||||
pixel = (d << 6) | (c << 4) | (b << 2) | (a << 0)
|
||||
f.write(struct.pack("<B", pixel))
|
||||
elif len(palette) <= 16:
|
||||
for i in range(len(pixels) // 2):
|
||||
a = pixels[i * 2 + 0]
|
||||
b = pixels[i * 2 + 1]
|
||||
assert a <= 15 and b <= 15, (a, b)
|
||||
pixel = (b << 4) | (a << 0)
|
||||
f.write(struct.pack("<B", pixel))
|
||||
elif len(palette) <= 256:
|
||||
for pixel in pixels:
|
||||
assert pixel <= 255
|
||||
f.write(struct.pack("<B", pixel))
|
||||
else:
|
||||
assert False, len(palette)
|
||||
with open(out_file + '.pal', 'wb') as f:
|
||||
convert_colors(f, [(*c, 255) for c in palette])
|
@ -1,77 +0,0 @@
|
||||
from dataclasses import dataclass
|
||||
import string
|
||||
|
||||
class FixedPointOverflow(Exception):
|
||||
pass
|
||||
|
||||
@dataclass
|
||||
class FixedPoint:
|
||||
sign: int
|
||||
value: int
|
||||
point: int
|
||||
|
||||
def to_fixed_point(fp, integer_bits, fraction_bits):
|
||||
point = 1 << fraction_bits
|
||||
value = (fp.value * point) // fp.point
|
||||
if integer_bits is not None:
|
||||
integer_point = 1 << integer_bits
|
||||
integer = value // point
|
||||
if integer >= integer_point:
|
||||
raise FixedPointOverflow((integer, integer_point))
|
||||
return FixedPoint(
|
||||
fp.sign,
|
||||
value,
|
||||
point
|
||||
)
|
||||
|
||||
def to_int(fp):
|
||||
return fp.sign * fp.value
|
||||
|
||||
def to_float(fp):
|
||||
return fp.sign * fp.value / fp.point
|
||||
|
||||
def from_float(n):
|
||||
if n == 0.0:
|
||||
sign = 1
|
||||
value = 0
|
||||
else:
|
||||
sign = -1 if n < 0 else 1
|
||||
value = abs(round(n * (2 ** 32)))
|
||||
point = 2 ** 32
|
||||
return FixedPoint(sign, value, point)
|
||||
|
||||
assert from_float(0.5).to_float() == 0.5
|
||||
assert from_float(1.5).to_fixed_point(16, 16).value == 98304
|
||||
|
||||
def parse(s):
|
||||
sign = -1 if s.startswith('-') else 1
|
||||
s = s.removeprefix('-')
|
||||
integer, fraction = s.split('.')
|
||||
assert all(c in string.digits for c in integer), integer
|
||||
assert all(c in string.digits for c in fraction), fraction
|
||||
assert len(integer) > 0 and len(fraction) > 0, s
|
||||
point = 10 ** len(fraction)
|
||||
value = int(integer) * point + int(fraction)
|
||||
return FixedPoint(
|
||||
sign,
|
||||
value,
|
||||
point
|
||||
)
|
||||
|
||||
def equal(a, b):
|
||||
epsilon = 0.00001
|
||||
return (a - b) < epsilon
|
||||
|
||||
def assert_raises(e, f):
|
||||
try:
|
||||
f()
|
||||
except e:
|
||||
return
|
||||
raise AssertionError(f"expected {str(e)}")
|
||||
|
||||
assert parse("1.234").value == 1234
|
||||
assert equal(parse("1.234").to_float(), 1.234)
|
||||
assert parse("1.234").to_fixed_point(16, 16).value == 80871
|
||||
assert_raises(FixedPointOverflow,
|
||||
lambda: parse("2.234").to_fixed_point(1, 16))
|
||||
assert parse("2.234").to_fixed_point(2, 16).value == 146407
|
@ -1,35 +0,0 @@
|
||||
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
|
@ -1,47 +0,0 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass
|
||||
class NewMtl:
|
||||
name: str
|
||||
|
||||
@dataclass
|
||||
class MapKd:
|
||||
name: str
|
||||
|
||||
def parse_material_newmtl(args):
|
||||
name, = args.split()
|
||||
yield NewMtl(name.replace('-', '_').replace('.', '_'))
|
||||
|
||||
def parse_material_mapkd(args):
|
||||
name, = args.split()
|
||||
yield MapKd(name)
|
||||
|
||||
def parse_mtl_line(line):
|
||||
prefixes = [
|
||||
('newmtl ', parse_material_newmtl),
|
||||
('map_Kd ', parse_material_mapkd),
|
||||
]
|
||||
for prefix, parser in prefixes:
|
||||
if line.startswith(prefix):
|
||||
args = line.removeprefix(prefix)
|
||||
yield from parser(args)
|
||||
|
||||
def group_by_material(l):
|
||||
current_material = None
|
||||
for i in l:
|
||||
if type(i) is NewMtl:
|
||||
current_material = i
|
||||
elif type(i) is MapKd:
|
||||
assert current_material is not None
|
||||
yield (current_material, i)
|
||||
current_material = None
|
||||
else:
|
||||
assert False, type(i)
|
||||
|
||||
def parse_mtl_file(buf):
|
||||
return list(group_by_material((
|
||||
parsed
|
||||
for line in buf.strip().split('\n')
|
||||
for parsed in parse_mtl_line(line)
|
||||
if not line.startswith('#')
|
||||
)))
|
162
gen/parse_obj.py
162
gen/parse_obj.py
@ -1,162 +0,0 @@
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
import string
|
||||
from fixed_point import FixedPoint
|
||||
import fixed_point
|
||||
|
||||
@dataclass
|
||||
class VertexPosition:
|
||||
x: FixedPoint
|
||||
y: FixedPoint
|
||||
z: FixedPoint
|
||||
|
||||
@dataclass
|
||||
class VertexNormal:
|
||||
x: FixedPoint
|
||||
y: FixedPoint
|
||||
z: FixedPoint
|
||||
|
||||
@dataclass
|
||||
class VertexTexture:
|
||||
u: FixedPoint
|
||||
v: FixedPoint
|
||||
|
||||
@dataclass
|
||||
class IndexVTN:
|
||||
vertex_position: int
|
||||
vertex_texture: int
|
||||
vertex_normal: int
|
||||
|
||||
@dataclass
|
||||
class Triangle:
|
||||
a: IndexVTN
|
||||
b: IndexVTN
|
||||
c: IndexVTN
|
||||
|
||||
@dataclass
|
||||
class Quadrilateral:
|
||||
a: IndexVTN
|
||||
b: IndexVTN
|
||||
c: IndexVTN
|
||||
d: IndexVTN
|
||||
|
||||
@dataclass
|
||||
class Object:
|
||||
name: str
|
||||
|
||||
@dataclass
|
||||
class Material:
|
||||
lib: str
|
||||
name: str
|
||||
|
||||
@dataclass
|
||||
class MtlLib:
|
||||
name: str
|
||||
|
||||
def parse_fixed_point_vector(args, n):
|
||||
split = args.split()
|
||||
assert len(split) == n, (n, split)
|
||||
return tuple(map(fixed_point.parse, split))
|
||||
|
||||
def parse_vertex_position(args):
|
||||
coordinates = parse_fixed_point_vector(args, 3)
|
||||
yield VertexPosition(*coordinates)
|
||||
|
||||
def parse_vertex_normal(args):
|
||||
coordinates = parse_fixed_point_vector(args, 3)
|
||||
yield VertexNormal(*coordinates)
|
||||
|
||||
def parse_vertex_texture(args):
|
||||
coordinates = parse_fixed_point_vector(args, 2)
|
||||
yield VertexTexture(*coordinates)
|
||||
|
||||
def int_minus_one(s):
|
||||
n = int(s) - 1
|
||||
assert n >= 0
|
||||
return n
|
||||
|
||||
def _parse_vertex_indices(args):
|
||||
indices = args.split('/')
|
||||
assert len(indices) == 3, indices
|
||||
return IndexVTN(*map(int_minus_one, indices))
|
||||
|
||||
def parse_face(args):
|
||||
vertices = args.split()
|
||||
if len(vertices) == 3:
|
||||
yield Triangle(*map(_parse_vertex_indices, vertices))
|
||||
elif len(vertices) == 4:
|
||||
yield Quadrilateral(*map(_parse_vertex_indices, vertices))
|
||||
else:
|
||||
assert False, (len(vertices), args)
|
||||
|
||||
def safe(s):
|
||||
return s.replace('-', '_').replace('.', '_').replace(':', '_')
|
||||
|
||||
def parse_object(args):
|
||||
name, = args.split()
|
||||
yield Object(safe(name))
|
||||
|
||||
def parse_material(args):
|
||||
name, = args.split()
|
||||
yield Material(None, safe(name))
|
||||
|
||||
def parse_mtllib(args):
|
||||
name, = args.split()
|
||||
yield MtlLib(name)
|
||||
|
||||
def parse_obj_line(line):
|
||||
prefixes = [
|
||||
('v ', parse_vertex_position),
|
||||
('vn ', parse_vertex_normal),
|
||||
('vt ', parse_vertex_texture),
|
||||
('f ', parse_face),
|
||||
('o ', parse_object),
|
||||
('usemtl ', parse_material),
|
||||
('mtllib ', parse_mtllib),
|
||||
]
|
||||
for prefix, parser in prefixes:
|
||||
if line.startswith(prefix):
|
||||
args = line.removeprefix(prefix)
|
||||
yield from parser(args)
|
||||
|
||||
def group_by_type(l):
|
||||
vertices = defaultdict(list)
|
||||
current_object = None
|
||||
faces = defaultdict(lambda: defaultdict(list))
|
||||
materials = dict()
|
||||
current_mtllib = None
|
||||
multi_material_index = 0
|
||||
for i in l:
|
||||
if type(i) in {VertexPosition, VertexTexture, VertexNormal}:
|
||||
vertices[type(i)].append(i)
|
||||
elif type(i) in {Triangle, Quadrilateral}:
|
||||
assert current_object is not None
|
||||
faces[current_object.name][type(i)].append(i)
|
||||
elif type(i) is Material:
|
||||
assert current_object is not None
|
||||
assert current_mtllib is not None
|
||||
i.lib = current_mtllib.name
|
||||
if current_object.name in materials:
|
||||
if multi_material_index != 0:
|
||||
current_object.name = current_object.name[:-4]
|
||||
current_object.name += f"_{multi_material_index:03}"
|
||||
multi_material_index += 1
|
||||
assert current_object.name not in materials
|
||||
materials[current_object.name] = i
|
||||
elif type(i) is Object:
|
||||
multi_material_index = 0
|
||||
current_object = i
|
||||
elif type(i) is MtlLib:
|
||||
current_mtllib = i
|
||||
else:
|
||||
assert False, type(i)
|
||||
|
||||
return dict(vertices), dict((k, dict(v)) for k, v in faces.items()), materials
|
||||
|
||||
def parse_obj_file(buf):
|
||||
return group_by_type((
|
||||
parsed
|
||||
for line in buf.strip().split('\n')
|
||||
for parsed in parse_obj_line(line)
|
||||
if not line.startswith('#')
|
||||
))
|
@ -1,9 +0,0 @@
|
||||
from os import path
|
||||
|
||||
def texture_path(s):
|
||||
#return path.join('..', 'texture', s)
|
||||
return s
|
||||
|
||||
def model_path(s):
|
||||
#return path.join('..', 'model', s)
|
||||
return s
|
@ -1,34 +0,0 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass
|
||||
class Profile:
|
||||
position: tuple[int, int]
|
||||
texture: tuple[int, int]
|
||||
normal: tuple[int, int]
|
||||
|
||||
@dataclass
|
||||
class FixedPointBits:
|
||||
integer: int
|
||||
fraction: int
|
||||
|
||||
def to_str(self):
|
||||
return f"{self.integer}.{self.fraction} fixed-point"
|
||||
|
||||
@dataclass
|
||||
class FloatingPoint:
|
||||
def to_str(self):
|
||||
return f"floating-point"
|
||||
|
||||
profiles = {}
|
||||
|
||||
profiles["nds"] = Profile(
|
||||
position = FixedPointBits(3, 12), # 3.12
|
||||
normal = FixedPointBits(0, 9), # 0.9
|
||||
texture = FixedPointBits(1, 14), # 1.14
|
||||
)
|
||||
|
||||
profiles["dreamcast"] = Profile(
|
||||
position = FloatingPoint(),
|
||||
normal = FloatingPoint(),
|
||||
texture = FloatingPoint(),
|
||||
)
|
@ -1,119 +0,0 @@
|
||||
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
|
||||
|
||||
material_filenames = sys.argv[1:]
|
||||
|
||||
def render_material_enum(newmtl_mapkd):
|
||||
yield f"enum material {{"
|
||||
for newmtl, mapkd in newmtl_mapkd:
|
||||
yield f"{newmtl.name},";
|
||||
yield "};"
|
||||
|
||||
def render_pixel_descriptor(offset, mapkd, dimensions):
|
||||
name, _ext = mapkd.name.rsplit('.', maxsplit=1)
|
||||
pixel_name = f"{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_metadata(mapkd):
|
||||
path = texture_path(mapkd.name)
|
||||
with Image.open(path) as im:
|
||||
dimensions = im.size
|
||||
colors = len(im.palette.colors)
|
||||
return dimensions, colors
|
||||
|
||||
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(offset, mapkd):
|
||||
dimensions, colors = image_metadata(mapkd)
|
||||
palette_size = round_up_colors(mapkd.name, colors)
|
||||
|
||||
# pixel descriptor
|
||||
yield from render_pixel_descriptor(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(newmtl_mapkd):
|
||||
yield "struct material_descriptor material[] = {"
|
||||
offset = Offset(0, 0)
|
||||
for newmtl, mapkd in newmtl_mapkd:
|
||||
yield f"[{newmtl.name}] = {{"
|
||||
yield from render_material(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__":
|
||||
material_filenames = sys.argv[1:]
|
||||
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(newmtl_mapkd))
|
||||
render(render_materials(newmtl_mapkd))
|
||||
sys.stdout.write(out.getvalue())
|
@ -1,174 +0,0 @@
|
||||
from dataclasses import astuple
|
||||
import sys
|
||||
from generate import renderer
|
||||
import math
|
||||
|
||||
import fixed_point
|
||||
|
||||
from parse_obj import parse_obj_file
|
||||
from parse_obj import VertexPosition
|
||||
from parse_obj import VertexNormal
|
||||
from parse_obj import VertexTexture
|
||||
from parse_obj import Triangle
|
||||
from parse_obj import Quadrilateral
|
||||
|
||||
import profiles
|
||||
|
||||
def render_index_vtn(index_vtn):
|
||||
s = ", ".join(map(str, index_vtn))
|
||||
yield f"{{{s}}},"
|
||||
|
||||
def render_face(face):
|
||||
yield "{ .v = {"
|
||||
for index_vtn in astuple(face):
|
||||
yield from render_index_vtn(index_vtn)
|
||||
yield "}},"
|
||||
|
||||
def render_faces(prefix, name, faces):
|
||||
yield f"union {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 unit_vector(vec):
|
||||
x = vec.x.to_float()
|
||||
y = vec.y.to_float()
|
||||
z = vec.z.to_float()
|
||||
norm = math.sqrt(x ** 2 + y ** 2 + z ** 2)
|
||||
return type(vec)(
|
||||
fixed_point.parse(str(x / norm)),
|
||||
fixed_point.parse(str(y / norm)),
|
||||
fixed_point.parse(str(z / norm))
|
||||
)
|
||||
|
||||
def xyz(vec):
|
||||
return (vec.x, vec.y, vec.z)
|
||||
|
||||
def uv(vec):
|
||||
return (vec.u, vec.v)
|
||||
|
||||
def render_vertex(profile_item, vertex_tuple):
|
||||
def _profile_item(profile_item, fp):
|
||||
if type(profile_item) == profiles.FixedPointBits:
|
||||
return fp.to_fixed_point(profile_item.integer, profile_item.fraction).to_int()
|
||||
elif type(profile_item) == profiles.FloatingPoint:
|
||||
return fp.to_float()
|
||||
else:
|
||||
assert False, type(profile_item)
|
||||
|
||||
s = ", ".join(
|
||||
str(_profile_item(profile_item, fp))
|
||||
for fp in vertex_tuple
|
||||
)
|
||||
yield f"{{{s}}},"
|
||||
|
||||
def render_vertices(profile_item, prefix, name, vertices):
|
||||
yield f"// {profile_item.to_str()}"
|
||||
yield f"vertex_{name} {prefix}_{name}[] = {{"
|
||||
for i, vertex in enumerate(vertices):
|
||||
yield from render_vertex(profile_item, vertex)
|
||||
yield "};"
|
||||
|
||||
def render_vertex_positions(profile, prefix, vertex_positions):
|
||||
yield from render_vertices(profile.position,
|
||||
prefix,
|
||||
"position",
|
||||
map(xyz, vertex_positions))
|
||||
|
||||
def render_vertex_normals(profile, prefix, vertex_normals):
|
||||
yield from render_vertices(profile.normal,
|
||||
prefix,
|
||||
"normal",
|
||||
map(xyz, map(unit_vector, vertex_normals)))
|
||||
|
||||
def render_vertex_texture(profile, prefix, vertex_textures):
|
||||
yield from render_vertices(profile.texture,
|
||||
prefix,
|
||||
"texture",
|
||||
map(uv, vertex_textures))
|
||||
|
||||
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_object_list(prefix, object_names):
|
||||
yield f"struct object * {prefix}_object_list[] = {{"
|
||||
for object_name in object_names:
|
||||
yield f"&{prefix}_{object_name},"
|
||||
yield "};"
|
||||
|
||||
def render_model(prefix, object_count):
|
||||
yield f"struct model {prefix}_model = {{"
|
||||
yield f".position = &{prefix}_position[0],"
|
||||
yield f".texture = &{prefix}_texture[0],"
|
||||
yield f".normal = &{prefix}_normal[0],"
|
||||
yield f".object = &{prefix}_object_list[0],"
|
||||
yield f".object_count = {object_count},"
|
||||
yield "};"
|
||||
|
||||
def render_header():
|
||||
yield "#pragma once"
|
||||
yield ""
|
||||
yield "#include <stddef.h>"
|
||||
yield ""
|
||||
yield '#include "../model.h"'
|
||||
yield ""
|
||||
|
||||
obj_filename = sys.argv[1]
|
||||
prefix = sys.argv[2]
|
||||
profile_name = sys.argv[3]
|
||||
|
||||
profile = profiles.profiles[profile_name]
|
||||
|
||||
with open(obj_filename) as f:
|
||||
buf = f.read()
|
||||
|
||||
vertices, faces, materials = parse_obj_file(buf)
|
||||
render, out = renderer()
|
||||
render(render_header())
|
||||
render(render_vertex_positions(profile, prefix, vertices[VertexPosition]))
|
||||
render(render_vertex_texture(profile, prefix, vertices[VertexTexture]))
|
||||
render(render_vertex_normals(profile, prefix, vertices[VertexNormal]))
|
||||
|
||||
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)));
|
||||
|
||||
render(render_object_list(prefix, faces.keys()))
|
||||
render(render_model(prefix, len(faces)))
|
||||
|
||||
sys.stdout.write(out.getvalue())
|
2
header.s
2
header.s
@ -5,7 +5,7 @@
|
||||
.ascii "00" /* Maker Code */
|
||||
.byte 0x0 /* Unit Code */
|
||||
.byte 0x0 /* Device type */
|
||||
.byte 0x0 /* Device capacity */
|
||||
.byte 0x1 /* Device capacity */
|
||||
.fill 7,1,0x0 /* Reserved */
|
||||
.byte 0x0 /* Reserved */
|
||||
.byte 0x0 /* NDS region */
|
||||
|
1
model_generator
Symbolic link
1
model_generator
Symbolic link
@ -0,0 +1 @@
|
||||
../model_generator/
|
Loading…
Reference in New Issue
Block a user