From ce55ca8ab70c2a17ed78b84d47c0a7afdc7104f6 Mon Sep 17 00:00:00 2001 From: Luke Hubmayer-Werner Date: Fri, 30 Mar 2018 15:10:56 +1030 Subject: [PATCH] layering for zone backgrounds. TODO: 2bpp blocks --- ff5reader.py | 9 +++--- includes/qthelpers.py | 2 +- includes/snes.py | 71 +++++++++++++++++++++++++++---------------- 3 files changed, 50 insertions(+), 32 deletions(-) diff --git a/ff5reader.py b/ff5reader.py index 03779b7..af2674a 100755 --- a/ff5reader.py +++ b/ff5reader.py @@ -256,9 +256,10 @@ class FF5Reader(QMainWindow): field_blocks = [] zone_pxs = [] for z in zones: - blocks = make_field_map_blocks_px2(ROM_jp, z, field_tiles, field_minitiles, field_blocksets) - field_blocks.append(stitch_tileset_px(blocks)) - zone_pxs += make_zone_pxs(blocks, [blockmaps[b] for b in z.blockmaps if b!=-1]) + blocks = make_field_map_blocks_px(ROM_jp, z, field_tiles, field_minitiles, field_blocksets) + field_blocks.append(stitch_tileset_px([b.all for b in blocks])) + #zone_pxs += make_zone_pxs(blocks, [blockmaps[b] for b in z.blockmaps if b!=-1]) + zone_pxs += make_zone_pxs2(blocks, blockmaps, z) perfcount() print('Generating Battle backgrounds') @@ -313,7 +314,7 @@ class FF5Reader(QMainWindow): backgrounds_tab.addTab(make_px_table(worldpixmaps, cols=1, scale=1, large=True), 'Worldmaps') backgrounds_tab.addTab(make_px_table(fieldmap_tiles, cols=16, scale=1), 'Fieldmap Tiles') backgrounds_tab.addTab(make_px_table(field_blocks, cols=16, scale=1), 'Field Blocks') - backgrounds_tab.addTab(make_px_table(zone_pxs, cols=3, scale=1, large=1), 'Zone') + backgrounds_tab.addTab(make_px_table(zone_pxs, cols=4, scale=1, large=1), 'Zone') backgrounds_tab.addTab(make_px_table(battle_bgs, cols=8, scale=1), 'Battle BGs') self.ff4widget.addTab(make_px_table(self.battle_strips_ff4, cols=16, scale=2), 'Character Battle Sprites') diff --git a/includes/qthelpers.py b/includes/qthelpers.py index e51fdac..f92d505 100644 --- a/includes/qthelpers.py +++ b/includes/qthelpers.py @@ -169,7 +169,7 @@ def make_px_table(items, cols=16, scale=4, large=False): for i, item in enumerate(items): if isinstance(item, QWidget): table.setCellWidget(i // cols, i % cols, item) - else: + elif item: lab = Label() lab.setContent(item, scale=scale) lab.setAlignment(QtCore.Qt.AlignCenter) diff --git a/includes/snes.py b/includes/snes.py index ceac371..15fe8d1 100644 --- a/includes/snes.py +++ b/includes/snes.py @@ -22,7 +22,8 @@ from includes.helpers import * from includes.snestile import * from collections import namedtuple -zone = namedtuple('zone', 'npcs name shadowflags blockset tilesets blockmaps palette music') +Zone = namedtuple('Zone', 'npcs name shadowflags blockset tilesets blockmaps palette music') +Block = namedtuple('Block', 'priority0 priority1 all') def parse_zone(rom, id, start_address=0x0E9C00): ptr = start_address+(id*0x1A) @@ -35,14 +36,14 @@ def parse_zone(rom, id, start_address=0x0E9C00): (tilesets_b & 0x000FC0) >> 6, (tilesets_b & 0x03F000) >> 12, (tilesets_b & 0xFC0000) >> 18] - pal_address = 0x03BB00 + (indirect(rom, ptr+0x16)<<8) blockmaps_b = indirect(rom, ptr+0xC, length=4) blockmaps = [(blockmaps_b & 0x000003FF) - 1, ((blockmaps_b & 0x000FFC00) >> 10) - 1, ((blockmaps_b & 0x3FF00000) >> 20) - 1] + pal_address = 0x03BB00 + (rom[ptr+0x16]<<8) palettes = [generate_palette(rom, pal_address+i*32, transparent=True) for i in range(8)] music = rom[ptr+0x19] - return zone(npcs, name, shadowflags, blockset, tilesets, blockmaps, palettes, music) + return Zone(npcs, name, shadowflags, blockset, tilesets, blockmaps, palettes, music) def make_battle_strip(rom, palette_address, tile_address, num_tiles, bpp=4): @@ -167,14 +168,6 @@ def make_worldmap_chunk(rom, id, length=256): i += 1 return chunk -def make_worldmap_chunk_pixmap(rom, id, palette_address, tiles): - chunk = make_worldmap_chunk(rom, id) - palette = generate_palette(rom, palette_address, length=0x320, transparent=True) - canvas = Canvas_Indexed(len(chunk), 1, tilesize=16) - for i, c in enumerate(chunk): - canvas.draw_tile(i, 0, tiles[c]) - return canvas.pixmap(palette) - def make_worldmap_pixmap(rom, map_id, palette_address, tiles): id_offset = map_id*256 palette = generate_palette(rom, palette_address, length=0x320, transparent=True) @@ -249,27 +242,29 @@ def get_field_map_block_layouts(rom, id, start_address=0x0F0000): output = [] for i in range(0, 0x200, 2): output.append([data[j+i+k] for j in range(0, 0x800, 0x200) for k in range(2)]) - #for i in range(0, 0x800, 8): - #output.append([data[i+k] for k in range(8)]) return output -def make_field_map_blocks_px(rom, id, tilesets, minitilesets, blockmaps): - *i_tiles, i_minitiles, palettes = get_field_map_tiles(rom, id) +def make_field_map_blocks_px(rom, zone, tilesets, minitilesets, blocksets): + *i_tiles, i_minitiles = zone.tilesets tiles = tilesets[i_tiles[0]] + tilesets[i_tiles[1]] + tilesets[i_tiles[2]] tiles += minitilesets[i_minitiles] - i_blockmap = rom[0x0E9C08 + (id * 0x1A)] - blockmap = blockmaps[i_blockmap] + blockset = blocksets[zone.blockset] + blocks = [Block(*[b.pixmap(zone.palette) for b in make_block(tm, tiles)]) for tm in blockset] + return blocks - blocks = [make_tilemap_canvas(tm, tiles, cols=2, rows=2, pal_adjust=0, tile_modulo=0x1000) for tm in blockmap] - return [b.pixmap(palettes) for b in blocks] - -def make_field_map_blocks_px2(rom, _zone, tilesets, minitilesets, blocksets): - *i_tiles, i_minitiles = _zone.tilesets - tiles = tilesets[i_tiles[0]] + tilesets[i_tiles[1]] + tilesets[i_tiles[2]] - tiles += minitilesets[i_minitiles] - blockset = blocksets[_zone.blockset] - blocks = [make_tilemap_canvas(tm, tiles, cols=2, rows=2, pal_adjust=0, tile_modulo=0x1000) for tm in blockset] - return [b.pixmap(_zone.palette) for b in blocks] +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)) + for i in range(len(tilemap)//2): + tile_index, p, h_flip, v_flip, priority = parse_tileset_word(tilemap[i*2:(i+1)*2]) + x = i % cols + y = i //cols + try: + tile = tiles[(tile_index+tile_adjust)%tile_modulo] + canvases[priority].draw_tile(x, y, tile, h_flip, v_flip, p+pal_adjust) + canvases[2].draw_tile(x, y, tile, h_flip, v_flip, p+pal_adjust) + except BaseException as e: + print(e, p, hex(tile_index,2), hex(tile_adjust,2), hex(tile_index+tile_adjust,2)) + return canvases def get_blockmaps(rom, start_address=0x0B0000, num=0x148): bank = 0x0B0000 @@ -291,6 +286,28 @@ def make_zone_pxs(blocks, blockmaps): output.append(canvas.pixmap()) 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): ''' Decompresses the tilemap for a battle background.