background: move background-packing to new file
This commit is contained in:
parent
f4fe943b9b
commit
0f4f1b69a9
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.pyc
|
||||
__pycache__
|
255
aseprite.py
255
aseprite.py
@ -1,11 +1,8 @@
|
||||
import struct
|
||||
import sys
|
||||
from dataclasses import dataclass
|
||||
from pprint import pprint, pformat
|
||||
import textwrap
|
||||
from typing import Union, Optional
|
||||
import zlib
|
||||
from operator import itemgetter
|
||||
|
||||
class CustomInt:
|
||||
value: int
|
||||
@ -486,212 +483,58 @@ def parse_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 parse_file(mem):
|
||||
header, mem = parse_header(mem)
|
||||
#pprint(header)
|
||||
assert header.color_depth == 8, header.color_depth
|
||||
|
||||
def pack_bgr555(red, green, blue):
|
||||
bgr = (
|
||||
((red >> 3) << 0) |
|
||||
((green >> 3) << 5) |
|
||||
((blue >> 3) << 10)
|
||||
)
|
||||
return struct.pack(">H", bgr)
|
||||
frame_header, mem = parse_frame_header(mem)
|
||||
#pprint(frame_header)
|
||||
|
||||
def pack_index(i):
|
||||
return struct.pack(">I", i)
|
||||
tilesets = dict() # by tileset id
|
||||
layers = []
|
||||
palette = None
|
||||
cel_chunks = dict() # by layer index
|
||||
|
||||
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))
|
||||
for _ in range(frame_header.number_of_chunks):
|
||||
chunk, mem = parse_chunk(mem)
|
||||
#pprinti(chunk, 1)
|
||||
if chunk.chunk_type == 0x4:
|
||||
old_palette_chunk, _ = parse_old_palette_chunk(chunk.data)
|
||||
#pprinti(old_palette_chunk, 2)
|
||||
assert palette is None
|
||||
palette = old_palette_chunk
|
||||
elif chunk.chunk_type == 0x2019:
|
||||
palette_chunk, _ = parse_palette_chunk(chunk.data)
|
||||
#pprinti(palette_chunk, 2)
|
||||
assert palette is None
|
||||
palette = palette_chunk
|
||||
elif chunk.chunk_type == 0x2023:
|
||||
tileset_chunk, _ = parse_tileset_chunk(chunk.data)
|
||||
assert tileset_chunk.tileset_id not in tilesets
|
||||
tilesets[tileset_chunk.tileset_id] = tileset_chunk
|
||||
#pprinti(tileset_chunk, 2)
|
||||
elif chunk.chunk_type == 0x2004:
|
||||
layer_chunk, _ = parse_layer_chunk(chunk.data, header.flags)
|
||||
assert layer_chunk.layer_type == 2
|
||||
layers.append(layer_chunk)
|
||||
#pprinti(layer_chunk, 2)
|
||||
elif chunk.chunk_type == 0x2005:
|
||||
cel_chunk, _ = parse_cel_chunk(chunk.data)
|
||||
#pprinti(cel_chunk, 2)
|
||||
assert cel_chunk.layer_index not in cel_chunks
|
||||
cel_chunks[cel_chunk.layer_index] = cel_chunk
|
||||
elif chunk.chunk_type == 0x2020:
|
||||
# user data
|
||||
pass
|
||||
elif chunk.chunk_type == 0x2007:
|
||||
# color profile
|
||||
pass
|
||||
else:
|
||||
print("unhandled chunk: ")
|
||||
pprinti(chunk, 1)
|
||||
|
||||
def pack_palette_chunk(palette_chunk):
|
||||
with open("palette.bin", "wb") as f:
|
||||
assert palette_chunk.first_color_index_to_change == 0
|
||||
assert palette is not None
|
||||
|
||||
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)
|
||||
|
||||
header, mem = parse_header(mem)
|
||||
#pprint(header)
|
||||
assert header.color_depth == 8, header.color_depth
|
||||
|
||||
frame_header, mem = parse_frame_header(mem)
|
||||
#pprint(frame_header)
|
||||
|
||||
tilesets = dict() # by tileset id
|
||||
layers = []
|
||||
palette = None
|
||||
cel_chunks = dict() # by layer index
|
||||
|
||||
for _ in range(frame_header.number_of_chunks):
|
||||
chunk, mem = parse_chunk(mem)
|
||||
#pprinti(chunk, 1)
|
||||
if chunk.chunk_type == 0x4:
|
||||
old_palette_chunk, _ = parse_old_palette_chunk(chunk.data)
|
||||
#pprinti(old_palette_chunk, 2)
|
||||
assert palette is None
|
||||
palette = old_palette_chunk
|
||||
elif chunk.chunk_type == 0x2019:
|
||||
palette_chunk, _ = parse_palette_chunk(chunk.data)
|
||||
#pprinti(palette_chunk, 2)
|
||||
assert palette is None
|
||||
palette = palette_chunk
|
||||
elif chunk.chunk_type == 0x2023:
|
||||
tileset_chunk, _ = parse_tileset_chunk(chunk.data)
|
||||
assert tileset_chunk.tileset_id not in tilesets
|
||||
tilesets[tileset_chunk.tileset_id] = tileset_chunk
|
||||
#pprinti(tileset_chunk, 2)
|
||||
elif chunk.chunk_type == 0x2004:
|
||||
layer_chunk, _ = parse_layer_chunk(chunk.data, header.flags)
|
||||
assert layer_chunk.layer_type == 2
|
||||
layers.append(layer_chunk)
|
||||
#pprinti(layer_chunk, 2)
|
||||
elif chunk.chunk_type == 0x2005:
|
||||
cel_chunk, _ = parse_cel_chunk(chunk.data)
|
||||
#pprinti(cel_chunk, 2)
|
||||
assert cel_chunk.layer_index not in cel_chunks
|
||||
cel_chunks[cel_chunk.layer_index] = cel_chunk
|
||||
elif chunk.chunk_type == 0x2020:
|
||||
# user data
|
||||
pass
|
||||
elif chunk.chunk_type == 0x2007:
|
||||
# color profile
|
||||
pass
|
||||
else:
|
||||
print("unhandled chunk: ")
|
||||
pprinti(chunk, 1)
|
||||
|
||||
assert palette is not None
|
||||
|
||||
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}");
|
||||
return tilesets, layers, palette, cel_chunks
|
||||
|
168
background.py
Normal file
168
background.py
Normal 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}");
|
Loading…
x
Reference in New Issue
Block a user