all repos — mgba @ 6d898542c765f4efc4a094c5ebd3f3465c36f417

mGBA Game Boy Advance Emulator

src/platform/python/mgba/core.py (view raw)

  1# Copyright (c) 2013-2016 Jeffrey Pfau
  2#
  3# This Source Code Form is subject to the terms of the Mozilla Public
  4# License, v. 2.0. If a copy of the MPL was not distributed with this
  5# file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6from ._pylib import ffi, lib
  7from . import tile
  8from cached_property import cached_property
  9
 10def find(path):
 11    core = lib.mCoreFind(path.encode('UTF-8'))
 12    if core == ffi.NULL:
 13        return None
 14    return Core._init(core)
 15
 16def findVF(vf):
 17    core = lib.mCoreFindVF(vf.handle)
 18    if core == ffi.NULL:
 19        return None
 20    return Core._init(core)
 21
 22def loadPath(path):
 23    core = find(path)
 24    if not core or not core.loadFile(path):
 25        return None
 26    return core
 27
 28def loadVF(vf):
 29    core = findVF(vf)
 30    if not core or not core.loadROM(vf):
 31        return None
 32    return core
 33
 34def needsReset(f):
 35    def wrapper(self, *args, **kwargs):
 36        if not self._wasReset:
 37            raise RuntimeError("Core must be reset first")
 38        return f(self, *args, **kwargs)
 39    return wrapper
 40
 41class Core(object):
 42    def __init__(self, native):
 43        self._core = native
 44        self._wasReset = False
 45
 46    @cached_property
 47    def tiles(self):
 48        return tile.TileView(self)
 49
 50    @classmethod
 51    def _init(cls, native):
 52        core = ffi.gc(native, native.deinit)
 53        success = bool(core.init(core))
 54        if not success:
 55            raise RuntimeError("Failed to initialize core")
 56        if hasattr(cls, 'PLATFORM_GBA') and core.platform(core) == cls.PLATFORM_GBA:
 57            return GBA(core)
 58        if hasattr(cls, 'PLATFORM_GB') and core.platform(core) == cls.PLATFORM_GB:
 59            return GB(core)
 60        return Core(core)
 61
 62    def _deinit(self):
 63        self._core.deinit(self._core)
 64
 65    def loadFile(self, path):
 66        return bool(lib.mCoreLoadFile(self._core, path.encode('UTF-8')))
 67
 68    def isROM(self, vf):
 69        return bool(self._core.isROM(vf.handle))
 70
 71    def loadROM(self, vf):
 72        return bool(self._core.loadROM(self._core, vf.handle))
 73
 74    def loadSave(self, vf):
 75        return bool(self._core.loadSave(self._core, vf.handle))
 76
 77    def loadTemporarySave(self, vf):
 78        return bool(self._core.loadTemporarySave(self._core, vf.handle))
 79
 80    def loadPatch(self, vf):
 81        return bool(self._core.loadPatch(self._core, vf.handle))
 82
 83    def autoloadSave(self):
 84        return bool(lib.mCoreAutoloadSave(self._core))
 85
 86    def autoloadPatch(self):
 87        return bool(lib.mCoreAutoloadPatch(self._core))
 88
 89    def platform(self):
 90        return self._core.platform(self._core)
 91
 92    def desiredVideoDimensions(self):
 93        width = ffi.new("unsigned*")
 94        height = ffi.new("unsigned*")
 95        self._core.desiredVideoDimensions(self._core, width, height)
 96        return width[0], height[0]
 97
 98    def setVideoBuffer(self, image):
 99        self._core.setVideoBuffer(self._core, image.buffer, image.stride)
100
101    def reset(self):
102        self._core.reset(self._core)
103        self._wasReset = True
104
105    @needsReset
106    def runFrame(self):
107        self._core.runFrame(self._core)
108
109    @needsReset
110    def runLoop(self):
111        self._core.runLoop(self._core)
112
113    @needsReset
114    def step(self):
115        self._core.step(self._core)
116
117    @staticmethod
118    def _keysToInt(*args, **kwargs):
119        keys = 0
120        if 'raw' in kwargs:
121            keys = kwargs['raw']
122        for key in args:
123            keys |= 1 << key
124        return keys
125
126    def setKeys(self, *args, **kwargs):
127        self._core.setKeys(self._core, self._keysToInt(*args, **kwargs))
128
129    def addKeys(self, *args, **kwargs):
130        self._core.addKeys(self._core, self._keysToInt(*args, **kwargs))
131
132    def clearKeys(self, *args, **kwargs):
133        self._core.clearKeys(self._core, self._keysToInt(*args, **kwargs))
134
135    @needsReset
136    def frameCounter(self):
137        return self._core.frameCounter(self._core)
138
139    def frameCycles(self):
140        return self._core.frameCycles(self._core)
141
142    def frequency(self):
143        return self._core.frequency(self._core)
144
145    def getGameTitle(self):
146        title = ffi.new("char[16]")
147        self._core.getGameTitle(self._core, title)
148        return ffi.string(title, 16).decode("ascii")
149
150    def getGameCode(self):
151        code = ffi.new("char[12]")
152        self._core.getGameCode(self._core, code)
153        return ffi.string(code, 12).decode("ascii")
154
155if hasattr(lib, 'PLATFORM_GBA'):
156    from .gba import GBA
157    Core.PLATFORM_GBA = lib.PLATFORM_GBA
158
159if hasattr(lib, 'PLATFORM_GB'):
160    from .gb import GB
161    from .lr35902 import LR35902Core
162    Core.PLATFORM_GB = lib.PLATFORM_GB