mirror of https://github.com/mgba-emu/mgba.git
Python: Fix tiles
This commit is contained in:
parent
dbeff59c06
commit
ba2a31c3f2
|
@ -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 = {
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
|
||||||
|
|
Loading…
Reference in New Issue