Mercurial > hg > tilerswift
view nes.py @ 101:822e2fb5197c
refactor: move the NES ROM manipulation code into its own module
Also, rename the color module to colour 'cause I got tired of
misspelling it when I didn't have to.
author | Jordi Gutiérrez Hermoso <jordigh@octave.org> |
---|---|
date | Sat, 14 Sep 2019 23:33:01 -0400 |
parents | |
children | d5e69fe5c81a |
line wrap: on
line source
from PyQt5 import QtGui as QG from colours import TILE_PALETTES, palette_to_qt class NES_ROM(object): def __init__(self, filename): self.filename = filename self.read_rom() def read_rom(self): with open(self.filename, 'rb') as f: self.ines = f.read() self.header = self.ines[0:16] body = self.ines[16:] PRG_size = self.header[4]*16384 CHR_size = self.header[5]*8192 self.PRG = body[0:PRG_size] if CHR_size == 0: # No chr, just read the whole ROM as tiles tile_data = body self.CHR = None else: self.CHR = body[PRG_size:PRG_size+CHR_size] tile_data = self.CHR self.tiles = [Tile(tile_data[i:i+16]) for i in range(0, len(tile_data), 16)] class Tile(object): default_palette = TILE_PALETTES["Primary"] def __init__(self, raw_tile): super().__init__() self.raw_tile = raw_tile self.set_palette(self.default_palette.copy()) def __repr__(self): num_to_ascii = {0: " ", 1: ".", 2: "o", 3: "#"} return "_"*10 + "\n" + "\n".join( "[" + "".join([num_to_ascii[val] for val in row]) + "]" for row in self.tile ) + "\n" + "-"*10 def set_palette(self, new_palette): self.palette = new_palette.copy() self.update_pixmap() def update_pixmap(self): img_data = bytes(sum(self.tile, [])) image = QG.QImage(img_data, 8, 8, QG.QImage.Format_Indexed8) image.setColorTable(palette_to_qt(self.palette)) self.pixmap = QG.QPixmap(image) def get_tile(self): if getattr(self, "_tile", None) is None: self._tile = self.parse_tile(self.raw_tile) return self._tile def set_tile(self, tile): del self._tile self.raw_tile = self.unparse_tile(tile) self.update_pixmap() def del_tile(self): del self._tile del self.raw_tile tile = property(get_tile, set_tile, del_tile, "A tile parsed as an 8x8 array of ints") @classmethod def parse_tile(cls, tile): """Given a raw tile's bytes, convert it to an 8x8 array of integers.""" lowplane, hiplane = tile[0:8], tile[8:16] rows = [] for lowbyte, hibyte in zip(lowplane, hiplane): row = [ ((lowbyte >> idx) & 1) + 2*((hibyte >> idx) & 1) for idx in range(7, -1, -1) ] rows.append(row) return rows @classmethod def unparse_tile(cls, rows): """Given an 8x8 array of integers, convert it to a raw tile's bytes.""" lowplane = bytes([int(''.join(str(num & 1) for num in row), 2) for row in rows]) hiplane = bytes([int(''.join(str((num & 2) >> 1) for num in row), 2) for row in rows]) return lowplane + hiplane