background: move background-packing to new file

This commit is contained in:
Zack Buhman 2025-09-02 19:26:55 -05:00
parent f4fe943b9b
commit 0f4f1b69a9
3 changed files with 219 additions and 206 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.pyc
__pycache__

View File

@ -1,11 +1,8 @@
import struct import struct
import sys import sys
from dataclasses import dataclass from dataclasses import dataclass
from pprint import pprint, pformat
import textwrap
from typing import Union, Optional from typing import Union, Optional
import zlib import zlib
from operator import itemgetter
class CustomInt: class CustomInt:
value: int value: int
@ -486,144 +483,8 @@ def parse_cel_chunk(mem):
return cel_chunk, mem return cel_chunk, mem
with open(sys.argv[1], 'rb') as f:
buf = f.read()
mem = memoryview(buf)
def pprinti(o, i):
s = pformat(o)
print(textwrap.indent(s, ' ' * i))
def pack_bgr555(red, green, blue):
bgr = (
((red >> 3) << 0) |
((green >> 3) << 5) |
((blue >> 3) << 10)
)
return struct.pack(">H", bgr)
def pack_index(i):
return struct.pack(">I", i)
def pack_old_palette_chunk(old_palette_chunk):
with open("palette.bin", "wb") as f:
for color in old_palette_chunk.packets[0].colors:
f.write(pack_bgr555(*color))
def pack_palette_chunk(palette_chunk):
with open("palette.bin", "wb") as f:
assert palette_chunk.first_color_index_to_change == 0
for entry in palette_chunk.entries:
color = (entry.red, entry.green, entry.blue)
f.write(pack_bgr555(*color))
print("palette.bin", f.tell(), file=sys.stderr)
def pack_palette(palette):
if type(palette) is PaletteChunk:
pack_palette_chunk(palette)
elif type(palette) is OldPaletteChunk:
pack_old_palette_chunk(palette)
else:
assert False, type(palette)
def pack_character_2x2(tileset_chunk, offset):
#tileset_chunk.number_of_tiles,
#tileset_chunk.tile_width,
#tileset_chunk.tile_height,
assert tileset_chunk.tile_width == 16
assert tileset_chunk.tile_height == 16
assert type(tileset_chunk.data) == TilesetChunkInternal
buf = bytearray(16 * 16)
for cell_ix in range(4):
for y in range(8):
for x in range(8):
tileset_x = 8 * (cell_ix % 2) + x
tileset_y = 8 * (cell_ix // 2) + y
px = tileset_chunk.data.pixel[offset + tileset_y * 16 + tileset_x]
buf[cell_ix * 8 * 8 + y * 8 + x] = px
return bytes(buf)
def pack_character_1x1(tileset_chunk, offset):
assert tileset_chunk.tile_width == 8
assert tileset_chunk.tile_height == 8
assert type(tileset_chunk.data) == TilesetChunkInternal
buf = bytearray(8 * 8)
for y in range(8):
for x in range(8):
tileset_x = x
tileset_y = y
px = tileset_chunk.data.pixel[offset + tileset_y * 8 + tileset_x]
buf[y * 8 + x] = px
return bytes(buf)
def pack_character_patterns(filename, tileset_chunk):
with open(filename, "wb") as f:
for i in range(tileset_chunk.number_of_tiles):
offset = tileset_chunk.tile_width * tileset_chunk.tile_height * i
if tileset_chunk.tile_width == 8 and tileset_chunk.tile_height == 8:
buf = pack_character_1x1(tileset_chunk, offset)
elif tileset_chunk.tile_width == 16 and tileset_chunk.tile_height == 16:
buf = pack_character_2x2(tileset_chunk, offset)
else:
assert False, (tileset_chunk.tile_width, tileset_chunk.tile_height)
f.write(buf)
print(filename, f.tell(), file=sys.stderr)
def pack_pattern_name_table(filename, cel_chunk, x_cells, y_cells):
with open(filename, "wb") as f:
assert type(cel_chunk.data) == CelChunk_CompressedTilemap
#assert cel_chunk.data.width_in_number_of_tiles <= 64
#assert cel_chunk.data.height_in_number_of_tiles <= 64
tile_width = cel_chunk.data.width_in_number_of_tiles
tile_height = cel_chunk.data.height_in_number_of_tiles
print(tile_width, tile_height)
h_pages = ((tile_width + (x_cells - 1)) & (~(x_cells - 1))) // x_cells
v_pages = ((tile_height + (y_cells - 1)) & (~(y_cells - 1))) // y_cells
if h_pages > 2:
h_pages = 2
if v_pages > 2:
v_pages = 2
print("h_pages, v_pages", h_pages, v_pages)
for v_page in range(v_pages):
for h_page in range(h_pages):
for y in range(y_cells):
for x in range(x_cells):
tx = (h_page * x_cells) + x
ty = (v_page * y_cells) + y
if tx >= tile_width or ty >= tile_height:
f.write(pack_index(0))
else:
cel_chunk_ix = ty * tile_width + tx
tile_data = cel_chunk.data.tile[cel_chunk_ix]
tile_id = tile_data & cel_chunk.data.bitmask_for_tile_id.value
x_flip = (tile_data & cel_chunk.data.bitmask_for_x_flip.value) != 0
y_flip = (tile_data & cel_chunk.data.bitmask_for_y_flip.value) != 0
pattern = (int(y_flip) << 31) | (int(x_flip) << 30) | tile_id
f.write(pack_index(pattern))
print(filename, f.tell(), file=sys.stderr)
def parse_file(mem):
header, mem = parse_header(mem) header, mem = parse_header(mem)
#pprint(header) #pprint(header)
assert header.color_depth == 8, header.color_depth assert header.color_depth == 8, header.color_depth
@ -676,22 +537,4 @@ for _ in range(frame_header.number_of_chunks):
assert palette is not None assert palette is not None
pack_palette(palette) return tilesets, layers, palette, cel_chunks
for tileset_index, tileset_chunk in sorted(tilesets.items(), key=itemgetter(0)):
filename = f"character_pattern__tileset_{tileset_index}.bin"
pack_character_patterns(filename, tileset_chunk)
for layer_index, cel_chunk in sorted(cel_chunks.items(), key=itemgetter(0)):
filename = f"pattern_name_table__layer_{layer_index}.bin"
#layers[layer_index]
print(f"layer={layer_index} layer_name={layers[layer_index].layer_name} tileset={layers[layer_index].tileset_index}");
tileset_chunk = tilesets[layers[layer_index].tileset_index]
x_cells = 64 // (tileset_chunk.tile_width // 8)
y_cells = 64 // (tileset_chunk.tile_height // 8)
pack_pattern_name_table(filename, cel_chunk, x_cells, y_cells)
#for layer_index, layer_chunk in enumerate(layers):
# print(f"layer={layer_index} layer_name={layer_chunk.layer_name} tileset={layer_chunk.tileset_index}");

168
background.py Normal file
View File

@ -0,0 +1,168 @@
import sys
from pprint import pprint, pformat
import textwrap
import struct
from operator import itemgetter
from aseprite import parse_file
from aseprite import PaletteChunk, OldPaletteChunk, TilesetChunkInternal, CelChunk_CompressedTilemap
def pprinti(o, i):
s = pformat(o)
print(textwrap.indent(s, ' ' * i))
def pack_bgr555(red, green, blue):
bgr = (
((red >> 3) << 0) |
((green >> 3) << 5) |
((blue >> 3) << 10)
)
return struct.pack(">H", bgr)
def pack_index(i):
return struct.pack(">I", i)
def pack_old_palette_chunk(old_palette_chunk):
with open("palette.bin", "wb") as f:
for color in old_palette_chunk.packets[0].colors:
f.write(pack_bgr555(*color))
def pack_palette_chunk(palette_chunk):
with open("palette.bin", "wb") as f:
assert palette_chunk.first_color_index_to_change == 0
for entry in palette_chunk.entries:
color = (entry.red, entry.green, entry.blue)
f.write(pack_bgr555(*color))
print("palette.bin", f.tell(), file=sys.stderr)
def pack_palette(palette):
if type(palette) is PaletteChunk:
pack_palette_chunk(palette)
elif type(palette) is OldPaletteChunk:
pack_old_palette_chunk(palette)
else:
assert False, type(palette)
def pack_character_2x2(tileset_chunk, offset):
#tileset_chunk.number_of_tiles,
#tileset_chunk.tile_width,
#tileset_chunk.tile_height,
assert tileset_chunk.tile_width == 16
assert tileset_chunk.tile_height == 16
assert type(tileset_chunk.data) == TilesetChunkInternal
buf = bytearray(16 * 16)
for cell_ix in range(4):
for y in range(8):
for x in range(8):
tileset_x = 8 * (cell_ix % 2) + x
tileset_y = 8 * (cell_ix // 2) + y
px = tileset_chunk.data.pixel[offset + tileset_y * 16 + tileset_x]
buf[cell_ix * 8 * 8 + y * 8 + x] = px
return bytes(buf)
def pack_character_1x1(tileset_chunk, offset):
assert tileset_chunk.tile_width == 8
assert tileset_chunk.tile_height == 8
assert type(tileset_chunk.data) == TilesetChunkInternal
buf = bytearray(8 * 8)
for y in range(8):
for x in range(8):
tileset_x = x
tileset_y = y
px = tileset_chunk.data.pixel[offset + tileset_y * 8 + tileset_x]
buf[y * 8 + x] = px
return bytes(buf)
def pack_character_patterns(filename, tileset_chunk):
with open(filename, "wb") as f:
for i in range(tileset_chunk.number_of_tiles):
offset = tileset_chunk.tile_width * tileset_chunk.tile_height * i
if tileset_chunk.tile_width == 8 and tileset_chunk.tile_height == 8:
buf = pack_character_1x1(tileset_chunk, offset)
elif tileset_chunk.tile_width == 16 and tileset_chunk.tile_height == 16:
buf = pack_character_2x2(tileset_chunk, offset)
else:
assert False, (tileset_chunk.tile_width, tileset_chunk.tile_height)
f.write(buf)
print(filename, f.tell(), file=sys.stderr)
def pack_pattern_name_table(filename, cel_chunk, x_cells, y_cells):
with open(filename, "wb") as f:
assert type(cel_chunk.data) == CelChunk_CompressedTilemap
#assert cel_chunk.data.width_in_number_of_tiles <= 64
#assert cel_chunk.data.height_in_number_of_tiles <= 64
tile_width = cel_chunk.data.width_in_number_of_tiles
tile_height = cel_chunk.data.height_in_number_of_tiles
print(tile_width, tile_height)
h_pages = ((tile_width + (x_cells - 1)) & (~(x_cells - 1))) // x_cells
v_pages = ((tile_height + (y_cells - 1)) & (~(y_cells - 1))) // y_cells
if h_pages > 2:
h_pages = 2
if v_pages > 2:
v_pages = 2
print("h_pages, v_pages", h_pages, v_pages)
for v_page in range(v_pages):
for h_page in range(h_pages):
for y in range(y_cells):
for x in range(x_cells):
tx = (h_page * x_cells) + x
ty = (v_page * y_cells) + y
if tx >= tile_width or ty >= tile_height:
f.write(pack_index(0))
else:
cel_chunk_ix = ty * tile_width + tx
tile_data = cel_chunk.data.tile[cel_chunk_ix]
tile_id = tile_data & cel_chunk.data.bitmask_for_tile_id.value
x_flip = (tile_data & cel_chunk.data.bitmask_for_x_flip.value) != 0
y_flip = (tile_data & cel_chunk.data.bitmask_for_y_flip.value) != 0
pattern = (int(y_flip) << 31) | (int(x_flip) << 30) | tile_id
f.write(pack_index(pattern))
print(filename, f.tell(), file=sys.stderr)
with open(sys.argv[1], 'rb') as f:
buf = f.read()
mem = memoryview(buf)
tilesets, layers, palette, cel_chunks = parse_file(buf)
pack_palette(palette)
for tileset_index, tileset_chunk in sorted(tilesets.items(), key=itemgetter(0)):
filename = f"character_pattern__tileset_{tileset_index}.bin"
pack_character_patterns(filename, tileset_chunk)
for layer_index, cel_chunk in sorted(cel_chunks.items(), key=itemgetter(0)):
filename = f"pattern_name_table__layer_{layer_index}.bin"
#layers[layer_index]
print(f"layer={layer_index} layer_name={layers[layer_index].layer_name} tileset={layers[layer_index].tileset_index}");
tileset_chunk = tilesets[layers[layer_index].tileset_index]
x_cells = 64 // (tileset_chunk.tile_width // 8)
y_cells = 64 // (tileset_chunk.tile_height // 8)
pack_pattern_name_table(filename, cel_chunk, x_cells, y_cells)
#for layer_index, layer_chunk in enumerate(layers):
# print(f"layer={layer_index} layer_name={layer_chunk.layer_name} tileset={layer_chunk.tileset_index}");