Mercurial > hg > tilerswift
comparison nes.py @ 124:a74c65cd0ce3 draft
NES_ROM: refactor ctor and read_rom to allow initial position and palettes
This is a prelude to allowing restoring ROMs from json data.
author | Jordi Gutiérrez Hermoso <jordigh@octave.org> |
---|---|
date | Wed, 02 Oct 2019 09:13:48 -0400 |
parents | 7b3cb931be9c |
children | 1117edef8b2b |
comparison
equal
deleted
inserted
replaced
123:7b3cb931be9c | 124:a74c65cd0ce3 |
---|---|
5 from colours import TILE_PALETTES, palette_to_qt | 5 from colours import TILE_PALETTES, palette_to_qt |
6 from exceptions import ROMOpeningError | 6 from exceptions import ROMOpeningError |
7 | 7 |
8 | 8 |
9 class NES_ROM(object): | 9 class NES_ROM(object): |
10 def __init__(self, filename): | 10 def __init__(self, filename=None, initial_position=0, palettes=None): |
11 self.filename = filename | 11 self.filename = filename |
12 | 12 |
13 # To track circular rotation of the PRG bytes, in case the | 13 # To track circular rotation of the PRG bytes, in case the |
14 # tiles aren't aligned to 16-byte boundaries and the user | 14 # tiles aren't aligned to 16-byte boundaries and the user |
15 # moves it. | 15 # moves it. |
16 self.initial_position = 0 | 16 self.initial_position = initial_position |
17 self.read_rom() | 17 |
18 | 18 self.parse_rom(palettes) |
19 def read_rom(self): | 19 |
20 if self.filename.lower().endswith('.nes'): | 20 @staticmethod |
21 with open(self.filename, 'rb') as rom: | 21 def read_ines(filename): |
22 self.ines = rom.read() | 22 if filename.lower().endswith('.nes'): |
23 elif self.filename.lower().endswith('.zip'): | 23 with open(filename, 'rb') as rom: |
24 ines = rom.read() | |
25 elif filename.lower().endswith('.zip'): | |
24 try: | 26 try: |
25 with ZipFile(self.filename, 'r') as rom: | 27 with ZipFile(filename, 'r') as rom: |
26 nesfiles = [f for f in rom.filelist if not f.is_dir() | 28 nesfiles = [f for f in rom.filelist if not f.is_dir() |
27 and f.filename.lower().endswith(".nes")] | 29 and f.filename.lower().endswith(".nes")] |
28 if len(nesfiles) != 1: | 30 if len(nesfiles) != 1: |
29 raise ROMOpeningError( | 31 raise ROMOpeningError( |
30 "Zipfile does not contain exactly one NES file" | 32 "Zipfile does not contain exactly one NES file" |
31 ) | 33 ) |
32 self.ines = rom.open(nesfiles[0]).read() | 34 ines = rom.open(nesfiles[0]).read() |
33 except BadZipFile as exc: | 35 except BadZipFile as exc: |
34 raise ROMOpeningError(f"Problem opening zip file:\n{exc}") | 36 raise ROMOpeningError(f"Problem opening zip file:\n{exc}") |
35 else: | 37 else: |
36 raise ROMOpeningError( | 38 raise ROMOpeningError( |
37 f"Cannot deduce file type from file name:\n\n" | 39 f"Cannot deduce file type from file name:\n\n" |
38 f"{self.filename.split('/')[-1]}" | 40 f"{filename.split('/')[-1]}" |
39 ) | 41 ) |
42 return ines | |
43 | |
44 def parse_rom(self, palettes): | |
45 self.ines = self.read_ines(self.filename) | |
40 | 46 |
41 self.header = self.ines[0:16] | 47 self.header = self.ines[0:16] |
42 body = self.ines[16:] | 48 body = self.ines[16:] |
43 PRG_size = self.header[4]*16384 | 49 PRG_size = self.header[4]*16384 |
44 CHR_size = self.header[5]*8192 | 50 CHR_size = self.header[5]*8192 |
45 | 51 |
46 self.PRG = body[0:PRG_size] | 52 self.PRG = body[0:PRG_size] |
53 | |
47 if CHR_size == 0: | 54 if CHR_size == 0: |
48 # No chr, just read the whole ROM as tiles | 55 # No chr, just read the whole ROM as tiles |
49 self.CHR = None | 56 self.CHR = None |
50 self.tile_data = list(body) | 57 self.tile_data = list(body) |
51 else: | 58 else: |
52 self.CHR = body[PRG_size:PRG_size+CHR_size] | 59 self.CHR = body[PRG_size:PRG_size+CHR_size] |
53 self.tile_data = list(self.CHR) | 60 self.tile_data = list(self.CHR) |
54 | 61 |
55 self.tiles = [Tile(idx, self.tile_data) | 62 self.rotate_tile_data(self.initial_position) |
56 for idx in range(0, len(self.tile_data)//16)] | 63 |
64 numtiles = len(self.tile_data)//16 | |
65 if not palettes: | |
66 palettes = [None]*numtiles | |
67 elif len(palettes) != numtiles: | |
68 raise ValueError( | |
69 "JSON data does not contain the same amount of tile palattes as tiles in ROM" | |
70 ) | |
71 | |
72 self.tiles = [Tile(idx, self.tile_data, palette=palette) | |
73 for (idx, palette) in enumerate(palettes)] | |
57 | 74 |
58 def update_tiles(self): | 75 def update_tiles(self): |
59 for tile in self.tiles: | 76 for tile in self.tiles: |
60 tile.clear_caches() | 77 tile.clear_caches() |
61 | 78 |