color_convert: add mipmap generation
This commit is contained in:
parent
5f4b0070a6
commit
9b07ba183c
@ -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("<B", pixel))
|
||||
assert False, len(palette)
|
||||
yield 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))
|
||||
yield pixel
|
||||
elif len(palette) <= 256:
|
||||
for pixel in pixels:
|
||||
assert pixel <= 255
|
||||
f.write(struct.pack("<B", pixel))
|
||||
yield pixel
|
||||
else:
|
||||
assert False, len(palette)
|
||||
|
||||
@ -82,33 +83,74 @@ def pack_indices(f, indices):
|
||||
for value in indices:
|
||||
f.write(struct.pack("<B", value))
|
||||
|
||||
def mip_levels(n):
|
||||
while True:
|
||||
n = n >> 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
|
||||
|
18
twiddle.py
18
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user