add twiddle
This commit is contained in:
parent
5097e0e5ac
commit
5f4b0070a6
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
__pycache__/
|
@ -2,6 +2,7 @@ import struct
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
from twiddle import texture as twiddle_texture
|
||||||
|
|
||||||
class color_format:
|
class color_format:
|
||||||
def gbgr1555(r, g, b, a): # nintendo ds
|
def gbgr1555(r, g, b, a): # nintendo ds
|
||||||
@ -29,7 +30,7 @@ class color_format:
|
|||||||
r5 = (r >> 3) & 31
|
r5 = (r >> 3) & 31
|
||||||
g6 = (g >> 2) & 63
|
g6 = (g >> 2) & 63
|
||||||
b5 = (b >> 3) & 31
|
b5 = (b >> 3) & 31
|
||||||
return (r5 << 11) | (g5 << 5) | (b5 << 0)
|
return (r5 << 11) | (g6 << 5) | (b5 << 0)
|
||||||
|
|
||||||
def axxx4444(r, g, b, a):
|
def axxx4444(r, g, b, a):
|
||||||
a4 = (a >> 4) & 15
|
a4 = (a >> 4) & 15
|
||||||
@ -44,12 +45,12 @@ class color_format:
|
|||||||
("axxx4444", color_format.axxx4444),
|
("axxx4444", color_format.axxx4444),
|
||||||
])[s]
|
])[s]
|
||||||
|
|
||||||
def convert_colors(f, convert, colors):
|
def convert_colors(convert, colors):
|
||||||
for color in colors:
|
for color in colors:
|
||||||
value = convert(*color)
|
value = convert(*color)
|
||||||
f.write(struct.pack("<H", value))
|
yield value
|
||||||
|
|
||||||
def convert_indices(f, palette, pixels):
|
def convert_indices(palette, pixels):
|
||||||
if len(palette) <= 4:
|
if len(palette) <= 4:
|
||||||
for i in range(len(pixels) // 4):
|
for i in range(len(pixels) // 4):
|
||||||
a = pixels[i * 4 + 0]
|
a = pixels[i * 4 + 0]
|
||||||
@ -73,22 +74,47 @@ def convert_indices(f, palette, pixels):
|
|||||||
else:
|
else:
|
||||||
assert False, len(palette)
|
assert False, len(palette)
|
||||||
|
|
||||||
|
def pack_colors(f, colors):
|
||||||
|
for value in colors:
|
||||||
|
f.write(struct.pack("<H", value))
|
||||||
|
|
||||||
|
def pack_indices(f, indices):
|
||||||
|
for value in indices:
|
||||||
|
f.write(struct.pack("<B", value))
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
in_file = sys.argv[1]
|
in_file = sys.argv[1]
|
||||||
format = sys.argv[2]
|
format = sys.argv[2]
|
||||||
out_file = sys.argv[3]
|
assert sys.argv[3] in {"twiddled", "non_twiddled"}
|
||||||
|
is_twiddled = sys.argv[3] == "twiddled"
|
||||||
|
out_file = sys.argv[4]
|
||||||
|
|
||||||
convert = color_format.from_string(format)
|
convert = color_format.from_string(format)
|
||||||
|
|
||||||
with Image.open(in_file) as im:
|
with Image.open(in_file) as im:
|
||||||
|
width, height = im.size
|
||||||
if not im.palette:
|
if not im.palette:
|
||||||
pixels = list(im.convert("RGBA").getdata())
|
pixels = list(im.convert("RGBA").getdata())
|
||||||
|
colors = list(convert_colors(convert, pixels))
|
||||||
|
if is_twiddled:
|
||||||
|
new_colors = [0] * len(colors)
|
||||||
|
twiddle_texture(new_colors, colors, width, height)
|
||||||
|
colors = new_colors
|
||||||
with open(out_file, 'wb') as f:
|
with open(out_file, 'wb') as f:
|
||||||
convert_colors(f, convert, pixels)
|
pack_colors(f, colors)
|
||||||
else:
|
else:
|
||||||
pixels = list(im.convert("P").getdata())
|
pixels = list(im.convert("P").getdata())
|
||||||
palette = list(im.palette.colors)
|
palette = list(im.palette.colors)
|
||||||
with open(out_file, 'wb') as f:
|
indices = list(convert_indices(palette, pixels))
|
||||||
convert_indices(f, palette, pixels)
|
colors = list(convert_colors(convert, [(*c, 255) for c in palette]))
|
||||||
|
|
||||||
|
if twiddle:
|
||||||
|
new_indices = [0] * len(indices)
|
||||||
|
twiddle_texture(new_indices, indices, width, height)
|
||||||
|
indices = new_indices
|
||||||
|
|
||||||
with open(out_file + '.pal', 'wb') as f:
|
with open(out_file + '.pal', 'wb') as f:
|
||||||
convert_colors(f, convert, [(*c, 255) for c in palette])
|
pack_colors(f, colors)
|
||||||
|
|
||||||
|
with open(out_file, 'wb') as f:
|
||||||
|
pack_indices(f, indices)
|
||||||
|
@ -8,17 +8,19 @@ from PIL import Image
|
|||||||
|
|
||||||
from parse_material import parse_mtl_file
|
from parse_material import parse_mtl_file
|
||||||
|
|
||||||
material_filenames = sys.argv[1:]
|
def render_material_enum(prefix, newmtl_mapkd):
|
||||||
|
|
||||||
def render_material_enum(newmtl_mapkd):
|
|
||||||
yield f"enum material {{"
|
yield f"enum material {{"
|
||||||
for newmtl, mapkd in newmtl_mapkd:
|
for newmtl, mapkd in newmtl_mapkd:
|
||||||
yield f"{newmtl.name},";
|
yield f"{prefix}_{newmtl.name},";
|
||||||
yield "};"
|
yield "};"
|
||||||
|
|
||||||
def render_pixel_descriptor(offset, mapkd, dimensions):
|
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)
|
name, _ext = mapkd.name.rsplit('.', maxsplit=1)
|
||||||
pixel_name = f"{name}_data"
|
pixel_name = f"{transform_filename(prefix, name)}_data"
|
||||||
width, height = dimensions
|
width, height = dimensions
|
||||||
yield ".pixel = {"
|
yield ".pixel = {"
|
||||||
yield f".start = (uint8_t *)&_binary_{pixel_name}_start,"
|
yield f".start = (uint8_t *)&_binary_{pixel_name}_start,"
|
||||||
@ -54,12 +56,10 @@ def round_up_colors(name, colors):
|
|||||||
else:
|
else:
|
||||||
assert False, (name, colors)
|
assert False, (name, colors)
|
||||||
|
|
||||||
def image_metadata(mapkd):
|
def image(mapkd):
|
||||||
path = texture_path(mapkd.name)
|
path = texture_path(mapkd.name)
|
||||||
with Image.open(path) as im:
|
im = Image.open(path)
|
||||||
dimensions = im.size
|
return im
|
||||||
colors = len(im.palette.colors)
|
|
||||||
return dimensions, colors
|
|
||||||
|
|
||||||
def round_up_n(x, multiple):
|
def round_up_n(x, multiple):
|
||||||
return ((x + multiple - 1) // multiple) * multiple
|
return ((x + multiple - 1) // multiple) * multiple
|
||||||
@ -68,27 +68,30 @@ def bytes_per_pixel(palette_size):
|
|||||||
bits_per_pixel = int(log(palette_size)/log(2))
|
bits_per_pixel = int(log(palette_size)/log(2))
|
||||||
return bits_per_pixel / 8
|
return bits_per_pixel / 8
|
||||||
|
|
||||||
def render_material(offset, mapkd):
|
def render_material(prefix, offset, mapkd):
|
||||||
dimensions, colors = image_metadata(mapkd)
|
im = image(mapkd)
|
||||||
palette_size = round_up_colors(mapkd.name, colors)
|
dimensions = im.size
|
||||||
|
#colors = len(im.palette.colors)
|
||||||
|
|
||||||
|
#palette_size = round_up_colors(mapkd.name, colors)
|
||||||
|
|
||||||
# pixel descriptor
|
# pixel descriptor
|
||||||
yield from render_pixel_descriptor(offset, mapkd, dimensions)
|
yield from render_pixel_descriptor(prefix, offset, mapkd, dimensions)
|
||||||
pixel_size = bytes_per_pixel(palette_size) * dimensions[0] * dimensions[1]
|
#pixel_size = bytes_per_pixel(palette_size) * dimensions[0] * dimensions[1]
|
||||||
#pixel_size = 2 * dimensions[0] * dimensions[1]
|
pixel_size = 2 * dimensions[0] * dimensions[1]
|
||||||
assert int(pixel_size) == pixel_size
|
assert int(pixel_size) == pixel_size
|
||||||
offset.pixel += round_up_n(int(pixel_size), 8)
|
offset.pixel += round_up_n(int(pixel_size), 8)
|
||||||
|
|
||||||
# palette descriptor
|
# palette descriptor
|
||||||
yield from render_palette_descriptor(offset, mapkd, palette_size)
|
#yield from render_palette_descriptor(offset, mapkd, palette_size)
|
||||||
offset.palette += round_up_n(colors * 2, 16)
|
#offset.palette += round_up_n(colors * 2, 16)
|
||||||
|
|
||||||
def render_materials(newmtl_mapkd):
|
def render_materials(prefix, newmtl_mapkd):
|
||||||
yield "struct material_descriptor material[] = {"
|
yield f"const struct material_descriptor {prefix}_material[] = {{"
|
||||||
offset = Offset(0, 0)
|
offset = Offset(0, 0)
|
||||||
for newmtl, mapkd in newmtl_mapkd:
|
for newmtl, mapkd in newmtl_mapkd:
|
||||||
yield f"[{newmtl.name}] = {{"
|
yield f"[{prefix}_{newmtl.name}] = {{"
|
||||||
yield from render_material(offset, mapkd)
|
yield from render_material(prefix, offset, mapkd)
|
||||||
yield "},"
|
yield "},"
|
||||||
yield "};"
|
yield "};"
|
||||||
|
|
||||||
@ -101,7 +104,8 @@ def render_header():
|
|||||||
yield ""
|
yield ""
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
material_filenames = sys.argv[1:]
|
prefix = sys.argv[1]
|
||||||
|
material_filenames = sys.argv[2:]
|
||||||
assert material_filenames
|
assert material_filenames
|
||||||
newmtl_mapkd = []
|
newmtl_mapkd = []
|
||||||
for material_filename in material_filenames:
|
for material_filename in material_filenames:
|
||||||
@ -114,6 +118,6 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
render, out = renderer()
|
render, out = renderer()
|
||||||
render(render_header())
|
render(render_header())
|
||||||
render(render_material_enum(newmtl_mapkd))
|
render(render_material_enum(prefix, newmtl_mapkd))
|
||||||
render(render_materials(newmtl_mapkd))
|
render(render_materials(prefix, newmtl_mapkd))
|
||||||
sys.stdout.write(out.getvalue())
|
sys.stdout.write(out.getvalue())
|
||||||
|
43
twiddle.py
Normal file
43
twiddle.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
def log2(n):
|
||||||
|
return {
|
||||||
|
8: 3,
|
||||||
|
16: 4,
|
||||||
|
32: 5,
|
||||||
|
64: 6,
|
||||||
|
128: 7,
|
||||||
|
256: 8,
|
||||||
|
512: 9,
|
||||||
|
1024: 10,
|
||||||
|
}[n]
|
||||||
|
|
||||||
|
def from_xy(x, y, width, height):
|
||||||
|
# maximum texture size : 1024x1024
|
||||||
|
# maximum 1-dimensional index: 0xfffff
|
||||||
|
# bits : 19-0
|
||||||
|
|
||||||
|
# y bits: 0, 2, 4, 6, 8, 10, 12, 14, 16, 18
|
||||||
|
# x bits: 1, 3, 5, 7, 9, 11, 13, 15, 17, 19
|
||||||
|
|
||||||
|
width_max = log2(width)
|
||||||
|
height_max = log2(height)
|
||||||
|
|
||||||
|
twiddle_ix = 0
|
||||||
|
for i in range(20 // 2):
|
||||||
|
if (i < width_max and i < height_max):
|
||||||
|
twiddle_ix |= ((y >> i) & 1) << (i * 2 + 0)
|
||||||
|
twiddle_ix |= ((x >> i) & 1) << (i * 2 + 1)
|
||||||
|
elif (i < width_max):
|
||||||
|
twiddle_ix |= ((x >> i) & 1) << (i + height_max)
|
||||||
|
elif (i < height_max):
|
||||||
|
twiddle_ix |= ((y >> i) & 1) << (i + width_max)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
return twiddle_ix
|
||||||
|
|
||||||
|
def texture(dst, src, width, height):
|
||||||
|
for y in range(height):
|
||||||
|
for x in range(width):
|
||||||
|
twiddle_ix = from_xy(x, y, width, height)
|
||||||
|
value = src[y * width + x]
|
||||||
|
dst[twiddle_ix] = value
|
Loading…
x
Reference in New Issue
Block a user