Various fixes and optimisations for zone map generation.
This commit is contained in:
parent
ce55ca8ab7
commit
20c7e28e38
69
ff5reader.py
69
ff5reader.py
|
@ -97,19 +97,6 @@ if pyqt_version == 0:
|
||||||
'Make sure you installed the PyQt4 package.')
|
'Make sure you installed the PyQt4 package.')
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
||||||
with open(filename_en, 'rb') as file:
|
|
||||||
ROM_en = file.read()
|
|
||||||
print(len(ROM_en), filename_en)
|
|
||||||
with open(filename_jp, 'rb') as file:
|
|
||||||
ROM_jp = file.read()
|
|
||||||
print(len(ROM_jp), filename_jp)
|
|
||||||
with open(filename_jp_ff4, 'rb') as file:
|
|
||||||
ROM_FF4jp = file.read()
|
|
||||||
print(len(ROM_FF4jp), filename_jp_ff4)
|
|
||||||
with open(filename_jp_ff6, 'rb') as file:
|
|
||||||
ROM_FF6jp = file.read()
|
|
||||||
print(len(ROM_FF6jp), filename_jp_ff6)
|
|
||||||
|
|
||||||
|
|
||||||
class FF5Reader(QMainWindow):
|
class FF5Reader(QMainWindow):
|
||||||
'''
|
'''
|
||||||
|
@ -118,6 +105,21 @@ class FF5Reader(QMainWindow):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
QMainWindow.__init__(self, None)
|
QMainWindow.__init__(self, None)
|
||||||
perfcount()
|
perfcount()
|
||||||
|
print('Reading ROMs')
|
||||||
|
with open(filename_en, 'rb') as file:
|
||||||
|
ROM_en = file.read()
|
||||||
|
print(len(ROM_en), filename_en)
|
||||||
|
with open(filename_jp, 'rb') as file:
|
||||||
|
ROM_jp = file.read()
|
||||||
|
print(len(ROM_jp), filename_jp)
|
||||||
|
with open(filename_jp_ff4, 'rb') as file:
|
||||||
|
ROM_FF4jp = file.read()
|
||||||
|
print(len(ROM_FF4jp), filename_jp_ff4)
|
||||||
|
with open(filename_jp_ff6, 'rb') as file:
|
||||||
|
ROM_FF6jp = file.read()
|
||||||
|
print(len(ROM_FF6jp), filename_jp_ff6)
|
||||||
|
perfcount()
|
||||||
|
|
||||||
print('Generating Glyphs')
|
print('Generating Glyphs')
|
||||||
self.glyph_sprites = {
|
self.glyph_sprites = {
|
||||||
'glyphs_en_s': generate_glyphs(ROM_en, 0x11F000),
|
'glyphs_en_s': generate_glyphs(ROM_en, 0x11F000),
|
||||||
|
@ -126,7 +128,7 @@ class FF5Reader(QMainWindow):
|
||||||
'glyphs_jp_l': generate_glyphs_large(ROM_jp, 0x03E800),
|
'glyphs_jp_l': generate_glyphs_large(ROM_jp, 0x03E800),
|
||||||
'glyphs_kanji': generate_glyphs_large(ROM_jp, 0x1BD000, 0x1AA), # Kanji are unchanged in EN version
|
'glyphs_kanji': generate_glyphs_large(ROM_jp, 0x1BD000, 0x1AA), # Kanji are unchanged in EN version
|
||||||
}
|
}
|
||||||
make_string_img_list = functools.partial(_make_string_img_list, **self.glyph_sprites)
|
make_string_img_list = functools.partial(_make_string_img_list, ROM_en, ROM_jp, **self.glyph_sprites)
|
||||||
perfcount()
|
perfcount()
|
||||||
|
|
||||||
stringlist_headers = ['Address', 'ID', 'Name']
|
stringlist_headers = ['Address', 'ID', 'Name']
|
||||||
|
@ -161,7 +163,7 @@ class FF5Reader(QMainWindow):
|
||||||
zone_structure = [('NPC Layer', 2, None), # 00 01
|
zone_structure = [('NPC Layer', 2, None), # 00 01
|
||||||
('Name', 1, [z[2] for z in zone_names]), # 02
|
('Name', 1, [z[2] for z in zone_names]), # 02
|
||||||
('ShadowFlags', 1, None), # 03
|
('ShadowFlags', 1, None), # 03
|
||||||
('Graphic maths', 1, None), # 04
|
('Graphic maths', 1, None), # 04 - MSb animation-related, 6 LSbs are ID for table in 0x005BB8 which writes to $2131-$2133 (Color Math Designation, Subscreen BG color)
|
||||||
('Tile properties', 1, None), # 05
|
('Tile properties', 1, None), # 05
|
||||||
('Flags '+hex(6), 1, None), # 06
|
('Flags '+hex(6), 1, None), # 06
|
||||||
(hex(7), 1, None), # 07
|
(hex(7), 1, None), # 07
|
||||||
|
@ -255,11 +257,14 @@ class FF5Reader(QMainWindow):
|
||||||
blockmaps = get_blockmaps(ROM_jp)
|
blockmaps = get_blockmaps(ROM_jp)
|
||||||
field_blocks = []
|
field_blocks = []
|
||||||
zone_pxs = []
|
zone_pxs = []
|
||||||
|
block_cache = {'misses': 0, 'p_hits': 0, 'i_hits': 0}
|
||||||
|
zone_px_cache = {'misses': 0, 'hits': 0}
|
||||||
for z in zones:
|
for z in zones:
|
||||||
blocks = make_field_map_blocks_px(ROM_jp, z, field_tiles, field_minitiles, field_blocksets)
|
blocks, miniblocks = make_field_map_blocks_px(ROM_jp, z, field_tiles, field_minitiles, field_blocksets, block_cache)
|
||||||
field_blocks.append(stitch_tileset_px([b.all for b in blocks]))
|
field_blocks.append(stitch_tileset_px([b.all for b in blocks+miniblocks]))
|
||||||
#zone_pxs += make_zone_pxs(blocks, [blockmaps[b] for b in z.blockmaps if b!=-1])
|
zone_pxs += make_zone_pxs(blocks, miniblocks, blockmaps, z, zone_px_cache)
|
||||||
zone_pxs += make_zone_pxs2(blocks, blockmaps, z)
|
print('Block cache results: {misses} misses, {p_hits} full hits, {i_hits} palette misses'.format(**block_cache))
|
||||||
|
print('Zone pixmap cache results: {misses} misses, {hits} hits'.format(**zone_px_cache))
|
||||||
perfcount()
|
perfcount()
|
||||||
|
|
||||||
print('Generating Battle backgrounds')
|
print('Generating Battle backgrounds')
|
||||||
|
@ -464,7 +469,7 @@ def make_string_img_large(bytestring, glyphs, glyphs_kanji, macros=None, jp=Fals
|
||||||
return string, QPixmap.fromImage(img.copy(0, 0, xmax, y+16))
|
return string, QPixmap.fromImage(img.copy(0, 0, xmax, y+16))
|
||||||
|
|
||||||
|
|
||||||
def _make_string_img_list(start, length, num,
|
def _make_string_img_list(rom_e, rom_j, start, length, num,
|
||||||
start_jp=None, len_jp=None, start_str=None, start_jp_str=None,
|
start_jp=None, len_jp=None, start_str=None, start_jp_str=None,
|
||||||
indirect=False, large=False, macros_en=None, macros_jp=None,
|
indirect=False, large=False, macros_en=None, macros_jp=None,
|
||||||
glyphs_en_s=None, glyphs_en_l=None,
|
glyphs_en_s=None, glyphs_en_l=None,
|
||||||
|
@ -480,13 +485,13 @@ def _make_string_img_list(start, length, num,
|
||||||
for id in range(num):
|
for id in range(num):
|
||||||
en = start + (id*length)
|
en = start + (id*length)
|
||||||
jp = start_jp + (id*len_jp)
|
jp = start_jp + (id*len_jp)
|
||||||
en_start = int.from_bytes(ROM_en[en:en+length],'little') + start_str
|
en_start = int.from_bytes(rom_e[en:en+length],'little') + start_str
|
||||||
en_end = int.from_bytes(ROM_en[en+length:en+(length*2)],'little') + start_str
|
en_end = int.from_bytes(rom_e[en+length:en+(length*2)],'little') + start_str
|
||||||
if en_start >= 0xC00000: # SNES memory space has the ROM starting at 0xC00000 in HiROM mode.
|
if en_start >= 0xC00000: # SNES memory space has the ROM starting at 0xC00000 in HiROM mode.
|
||||||
en_start -= 0xC00000
|
en_start -= 0xC00000
|
||||||
en_end -= 0xC00000
|
en_end -= 0xC00000
|
||||||
jp_start = int.from_bytes(ROM_jp[jp:jp+len_jp],'little') + start_jp_str
|
jp_start = int.from_bytes(rom_j[jp:jp+len_jp],'little') + start_jp_str
|
||||||
jp_end = int.from_bytes(ROM_jp[jp+len_jp:jp+(len_jp*2)],'little') + start_jp_str
|
jp_end = int.from_bytes(rom_j[jp+len_jp:jp+(len_jp*2)],'little') + start_jp_str
|
||||||
if jp_start >= 0xC00000: # SNES memory space has the ROM starting at 0xC00000 in HiROM mode.
|
if jp_start >= 0xC00000: # SNES memory space has the ROM starting at 0xC00000 in HiROM mode.
|
||||||
jp_start -= 0xC00000
|
jp_start -= 0xC00000
|
||||||
jp_end -= 0xC00000
|
jp_end -= 0xC00000
|
||||||
|
@ -494,17 +499,17 @@ def _make_string_img_list(start, length, num,
|
||||||
break
|
break
|
||||||
try: # When dealing with pointer redirection we might end up passing empty strings
|
try: # When dealing with pointer redirection we might end up passing empty strings
|
||||||
if large:
|
if large:
|
||||||
str_en, img_en = make_string_img_large(ROM_en[en_start:en_end], glyphs_en_l, glyphs_kanji, macros_en)
|
str_en, img_en = make_string_img_large(rom_e[en_start:en_end], glyphs_en_l, glyphs_kanji, macros_en)
|
||||||
else:
|
else:
|
||||||
str_en, img_en = make_string_img_small(ROM_en[en_start:en_end], glyphs_en_s)
|
str_en, img_en = make_string_img_small(rom_e[en_start:en_end], glyphs_en_s)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
str_en = ''
|
str_en = ''
|
||||||
img_en = None
|
img_en = None
|
||||||
try:
|
try:
|
||||||
if large:
|
if large:
|
||||||
str_jp, img_jp = make_string_img_large(ROM_jp[jp_start:jp_end], glyphs_jp_l, glyphs_kanji, macros_jp, jp=True)
|
str_jp, img_jp = make_string_img_large(rom_j[jp_start:jp_end], glyphs_jp_l, glyphs_kanji, macros_jp, jp=True)
|
||||||
else:
|
else:
|
||||||
str_jp, img_jp = make_string_img_small(ROM_jp[jp_start:jp_end], glyphs_jp_s, jp=True)
|
str_jp, img_jp = make_string_img_small(rom_j[jp_start:jp_end], glyphs_jp_s, jp=True)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
str_jp = ''
|
str_jp = ''
|
||||||
img_jp = None
|
img_jp = None
|
||||||
|
@ -517,11 +522,11 @@ def _make_string_img_list(start, length, num,
|
||||||
j1 = start + (id*length)
|
j1 = start + (id*length)
|
||||||
j2 = start_jp + (id*len_jp)
|
j2 = start_jp + (id*len_jp)
|
||||||
if large:
|
if large:
|
||||||
str_en, img_en = make_string_img_large(ROM_en[j1:j1+length], glyphs_en_l, glyphs_kanji, macros_en)
|
str_en, img_en = make_string_img_large(rom_e[j1:j1+length], glyphs_en_l, glyphs_kanji, macros_en)
|
||||||
str_jp, img_jp = make_string_img_large(ROM_jp[j2:j2+len_jp], glyphs_jp_l, glyphs_kanji, macros_jp, jp=True)
|
str_jp, img_jp = make_string_img_large(rom_j[j2:j2+len_jp], glyphs_jp_l, glyphs_kanji, macros_jp, jp=True)
|
||||||
else:
|
else:
|
||||||
str_en, img_en = make_string_img_small(ROM_en[j1:j1+length], glyphs_en_s)
|
str_en, img_en = make_string_img_small(rom_e[j1:j1+length], glyphs_en_s)
|
||||||
str_jp, img_jp = make_string_img_small(ROM_jp[j2:j2+len_jp], glyphs_jp_s, jp=True)
|
str_jp, img_jp = make_string_img_small(rom_j[j2:j2+len_jp], glyphs_jp_s, jp=True)
|
||||||
stringlist.append([hex(j1, 6), hex(id, id_digits), str_en, img_en, str_jp, img_jp])
|
stringlist.append([hex(j1, 6), hex(id, id_digits), str_en, img_en, str_jp, img_jp])
|
||||||
return stringlist
|
return stringlist
|
||||||
|
|
||||||
|
|
159
includes/snes.py
159
includes/snes.py
|
@ -22,8 +22,9 @@ from includes.helpers import *
|
||||||
from includes.snestile import *
|
from includes.snestile import *
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
Zone = namedtuple('Zone', 'npcs name shadowflags blockset tilesets blockmaps palette music')
|
Zone = namedtuple('Zone', 'npcs name shadowflags blockset tilesets blockmaps pal palette music')
|
||||||
Block = namedtuple('Block', 'priority0 priority1 all')
|
Block = namedtuple('Block', 'priority0 priority1 all')
|
||||||
|
TileMapping = namedtuple('TileMapping', 'tile palette h_flip v_flip priority')
|
||||||
|
|
||||||
def parse_zone(rom, id, start_address=0x0E9C00):
|
def parse_zone(rom, id, start_address=0x0E9C00):
|
||||||
ptr = start_address+(id*0x1A)
|
ptr = start_address+(id*0x1A)
|
||||||
|
@ -40,10 +41,22 @@ def parse_zone(rom, id, start_address=0x0E9C00):
|
||||||
blockmaps = [(blockmaps_b & 0x000003FF) - 1,
|
blockmaps = [(blockmaps_b & 0x000003FF) - 1,
|
||||||
((blockmaps_b & 0x000FFC00) >> 10) - 1,
|
((blockmaps_b & 0x000FFC00) >> 10) - 1,
|
||||||
((blockmaps_b & 0x3FF00000) >> 20) - 1]
|
((blockmaps_b & 0x3FF00000) >> 20) - 1]
|
||||||
pal_address = 0x03BB00 + (rom[ptr+0x16]<<8)
|
pal = rom[ptr+0x16]
|
||||||
|
pal_address = 0x03BB00 + (pal<<8)
|
||||||
palettes = [generate_palette(rom, pal_address+i*32, transparent=True) for i in range(8)]
|
palettes = [generate_palette(rom, pal_address+i*32, transparent=True) for i in range(8)]
|
||||||
music = rom[ptr+0x19]
|
music = rom[ptr+0x19]
|
||||||
return Zone(npcs, name, shadowflags, blockset, tilesets, blockmaps, palettes, music)
|
return Zone(npcs, name, shadowflags, blockset, tilesets, blockmaps, pal, palettes, music)
|
||||||
|
|
||||||
|
'''
|
||||||
|
This is a bit of a mess of pointer chains for now, so generalising it will have to wait.
|
||||||
|
UPDATE: i2-i7 merely obtain a zone ID. Whoops.
|
||||||
|
'''
|
||||||
|
#i2 = indirect(rom, 0x0E2400 + id*2)
|
||||||
|
#i3 = indirect(rom, 0x0E2402 + i2)*2
|
||||||
|
#i4 = indirect(rom, 0x18E080 + i3)
|
||||||
|
#i5 = indirect(rom, 0x18E081 + i4+4)*3
|
||||||
|
#i6 = indirect(rom, 0x083320 + i5)
|
||||||
|
#i7 = indirect(rom, 0x080001 + i6) & 0x03FF
|
||||||
|
|
||||||
|
|
||||||
def make_battle_strip(rom, palette_address, tile_address, num_tiles, bpp=4):
|
def make_battle_strip(rom, palette_address, tile_address, num_tiles, bpp=4):
|
||||||
|
@ -204,36 +217,14 @@ def stitch_tileset_px(tiles_px):
|
||||||
canvas.draw_pixmap(i%16, i//16, tile)
|
canvas.draw_pixmap(i%16, i//16, tile)
|
||||||
return canvas.pixmap()
|
return canvas.pixmap()
|
||||||
|
|
||||||
def get_field_map_tiles(rom, id):
|
|
||||||
'''
|
|
||||||
This is a bit of a mess of pointer chains for now, so generalising it will have to wait.
|
|
||||||
Palette selection is probably determined by the tilemap which is outside the scope of this, so we'll just use #1.
|
|
||||||
UPDATE: i2-i7 merely obtain a zone ID. Whoops.
|
|
||||||
'''
|
|
||||||
#i2 = indirect(rom, 0x0E2400 + id*2)
|
|
||||||
#i3 = indirect(rom, 0x0E2402 + i2)*2
|
|
||||||
#i4 = indirect(rom, 0x18E080 + i3)
|
|
||||||
#i5 = indirect(rom, 0x18E081 + i4+4)*3
|
|
||||||
#i6 = indirect(rom, 0x083320 + i5)
|
|
||||||
#i7 = indirect(rom, 0x080001 + i6) & 0x03FF
|
|
||||||
i8 = id * 0x1A
|
|
||||||
tilesets = indirect(rom, 0x0E9C09 + i8, length=3)
|
|
||||||
tile_index_0 = (tilesets & 0x00003F) # (indirect(rom, 0x0E9C09 + i8) & 0x003F)
|
|
||||||
tile_index_1 = (tilesets & 0x000FC0) >> 6 # (indirect(rom, 0x0E9C09 + i8) & 0x0FC0)>>6
|
|
||||||
tile_index_2 = (tilesets & 0x03F000) >> 12 # (indirect(rom, 0x0E9C0A + i8) & 0x03F0)>>4
|
|
||||||
minitile_index = (tilesets & 0xFC0000) >> 18 # (indirect(rom, 0x0E9C0A + i8) & 0x03F0)>>4
|
|
||||||
pal_offset = indirect(rom, 0x0E9C16 + i8) * 0x100
|
|
||||||
palette_address = 0x03BB00 + pal_offset
|
|
||||||
palettes = [generate_palette(rom, palette_address+i*32, transparent=True) for i in range(8)]
|
|
||||||
return tile_index_0, tile_index_1, tile_index_2, minitile_index, palettes
|
|
||||||
|
|
||||||
def make_field_map_tile_pixmap(rom, id, st_tiles, st_minitiles):
|
def make_field_map_tile_pixmap(rom, id, st_tiles, st_minitiles):
|
||||||
*tiles, minitile, palettes = get_field_map_tiles(rom, id)
|
#*tiles, minitile, palettes = get_field_map_tiles(rom, id)
|
||||||
p = palettes[1]
|
zone = parse_zone(rom, id)
|
||||||
|
p = zone.palette[1]
|
||||||
canvas = Canvas(16, 64)
|
canvas = Canvas(16, 64)
|
||||||
for i, ts in enumerate(tiles):
|
for i, ts in enumerate(zone.tilesets[:-1]):
|
||||||
canvas.draw_pixmap(0, i*16, st_tiles[ts].pixmap(p))
|
canvas.draw_pixmap(0, i*16, st_tiles[ts].pixmap(p))
|
||||||
canvas.draw_pixmap(0, 48, st_minitiles[minitile].pixmap(p))
|
canvas.draw_pixmap(0, 48, st_minitiles[zone.tilesets[-1]].pixmap(p))
|
||||||
return canvas.pixmap()
|
return canvas.pixmap()
|
||||||
|
|
||||||
def get_field_map_block_layouts(rom, id, start_address=0x0F0000):
|
def get_field_map_block_layouts(rom, id, start_address=0x0F0000):
|
||||||
|
@ -244,26 +235,42 @@ def get_field_map_block_layouts(rom, id, start_address=0x0F0000):
|
||||||
output.append([data[j+i+k] for j in range(0, 0x800, 0x200) for k in range(2)])
|
output.append([data[j+i+k] for j in range(0, 0x800, 0x200) for k in range(2)])
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def make_field_map_blocks_px(rom, zone, tilesets, minitilesets, blocksets):
|
def make_field_map_blocks_px(rom, zone, tilesets, minitilesets, blocksets, cache):
|
||||||
*i_tiles, i_minitiles = zone.tilesets
|
cache_key_i = '{} {}'.format(' '.join([str(i) for i in zone.tilesets]), zone.blockset)
|
||||||
tiles = tilesets[i_tiles[0]] + tilesets[i_tiles[1]] + tilesets[i_tiles[2]]
|
cache_key_p = '{} {}'.format(cache_key_i, zone.pal)
|
||||||
tiles += minitilesets[i_minitiles]
|
if cache_key_p in cache:
|
||||||
blockset = blocksets[zone.blockset]
|
cache['p_hits'] += 1
|
||||||
blocks = [Block(*[b.pixmap(zone.palette) for b in make_block(tm, tiles)]) for tm in blockset]
|
return cache[cache_key_p]
|
||||||
return blocks
|
elif cache_key_i in cache:
|
||||||
|
cache['i_hits'] += 1
|
||||||
|
blocks, miniblocks = cache[cache_key_i]
|
||||||
|
else:
|
||||||
|
cache['misses'] += 1
|
||||||
|
*i_tiles, i_minitiles = zone.tilesets
|
||||||
|
tiles = tilesets[i_tiles[0]] + tilesets[i_tiles[1]] + tilesets[i_tiles[2]]
|
||||||
|
minitiles = minitilesets[i_minitiles]
|
||||||
|
blockset = blocksets[zone.blockset]
|
||||||
|
blockset_parsed = [[parse_tileset_word(tm[i*2:(i+1)*2]) for i in range(len(tm)//2)] for tm in blockset]
|
||||||
|
blocks = [Block(*make_block(bs, tiles)) for bs in blockset_parsed]
|
||||||
|
miniblocks = [Block(*make_block(bs, minitiles, tile_modulo=len(minitiles))) for bs in blockset_parsed]
|
||||||
|
cache[cache_key_i] = (blocks, miniblocks)
|
||||||
|
|
||||||
|
blocks_px = [Block(*[i.pixmap(zone.palette) for i in b]) for b in blocks]
|
||||||
|
miniblocks_px = [Block(*[i.pixmap(zone.palette) for i in b]) for b in miniblocks]
|
||||||
|
cache[cache_key_p] = (blocks_px, miniblocks_px)
|
||||||
|
return blocks_px, miniblocks_px
|
||||||
|
|
||||||
def make_block(tilemap, tiles, cols=2, rows=2, tile_adjust=0, pal_adjust=0, tile_modulo=0x1000):
|
def make_block(tilemap, tiles, cols=2, rows=2, tile_adjust=0, pal_adjust=0, tile_modulo=0x1000):
|
||||||
canvases = (Canvas_Indexed(cols, rows), Canvas_Indexed(cols, rows), Canvas_Indexed(cols, rows))
|
canvases = (Canvas_Indexed(cols, rows), Canvas_Indexed(cols, rows), Canvas_Indexed(cols, rows))
|
||||||
for i in range(len(tilemap)//2):
|
for i, tm in enumerate(tilemap):
|
||||||
tile_index, p, h_flip, v_flip, priority = parse_tileset_word(tilemap[i*2:(i+1)*2])
|
|
||||||
x = i % cols
|
x = i % cols
|
||||||
y = i //cols
|
y = i //cols
|
||||||
try:
|
try:
|
||||||
tile = tiles[(tile_index+tile_adjust)%tile_modulo]
|
tile = tiles[(tm.tile+tile_adjust)%tile_modulo]
|
||||||
canvases[priority].draw_tile(x, y, tile, h_flip, v_flip, p+pal_adjust)
|
canvases[tm.priority].draw_tile(x, y, tile, tm.h_flip, tm.v_flip, tm.palette+pal_adjust)
|
||||||
canvases[2].draw_tile(x, y, tile, h_flip, v_flip, p+pal_adjust)
|
canvases[2].draw_tile(x, y, tile, tm.h_flip, tm.v_flip, tm.palette+pal_adjust)
|
||||||
except BaseException as e:
|
except BaseException as e:
|
||||||
print(e, p, hex(tile_index,2), hex(tile_adjust,2), hex(tile_index+tile_adjust,2))
|
print(e, tm.palette, hex(tm.tile,2), hex(tile_adjust,2), hex(tm.tile+tile_adjust,2))
|
||||||
return canvases
|
return canvases
|
||||||
|
|
||||||
def get_blockmaps(rom, start_address=0x0B0000, num=0x148):
|
def get_blockmaps(rom, start_address=0x0B0000, num=0x148):
|
||||||
|
@ -277,36 +284,36 @@ def get_blockmaps(rom, start_address=0x0B0000, num=0x148):
|
||||||
blockmaps = [decompress_lzss(rom, ptr) for ptr in ptrs]
|
blockmaps = [decompress_lzss(rom, ptr) for ptr in ptrs]
|
||||||
return blockmaps
|
return blockmaps
|
||||||
|
|
||||||
def make_zone_pxs(blocks, blockmaps):
|
def make_zone_pxs(blocks, miniblocks, blockmaps, zone, cache):
|
||||||
output = []
|
cache_key = '{} {} {}'.format(' '.join([str(i) for i in zone.blockmaps+zone.tilesets]), zone.blockset, zone.pal)
|
||||||
for bm in blockmaps:
|
if cache_key in cache:
|
||||||
|
cache['hits'] += 1
|
||||||
|
return cache[cache_key]
|
||||||
|
else:
|
||||||
|
cache['misses'] += 1
|
||||||
|
output = []
|
||||||
|
layers = [None, None, None, None, None, None] # bg1.0 bg1.1 bg2.0 bg2.1 bg3.0 bg3.1
|
||||||
|
order = [4, 2, 0, 3, 1, 5] # Draw order from http://problemkaputt.de/fullsnes.htm#snespictureprocessingunitppu
|
||||||
|
for i, i_b in enumerate(zone.blockmaps):
|
||||||
|
if i_b == -1:
|
||||||
|
output.append(None)
|
||||||
|
else:
|
||||||
|
canvases = (Canvas(64, 64, tilesize=16), Canvas(64, 64, tilesize=16), Canvas(64, 64, tilesize=16))
|
||||||
|
_blocks = blocks if i < 2 else miniblocks
|
||||||
|
for j, b in enumerate(blockmaps[i_b]):
|
||||||
|
block = _blocks[b]
|
||||||
|
canvases[0].draw_pixmap(j%64, j//64, block.priority0)
|
||||||
|
canvases[1].draw_pixmap(j%64, j//64, block.priority1)
|
||||||
|
canvases[2].draw_pixmap(j%64, j//64, block.all)
|
||||||
|
output.append(canvases[2].pixmap())
|
||||||
|
layers[i*2:(i+1)*2] = canvases[0:2]
|
||||||
canvas = Canvas(64, 64, tilesize=16)
|
canvas = Canvas(64, 64, tilesize=16)
|
||||||
for i, b in enumerate(bm):
|
for i in order:
|
||||||
canvas.draw_pixmap(i%64, i//64, blocks[b])
|
if layers[i]:
|
||||||
|
canvas.draw_pixmap(0, 0, layers[i].pixmap())
|
||||||
output.append(canvas.pixmap())
|
output.append(canvas.pixmap())
|
||||||
return output
|
cache[cache_key] = output
|
||||||
|
return output
|
||||||
def make_zone_pxs2(blocks, blockmaps, zone):
|
|
||||||
output = []
|
|
||||||
layers = [None, None, None, None, None, None] # bg1.0 bg1.1 bg2.0 bg2.1 bg3.0 bg3.1
|
|
||||||
order = [4, 2, 0, 3, 1, 5] # Draw order from http://problemkaputt.de/fullsnes.htm#snespictureprocessingunitppu
|
|
||||||
for i, i_b in enumerate(zone.blockmaps):
|
|
||||||
if i_b == -1:
|
|
||||||
output.append(None)
|
|
||||||
else:
|
|
||||||
canvases = (Canvas(64, 64, tilesize=16), Canvas(64, 64, tilesize=16), Canvas(64, 64, tilesize=16))
|
|
||||||
for j, b in enumerate(blockmaps[i_b]):
|
|
||||||
canvases[0].draw_pixmap(j%64, j//64, blocks[b].priority0)
|
|
||||||
canvases[1].draw_pixmap(j%64, j//64, blocks[b].priority1)
|
|
||||||
canvases[2].draw_pixmap(j%64, j//64, blocks[b].all)
|
|
||||||
output.append(canvases[2].pixmap())
|
|
||||||
layers[i*2:(i+1)*2] = canvases[0:2]
|
|
||||||
canvas = Canvas(64, 64, tilesize=16)
|
|
||||||
for i in order:
|
|
||||||
if layers[i]:
|
|
||||||
canvas.draw_pixmap(0, 0, layers[i].pixmap())
|
|
||||||
output.append(canvas.pixmap())
|
|
||||||
return output
|
|
||||||
|
|
||||||
def decompress_battle_tilemap(rom, address):
|
def decompress_battle_tilemap(rom, address):
|
||||||
'''
|
'''
|
||||||
|
@ -371,7 +378,7 @@ def parse_tileset_word(data):
|
||||||
priority = (b & 0x20) >> 5
|
priority = (b & 0x20) >> 5
|
||||||
h_flip = (b & 0x40) >> 6
|
h_flip = (b & 0x40) >> 6
|
||||||
v_flip = (b & 0x80) >> 7
|
v_flip = (b & 0x80) >> 7
|
||||||
return tile_index, palette, h_flip, v_flip, priority
|
return TileMapping(tile_index, palette, h_flip, v_flip, priority)
|
||||||
|
|
||||||
def make_tilemap_canvas(tilemap, tiles, cols=64, rows=64, tile_adjust=0, pal_adjust=-1, tile_modulo=0x80):
|
def make_tilemap_canvas(tilemap, tiles, cols=64, rows=64, tile_adjust=0, pal_adjust=-1, tile_modulo=0x80):
|
||||||
'''
|
'''
|
||||||
|
@ -380,7 +387,7 @@ def make_tilemap_canvas(tilemap, tiles, cols=64, rows=64, tile_adjust=0, pal_adj
|
||||||
'''
|
'''
|
||||||
canvas = Canvas_Indexed(cols, rows)
|
canvas = Canvas_Indexed(cols, rows)
|
||||||
for i in range(len(tilemap)//2):
|
for i in range(len(tilemap)//2):
|
||||||
tile_index, p, h_flip, v_flip, priority = parse_tileset_word(tilemap[i*2:(i+1)*2])
|
tm = parse_tileset_word(tilemap[i*2:(i+1)*2])
|
||||||
if cols > 32:
|
if cols > 32:
|
||||||
x = (i % 32) + 32*((i//1024) % 2)
|
x = (i % 32) + 32*((i//1024) % 2)
|
||||||
y = (i //32) - 32*((i//1024) % 2)
|
y = (i //32) - 32*((i//1024) % 2)
|
||||||
|
@ -388,10 +395,10 @@ def make_tilemap_canvas(tilemap, tiles, cols=64, rows=64, tile_adjust=0, pal_adj
|
||||||
x = i % cols
|
x = i % cols
|
||||||
y = i //cols
|
y = i //cols
|
||||||
try:
|
try:
|
||||||
tile = tiles[(tile_index+tile_adjust)%tile_modulo]
|
tile = tiles[(tm.tile+tile_adjust)%tile_modulo]
|
||||||
canvas.draw_tile(x, y, tile, h_flip, v_flip, p+pal_adjust)
|
canvas.draw_tile(x, y, tile, tm.h_flip, tm.v_flip, tm.palette+pal_adjust)
|
||||||
except BaseException as e:
|
except BaseException as e:
|
||||||
print(e, p, hex(tile_index,2), hex(tile_adjust,2), hex(tile_index+tile_adjust,2))
|
print(e, tm.palette, hex(tm.tile,2), hex(tile_adjust,2), hex(tm.tile+tile_adjust,2))
|
||||||
return canvas
|
return canvas
|
||||||
|
|
||||||
def make_tilemap_pixmap(tilemap, tiles, palettes, cols=64, rows=64, tile_adjust=0, pal_adjust=-1):
|
def make_tilemap_pixmap(tilemap, tiles, palettes, cols=64, rows=64, tile_adjust=0, pal_adjust=-1):
|
||||||
|
|
|
@ -254,12 +254,12 @@ class Canvas_Indexed:
|
||||||
self.max_col = 1
|
self.max_col = 1
|
||||||
self.max_row = 1
|
self.max_row = 1
|
||||||
|
|
||||||
def draw_tile(self, col, row, image, h_flip=False, v_flip=False, palette=0):
|
def draw_tile(self, col, row, image, h_flip=False, v_flip=False, palette=0, bpp=4):
|
||||||
image = image.mirrored(h_flip, v_flip)
|
image = image.mirrored(h_flip, v_flip)
|
||||||
imgbits = image.bits()
|
imgbits = image.bits()
|
||||||
imgbits.setsize(image.byteCount())
|
imgbits.setsize(image.byteCount())
|
||||||
if palette:
|
if palette:
|
||||||
p = palette<<4
|
p = palette<<bpp
|
||||||
imgbits[:] = bytes([int(i[0])|p for i in imgbits])
|
imgbits[:] = bytes([int(i[0])|p for i in imgbits])
|
||||||
x = col*self.tilesize
|
x = col*self.tilesize
|
||||||
y = row*self.tilesize
|
y = row*self.tilesize
|
||||||
|
|
Loading…
Reference in New Issue