Python: Fix tiles

This commit is contained in:
Vicki Pfau 2017-09-24 21:33:03 -07:00
parent dbeff59c06
commit ba2a31c3f2
7 changed files with 60 additions and 43 deletions

View File

@ -75,7 +75,7 @@ ffi.embedding_init_code("""
venv = os.getenv('VIRTUAL_ENV') venv = os.getenv('VIRTUAL_ENV')
if venv: if venv:
activate = os.path.join(venv, 'bin', 'activate_this.py') activate = os.path.join(venv, 'bin', 'activate_this.py')
execfile(activate, dict(__file__=activate)) exec(compile(open(activate, "rb").read(), activate, 'exec'), dict(__file__=activate))
from mgba._pylib import ffi, lib from mgba._pylib import ffi, lib
symbols = {} symbols = {}
globalSyms = { globalSyms = {

View File

@ -105,9 +105,17 @@ class Core(object):
self._core.addCoreCallbacks(self._core, self._callbacks.context) self._core.addCoreCallbacks(self._core, self._callbacks.context)
self.config = Config(ffi.addressof(native.config)) self.config = Config(ffi.addressof(native.config))
@cached_property
def graphicsCache(self):
return tile.CacheSet(self)
@cached_property @cached_property
def tiles(self): def tiles(self):
return tile.TileView(self) t = []
ts = ffi.addressof(self.graphicsCache.cache.tiles)
for i in range(lib.mTileCacheSetSize(ts)):
t.append(tile.TileView(lib.mTileCacheSetGetPointer(ts, i)))
return t
@classmethod @classmethod
def _init(cls, native): def _init(cls, native):

View File

@ -27,13 +27,13 @@ class GB(Core):
self.cpu = LR35902Core(self._core.cpu) self.cpu = LR35902Core(self._core.cpu)
@needsReset @needsReset
def _initTileCache(self, cache): def _initCache(self, cache):
lib.GBVideoTileCacheInit(cache) lib.GBVideoCacheInit(cache)
lib.GBVideoTileCacheAssociate(cache, ffi.addressof(self._native.video)) lib.GBVideoCacheAssociate(cache, ffi.addressof(self._native.video))
def _deinitTileCache(self, cache): def _deinitCache(self, cache):
self._native.video.renderer.cache = ffi.NULL self._native.video.renderer.cache = ffi.NULL
lib.mTileCacheDeinit(cache) lib.mCacheSetDeinit(cache)
def reset(self): def reset(self):
super(GB, self).reset() super(GB, self).reset()
@ -135,6 +135,7 @@ class GBSprite(Sprite):
self.paletteId = self._attr & 7 self.paletteId = self._attr & 7
else: else:
self.paletteId = (self._attr >> 4) & 1 self.paletteId = (self._attr >> 4) & 1
self.paletteId += 8
class GBObjs: class GBObjs:
@ -149,5 +150,5 @@ class GBObjs:
if index >= len(self): if index >= len(self):
raise IndexError() raise IndexError()
sprite = GBSprite(self._obj[index], self._core) sprite = GBSprite(self._obj[index], self._core)
sprite.constitute(self._core.tiles, 0, 0) sprite.constitute(self._core.tiles[0], 0)
return sprite return sprite

View File

@ -35,13 +35,13 @@ class GBA(Core):
self.cpu = ARMCore(self._core.cpu) self.cpu = ARMCore(self._core.cpu)
@needsReset @needsReset
def _initTileCache(self, cache): def _initCache(self, cache):
lib.GBAVideoTileCacheInit(cache) lib.GBAVideoCacheInit(cache)
lib.GBAVideoTileCacheAssociate(cache, ffi.addressof(self._native.video)) lib.GBAVideoCacheAssociate(cache, ffi.addressof(self._native.video))
def _deinitTileCache(self, cache): def _deinitCache(self, cache):
self._native.video.renderer.cache = ffi.NULL self._native.video.renderer.cache = ffi.NULL
lib.mTileCacheDeinit(cache) lib.mCacheSetDeinit(cache)
def reset(self): def reset(self):
super(GBA, self).reset() super(GBA, self).reset()
@ -127,6 +127,7 @@ class GBAObjs:
if index >= len(self): if index >= len(self):
raise IndexError() raise IndexError()
sprite = GBASprite(self._obj[index]) sprite = GBASprite(self._obj[index])
tiles = self._core.tiles[3 if sprite._256Color else 2]
map1D = bool(self._core._native.memory.io[0] & 0x40) map1D = bool(self._core._native.memory.io[0] & 0x40)
sprite.constitute(self._core.tiles, 0 if map1D else 0x20, int(sprite._256Color)) sprite.constitute(tiles, 0 if map1D else 0x20)
return sprite return sprite

View File

@ -12,10 +12,11 @@ except ImportError:
pass pass
class Image: class Image:
def __init__(self, width, height, stride=0): def __init__(self, width, height, stride=0, alpha=False):
self.width = width self.width = width
self.height = height self.height = height
self.stride = stride self.stride = stride
self.alpha = alpha
self.constitute() self.constitute()
def constitute(self): def constitute(self):
@ -24,7 +25,7 @@ class Image:
self.buffer = ffi.new("color_t[{}]".format(self.stride * self.height)) self.buffer = ffi.new("color_t[{}]".format(self.stride * self.height))
def savePNG(self, f): def savePNG(self, f):
p = png.PNG(f) p = png.PNG(f, mode=png.MODE_RGBA if self.alpha else png.MODE_RGB)
success = p.writeHeader(self) success = p.writeHeader(self)
success = success and p.writePixels(self) success = success and p.writePixels(self)
p.writeClose() p.writeClose()
@ -32,8 +33,9 @@ class Image:
if 'PImage' in globals(): if 'PImage' in globals():
def toPIL(self): def toPIL(self):
return PImage.frombytes("RGBX", (self.width, self.height), ffi.buffer(self.buffer), "raw", type = "RGBA" if self.alpha else "RGBX"
"RGBX", self.stride * 4) return PImage.frombytes(type, (self.width, self.height), ffi.buffer(self.buffer), "raw",
type, self.stride * 4)
def u16ToU32(c): def u16ToU32(c):
r = c & 0x1F r = c & 0x1F

View File

@ -6,17 +6,32 @@
from ._pylib import ffi, lib from ._pylib import ffi, lib
from . import vfs from . import vfs
MODE_RGB = 0
MODE_RGBA = 1
MODE_INDEX = 2
class PNG: class PNG:
def __init__(self, f): def __init__(self, f, mode=MODE_RGB):
self.vf = vfs.open(f) self.vf = vfs.open(f)
self.mode = mode
def writeHeader(self, image): def writeHeader(self, image):
self._png = lib.PNGWriteOpen(self.vf.handle) self._png = lib.PNGWriteOpen(self.vf.handle)
if self.mode == MODE_RGB:
self._info = lib.PNGWriteHeader(self._png, image.width, image.height) self._info = lib.PNGWriteHeader(self._png, image.width, image.height)
if self.mode == MODE_RGBA:
self._info = lib.PNGWriteHeaderA(self._png, image.width, image.height)
if self.mode == MODE_INDEX:
self._info = lib.PNGWriteHeader8(self._png, image.width, image.height)
return self._info != ffi.NULL return self._info != ffi.NULL
def writePixels(self, image): def writePixels(self, image):
if self.mode == MODE_RGB:
return lib.PNGWritePixels(self._png, image.width, image.height, image.stride, image.buffer) return lib.PNGWritePixels(self._png, image.width, image.height, image.stride, image.buffer)
if self.mode == MODE_RGBA:
return lib.PNGWritePixelsA(self._png, image.width, image.height, image.stride, image.buffer)
if self.mode == MODE_INDEX:
return lib.PNGWritePixels8(self._png, image.width, image.height, image.stride, image.buffer)
def writeClose(self): def writeClose(self):
lib.PNGWriteClose(self._png, self._info) lib.PNGWriteClose(self._png, self._info)

View File

@ -17,41 +17,31 @@ class Tile:
def composite(self, i, x, y): def composite(self, i, x, y):
for iy in range(8): for iy in range(8):
for ix in range(8): ffi.memmove(ffi.addressof(i.buffer, x + (iy + y) * i.stride), ffi.addressof(self.buffer, iy * 8), 8 * ffi.sizeof("color_t"))
i.buffer[ix + x + (iy + y) * i.stride] = image.u16ToColor(self.buffer[ix + iy * 8])
class TileView: class CacheSet:
def __init__(self, core): def __init__(self, core):
self.core = core self.core = core
self.cache = ffi.gc(ffi.new("struct mTileCache*"), core._deinitTileCache) self.cache = ffi.gc(ffi.new("struct mCacheSet*"), core._deinitCache)
core._initTileCache(self.cache) core._initCache(self.cache)
lib.mTileCacheSetPalette(self.cache, 0)
self.paletteSet = 0 class TileView:
def __init__(self, cache):
self.cache = cache
def getTile(self, tile, palette): def getTile(self, tile, palette):
return Tile(lib.mTileCacheGetTile(self.cache, tile, palette)) return Tile(lib.mTileCacheGetTile(self.cache, tile, palette))
def setPalette(self, paletteSet):
if paletteSet > 1 or paletteSet < 0:
raise IndexError("Palette Set ID out of bounds")
lib.mTileCacheSetPalette(self.cache, paletteSet)
self.paletteSet = paletteSet
class Sprite(object): class Sprite(object):
TILE_BASE = 0, 0 def constitute(self, tileView, tilePitch):
PALETTE_BASE = 0, 0 i = image.Image(self.width, self.height, alpha=True)
tileId = self.tile
def constitute(self, tileView, tilePitch, paletteSet):
oldPaletteSet = tileView.paletteSet
tileView.setPalette(paletteSet)
i = image.Image(self.width, self.height)
tileId = self.tile + self.TILE_BASE[paletteSet]
for y in range(self.height // 8): for y in range(self.height // 8):
for x in range(self.width // 8): for x in range(self.width // 8):
tile = tileView.getTile(tileId, self.paletteId + self.PALETTE_BASE[paletteSet]) tile = tileView.getTile(tileId, self.paletteId)
tile.composite(i, x * 8, y * 8) tile.composite(i, x * 8, y * 8)
tileId += 1 tileId += 1
if tilePitch: if tilePitch:
tileId += tilePitch - self.width // 8 tileId += tilePitch - self.width // 8
self.image = i self.image = i
tileView.setPalette(oldPaletteSet)