Added FF5 worldmap tiles. Other SNES FFs probably follow the same pattern.
This commit is contained in:
parent
b246973513
commit
adbadad532
113
ff5reader.py
113
ff5reader.py
|
@ -8,7 +8,7 @@ import os
|
||||||
from struct import unpack
|
from struct import unpack
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
from array import array
|
from array import array
|
||||||
from snestile import generate_glyphs, generate_glyphs_large, generate_palette, create_tile
|
from snestile import generate_glyphs, generate_glyphs_large, generate_palette, create_tile, create_tile_mode7_compressed
|
||||||
import const
|
import const
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
@ -207,35 +207,50 @@ class FF5Reader(QMainWindow):
|
||||||
for i in range(0x180):
|
for i in range(0x180):
|
||||||
enemy_sprite_data.append(parse_struct(ROM_en, address + (i*5), enemy_sprite_structure) + enemy_names[i][2:4])
|
enemy_sprite_data.append(parse_struct(ROM_en, address + (i*5), enemy_sprite_structure) + enemy_names[i][2:4])
|
||||||
|
|
||||||
|
worldmap_tiles = make_world_map_tiles(ROM_jp, 0x1B8000, 0x0FF9C0, 0x0FFCC0)
|
||||||
|
worldmap_tiles += make_world_map_tiles(ROM_jp, 0x1BA000, 0x0FFAC0, 0x0FFDC0)
|
||||||
|
worldmap_tiles += make_world_map_tiles(ROM_jp, 0x1BC000, 0x0FFBC0, 0x0FFEC0, length=128)
|
||||||
self.battle_strips = make_character_battle_sprites(ROM_en)
|
self.battle_strips = make_character_battle_sprites(ROM_en)
|
||||||
status_strips = make_character_status_sprites(ROM_en)
|
status_strips = make_character_status_sprites(ROM_en)
|
||||||
enemy_sprites = make_enemy_sprites(ROM_en)
|
enemy_sprites = make_enemy_sprites(ROM_en)
|
||||||
self.battle_strips_ff4 = make_character_battle_sprites_ff4(ROM_FF4jp)
|
self.battle_strips_ff4 = make_character_battle_sprites_ff4(ROM_FF4jp)
|
||||||
|
self.field_strips_ff4 = make_character_field_sprites_ff4(ROM_FF4jp)
|
||||||
|
self.portraits_ff4 = make_character_portrait_sprites_ff4(ROM_FF4jp)
|
||||||
self.battle_strips_ff6 = make_character_battle_sprites_ff6(ROM_FF6jp)
|
self.battle_strips_ff6 = make_character_battle_sprites_ff6(ROM_FF6jp)
|
||||||
self.portraits_ff6 = make_character_portrait_sprites_ff6(ROM_FF6jp)
|
self.portraits_ff6 = make_character_portrait_sprites_ff6(ROM_FF6jp)
|
||||||
|
|
||||||
enemy_sprites_named = [stack_labels(s, d[-2]) for s, d in zip(enemy_sprites, enemy_sprite_data)]
|
enemy_sprites_named = [stack_labels(s, d[-2]) for s, d in zip(enemy_sprites, enemy_sprite_data)]
|
||||||
|
|
||||||
self.tabwidget = QTabWidget()
|
self.gamewidget = QTabWidget()
|
||||||
|
self.ff4widget = QTabWidget()
|
||||||
|
self.ff5widget = QTabWidget()
|
||||||
|
self.ff6widget = QTabWidget()
|
||||||
|
self.gamewidget.addTab(self.ff5widget, 'FFV')
|
||||||
|
self.gamewidget.addTab(self.ff4widget, 'FFIV')
|
||||||
|
self.gamewidget.addTab(self.ff6widget, 'FFVI')
|
||||||
strings_tab = QTabWidget()
|
strings_tab = QTabWidget()
|
||||||
structs_tab = QTabWidget()
|
structs_tab = QTabWidget()
|
||||||
sprites_tab = QTabWidget()
|
sprites_tab = QTabWidget()
|
||||||
self.tabwidget.addTab(strings_tab, 'Strings')
|
self.ff5widget.addTab(strings_tab, 'Strings')
|
||||||
self.tabwidget.addTab(structs_tab, 'Structs')
|
self.ff5widget.addTab(structs_tab, 'Structs')
|
||||||
self.tabwidget.addTab(sprites_tab, 'Images')
|
self.ff5widget.addTab(sprites_tab, 'Images')
|
||||||
|
|
||||||
sprites_tab.addTab(make_pixmap_table(glyph_sprites_en_small, scale=4), 'Glyphs (EN)')
|
sprites_tab.addTab(make_pixmap_table(glyph_sprites_en_small, scale=4), 'Glyphs (EN)')
|
||||||
sprites_tab.addTab(make_pixmap_table(glyph_sprites_en_large, scale=2), 'Glyphs (Dialogue EN)')
|
sprites_tab.addTab(make_pixmap_table(glyph_sprites_en_large, scale=2), 'Glyphs (Dialogue EN)')
|
||||||
sprites_tab.addTab(make_pixmap_table(glyph_sprites_jp_small, scale=4), 'Glyphs (JP)')
|
sprites_tab.addTab(make_pixmap_table(glyph_sprites_jp_small, scale=4), 'Glyphs (JP)')
|
||||||
sprites_tab.addTab(make_pixmap_table(glyph_sprites_jp_large, scale=2), 'Glyphs (Large JP)')
|
sprites_tab.addTab(make_pixmap_table(glyph_sprites_jp_large, scale=2), 'Glyphs (Large JP)')
|
||||||
sprites_tab.addTab(make_pixmap_table(glyph_sprites_kanji, scale=2), 'Glyphs (Kanji)')
|
sprites_tab.addTab(make_pixmap_table(glyph_sprites_kanji, scale=2), 'Glyphs (Kanji)')
|
||||||
|
sprites_tab.addTab(make_pixmap_table(worldmap_tiles, cols=16, scale=4), 'Worldmap Tiles')
|
||||||
sprites_tab.addTab(make_pixmap_table(self.battle_strips, cols=22, scale=2), 'Character Battle Sprites')
|
sprites_tab.addTab(make_pixmap_table(self.battle_strips, cols=22, scale=2), 'Character Battle Sprites')
|
||||||
sprites_tab.addTab(make_pixmap_table(status_strips, cols=22, scale=2), 'Status Sprites')
|
sprites_tab.addTab(make_pixmap_table(status_strips, cols=22, scale=2), 'Status Sprites')
|
||||||
#sprites_tab.addTab(make_pixmap_table(enemy_sprites, scale=1), 'Enemy Sprites')
|
#sprites_tab.addTab(make_pixmap_table(enemy_sprites, scale=1), 'Enemy Sprites')
|
||||||
sprites_tab.addTab(make_pixmap_table(enemy_sprites_named, cols=32, scale=1), 'Enemy Sprites')
|
sprites_tab.addTab(make_pixmap_table(enemy_sprites_named, cols=32, scale=1), 'Enemy Sprites')
|
||||||
sprites_tab.addTab(make_pixmap_table(self.battle_strips_ff4, cols=16, scale=2), 'FF4 Character Battle Sprites')
|
|
||||||
sprites_tab.addTab(make_pixmap_table(self.battle_strips_ff6, cols=32, scale=2), 'FF6 Character Battle Sprites')
|
self.ff4widget.addTab(make_pixmap_table(self.battle_strips_ff4, cols=16, scale=2), 'Character Battle Sprites')
|
||||||
sprites_tab.addTab(make_pixmap_table(self.portraits_ff6, cols=19, scale=2), 'FF6 Character Portraits')
|
self.ff4widget.addTab(make_pixmap_table(self.portraits_ff4, cols=14, scale=2), 'Character Portraits')
|
||||||
|
self.ff4widget.addTab(make_pixmap_table(self.field_strips_ff4, cols=17, scale=2), 'Character Field Sprites')
|
||||||
|
self.ff6widget.addTab(make_pixmap_table(self.battle_strips_ff6, cols=32, scale=2), 'Character Sprites')
|
||||||
|
self.ff6widget.addTab(make_pixmap_table(self.portraits_ff6, cols=19, scale=2), 'Character Portraits')
|
||||||
|
|
||||||
|
|
||||||
structs_tab.addTab(make_table(zone_headers, zone_data, True), 'Zones')
|
structs_tab.addTab(make_table(zone_headers, zone_data, True), 'Zones')
|
||||||
|
@ -263,7 +278,7 @@ class FF5Reader(QMainWindow):
|
||||||
strings_tab.addTab(self.string_decoder, 'String Decoder')
|
strings_tab.addTab(self.string_decoder, 'String Decoder')
|
||||||
|
|
||||||
layout = QHBoxLayout()
|
layout = QHBoxLayout()
|
||||||
layout.addWidget(self.tabwidget)
|
layout.addWidget(self.gamewidget)
|
||||||
self.main_widget = QWidget(self)
|
self.main_widget = QWidget(self)
|
||||||
self.main_widget.setLayout(layout)
|
self.main_widget.setLayout(layout)
|
||||||
self.main_widget.setMinimumSize(800,600)
|
self.main_widget.setMinimumSize(800,600)
|
||||||
|
@ -351,24 +366,35 @@ def make_enemy_sprites(rom):
|
||||||
return sprites
|
return sprites
|
||||||
|
|
||||||
|
|
||||||
def make_battle_strip(rom, palette_address, tile_address, num_tiles):
|
def make_world_map_tiles(rom, tiles_address, lut_address, palette_address, length=0x100):
|
||||||
palette = generate_palette(rom, palette_address, transparent=True)
|
tiles = []
|
||||||
# We don't want the background drawn, so we'll make that colour transparent
|
palettes = [generate_palette(rom, palette_address+i*32, transparent=True) for i in range(16)]
|
||||||
|
for i in range(length):
|
||||||
|
palette = palettes[rom[lut_address+i]//16]
|
||||||
|
tiles.append(create_tile_mode7_compressed(rom[tiles_address+i*32:tiles_address+i*32+32], palette))
|
||||||
|
return tiles
|
||||||
|
|
||||||
|
def make_battle_strip(rom, palette_address, tile_address, num_tiles, bpp=4):
|
||||||
|
if isinstance(palette_address, int):
|
||||||
|
palette = generate_palette(rom, palette_address, transparent=True)
|
||||||
|
else:
|
||||||
|
palette = palette_address
|
||||||
|
b = 24 if bpp==3 else 32
|
||||||
battle_strip = Canvas(2, divceil(num_tiles, 2)) # KO sprites are here which means more tiles than FFV
|
battle_strip = Canvas(2, divceil(num_tiles, 2)) # KO sprites are here which means more tiles than FFV
|
||||||
for j in range(num_tiles):
|
for j in range(num_tiles):
|
||||||
offset = tile_address+(j*32)
|
offset = tile_address+(j*b)
|
||||||
battle_strip.draw_pixmap(j%2, j//2, create_tile(rom[offset:offset+32], palette))
|
battle_strip.draw_pixmap(j%2, j//2, create_tile(rom[offset:offset+b], palette))
|
||||||
return battle_strip.pixmap()
|
return battle_strip.pixmap()
|
||||||
|
|
||||||
|
|
||||||
def make_character_battle_sprites_ff4(rom):
|
def make_character_battle_sprites_ff4(rom):
|
||||||
tile_address = 0x0D0000
|
tile_address = 0xD0000
|
||||||
pig_tile_address = 0x0D7000
|
pig_tile_address = 0xD7000
|
||||||
golbez_tile_address = 0x0D7600
|
golbez_tile_address = 0xD7600
|
||||||
anna_tile_address = 0x0D7960
|
anna_tile_address = 0xD7960
|
||||||
palette_address = 0x0E7D00
|
palette_address = 0xE7D00
|
||||||
golbez_palette_address = 0x0E7EC0
|
golbez_palette_address = 0xE7EC0
|
||||||
anna_palette_address = 0x0E7EE0
|
anna_palette_address = 0xE7EE0
|
||||||
battle_strips = []
|
battle_strips = []
|
||||||
for i in range(0, 14*32, 32): # 14 regular characters. Pig, Golbez and Anna follow with different tile spacing and palette order.
|
for i in range(0, 14*32, 32): # 14 regular characters. Pig, Golbez and Anna follow with different tile spacing and palette order.
|
||||||
battle_strips.append(make_battle_strip(rom, palette_address+i, tile_address+(i*64), 64)) # KO sprites are here which means more tiles per strip than FFV
|
battle_strips.append(make_battle_strip(rom, palette_address+i, tile_address+(i*64), 64)) # KO sprites are here which means more tiles per strip than FFV
|
||||||
|
@ -378,6 +404,51 @@ def make_character_battle_sprites_ff4(rom):
|
||||||
battle_strips.append(make_battle_strip(rom, palette_address+i, pig_tile_address, 48))
|
battle_strips.append(make_battle_strip(rom, palette_address+i, pig_tile_address, 48))
|
||||||
return battle_strips
|
return battle_strips
|
||||||
|
|
||||||
|
def make_character_field_sprites_ff4(rom):
|
||||||
|
tile_address = 0xD8000
|
||||||
|
palette_address = 0x68000
|
||||||
|
palettes = [generate_palette(rom, palette_address+i*16, transparent=True) for i in range(8)]
|
||||||
|
LUT = [0, 0, 1, 2, 2, 2, 0, 1, 1, 3, 0, 1, 0, 0, 0,0,0]
|
||||||
|
strips = []
|
||||||
|
for p, i in zip(LUT, range(0, 17*24*32, 24*32)): # 14 regular characters. Mini, toad, pig.
|
||||||
|
strips.append(make_battle_strip(rom, palettes[p], tile_address+(i), 32, bpp=3))
|
||||||
|
for palette in palettes:
|
||||||
|
for i in range(0, 42*24*16, 24*16): # 42 others
|
||||||
|
strips.append(make_battle_strip(rom, palette, tile_address+(17*24*32)+(i), 16, bpp=3))
|
||||||
|
#for i in range(0, 16*24, 24): # 16 pigs.
|
||||||
|
#strips.append(make_battle_strip(rom, palette_address+i, tile_address, 48))
|
||||||
|
return strips
|
||||||
|
|
||||||
|
def make_character_portrait_sprites_ff4(rom):
|
||||||
|
# 4x4 tiles per character, all 3bpp
|
||||||
|
tile_address = 0xED3C0
|
||||||
|
palette_address = 0x686D0
|
||||||
|
palettes = [generate_palette(rom, palette_address+i*16, transparent=True) for i in range(14)]
|
||||||
|
portraits = []
|
||||||
|
for palette, t_start in zip(palettes, [tile_address+i*16*24 for i in range(14)]):
|
||||||
|
canvas = Canvas(4, 4)
|
||||||
|
for t in range(16):
|
||||||
|
offset = t_start+(t*24)
|
||||||
|
canvas.draw_pixmap(t%4, t//4, create_tile(rom[offset:offset+24], palette))
|
||||||
|
portraits.append(canvas.pixmap())
|
||||||
|
# Pig, mini, toad
|
||||||
|
for t_start in [tile_address+i*16*24 for i in range(14, 17)]:
|
||||||
|
for palette in palettes:
|
||||||
|
canvas = Canvas(4, 4)
|
||||||
|
for t in range(16):
|
||||||
|
offset = t_start+(t*24)
|
||||||
|
canvas.draw_pixmap(t%4, t//4, create_tile(rom[offset:offset+24], palette))
|
||||||
|
portraits.append(canvas.pixmap())
|
||||||
|
# Palette-swap time!
|
||||||
|
for palette in palettes:
|
||||||
|
for t_start in [tile_address+i*16*24 for i in range(14)]:
|
||||||
|
canvas = Canvas(4, 4)
|
||||||
|
for t in range(16):
|
||||||
|
offset = t_start+(t*24)
|
||||||
|
canvas.draw_pixmap(t%4, t//4, create_tile(rom[offset:offset+24], palette))
|
||||||
|
portraits.append(canvas.pixmap())
|
||||||
|
return portraits
|
||||||
|
|
||||||
|
|
||||||
def make_character_battle_sprites_ff6(rom):
|
def make_character_battle_sprites_ff6(rom):
|
||||||
# Palettes are non-trivial for this, will need a LUT
|
# Palettes are non-trivial for this, will need a LUT
|
||||||
|
|
199
snestile.py
199
snestile.py
|
@ -26,43 +26,60 @@ if pyqt_version == 0:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
def create_tile(bytes, palette):
|
def create_tile(data, palette):
|
||||||
'''
|
'''
|
||||||
Creates a QPixmap of a SNES tile. DO NOT USE OUTSIDE OF QApplication CONTEXT
|
Creates a QPixmap of a SNES tile. DO NOT USE OUTSIDE OF QApplication CONTEXT
|
||||||
'''
|
'''
|
||||||
planes = len(bytes)//8
|
planes = len(data)//8
|
||||||
tile = array('B', range(64))
|
tile = array('B', range(64))
|
||||||
img = QImage(8, 8, QImage.Format_Indexed8)
|
img = QImage(8, 8, QImage.Format_Indexed8)
|
||||||
imgbits = img.bits()
|
imgbits = img.bits()
|
||||||
imgbits.setsize(img.byteCount())
|
imgbits.setsize(img.byteCount())
|
||||||
if planes == 0:
|
if planes == 0:
|
||||||
raise ValueError("Empty bytes passed")
|
raise ValueError("Empty bytes passed")
|
||||||
if planes == 1:
|
if planes == 1:
|
||||||
img.setColorTable([0x00000080, 0xFFFFFFFF])
|
img.setColorTable([0x00000080, 0xFFFFFFFF])
|
||||||
for i, (j, x) in enumerate([(j,x) for j in range(8) for x in reversed(range(8))]):
|
for i, (j, x) in enumerate([(j,x) for j in range(8) for x in reversed(range(8))]):
|
||||||
tile[i] = (bytes[j] >> x & 1)
|
tile[i] = (data[j] >> x & 1)
|
||||||
else:
|
else:
|
||||||
img.setColorTable(palette)
|
img.setColorTable(palette)
|
||||||
for i, (j, x) in enumerate([(j,x) for j in range(0, 16, 2) for x in reversed(range(8))]):
|
for i, (j, x) in enumerate([(j,x) for j in range(0, 16, 2) for x in reversed(range(8))]):
|
||||||
tile[i] = (bytes[j] >> x & 1) | ((bytes[j+1] >> x & 1) << 1)
|
tile[i] = (data[j] >> x & 1) | ((data[j+1] >> x & 1) << 1)
|
||||||
if planes == 3:
|
if planes == 3:
|
||||||
for i, (j, x) in enumerate([(j,x) for j in range(16, 24, 1) for x in reversed(range(8))]):
|
for i, (j, x) in enumerate([(j,x) for j in range(16, 24, 1) for x in reversed(range(8))]):
|
||||||
tile[i] |= ((bytes[j] >> x & 1) << 2)
|
tile[i] |= ((data[j] >> x & 1) << 2)
|
||||||
elif planes >= 4:
|
elif planes >= 4:
|
||||||
for i, (j, x) in enumerate([(j,x) for j in range(16, 32, 2) for x in reversed(range(8))]):
|
for i, (j, x) in enumerate([(j,x) for j in range(16, 32, 2) for x in reversed(range(8))]):
|
||||||
tile[i] |= ((bytes[j] >> x & 1) << 2) | ((bytes[j+1] >> x & 1) << 3)
|
tile[i] |= ((data[j] >> x & 1) << 2) | ((data[j+1] >> x & 1) << 3)
|
||||||
if planes == 8:
|
if planes == 8:
|
||||||
for i, (j, x) in enumerate([(j,x) for j in range(32, 48, 2) for x in reversed(range(8))]):
|
for i, (j, x) in enumerate([(j,x) for j in range(32, 48, 2) for x in reversed(range(8))]):
|
||||||
tile[i] |= ((bytes[j] >> x & 1) << 4) | ((bytes[j+1] >> x & 1) << 5) \
|
tile[i] |= ((data[j] >> x & 1) << 4) | ((data[j+1] >> x & 1) << 5) \
|
||||||
| ((bytes[j+16] >> x & 1) << 6) | ((bytes[j+17] >> x & 1) << 7)
|
| ((data[j+16] >> x & 1) << 6) | ((data[j+17] >> x & 1) << 7)
|
||||||
imgbits[:64] = tile
|
imgbits[:64] = tile
|
||||||
return QPixmap.fromImage(img)
|
return QPixmap.fromImage(img)
|
||||||
|
|
||||||
def create_tile_old(bytes, palette):
|
def create_tile_mode7(data, palette):
|
||||||
|
# Each byte is a pixel. 8bit palette.
|
||||||
|
tile = array('B', range(64))
|
||||||
|
tile = data[:64]
|
||||||
|
img = QImage(8, 8, QImage.Format_Indexed8)
|
||||||
|
img.setColorTable(palette)
|
||||||
|
imgbits = img.bits()
|
||||||
|
imgbits.setsize(img.byteCount())
|
||||||
|
imgbits[:64] = tile
|
||||||
|
return QPixmap.fromImage(img)
|
||||||
|
|
||||||
|
def create_tile_mode7_compressed(data, palette):
|
||||||
|
# Each byte is two pixels i.e. 0xEF is Mode 7 0xF 0xE
|
||||||
|
# Palette is externally determined by LUT, only send 4bit palette
|
||||||
|
newdata = b''.join([bytes([j%16, j//16]) for j in data])
|
||||||
|
return create_tile_mode7(newdata, palette)
|
||||||
|
|
||||||
|
def create_tile_old(data, palette):
|
||||||
'''
|
'''
|
||||||
Creates a QPixmap of a SNES tile. DO NOT USE OUTSIDE OF QApplication CONTEXT
|
Creates a QPixmap of a SNES tile. DO NOT USE OUTSIDE OF QApplication CONTEXT
|
||||||
'''
|
'''
|
||||||
planes = len(bytes)//8
|
planes = len(data)//8
|
||||||
tile = array('B', range(64))
|
tile = array('B', range(64))
|
||||||
img = QImage(8, 8, QImage.Format_Indexed8)
|
img = QImage(8, 8, QImage.Format_Indexed8)
|
||||||
imgbits = img.bits()
|
imgbits = img.bits()
|
||||||
|
@ -73,88 +90,88 @@ def create_tile_old(bytes, palette):
|
||||||
img.setColorTable([0x00000080, 0xFFFFFFFF])
|
img.setColorTable([0x00000080, 0xFFFFFFFF])
|
||||||
t_ptr = 0
|
t_ptr = 0
|
||||||
for j, x in [(j,x) for j in range(8) for x in reversed(range(8))]:
|
for j, x in [(j,x) for j in range(8) for x in reversed(range(8))]:
|
||||||
tile[t_ptr] = (bytes[j] >> x & 1)
|
tile[t_ptr] = (data[j] >> x & 1)
|
||||||
t_ptr += 1
|
t_ptr += 1
|
||||||
else:
|
else:
|
||||||
img.setColorTable(palette)
|
img.setColorTable(palette)
|
||||||
t_ptr = 0
|
t_ptr = 0
|
||||||
for j, x in [(j,x) for j in range(0, 16, 2) for x in reversed(range(8))]:
|
for j, x in [(j,x) for j in range(0, 16, 2) for x in reversed(range(8))]:
|
||||||
tile[t_ptr] = (bytes[j] >> x & 1) | ((bytes[j+1] >> x & 1) << 1)
|
tile[t_ptr] = (data[j] >> x & 1) | ((data[j+1] >> x & 1) << 1)
|
||||||
t_ptr += 1
|
t_ptr += 1
|
||||||
t_ptr = 0
|
t_ptr = 0
|
||||||
if planes == 3:
|
if planes == 3:
|
||||||
for j, x in [(j,x) for j in range(16, 24, 1) for x in reversed(range(8))]:
|
for j, x in [(j,x) for j in range(16, 24, 1) for x in reversed(range(8))]:
|
||||||
tile[t_ptr] |= ((bytes[j] >> x & 1) << 2)
|
tile[t_ptr] |= ((data[j] >> x & 1) << 2)
|
||||||
t_ptr += 1
|
t_ptr += 1
|
||||||
elif planes >= 4:
|
elif planes >= 4:
|
||||||
for j, x in [(j,x) for j in range(16, 32, 2) for x in reversed(range(8))]:
|
for j, x in [(j,x) for j in range(16, 32, 2) for x in reversed(range(8))]:
|
||||||
tile[t_ptr] |= ((bytes[j] >> x & 1) << 2) | ((bytes[j+1] >> x & 1) << 3)
|
tile[t_ptr] |= ((data[j] >> x & 1) << 2) | ((data[j+1] >> x & 1) << 3)
|
||||||
t_ptr += 1
|
t_ptr += 1
|
||||||
if planes == 8:
|
if planes == 8:
|
||||||
t_ptr = 0
|
t_ptr = 0
|
||||||
for j, x in [(j,x) for j in range(32, 48, 2) for x in reversed(range(8))]:
|
for j, x in [(j,x) for j in range(32, 48, 2) for x in reversed(range(8))]:
|
||||||
tile[t_ptr] |= ((bytes[j] >> x & 1) << 4) | ((bytes[j+1] >> x & 1) << 5) \
|
tile[t_ptr] |= ((data[j] >> x & 1) << 4) | ((data[j+1] >> x & 1) << 5) \
|
||||||
| ((bytes[j+16] >> x & 1) << 6) | ((bytes[j+17] >> x & 1) << 7)
|
| ((data[j+16] >> x & 1) << 6) | ((data[j+17] >> x & 1) << 7)
|
||||||
t_ptr += 1
|
t_ptr += 1
|
||||||
imgbits[:64] = tile
|
imgbits[:64] = tile
|
||||||
return QPixmap.fromImage(img)
|
return QPixmap.fromImage(img)
|
||||||
|
|
||||||
def create_tritile(bytes):
|
def create_tritile(data):
|
||||||
img = QImage(16, 12, QImage.Format_Indexed8)
|
img = QImage(16, 12, QImage.Format_Indexed8)
|
||||||
imgbits = img.bits()
|
imgbits = img.bits()
|
||||||
imgbits.setsize(img.byteCount())
|
imgbits.setsize(img.byteCount())
|
||||||
img.setColorTable(const.dialogue_palette)
|
img.setColorTable(const.dialogue_palette)
|
||||||
tile = array('B', range(192))
|
tile = array('B', range(192))
|
||||||
for p, row, b in [(p,j,b) for p in range(2) for j in range(12) for b in reversed(range(8))]:
|
for p, row, b in [(p,j,b) for p in range(2) for j in range(12) for b in reversed(range(8))]:
|
||||||
tile[(7-b) + (row*16) + (p*8)] = (bytes[row + (p*12)] >> b & 1)
|
tile[(7-b) + (row*16) + (p*8)] = (data[row + (p*12)] >> b & 1)
|
||||||
imgbits[:192] = tile
|
imgbits[:192] = tile
|
||||||
return QPixmap.fromImage(img)
|
return QPixmap.fromImage(img)
|
||||||
|
|
||||||
def create_quadtile(bytes, ltr=False):
|
def create_quadtile(data, ltr=False):
|
||||||
img = QImage(16, 16, QImage.Format_ARGB32_Premultiplied)
|
img = QImage(16, 16, QImage.Format_ARGB32_Premultiplied)
|
||||||
img.fill(QColor(0,0,0,0))
|
img.fill(QColor(0,0,0,0))
|
||||||
painter = QtGui.QPainter(img)
|
painter = QtGui.QPainter(img)
|
||||||
painter.drawPixmap(0, 0, create_tile(bytes[0:8]))
|
painter.drawPixmap(0, 0, create_tile(data[0:8]))
|
||||||
painter.drawPixmap(8, 8, create_tile(bytes[24:32]))
|
painter.drawPixmap(8, 8, create_tile(data[24:32]))
|
||||||
if ltr:
|
if ltr:
|
||||||
painter.drawPixmap(8, 0, create_tile(bytes[8:16]))
|
painter.drawPixmap(8, 0, create_tile(data[8:16]))
|
||||||
painter.drawPixmap(0, 8, create_tile(bytes[16:24]))
|
painter.drawPixmap(0, 8, create_tile(data[16:24]))
|
||||||
else:
|
else:
|
||||||
painter.drawPixmap(0, 8, create_tile(bytes[8:16]))
|
painter.drawPixmap(0, 8, create_tile(data[8:16]))
|
||||||
painter.drawPixmap(8, 0, create_tile(bytes[16:24]))
|
painter.drawPixmap(8, 0, create_tile(data[16:24]))
|
||||||
del painter
|
del painter
|
||||||
return QPixmap.fromImage(img)
|
return QPixmap.fromImage(img)
|
||||||
|
|
||||||
def generate_glyphs(rom, offset, num=0x100, palette=const.small_palette):
|
def generate_glyphs(rom, offset, num=0x100, palette=const.small_palette):
|
||||||
spritelist = []
|
spritelist = []
|
||||||
for i in range(num):
|
for i in range(num):
|
||||||
j = offset + (i*16)
|
j = offset + (i*16)
|
||||||
spritelist.append(create_tile(rom[j:j+16], palette))
|
spritelist.append(create_tile(rom[j:j+16], palette))
|
||||||
return spritelist
|
return spritelist
|
||||||
|
|
||||||
def generate_glyphs_large(rom, offset, num=0x100):
|
def generate_glyphs_large(rom, offset, num=0x100):
|
||||||
spritelist = []
|
spritelist = []
|
||||||
for i in range(num):
|
for i in range(num):
|
||||||
j = offset + (i*24)
|
j = offset + (i*24)
|
||||||
spritelist.append(create_tritile(rom[j:j+24]))
|
spritelist.append(create_tritile(rom[j:j+24]))
|
||||||
return spritelist
|
return spritelist
|
||||||
|
|
||||||
def generate_palette(rom, offset, length=32, transparent=False):
|
def generate_palette(rom, offset, length=32, transparent=False):
|
||||||
'''
|
'''
|
||||||
Length is in bytes not colors (2 bytes per color)
|
Length is in bytes not colors (2 bytes per color)
|
||||||
We need to convert BGR555 to ARGB32 for each 2 bytes
|
We need to convert BGR555 to ARGB32 for each 2 bytes
|
||||||
'''
|
'''
|
||||||
palette = []
|
palette = []
|
||||||
for i in range(offset, offset+length, 2):
|
for i in range(offset, offset+length, 2):
|
||||||
if (i+2) < len(rom):
|
if (i+2) < len(rom):
|
||||||
short = unpack('<H', rom[i:i+2])[0]
|
short = unpack('<H', rom[i:i+2])[0]
|
||||||
b = (short & 0x7C00) >> 7 # b 0XXXXX00 00000000 -> 00000000 00000000 XXXXX000
|
b = (short & 0x7C00) >> 7 # b 0XXXXX00 00000000 -> 00000000 00000000 XXXXX000
|
||||||
g = (short & 0x03E0) << 6 # b 000000XX XXX00000 -> 00000000 XXXXX000 00000000
|
g = (short & 0x03E0) << 6 # b 000000XX XXX00000 -> 00000000 XXXXX000 00000000
|
||||||
r = (short & 0x001F) << 19 # b 00000000 000XXXXX -> XXXXX000 00000000 00000000
|
r = (short & 0x001F) << 19 # b 00000000 000XXXXX -> XXXXX000 00000000 00000000
|
||||||
color = 0xFF000000|r|g|b
|
color = 0xFF000000|r|g|b
|
||||||
else:
|
else:
|
||||||
color = 0 # Transparent
|
color = 0 # Transparent
|
||||||
palette.append(color)
|
palette.append(color)
|
||||||
if transparent:
|
if transparent:
|
||||||
palette[0] = 0
|
palette[0] = 0
|
||||||
return palette
|
return palette
|
||||||
|
|
Loading…
Reference in New Issue