diff --git a/color_convert.py b/color_convert.py index 23aa85c..07a6756 100644 --- a/color_convert.py +++ b/color_convert.py @@ -2,7 +2,7 @@ import struct import sys from PIL import Image -from twiddle import texture as twiddle_texture +from twiddle import texture as twiddle_texture, npot class color_format: def gbgr1555(r, g, b, a): # nintendo ds @@ -59,18 +59,19 @@ def convert_indices(palette, pixels): 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("> 1 + yield n + if n == 1: + break + +def generate_mips(im): + w, h = im.size + assert w == h and npot(w) == w, (w, h) + assert w >= 8, (w, h) + + images = [im] + [ + im.resize( + size=(l, l), + resample=Image.Resampling.LANCZOS, + ) + for l in mip_levels(w) + ] + + return list(reversed(images)) + +def write_mip(f, mip: Image, is_twiddled: bool, convert): + width, height = mip.size + print("mip", width, "offset", f"{f.tell():06x}") + pixels = list(im.convert("RGBA").getdata()) + colors = list(convert_colors(convert, pixels)) + if is_twiddled: + new_colors = [0] * width * height + max_twiddle_ix = twiddle_texture(new_colors, colors, width, height) + assert max_twiddle_ix + 1 == width * height, (max_twiddle_ix, width, height) + colors = new_colors[:max_twiddle_ix+1] + pack_colors(f, colors) + +def write_mips(f, im: Image, is_twiddled: bool, convert): + for mip in generate_mips(im): + write_mip(f, mip, is_twiddled, convert) + if __name__ == "__main__": in_file = sys.argv[1] format = sys.argv[2] assert sys.argv[3] in {"twiddled", "non_twiddled"} is_twiddled = sys.argv[3] == "twiddled" - out_file = sys.argv[4] + assert sys.argv[4] in {"mipmapped", "non_mipmapped"} + is_mipmapped = sys.argv[4] == "mipmapped" + out_file = sys.argv[5] convert = color_format.from_string(format) with Image.open(in_file) as im: width, height = im.size - if not im.palette: - 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 + assert width <= 1024 and height <= 1024, (width, height) + assert not im.palette + #if not im.palette: + if True: with open(out_file, 'wb') as f: - pack_colors(f, colors) + if is_mipmapped: + f.write(bytes([0] * 6)) + write_mips(f, im, is_twiddled, convert) + else: + write_mip(f, im, is_twiddled, convert) else: pixels = list(im.convert("P").getdata()) palette = list(im.palette.colors) indices = list(convert_indices(palette, pixels)) colors = list(convert_colors(convert, [(*c, 255) for c in palette])) - if twiddle: + if is_twiddled: new_indices = [0] * len(indices) twiddle_texture(new_indices, indices, width, height) indices = new_indices diff --git a/twiddle.py b/twiddle.py index 1bafdef..7dc9eca 100644 --- a/twiddle.py +++ b/twiddle.py @@ -1,5 +1,8 @@ def log2(n): return { + 1: 0, + 2: 1, + 4: 2, 8: 3, 16: 4, 32: 5, @@ -35,9 +38,24 @@ def from_xy(x, y, width, height): return twiddle_ix +def npot(v): + v -= 1; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v += 1; + return v + def texture(dst, src, width, height): + #pot_height = npot(height) + max_twiddle_ix = -1 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 + if twiddle_ix > max_twiddle_ix: + max_twiddle_ix = twiddle_ix + return max_twiddle_ix