mirror of https://github.com/mgba-emu/mgba.git
Merge branch 'feature/python-bindings'
This commit is contained in:
commit
6d898542c7
|
@ -2,3 +2,4 @@
|
|||
*.user*
|
||||
*~
|
||||
*.swp
|
||||
*.pyc
|
||||
|
|
|
@ -28,6 +28,7 @@ set(BUILD_PERF OFF CACHE BOOL "Build performance profiling tool")
|
|||
set(BUILD_TEST OFF CACHE BOOL "Build testing harness")
|
||||
set(BUILD_SUITE OFF CACHE BOOL "Build test suite")
|
||||
set(BUILD_EXAMPLE OFF CACHE BOOL "Build example frontends")
|
||||
set(BUILD_PYTHON OFF CACHE BOOL "Build Python bindings")
|
||||
set(BUILD_STATIC OFF CACHE BOOL "Build a static library")
|
||||
set(BUILD_SHARED ON CACHE BOOL "Build a shared library")
|
||||
set(SKIP_LIBRARY OFF CACHE BOOL "Skip building the library (useful for only building libretro or OpenEmu cores)")
|
||||
|
@ -151,6 +152,9 @@ add_custom_target(version-info ALL
|
|||
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/version.cmake)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/core/version.c.in ${CMAKE_CURRENT_BINARY_DIR}/version.c)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/core/flags.h.in ${CMAKE_CURRENT_BINARY_DIR}/flags.h)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/flags.h DESTINATION include/mgba COMPONENT lib${BINARY_NAME})
|
||||
|
||||
list(APPEND UTIL_SRC ${CMAKE_CURRENT_BINARY_DIR}/version.c)
|
||||
source_group("Generated sources" FILES ${CMAKE_CURRENT_BINARY_DIR}/version.c)
|
||||
|
||||
|
@ -755,6 +759,11 @@ if(BUILD_SUITE)
|
|||
add_test(${BINARY_NAME}-suite ${BINARY_NAME}-suite)
|
||||
endif()
|
||||
|
||||
if(BUILD_PYTHON)
|
||||
enable_testing()
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/platform/python ${CMAKE_CURRENT_BINARY_DIR}/python)
|
||||
endif()
|
||||
|
||||
if(BUILD_EXAMPLE)
|
||||
add_executable(${BINARY_NAME}-example-server ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/example/client-server/server.c)
|
||||
target_link_libraries(${BINARY_NAME}-example-server ${BINARY_NAME})
|
||||
|
@ -838,6 +847,7 @@ if(NOT QUIET)
|
|||
message(STATUS " Profiling: ${BUILD_PERF}")
|
||||
message(STATUS " Test harness: ${BUILD_TEST}")
|
||||
message(STATUS " Test suite: ${BUILD_SUITE}")
|
||||
message(STATUS " Python bindings: ${BUILD_PYTHON}")
|
||||
message(STATUS " Examples: ${BUILD_EXAMPLE}")
|
||||
message(STATUS "Cores:")
|
||||
message(STATUS " Libretro core: ${BUILD_LIBRETRO}")
|
||||
|
|
|
@ -75,7 +75,7 @@ union PSR {
|
|||
unsigned z : 1;
|
||||
unsigned c : 1;
|
||||
unsigned v : 1;
|
||||
unsigned : 20;
|
||||
unsigned unused : 20;
|
||||
unsigned i : 1;
|
||||
unsigned f : 1;
|
||||
unsigned t : 1;
|
||||
|
@ -85,7 +85,7 @@ union PSR {
|
|||
unsigned t : 1;
|
||||
unsigned f : 1;
|
||||
unsigned i : 1;
|
||||
unsigned : 20;
|
||||
unsigned unused : 20;
|
||||
unsigned v : 1;
|
||||
unsigned c : 1;
|
||||
unsigned z : 1;
|
||||
|
|
|
@ -12,6 +12,8 @@ CXX_GUARD_START
|
|||
|
||||
#include "debugger/debugger.h"
|
||||
|
||||
#include "arm/arm.h"
|
||||
|
||||
struct ARMDebugBreakpoint {
|
||||
uint32_t address;
|
||||
bool isSw;
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
#ifndef FLAGS_H
|
||||
#define FLAGS_H
|
||||
|
||||
#ifndef MINIMAL_CORE
|
||||
#cmakedefine MINIMAL_CORE @MINIMAL_CORE@
|
||||
#endif
|
||||
|
||||
// BUILD flags
|
||||
|
||||
#ifndef BUILD_GL
|
||||
#cmakedefine BUILD_GL
|
||||
#endif
|
||||
|
||||
#ifndef BUILD_GLES2
|
||||
#cmakedefine BUILD_GLES2
|
||||
#endif
|
||||
|
||||
// COLOR flags
|
||||
|
||||
#ifndef COLOR_16_BIT
|
||||
#cmakedefine COLOR_16_BIT
|
||||
#endif
|
||||
|
||||
#ifndef COLOR_5_6_5
|
||||
#cmakedefine COLOR_5_6_5
|
||||
#endif
|
||||
|
||||
// M_CORE flags
|
||||
|
||||
#ifndef M_CORE_GBA
|
||||
#cmakedefine M_CORE_GBA
|
||||
#endif
|
||||
|
||||
#ifndef M_CORE_GB
|
||||
#cmakedefine M_CORE_GB
|
||||
#endif
|
||||
|
||||
// USE flags
|
||||
|
||||
#ifndef MINIMAL_CORE
|
||||
|
||||
#ifndef USE_DEBUGGERS
|
||||
#cmakedefine USE_DEBUGGERS
|
||||
#endif
|
||||
|
||||
#ifndef USE_EDITLINE
|
||||
#cmakedefine USE_EDITLINE
|
||||
#endif
|
||||
|
||||
#ifndef USE_EPOXY
|
||||
#cmakedefine USE_EPOXY
|
||||
#endif
|
||||
|
||||
#ifndef USE_FFMPEG
|
||||
#cmakedefine USE_FFMPEG
|
||||
#endif
|
||||
|
||||
#ifndef USE_GDB_STUB
|
||||
#cmakedefine USE_GDB_STUB
|
||||
#endif
|
||||
|
||||
#ifndef USE_LIBAV
|
||||
#cmakedefine USE_LIBAV
|
||||
#endif
|
||||
|
||||
#ifndef USE_LIBZIP
|
||||
#cmakedefine USE_LIBZIP
|
||||
#endif
|
||||
|
||||
#ifndef USE_LZMA
|
||||
#cmakedefine USE_LZMA
|
||||
#endif
|
||||
|
||||
#ifndef USE_MAGICK
|
||||
#cmakedefine USE_MAGICK
|
||||
#endif
|
||||
|
||||
#ifndef USE_MINIZIP
|
||||
#cmakedefine USE_MINIZIP
|
||||
#endif
|
||||
|
||||
#ifndef USE_PNG
|
||||
#cmakedefine USE_PNG
|
||||
#endif
|
||||
|
||||
#ifndef USE_PTHREADS
|
||||
#cmakedefine USE_PTHREADS
|
||||
#endif
|
||||
|
||||
#ifndef USE_ZLIB
|
||||
#cmakedefine USE_ZLIB
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -44,4 +44,18 @@ const char* mLogCategoryName(int category) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void mLog(int category, enum mLogLevel level, const char* format, ...) {
|
||||
struct mLogger* context = mLogGetContext();
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
if (context) {
|
||||
context->log(context, category, level, format, args);
|
||||
} else {
|
||||
printf("%s: ", mLogCategoryName(category));
|
||||
vprintf(format, args);
|
||||
printf("\n");
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
mLOG_DEFINE_CATEGORY(STATUS, "Status")
|
||||
|
|
|
@ -32,19 +32,7 @@ int mLogGenerateCategory(const char*);
|
|||
const char* mLogCategoryName(int);
|
||||
|
||||
ATTRIBUTE_FORMAT(printf, 3, 4)
|
||||
static inline void mLog(int category, enum mLogLevel level, const char* format, ...) {
|
||||
struct mLogger* context = mLogGetContext();
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
if (context) {
|
||||
context->log(context, category, level, format, args);
|
||||
} else {
|
||||
printf("%s: ", mLogCategoryName(category));
|
||||
vprintf(format, args);
|
||||
printf("\n");
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
void mLog(int category, enum mLogLevel level, const char* format, ...);
|
||||
|
||||
#define mLOG(CATEGORY, LEVEL, ...) mLog(_mLOG_CAT_ ## CATEGORY (), mLOG_ ## LEVEL, __VA_ARGS__)
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
CXX_GUARD_START
|
||||
|
||||
#include "arm/arm.h"
|
||||
#include "core/cpu.h"
|
||||
#include "core/log.h"
|
||||
#include "util/vector.h"
|
||||
|
||||
|
@ -37,7 +37,7 @@ enum mDebuggerState {
|
|||
enum mWatchpointType {
|
||||
WATCHPOINT_WRITE = 1,
|
||||
WATCHPOINT_READ = 2,
|
||||
WATCHPOINT_RW = WATCHPOINT_WRITE | WATCHPOINT_READ
|
||||
WATCHPOINT_RW = 3
|
||||
};
|
||||
|
||||
enum mBreakpointType {
|
||||
|
|
|
@ -122,7 +122,6 @@ void GBHalt(struct LR35902Core* cpu);
|
|||
struct VFile;
|
||||
bool GBLoadROM(struct GB* gb, struct VFile* vf);
|
||||
bool GBLoadSave(struct GB* gb, struct VFile* vf);
|
||||
void GBYankROM(struct GB* gb);
|
||||
void GBUnloadROM(struct GB* gb);
|
||||
void GBSynthesizeROM(struct VFile* vf);
|
||||
|
||||
|
|
|
@ -19,17 +19,17 @@ enum {
|
|||
GB_VIDEO_HORIZONTAL_PIXELS = 160,
|
||||
GB_VIDEO_VERTICAL_PIXELS = 144,
|
||||
GB_VIDEO_VBLANK_PIXELS = 10,
|
||||
GB_VIDEO_VERTICAL_TOTAL_PIXELS = GB_VIDEO_VERTICAL_PIXELS + GB_VIDEO_VBLANK_PIXELS,
|
||||
GB_VIDEO_VERTICAL_TOTAL_PIXELS = 154,
|
||||
|
||||
// TODO: Figure out exact lengths
|
||||
GB_VIDEO_MODE_2_LENGTH = 76,
|
||||
GB_VIDEO_MODE_3_LENGTH_BASE = 171,
|
||||
GB_VIDEO_MODE_0_LENGTH_BASE = 209,
|
||||
|
||||
GB_VIDEO_HORIZONTAL_LENGTH = GB_VIDEO_MODE_0_LENGTH_BASE + GB_VIDEO_MODE_2_LENGTH + GB_VIDEO_MODE_3_LENGTH_BASE,
|
||||
GB_VIDEO_HORIZONTAL_LENGTH = 456,
|
||||
|
||||
GB_VIDEO_MODE_1_LENGTH = GB_VIDEO_HORIZONTAL_LENGTH * GB_VIDEO_VBLANK_PIXELS,
|
||||
GB_VIDEO_TOTAL_LENGTH = GB_VIDEO_HORIZONTAL_LENGTH * GB_VIDEO_VERTICAL_TOTAL_PIXELS,
|
||||
GB_VIDEO_MODE_1_LENGTH = 65664,
|
||||
GB_VIDEO_TOTAL_LENGTH = 70224,
|
||||
|
||||
GB_BASE_MAP = 0x1800,
|
||||
GB_SIZE_MAP = 0x0400
|
||||
|
|
|
@ -118,7 +118,7 @@ struct GBAMemory {
|
|||
uint32_t* wram;
|
||||
uint32_t* iwram;
|
||||
uint32_t* rom;
|
||||
uint16_t io[SIZE_IO >> 1];
|
||||
uint16_t io[512];
|
||||
|
||||
struct GBACartridgeHardware hw;
|
||||
struct GBASavedata savedata;
|
||||
|
|
|
@ -245,7 +245,7 @@ bool GBAVBMSetStream(struct GBAVBMContext* vbm, struct VFile* vf) {
|
|||
uint8_t flags;
|
||||
vf->read(vf, &flags, sizeof(flags));
|
||||
if (flags & 2) {
|
||||
#if USE_ZLIB
|
||||
#ifdef USE_ZLIB
|
||||
vbm->d.initFrom = INIT_FROM_SAVEGAME;
|
||||
#else
|
||||
// zlib is needed to parse the savegame
|
||||
|
|
|
@ -20,13 +20,13 @@ enum {
|
|||
VIDEO_HBLANK_PIXELS = 68,
|
||||
VIDEO_HDRAW_LENGTH = 1006,
|
||||
VIDEO_HBLANK_LENGTH = 226,
|
||||
VIDEO_HORIZONTAL_LENGTH = VIDEO_HDRAW_LENGTH + VIDEO_HBLANK_LENGTH,
|
||||
VIDEO_HORIZONTAL_LENGTH = 1232,
|
||||
|
||||
VIDEO_VERTICAL_PIXELS = 160,
|
||||
VIDEO_VBLANK_PIXELS = 68,
|
||||
VIDEO_VERTICAL_TOTAL_PIXELS = VIDEO_VERTICAL_PIXELS + VIDEO_VBLANK_PIXELS,
|
||||
VIDEO_VERTICAL_TOTAL_PIXELS = 228,
|
||||
|
||||
VIDEO_TOTAL_LENGTH = VIDEO_HORIZONTAL_LENGTH * VIDEO_VERTICAL_TOTAL_PIXELS,
|
||||
VIDEO_TOTAL_LENGTH = 280896,
|
||||
|
||||
OBJ_HBLANK_FREE_LENGTH = 954,
|
||||
OBJ_LENGTH = 1210,
|
||||
|
@ -178,7 +178,7 @@ struct GBAVideo {
|
|||
// VCOUNT
|
||||
int vcount;
|
||||
|
||||
uint16_t palette[SIZE_PALETTE_RAM >> 1];
|
||||
uint16_t palette[512];
|
||||
uint16_t* vram;
|
||||
union GBAOAM oam;
|
||||
|
||||
|
|
|
@ -8,6 +8,36 @@
|
|||
#include "lr35902/emitter-lr35902.h"
|
||||
#include "lr35902/lr35902.h"
|
||||
|
||||
static inline uint16_t LR35902ReadHL(struct LR35902Core* cpu) {
|
||||
uint16_t hl;
|
||||
LOAD_16LE(hl, 0, &cpu->hl);
|
||||
return hl;
|
||||
}
|
||||
|
||||
static inline void LR35902WriteHL(struct LR35902Core* cpu, uint16_t hl) {
|
||||
STORE_16LE(hl, 0, &cpu->hl);
|
||||
}
|
||||
|
||||
static inline uint16_t LR35902ReadBC(struct LR35902Core* cpu) {
|
||||
uint16_t bc;
|
||||
LOAD_16LE(bc, 0, &cpu->bc);
|
||||
return bc;
|
||||
}
|
||||
|
||||
static inline void LR35902WriteBC(struct LR35902Core* cpu, uint16_t bc) {
|
||||
STORE_16LE(bc, 0, &cpu->bc);
|
||||
}
|
||||
|
||||
static inline uint16_t LR35902ReadDE(struct LR35902Core* cpu) {
|
||||
uint16_t de;
|
||||
LOAD_16LE(de, 0, &cpu->de);
|
||||
return de;
|
||||
}
|
||||
|
||||
static inline void LR35902WriteDE(struct LR35902Core* cpu, uint16_t de) {
|
||||
STORE_16LE(de, 0, &cpu->de);
|
||||
}
|
||||
|
||||
#define DEFINE_INSTRUCTION_LR35902(NAME, BODY) \
|
||||
static void _LR35902Instruction ## NAME (struct LR35902Core* cpu) { \
|
||||
UNUSED(cpu); \
|
||||
|
|
|
@ -23,9 +23,9 @@ union FlagRegister {
|
|||
unsigned n : 1;
|
||||
unsigned h : 1;
|
||||
unsigned c : 1;
|
||||
unsigned : 4;
|
||||
unsigned unused : 4;
|
||||
#else
|
||||
unsigned : 4;
|
||||
unsigned unused : 4;
|
||||
unsigned c : 1;
|
||||
unsigned h : 1;
|
||||
unsigned n : 1;
|
||||
|
@ -127,36 +127,6 @@ struct LR35902Core {
|
|||
struct mCPUComponent** components;
|
||||
};
|
||||
|
||||
static inline uint16_t LR35902ReadHL(struct LR35902Core* cpu) {
|
||||
uint16_t hl;
|
||||
LOAD_16LE(hl, 0, &cpu->hl);
|
||||
return hl;
|
||||
}
|
||||
|
||||
static inline void LR35902WriteHL(struct LR35902Core* cpu, uint16_t hl) {
|
||||
STORE_16LE(hl, 0, &cpu->hl);
|
||||
}
|
||||
|
||||
static inline uint16_t LR35902ReadBC(struct LR35902Core* cpu) {
|
||||
uint16_t bc;
|
||||
LOAD_16LE(bc, 0, &cpu->bc);
|
||||
return bc;
|
||||
}
|
||||
|
||||
static inline void LR35902WriteBC(struct LR35902Core* cpu, uint16_t bc) {
|
||||
STORE_16LE(bc, 0, &cpu->bc);
|
||||
}
|
||||
|
||||
static inline uint16_t LR35902ReadDE(struct LR35902Core* cpu) {
|
||||
uint16_t de;
|
||||
LOAD_16LE(de, 0, &cpu->de);
|
||||
return de;
|
||||
}
|
||||
|
||||
static inline void LR35902WriteDE(struct LR35902Core* cpu, uint16_t de) {
|
||||
STORE_16LE(de, 0, &cpu->de);
|
||||
}
|
||||
|
||||
void LR35902Init(struct LR35902Core* cpu);
|
||||
void LR35902Deinit(struct LR35902Core* cpu);
|
||||
void LR35902SetComponents(struct LR35902Core* cpu, struct mCPUComponent* master, int extra, struct mCPUComponent** extras);
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
find_program(PYTHON python)
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in ${CMAKE_CURRENT_BINARY_DIR}/setup.py)
|
||||
|
||||
add_custom_command(OUTPUT build/lib/${BINARY_NAME}/__init__.py
|
||||
COMMAND BINDIR=${CMAKE_CURRENT_BINARY_DIR}/.. ${PYTHON} ${CMAKE_CURRENT_BINARY_DIR}/setup.py build --build-base ${CMAKE_CURRENT_BINARY_DIR}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
DEPENDS ${BINARY_NAME}
|
||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/setup.py
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/_builder.py)
|
||||
|
||||
add_custom_target(${BINARY_NAME}-py ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/build/lib/${BINARY_NAME}/__init__.py)
|
|
@ -0,0 +1,49 @@
|
|||
#define COMMON_H
|
||||
#define PNG_H
|
||||
#define _SYS_TIME_H
|
||||
#define _SYS_TIME_H_
|
||||
#define _TIME_H
|
||||
#define _TIME_H_
|
||||
|
||||
#define ATTRIBUTE_FORMAT(X, Y, Z)
|
||||
#define DECL_BITFIELD(newtype, oldtype) typedef oldtype newtype
|
||||
#define DECL_BIT(type, name, bit)
|
||||
#define DECL_BITS(type, name, bit, nbits)
|
||||
|
||||
#define CXX_GUARD_START
|
||||
#define CXX_GUARD_END
|
||||
|
||||
typedef int... time_t;
|
||||
typedef int... off_t;
|
||||
typedef ... va_list;
|
||||
typedef ...* png_structp;
|
||||
typedef ...* png_infop;
|
||||
typedef ...* png_unknown_chunkp;
|
||||
|
||||
void free(void*);
|
||||
|
||||
#include <limits.h>
|
||||
#undef const
|
||||
|
||||
#include "flags.h"
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/tile-cache.h"
|
||||
#include "platform/python/vfs-py.h"
|
||||
#include "platform/python/log.h"
|
||||
|
||||
#ifdef USE_PNG
|
||||
#include "util/png-io.h"
|
||||
#endif
|
||||
#ifdef M_CORE_GBA
|
||||
#include "arm/arm.h"
|
||||
#include "gba/gba.h"
|
||||
#include "gba/input.h"
|
||||
#include "gba/renderers/tile-cache.h"
|
||||
#endif
|
||||
#ifdef M_CORE_GB
|
||||
#include "lr35902/lr35902.h"
|
||||
#include "gb/gb.h"
|
||||
#include "gba/input.h"
|
||||
#include "gb/renderers/tile-cache.h"
|
||||
#endif
|
|
@ -0,0 +1,64 @@
|
|||
import cffi
|
||||
import os, os.path
|
||||
import shlex
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
ffi = cffi.FFI()
|
||||
pydir = os.path.dirname(os.path.abspath(__file__))
|
||||
srcdir = os.path.join(pydir, "..", "..")
|
||||
bindir = os.environ.get("BINDIR", os.path.join(os.getcwd(), ".."))
|
||||
|
||||
cpp = shlex.split(os.environ.get("CPP", "cc -E"))
|
||||
cppflags = shlex.split(os.environ.get("CPPFLAGS", ""))
|
||||
if __name__ == "__main__":
|
||||
cppflags.extend(sys.argv[1:])
|
||||
cppflags.extend(["-I" + srcdir, "-I" + bindir])
|
||||
|
||||
ffi.set_source("mgba._pylib", """
|
||||
#include "flags.h"
|
||||
#include "util/common.h"
|
||||
#include "core/core.h"
|
||||
#include "core/log.h"
|
||||
#include "core/tile-cache.h"
|
||||
#include "arm/arm.h"
|
||||
#include "gba/gba.h"
|
||||
#include "gba/input.h"
|
||||
#include "gba/renderers/tile-cache.h"
|
||||
#include "lr35902/lr35902.h"
|
||||
#include "gb/gb.h"
|
||||
#include "gb/renderers/tile-cache.h"
|
||||
#include "util/png-io.h"
|
||||
#include "util/vfs.h"
|
||||
|
||||
struct VFile* VFileFromPython(void* fileobj);
|
||||
|
||||
struct VFilePy {
|
||||
struct VFile d;
|
||||
void* fileobj;
|
||||
};
|
||||
|
||||
struct mLogger* mLoggerPythonCreate(void* pyobj);
|
||||
|
||||
struct mLoggerPy {
|
||||
struct mLogger d;
|
||||
void* pyobj;
|
||||
};
|
||||
""", include_dirs=[srcdir],
|
||||
extra_compile_args=cppflags,
|
||||
libraries=["mgba"],
|
||||
library_dirs=[bindir],
|
||||
sources=[os.path.join(pydir, path) for path in ["vfs-py.c", "log.c"]])
|
||||
|
||||
preprocessed = subprocess.check_output(cpp + ["-fno-inline", "-P"] + cppflags + [os.path.join(pydir, "_builder.h")], universal_newlines=True)
|
||||
|
||||
lines = []
|
||||
for line in preprocessed.splitlines():
|
||||
line = line.strip()
|
||||
if line.startswith('#'):
|
||||
continue
|
||||
lines.append(line)
|
||||
ffi.cdef('\n'.join(lines))
|
||||
|
||||
if __name__ == "__main__":
|
||||
ffi.compile()
|
|
@ -0,0 +1,27 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "core/log.h"
|
||||
|
||||
struct mLoggerPy {
|
||||
struct mLogger d;
|
||||
void* pyobj;
|
||||
};
|
||||
|
||||
void _pyLog(void* logger, int category, enum mLogLevel level, const char* message);
|
||||
|
||||
static void _pyLogShim(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) {
|
||||
struct mLoggerPy* pylogger = (struct mLoggerPy*) logger;
|
||||
char message[256] = {0};
|
||||
vsnprintf(message, sizeof(message) - 1, format, args);
|
||||
_pyLog(pylogger, category, level, message);
|
||||
}
|
||||
|
||||
struct mLogger* mLoggerPythonCreate(void* pyobj) {
|
||||
struct mLoggerPy* logger = malloc(sizeof(*logger));
|
||||
logger->d.log = _pyLogShim;
|
||||
logger->pyobj = pyobj;
|
||||
return &logger->d;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "core/log.h"
|
||||
|
||||
struct mLoggerPy {
|
||||
struct mLogger d;
|
||||
void* pyobj;
|
||||
};
|
||||
|
||||
struct mLogger* mLoggerPythonCreate(void* pyobj);
|
||||
|
||||
extern "Python+C" void _pyLog(void* logger, int category, enum mLogLevel level, const char* message);
|
|
@ -0,0 +1,28 @@
|
|||
# Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
from ._pylib import ffi, lib
|
||||
|
||||
class _ARMRegisters:
|
||||
def __init__(self, cpu):
|
||||
self._cpu = cpu
|
||||
|
||||
def __getitem__(self, r):
|
||||
if r > lib.ARM_PC:
|
||||
raise IndexError("Register out of range")
|
||||
return self._cpu._native.gprs[r]
|
||||
|
||||
def __setitem__(self, r, value):
|
||||
if r >= lib.ARM_PC:
|
||||
raise IndexError("Register out of range")
|
||||
self._cpu._native.gprs[r] = value
|
||||
|
||||
class ARMCore:
|
||||
def __init__(self, native):
|
||||
self._native = ffi.cast("struct ARMCore*", native)
|
||||
self.gprs = _ARMRegisters(self)
|
||||
self.cpsr = self._native.cpsr
|
||||
self.spsr = self._native.spsr
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
# Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
from ._pylib import ffi, lib
|
||||
from . import tile
|
||||
from cached_property import cached_property
|
||||
|
||||
def find(path):
|
||||
core = lib.mCoreFind(path.encode('UTF-8'))
|
||||
if core == ffi.NULL:
|
||||
return None
|
||||
return Core._init(core)
|
||||
|
||||
def findVF(vf):
|
||||
core = lib.mCoreFindVF(vf.handle)
|
||||
if core == ffi.NULL:
|
||||
return None
|
||||
return Core._init(core)
|
||||
|
||||
def loadPath(path):
|
||||
core = find(path)
|
||||
if not core or not core.loadFile(path):
|
||||
return None
|
||||
return core
|
||||
|
||||
def loadVF(vf):
|
||||
core = findVF(vf)
|
||||
if not core or not core.loadROM(vf):
|
||||
return None
|
||||
return core
|
||||
|
||||
def needsReset(f):
|
||||
def wrapper(self, *args, **kwargs):
|
||||
if not self._wasReset:
|
||||
raise RuntimeError("Core must be reset first")
|
||||
return f(self, *args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
class Core(object):
|
||||
def __init__(self, native):
|
||||
self._core = native
|
||||
self._wasReset = False
|
||||
|
||||
@cached_property
|
||||
def tiles(self):
|
||||
return tile.TileView(self)
|
||||
|
||||
@classmethod
|
||||
def _init(cls, native):
|
||||
core = ffi.gc(native, native.deinit)
|
||||
success = bool(core.init(core))
|
||||
if not success:
|
||||
raise RuntimeError("Failed to initialize core")
|
||||
if hasattr(cls, 'PLATFORM_GBA') and core.platform(core) == cls.PLATFORM_GBA:
|
||||
return GBA(core)
|
||||
if hasattr(cls, 'PLATFORM_GB') and core.platform(core) == cls.PLATFORM_GB:
|
||||
return GB(core)
|
||||
return Core(core)
|
||||
|
||||
def _deinit(self):
|
||||
self._core.deinit(self._core)
|
||||
|
||||
def loadFile(self, path):
|
||||
return bool(lib.mCoreLoadFile(self._core, path.encode('UTF-8')))
|
||||
|
||||
def isROM(self, vf):
|
||||
return bool(self._core.isROM(vf.handle))
|
||||
|
||||
def loadROM(self, vf):
|
||||
return bool(self._core.loadROM(self._core, vf.handle))
|
||||
|
||||
def loadSave(self, vf):
|
||||
return bool(self._core.loadSave(self._core, vf.handle))
|
||||
|
||||
def loadTemporarySave(self, vf):
|
||||
return bool(self._core.loadTemporarySave(self._core, vf.handle))
|
||||
|
||||
def loadPatch(self, vf):
|
||||
return bool(self._core.loadPatch(self._core, vf.handle))
|
||||
|
||||
def autoloadSave(self):
|
||||
return bool(lib.mCoreAutoloadSave(self._core))
|
||||
|
||||
def autoloadPatch(self):
|
||||
return bool(lib.mCoreAutoloadPatch(self._core))
|
||||
|
||||
def platform(self):
|
||||
return self._core.platform(self._core)
|
||||
|
||||
def desiredVideoDimensions(self):
|
||||
width = ffi.new("unsigned*")
|
||||
height = ffi.new("unsigned*")
|
||||
self._core.desiredVideoDimensions(self._core, width, height)
|
||||
return width[0], height[0]
|
||||
|
||||
def setVideoBuffer(self, image):
|
||||
self._core.setVideoBuffer(self._core, image.buffer, image.stride)
|
||||
|
||||
def reset(self):
|
||||
self._core.reset(self._core)
|
||||
self._wasReset = True
|
||||
|
||||
@needsReset
|
||||
def runFrame(self):
|
||||
self._core.runFrame(self._core)
|
||||
|
||||
@needsReset
|
||||
def runLoop(self):
|
||||
self._core.runLoop(self._core)
|
||||
|
||||
@needsReset
|
||||
def step(self):
|
||||
self._core.step(self._core)
|
||||
|
||||
@staticmethod
|
||||
def _keysToInt(*args, **kwargs):
|
||||
keys = 0
|
||||
if 'raw' in kwargs:
|
||||
keys = kwargs['raw']
|
||||
for key in args:
|
||||
keys |= 1 << key
|
||||
return keys
|
||||
|
||||
def setKeys(self, *args, **kwargs):
|
||||
self._core.setKeys(self._core, self._keysToInt(*args, **kwargs))
|
||||
|
||||
def addKeys(self, *args, **kwargs):
|
||||
self._core.addKeys(self._core, self._keysToInt(*args, **kwargs))
|
||||
|
||||
def clearKeys(self, *args, **kwargs):
|
||||
self._core.clearKeys(self._core, self._keysToInt(*args, **kwargs))
|
||||
|
||||
@needsReset
|
||||
def frameCounter(self):
|
||||
return self._core.frameCounter(self._core)
|
||||
|
||||
def frameCycles(self):
|
||||
return self._core.frameCycles(self._core)
|
||||
|
||||
def frequency(self):
|
||||
return self._core.frequency(self._core)
|
||||
|
||||
def getGameTitle(self):
|
||||
title = ffi.new("char[16]")
|
||||
self._core.getGameTitle(self._core, title)
|
||||
return ffi.string(title, 16).decode("ascii")
|
||||
|
||||
def getGameCode(self):
|
||||
code = ffi.new("char[12]")
|
||||
self._core.getGameCode(self._core, code)
|
||||
return ffi.string(code, 12).decode("ascii")
|
||||
|
||||
if hasattr(lib, 'PLATFORM_GBA'):
|
||||
from .gba import GBA
|
||||
Core.PLATFORM_GBA = lib.PLATFORM_GBA
|
||||
|
||||
if hasattr(lib, 'PLATFORM_GB'):
|
||||
from .gb import GB
|
||||
from .lr35902 import LR35902Core
|
||||
Core.PLATFORM_GB = lib.PLATFORM_GB
|
|
@ -0,0 +1,81 @@
|
|||
# Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
from ._pylib import ffi, lib
|
||||
from .lr35902 import LR35902Core
|
||||
from .core import Core, needsReset
|
||||
from .memory import Memory
|
||||
from .tile import Sprite
|
||||
|
||||
class GB(Core):
|
||||
KEY_A = lib.GBA_KEY_A
|
||||
KEY_B = lib.GBA_KEY_B
|
||||
KEY_SELECT = lib.GBA_KEY_SELECT
|
||||
KEY_START = lib.GBA_KEY_START
|
||||
KEY_DOWN = lib.GBA_KEY_DOWN
|
||||
KEY_UP = lib.GBA_KEY_UP
|
||||
KEY_LEFT = lib.GBA_KEY_LEFT
|
||||
KEY_RIGHT = lib.GBA_KEY_RIGHT
|
||||
|
||||
def __init__(self, native):
|
||||
super(GB, self).__init__(native)
|
||||
self._native = ffi.cast("struct GB*", native.board)
|
||||
self.sprites = GBObjs(self)
|
||||
self.cpu = LR35902Core(self._core.cpu)
|
||||
|
||||
@needsReset
|
||||
def _initTileCache(self, cache):
|
||||
lib.GBVideoTileCacheInit(cache)
|
||||
lib.GBVideoTileCacheAssociate(cache, ffi.addressof(self._native.video))
|
||||
|
||||
def _deinitTileCache(self, cache):
|
||||
self._native.video.renderer.cache = ffi.NULL
|
||||
lib.mTileCacheDeinit(cache)
|
||||
|
||||
class GBMemory(Memory):
|
||||
def __init__(self, core):
|
||||
super(GBMemory, self).__init__(core, 0x10000)
|
||||
|
||||
self.cart = Memory(core, lib.GB_SIZE_CART_BANK0 * 2, lib.GB_BASE_CART_BANK0)
|
||||
self.vram = Memory(core, lib.GB_SIZE_VRAM, lib.GB_BASE_VRAM)
|
||||
self.sram = Memory(core, lib.GB_SIZE_EXTERNAL_RAM, lib.GB_REGION_EXTERNAL_RAM)
|
||||
self.iwram = Memory(core, lib.GB_SIZE_WORKING_RAM_BANK0, lib.GB_BASE_WORKING_RAM_BANK0)
|
||||
self.oam = Memory(core, lib.GB_SIZE_OAM, lib.GB_BASE_OAM)
|
||||
self.io = Memory(core, lib.GB_SIZE_IO, lib.GB_BASE_IO)
|
||||
self.hram = Memory(core, lib.GB_SIZE_HRAM, lib.GB_BASE_HRAM)
|
||||
|
||||
class GBSprite(Sprite):
|
||||
PALETTE_BASE = 8,
|
||||
|
||||
def __init__(self, obj, core):
|
||||
self.x = obj.x
|
||||
self.y = obj.y
|
||||
self.tile = obj.tile
|
||||
self._attr = obj.attr
|
||||
self.width = 8
|
||||
lcdc = core._native.memory.io[0x40]
|
||||
self.height = 16 if lcdc & 4 else 8
|
||||
if core._native.model >= lib.GB_MODEL_CGB:
|
||||
if self._attr & 8:
|
||||
self.tile += 512
|
||||
self.paletteId = self._attr & 7
|
||||
else:
|
||||
self.paletteId = (self._attr >> 4) & 1
|
||||
|
||||
|
||||
class GBObjs:
|
||||
def __init__(self, core):
|
||||
self._core = core
|
||||
self._obj = core._native.video.oam.obj
|
||||
|
||||
def __len__(self):
|
||||
return 40
|
||||
|
||||
def __getitem__(self, index):
|
||||
if index >= len(self):
|
||||
raise IndexError()
|
||||
sprite = GBSprite(self._obj[index], self._core)
|
||||
sprite.constitute(self._core.tiles, 0, 0)
|
||||
return sprite
|
|
@ -0,0 +1,96 @@
|
|||
# Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
from ._pylib import ffi, lib
|
||||
from .arm import ARMCore
|
||||
from .core import Core, needsReset
|
||||
from .tile import Sprite
|
||||
from .memory import Memory
|
||||
|
||||
class GBA(Core):
|
||||
KEY_A = lib.GBA_KEY_A
|
||||
KEY_B = lib.GBA_KEY_B
|
||||
KEY_SELECT = lib.GBA_KEY_SELECT
|
||||
KEY_START = lib.GBA_KEY_START
|
||||
KEY_DOWN = lib.GBA_KEY_DOWN
|
||||
KEY_UP = lib.GBA_KEY_UP
|
||||
KEY_LEFT = lib.GBA_KEY_LEFT
|
||||
KEY_RIGHT = lib.GBA_KEY_RIGHT
|
||||
KEY_L = lib.GBA_KEY_L
|
||||
KEY_R = lib.GBA_KEY_R
|
||||
|
||||
def __init__(self, native):
|
||||
super(GBA, self).__init__(native)
|
||||
self._native = ffi.cast("struct GBA*", native.board)
|
||||
self.sprites = GBAObjs(self)
|
||||
self.cpu = ARMCore(self._core.cpu)
|
||||
|
||||
@needsReset
|
||||
def _initTileCache(self, cache):
|
||||
lib.GBAVideoTileCacheInit(cache)
|
||||
lib.GBAVideoTileCacheAssociate(cache, ffi.addressof(self._native.video))
|
||||
|
||||
def _deinitTileCache(self, cache):
|
||||
self._native.video.renderer.cache = ffi.NULL
|
||||
lib.mTileCacheDeinit(cache)
|
||||
|
||||
def reset(self):
|
||||
super(GBA, self).reset()
|
||||
self.memory = GBAMemory(self._core, self._native.memory.romSize)
|
||||
|
||||
class GBAMemory(Memory):
|
||||
def __init__(self, core, romSize=lib.SIZE_CART0):
|
||||
super(GBAMemory, self).__init__(core, 0x100000000)
|
||||
|
||||
self.bios = Memory(core, lib.SIZE_BIOS, lib.BASE_BIOS)
|
||||
self.wram = Memory(core, lib.SIZE_WORKING_RAM, lib.BASE_WORKING_RAM)
|
||||
self.iwram = Memory(core, lib.SIZE_WORKING_IRAM, lib.BASE_WORKING_IRAM)
|
||||
self.io = Memory(core, lib.SIZE_IO, lib.BASE_IO)
|
||||
self.palette = Memory(core, lib.SIZE_PALETTE_RAM, lib.BASE_PALETTE_RAM)
|
||||
self.vram = Memory(core, lib.SIZE_VRAM, lib.BASE_VRAM)
|
||||
self.oam = Memory(core, lib.SIZE_OAM, lib.BASE_OAM)
|
||||
self.cart0 = Memory(core, romSize, lib.BASE_CART0)
|
||||
self.cart1 = Memory(core, romSize, lib.BASE_CART1)
|
||||
self.cart2 = Memory(core, romSize, lib.BASE_CART2)
|
||||
self.cart = self.cart0
|
||||
self.rom = self.cart0
|
||||
self.sram = Memory(core, lib.SIZE_CART_SRAM, lib.BASE_CART_SRAM)
|
||||
|
||||
class GBASprite(Sprite):
|
||||
TILE_BASE = 0x800, 0x400
|
||||
PALETTE_BASE = 0x10, 1
|
||||
|
||||
def __init__(self, obj):
|
||||
self._a = obj.a
|
||||
self._b = obj.b
|
||||
self._c = obj.c
|
||||
self.x = self._b & 0x1FF
|
||||
self.y = self._a & 0xFF
|
||||
self._shape = self._a >> 14
|
||||
self._size = self._b >> 14
|
||||
self._256Color = bool(self._a & 0x2000)
|
||||
self.width, self.height = lib.GBAVideoObjSizes[self._shape * 4 + self._size]
|
||||
self.tile = self._c & 0x3FF
|
||||
if self._256Color:
|
||||
self.paletteId = 0
|
||||
self.tile >>= 1
|
||||
else:
|
||||
self.paletteId = self._c >> 12
|
||||
|
||||
class GBAObjs:
|
||||
def __init__(self, core):
|
||||
self._core = core
|
||||
self._obj = core._native.video.oam.obj
|
||||
|
||||
def __len__(self):
|
||||
return 128
|
||||
|
||||
def __getitem__(self, index):
|
||||
if index >= len(self):
|
||||
raise IndexError()
|
||||
sprite = GBASprite(self._obj[index])
|
||||
map1D = bool(self._core._native.memory.io[0] & 0x40)
|
||||
sprite.constitute(self._core.tiles, 0 if map1D else 0x20, int(sprite._256Color))
|
||||
return sprite
|
|
@ -0,0 +1,69 @@
|
|||
# Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
from ._pylib import ffi, lib
|
||||
from . import png
|
||||
|
||||
class Image:
|
||||
def __init__(self, width, height, stride=0):
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.stride = stride
|
||||
self.constitute()
|
||||
|
||||
def constitute(self):
|
||||
if self.stride <= 0:
|
||||
self.stride = self.width
|
||||
self.buffer = ffi.new("color_t[{}]".format(self.stride * self.height))
|
||||
|
||||
def savePNG(self, f):
|
||||
p = png.PNG(f)
|
||||
success = p.writeHeader(self)
|
||||
success = success and p.writePixels(self)
|
||||
p.writeClose()
|
||||
return success
|
||||
|
||||
def u16ToU32(c):
|
||||
r = c & 0x1F
|
||||
g = (c >> 5) & 0x1F
|
||||
b = (c >> 10) & 0x1F
|
||||
a = (c >> 15) & 1
|
||||
abgr = r << 3
|
||||
abgr |= g << 11
|
||||
abgr |= b << 19
|
||||
abgr |= (a * 0xFF) << 24
|
||||
return abgr
|
||||
|
||||
def u32ToU16(c):
|
||||
r = (c >> 3) & 0x1F
|
||||
g = (c >> 11) & 0x1F
|
||||
b = (c >> 19) & 0x1F
|
||||
a = c >> 31
|
||||
abgr = r
|
||||
abgr |= g << 5
|
||||
abgr |= b << 10
|
||||
abgr |= a << 15
|
||||
return abgr
|
||||
|
||||
if ffi.sizeof("color_t") == 2:
|
||||
def colorToU16(c):
|
||||
return c
|
||||
|
||||
colorToU32 = u16ToU32
|
||||
|
||||
def u16ToColor(c):
|
||||
return c
|
||||
|
||||
u32ToColor = u32ToU16
|
||||
else:
|
||||
def colorToU32(c):
|
||||
return c
|
||||
|
||||
colorToU16 = u32ToU16
|
||||
|
||||
def u32ToColor(c):
|
||||
return c
|
||||
|
||||
u16ToColor = u16ToU32
|
|
@ -0,0 +1,38 @@
|
|||
# Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
from ._pylib import ffi, lib
|
||||
|
||||
@ffi.def_extern()
|
||||
def _pyLog(logger, category, level, message):
|
||||
l = ffi.cast("struct mLoggerPy*", logger)
|
||||
ffi.from_handle(l.pyobj).log(category, level, ffi.string(message).decode('UTF-8'))
|
||||
|
||||
def installDefault(logger):
|
||||
lib.mLogSetDefaultLogger(logger._native)
|
||||
|
||||
class Logger(object):
|
||||
FATAL = lib.mLOG_FATAL
|
||||
DEBUG = lib.mLOG_DEBUG
|
||||
INFO = lib.mLOG_INFO
|
||||
WARN = lib.mLOG_WARN
|
||||
ERROR = lib.mLOG_ERROR
|
||||
STUB = lib.mLOG_STUB
|
||||
GAME_ERROR = lib.mLOG_GAME_ERROR
|
||||
|
||||
def __init__(self):
|
||||
self._handle = ffi.new_handle(self)
|
||||
self._native = ffi.gc(lib.mLoggerPythonCreate(self._handle), lib.free)
|
||||
|
||||
@staticmethod
|
||||
def categoryName(category):
|
||||
return ffi.string(lib.mLogCategoryName(category)).decode('UTF-8')
|
||||
|
||||
def log(self, category, level, message):
|
||||
print("{}: {}".format(self.categoryName(category), message))
|
||||
|
||||
class NullLogger(Logger):
|
||||
def log(self, category, level, message):
|
||||
pass
|
|
@ -0,0 +1,123 @@
|
|||
# Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
from ._pylib import ffi, lib
|
||||
|
||||
class LR35902Core:
|
||||
def __init__(self, native):
|
||||
self._native = ffi.cast("struct LR35902Core*", native)
|
||||
|
||||
@property
|
||||
def a(self):
|
||||
return self._native.a
|
||||
|
||||
@property
|
||||
def b(self):
|
||||
return self._native.b
|
||||
|
||||
@property
|
||||
def c(self):
|
||||
return self._native.c
|
||||
|
||||
@property
|
||||
def d(self):
|
||||
return self._native.d
|
||||
|
||||
@property
|
||||
def e(self):
|
||||
return self._native.e
|
||||
|
||||
@property
|
||||
def f(self):
|
||||
return self._native.f
|
||||
|
||||
@property
|
||||
def h(self):
|
||||
return self._native.h
|
||||
|
||||
@property
|
||||
def l(self):
|
||||
return self._native.l
|
||||
|
||||
@property
|
||||
def sp(self):
|
||||
return self._native.sp
|
||||
|
||||
@property
|
||||
def pc(self):
|
||||
return self._native.pc
|
||||
|
||||
@property
|
||||
def af(self):
|
||||
return (self.a << 8) | self.f
|
||||
|
||||
@property
|
||||
def bc(self):
|
||||
return (self.b << 8) | self.c
|
||||
|
||||
@property
|
||||
def de(self):
|
||||
return (self.d << 8) | self.e
|
||||
|
||||
@property
|
||||
def hl(self):
|
||||
return (self.h << 8) | self.l
|
||||
|
||||
@a.setter
|
||||
def a(self, value):
|
||||
self._native.a = value
|
||||
|
||||
@b.setter
|
||||
def b(self, value):
|
||||
self._native.b = value
|
||||
|
||||
@c.setter
|
||||
def c(self, value):
|
||||
self._native.c = value
|
||||
|
||||
@d.setter
|
||||
def d(self, value):
|
||||
self._native.d = value
|
||||
|
||||
@e.setter
|
||||
def e(self, value):
|
||||
self._native.e = value
|
||||
|
||||
@f.setter
|
||||
def f(self, value):
|
||||
self._native.f.packed = value
|
||||
self._native.f.unused = 0
|
||||
|
||||
@h.setter
|
||||
def h(self, value):
|
||||
self._native.h = value
|
||||
|
||||
@l.setter
|
||||
def l(self, value):
|
||||
self._native.l = value
|
||||
|
||||
@sp.setter
|
||||
def sp(self, value):
|
||||
self._native.sp = value
|
||||
|
||||
@af.setter
|
||||
def af(self, value):
|
||||
self.a = value >> 8
|
||||
self.f = value & 0xFF
|
||||
|
||||
@bc.setter
|
||||
def bc(self, value):
|
||||
self.b = value >> 8
|
||||
self.c = value & 0xFF
|
||||
|
||||
@de.setter
|
||||
def de(self, value):
|
||||
self.d = value >> 8
|
||||
self.e = value & 0xFF
|
||||
|
||||
@hl.setter
|
||||
def hl(self, value):
|
||||
self.h = value >> 8
|
||||
self.l = value & 0xFF
|
|
@ -0,0 +1,83 @@
|
|||
# Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
from ._pylib import ffi, lib
|
||||
|
||||
class MemoryView(object):
|
||||
def __init__(self, core, width, size, base=0, sign="u"):
|
||||
self._core = core
|
||||
self._width = width
|
||||
self._size = size
|
||||
self._base = base
|
||||
self._busRead = getattr(self._core, "busRead" + str(width * 8))
|
||||
self._busWrite = getattr(self._core, "busWrite" + str(width * 8))
|
||||
self._rawRead = getattr(self._core, "rawRead" + str(width * 8))
|
||||
self._rawWrite = getattr(self._core, "rawWrite" + str(width * 8))
|
||||
self._mask = (1 << (width * 8)) - 1 # Used to force values to fit within range so that negative values work
|
||||
if sign == "u" or sign == "unsigned":
|
||||
self._type = "uint{}_t".format(width * 8)
|
||||
elif sign == "i" or sign == "s" or sign == "signed":
|
||||
self._type = "int{}_t".format(width * 8)
|
||||
else:
|
||||
raise ValueError("Invalid sign type: '{}'".format(sign))
|
||||
|
||||
def _addrCheck(self, address):
|
||||
if isinstance(address, slice):
|
||||
start = address.start or 0
|
||||
stop = self._size - self._width if address.stop is None else address.stop
|
||||
else:
|
||||
start = address
|
||||
stop = address + self._width
|
||||
if start >= self._size or stop > self._size:
|
||||
raise IndexError()
|
||||
if start < 0 or stop < 0:
|
||||
raise IndexError()
|
||||
|
||||
def __len__(self):
|
||||
return self._size
|
||||
|
||||
def __getitem__(self, address):
|
||||
self._addrCheck(address)
|
||||
if isinstance(address, slice):
|
||||
start = address.start or 0
|
||||
stop = self._size - self._width if address.stop is None else address.stop
|
||||
step = address.step or self._width
|
||||
return [int(ffi.cast(self._type, self._busRead(self._core, self._base + a))) for a in range(start, stop, step)]
|
||||
else:
|
||||
return int(ffi.cast(self._type, self._busRead(self._core, self._base + address)))
|
||||
|
||||
def __setitem__(self, address, value):
|
||||
self._addrCheck(address)
|
||||
if isinstance(address, slice):
|
||||
start = address.start or 0
|
||||
stop = self._size - self._width if address.stop is None else address.stop
|
||||
step = address.step or self._width
|
||||
for a in range(start, stop, step):
|
||||
self._busWrite(self._core, self._base + a, value[a] & self._mask)
|
||||
else:
|
||||
self._busWrite(self._core, self._base + address, value & self._mask)
|
||||
|
||||
def rawRead(self, address, segment=-1):
|
||||
self._addrCheck(address)
|
||||
return int(ffi.cast(self._type, self._rawRead(self._core, self._base + address, segment)))
|
||||
|
||||
def rawWrite(self, address, value, segment=-1):
|
||||
self._addrCheck(address)
|
||||
self._rawWrite(self._core, self._base + address, segment, value & self._mask)
|
||||
|
||||
class Memory(object):
|
||||
def __init__(self, core, size, base=0):
|
||||
self.size = size
|
||||
self.base = base
|
||||
|
||||
self.u8 = MemoryView(core, 1, size, base, "u")
|
||||
self.u16 = MemoryView(core, 2, size, base, "u")
|
||||
self.u32 = MemoryView(core, 4, size, base, "u")
|
||||
self.s8 = MemoryView(core, 1, size, base, "s")
|
||||
self.s16 = MemoryView(core, 2, size, base, "s")
|
||||
self.s32 = MemoryView(core, 4, size, base, "s")
|
||||
|
||||
def __len__(self):
|
||||
return self._size
|
|
@ -0,0 +1,24 @@
|
|||
# Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
from ._pylib import ffi, lib
|
||||
from . import vfs
|
||||
|
||||
class PNG:
|
||||
def __init__(self, f):
|
||||
self.vf = vfs.open(f)
|
||||
|
||||
def writeHeader(self, image):
|
||||
self._png = lib.PNGWriteOpen(self.vf.handle)
|
||||
self._info = lib.PNGWriteHeader(self._png, image.width, image.height)
|
||||
return self._info != ffi.NULL
|
||||
|
||||
def writePixels(self, image):
|
||||
return lib.PNGWritePixels(self._png, image.width, image.height, image.stride, image.buffer)
|
||||
|
||||
def writeClose(self):
|
||||
lib.PNGWriteClose(self._png, self._info)
|
||||
del self._png
|
||||
del self._info
|
|
@ -0,0 +1,57 @@
|
|||
# Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
from ._pylib import ffi, lib
|
||||
from . import image
|
||||
|
||||
class Tile:
|
||||
def __init__(self, data):
|
||||
self.buffer = data
|
||||
|
||||
def toImage(self):
|
||||
i = image.Image(8, 8)
|
||||
self.composite(i, 0, 0)
|
||||
return i
|
||||
|
||||
def composite(self, i, x, y):
|
||||
for iy in range(8):
|
||||
for ix in range(8):
|
||||
i.buffer[ix + x + (iy + y) * i.stride] = image.u16ToColor(self.buffer[ix + iy * 8])
|
||||
|
||||
class TileView:
|
||||
def __init__(self, core):
|
||||
self.core = core
|
||||
self.cache = ffi.gc(ffi.new("struct mTileCache*"), core._deinitTileCache)
|
||||
core._initTileCache(self.cache)
|
||||
lib.mTileCacheSetPalette(self.cache, 0)
|
||||
self.paletteSet = 0
|
||||
|
||||
def getTile(self, 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):
|
||||
TILE_BASE = 0, 0
|
||||
PALETTE_BASE = 0, 0
|
||||
|
||||
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 x in range(self.width // 8):
|
||||
tile = tileView.getTile(tileId, self.paletteId + self.PALETTE_BASE[paletteSet])
|
||||
tile.composite(i, x * 8, y * 8)
|
||||
tileId += 1
|
||||
if tilePitch:
|
||||
tileId += tilePitch - self.width // 8
|
||||
self.image = i
|
||||
tileView.setPalette(oldPaletteSet)
|
|
@ -0,0 +1,130 @@
|
|||
# Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
from ._pylib import ffi, lib
|
||||
import mmap
|
||||
import os
|
||||
|
||||
@ffi.def_extern()
|
||||
def _vfpClose(vf):
|
||||
vfp = ffi.cast("struct VFilePy*", vf)
|
||||
ffi.from_handle(vfp.fileobj).close()
|
||||
|
||||
@ffi.def_extern()
|
||||
def _vfpSeek(vf, offset, whence):
|
||||
vfp = ffi.cast("struct VFilePy*", vf)
|
||||
f = ffi.from_handle(vfp.fileobj)
|
||||
f.seek(offset, whence)
|
||||
return f.tell()
|
||||
|
||||
@ffi.def_extern()
|
||||
def _vfpRead(vf, buffer, size):
|
||||
vfp = ffi.cast("struct VFilePy*", vf)
|
||||
pybuf = ffi.buffer(buffer, size)
|
||||
ffi.from_handle(vfp.fileobj).readinto(pybuf)
|
||||
return size
|
||||
|
||||
@ffi.def_extern()
|
||||
def _vfpWrite(vf, buffer, size):
|
||||
vfp = ffi.cast("struct VFilePy*", vf)
|
||||
pybuf = ffi.buffer(buffer, size)
|
||||
ffi.from_handle(vfp.fileobj).write(pybuf)
|
||||
return size
|
||||
|
||||
@ffi.def_extern()
|
||||
def _vfpMap(vf, size, flags):
|
||||
pass
|
||||
|
||||
@ffi.def_extern()
|
||||
def _vfpUnmap(vf, memory, size):
|
||||
pass
|
||||
|
||||
@ffi.def_extern()
|
||||
def _vfpTruncate(vf, size):
|
||||
vfp = ffi.cast("struct VFilePy*", vf)
|
||||
ffi.from_handle(vfp.fileobj).truncate(size)
|
||||
|
||||
@ffi.def_extern()
|
||||
def _vfpSize(vf):
|
||||
vfp = ffi.cast("struct VFilePy*", vf)
|
||||
f = ffi.from_handle(vfp.fileobj)
|
||||
pos = f.tell()
|
||||
f.seek(0, os.SEEK_END)
|
||||
size = f.tell()
|
||||
f.seek(pos, os.SEEK_SET)
|
||||
return size
|
||||
|
||||
@ffi.def_extern()
|
||||
def _vfpSync(vf, buffer, size):
|
||||
vfp = ffi.cast("struct VFilePy*", vf)
|
||||
f = ffi.from_handle(vfp.fileobj)
|
||||
if buffer and size:
|
||||
pos = f.tell()
|
||||
f.seek(0, os.SEEK_SET)
|
||||
_vfpWrite(vf, buffer, size)
|
||||
f.seek(pos, os.SEEK_SET)
|
||||
f.flush()
|
||||
os.fsync()
|
||||
return True
|
||||
|
||||
def open(f):
|
||||
handle = ffi.new_handle(f)
|
||||
vf = VFile(lib.VFileFromPython(handle))
|
||||
# Prevent garbage collection
|
||||
vf._fileobj = f
|
||||
vf._handle = handle
|
||||
return vf
|
||||
|
||||
def openPath(path, mode="r"):
|
||||
flags = 0
|
||||
if mode.startswith("r"):
|
||||
flags |= os.O_RDONLY
|
||||
elif mode.startswith("w"):
|
||||
flags |= os.O_WRONLY | os.O_CREAT | os.O_TRUNC
|
||||
elif mode.startswith("a"):
|
||||
flags |= os.O_WRONLY | os.O_CREAT | os.O_APPEND
|
||||
else:
|
||||
return None
|
||||
|
||||
if "+" in mode[1:]:
|
||||
flags |= os.O_RDWR
|
||||
if "x" in mode[1:]:
|
||||
flags |= os.O_EXCL
|
||||
|
||||
return VFile(lib.VFileOpen(path.encode("UTF-8"), flags))
|
||||
|
||||
class VFile:
|
||||
def __init__(self, vf):
|
||||
self.handle = vf
|
||||
|
||||
def close(self):
|
||||
return self.handle.close(self.handle)
|
||||
|
||||
def seek(self, offset, whence):
|
||||
return self.handle.seek(self.handle, offset, whence)
|
||||
|
||||
def read(self, buffer, size):
|
||||
return self.handle.read(self.handle, buffer, size)
|
||||
|
||||
def readline(self, buffer, size):
|
||||
return self.handle.readline(self.handle, buffer, size)
|
||||
|
||||
def write(self, buffer, size):
|
||||
return self.handle.write(self.handle, buffer, size)
|
||||
|
||||
def map(self, size, flags):
|
||||
return self.handle.map(self.handle, size, flags)
|
||||
|
||||
def unmap(self, memory, size):
|
||||
self.handle.unmap(self.handle, memory, size)
|
||||
|
||||
def truncate(self, size):
|
||||
self.handle.truncate(self.handle, size)
|
||||
|
||||
def size(self):
|
||||
return self.handle.size(self.handle)
|
||||
|
||||
def sync(self, buffer, size):
|
||||
return self.handle.sync(self.handle, buffer, size)
|
|
@ -0,0 +1,24 @@
|
|||
from setuptools import setup
|
||||
import re
|
||||
|
||||
classifiers = [
|
||||
"Programming Language :: C",
|
||||
"Programming Language :: Python :: 2",
|
||||
"Programming Language :: Python :: 3",
|
||||
"License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)",
|
||||
"Topic :: Games/Entertainment",
|
||||
"Topic :: System :: Emulators"
|
||||
]
|
||||
|
||||
setup(name="${BINARY_NAME}",
|
||||
version=re.sub("/", "-", "${VERSION_STRING}"),
|
||||
author="Jeffrey Pfau",
|
||||
author_email="jeffrey@endrift.com",
|
||||
url="http://github.com/mgba-emu/mgba/",
|
||||
packages=["mgba"],
|
||||
setup_requires=['cffi>=1.6'],
|
||||
install_requires=['cffi>=1.6', 'cached-property'],
|
||||
cffi_modules=["_builder.py:ffi"],
|
||||
license="MPL 2.0",
|
||||
classifiers=classifiers
|
||||
)
|
|
@ -0,0 +1,46 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "util/vfs.h"
|
||||
|
||||
struct VFilePy {
|
||||
struct VFile d;
|
||||
void* fileobj;
|
||||
};
|
||||
|
||||
bool _vfpClose(struct VFile* vf);
|
||||
off_t _vfpSeek(struct VFile* vf, off_t offset, int whence);
|
||||
ssize_t _vfpRead(struct VFile* vf, void* buffer, size_t size);
|
||||
ssize_t _vfpWrite(struct VFile* vf, const void* buffer, size_t size);
|
||||
void* _vfpMap(struct VFile* vf, size_t size, int flags);
|
||||
void _vfpUnmap(struct VFile* vf, void* memory, size_t size);
|
||||
void _vfpTruncate(struct VFile* vf, size_t size);
|
||||
ssize_t _vfpSize(struct VFile* vf);
|
||||
bool _vfpSync(struct VFile* vf, const void* buffer, size_t size);
|
||||
|
||||
struct VFile* VFileFromPython(void* fileobj) {
|
||||
if (!fileobj) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct VFilePy* vfp = malloc(sizeof(struct VFilePy));
|
||||
if (!vfp) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
vfp->fileobj = fileobj;
|
||||
vfp->d.close = _vfpClose;
|
||||
vfp->d.seek = _vfpSeek;
|
||||
vfp->d.read = _vfpRead;
|
||||
vfp->d.readline = VFileReadline;
|
||||
vfp->d.write = _vfpWrite;
|
||||
vfp->d.map = _vfpMap;
|
||||
vfp->d.unmap = _vfpUnmap;
|
||||
vfp->d.truncate = _vfpTruncate;
|
||||
vfp->d.size = _vfpSize;
|
||||
vfp->d.sync = _vfpSync;
|
||||
|
||||
return &vfp->d;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "util/vfs.h"
|
||||
|
||||
struct VFilePy {
|
||||
struct VFile d;
|
||||
void* fileobj;
|
||||
};
|
||||
|
||||
struct VFile* VFileFromPython(void* fileobj);
|
||||
|
||||
extern "Python+C" {
|
||||
|
||||
bool _vfpClose(struct VFile* vf);
|
||||
off_t _vfpSeek(struct VFile* vf, off_t offset, int whence);
|
||||
ssize_t _vfpRead(struct VFile* vf, void* buffer, size_t size);
|
||||
ssize_t _vfpWrite(struct VFile* vf, const void* buffer, size_t size);
|
||||
void* _vfpMap(struct VFile* vf, size_t size, int flags);
|
||||
void _vfpUnmap(struct VFile* vf, void* memory, size_t size);
|
||||
void _vfpTruncate(struct VFile* vf, size_t size);
|
||||
ssize_t _vfpSize(struct VFile* vf);
|
||||
bool _vfpSync(struct VFile* vf, const void* buffer, size_t size);
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
|
@ -7,16 +7,20 @@
|
|||
|
||||
#include "gl-common.h"
|
||||
|
||||
#include "core/thread.h"
|
||||
|
||||
#ifndef __APPLE__
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
static bool mSDLGLES2Init(struct mSDLRenderer* renderer);
|
||||
static void mSDLGLES2RunloopGBA(struct mSDLRenderer* renderer, void* user);
|
||||
static void mSDLGLES2Runloop(struct mSDLRenderer* renderer, void* user);
|
||||
static void mSDLGLES2Deinit(struct mSDLRenderer* renderer);
|
||||
|
||||
void mSDLGLES2Create(struct mSDLRenderer* renderer) {
|
||||
renderer->init = mSDLGLES2Init;
|
||||
renderer->deinit = mSDLGLES2Deinit;
|
||||
renderer->runloop = mSDLGLES2RunloopGBA;
|
||||
renderer->runloop = mSDLGLES2Runloop;
|
||||
}
|
||||
|
||||
bool mSDLGLES2Init(struct mSDLRenderer* renderer) {
|
||||
|
@ -93,8 +97,13 @@ bool mSDLGLES2Init(struct mSDLRenderer* renderer) {
|
|||
mSDLGLCommonInit(renderer);
|
||||
#endif
|
||||
|
||||
renderer->d.outputBuffer = memalign(16, VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4);
|
||||
renderer->d.outputBufferStride = VIDEO_HORIZONTAL_PIXELS;
|
||||
#ifndef __APPLE__
|
||||
renderer->outputBuffer = memalign(16, renderer->width * renderer->height * BYTES_PER_PIXEL);
|
||||
#else
|
||||
posix_memalign((void**) &renderer->outputBuffer, 16, renderer->width * renderer->height * BYTES_PER_PIXEL);
|
||||
#endif
|
||||
memset(renderer->outputBuffer, 0, renderer->width * renderer->height * BYTES_PER_PIXEL);
|
||||
renderer->core->setVideoBuffer(renderer->core, renderer->outputBuffer, renderer->width);
|
||||
|
||||
mGLES2ContextCreate(&renderer->gl2);
|
||||
renderer->gl2.d.user = renderer;
|
||||
|
@ -107,17 +116,17 @@ bool mSDLGLES2Init(struct mSDLRenderer* renderer) {
|
|||
}
|
||||
|
||||
void mSDLGLES2Runloop(struct mSDLRenderer* renderer, void* user) {
|
||||
struct GBAThread* context = user;
|
||||
struct mCoreThread* context = user;
|
||||
SDL_Event event;
|
||||
struct VideoBackend* v = &renderer->gl2.d;
|
||||
|
||||
while (context->state < THREAD_EXITING) {
|
||||
while (SDL_PollEvent(&event)) {
|
||||
mSDLHandleEventGBA(context, &renderer->player, &event);
|
||||
mSDLHandleEvent(context, &renderer->player, &event);
|
||||
}
|
||||
|
||||
if (mCoreSyncWaitFrameStart(&context->sync)) {
|
||||
v->postFrame(v, renderer->d.outputBuffer);
|
||||
v->postFrame(v, renderer->outputBuffer);
|
||||
}
|
||||
mCoreSyncWaitFrameEnd(&context->sync);
|
||||
v->drawFrame(v);
|
||||
|
@ -142,5 +151,5 @@ void mSDLGLES2Deinit(struct mSDLRenderer* renderer) {
|
|||
#elif SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
SDL_GL_DeleteContext(renderer->glCtx);
|
||||
#endif
|
||||
free(renderer->d.outputBuffer);
|
||||
free(renderer->outputBuffer);
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ void blip_set_rates( blip_t*, double clock_rate, double sample_rate );
|
|||
|
||||
enum { /** Maximum clock_rate/sample_rate ratio. For a given sample_rate,
|
||||
clock_rate must not be greater than sample_rate*blip_max_ratio. */
|
||||
blip_max_ratio = 1 << 20 };
|
||||
blip_max_ratio = 0x100000 };
|
||||
|
||||
/** Clears entire buffer. Afterwards, blip_samples_avail() == 0. */
|
||||
void blip_clear( blip_t* );
|
||||
|
|
|
@ -163,6 +163,14 @@ size_t TableSize(const struct Table* table) {
|
|||
return table->size;
|
||||
}
|
||||
|
||||
void HashTableInit(struct Table* table, size_t initialSize, void (deinitializer(void*))) {
|
||||
TableInit(table, initialSize, deinitializer);
|
||||
}
|
||||
|
||||
void HashTableDeinit(struct Table* table) {
|
||||
TableDeinit(table);
|
||||
}
|
||||
|
||||
void* HashTableLookup(const struct Table* table, const char* key) {
|
||||
uint32_t hash = hash32(key, strlen(key), 0);
|
||||
const struct TableList* list;
|
||||
|
|
|
@ -31,13 +31,8 @@ void TableClear(struct Table*);
|
|||
void TableEnumerate(const struct Table*, void (handler(uint32_t key, void* value, void* user)), void* user);
|
||||
size_t TableSize(const struct Table*);
|
||||
|
||||
static inline void HashTableInit(struct Table* table, size_t initialSize, void (deinitializer(void*))) {
|
||||
TableInit(table, initialSize, deinitializer);
|
||||
}
|
||||
|
||||
static inline void HashTableDeinit(struct Table* table) {
|
||||
TableDeinit(table);
|
||||
}
|
||||
void HashTableInit(struct Table* table, size_t initialSize, void (deinitializer(void*)));
|
||||
void HashTableDeinit(struct Table* table);
|
||||
|
||||
void* HashTableLookup(const struct Table*, const char* key);
|
||||
void HashTableInsert(struct Table*, const char* key, void* value);
|
||||
|
|
|
@ -104,7 +104,7 @@ struct VDir* VDirOpenArchive(const char* path) {
|
|||
dir = VDirOpenZip(path, 0);
|
||||
}
|
||||
#endif
|
||||
#if USE_LZMA
|
||||
#ifdef USE_LZMA
|
||||
if (!dir) {
|
||||
dir = VDirOpen7z(path, 0);
|
||||
}
|
||||
|
|
|
@ -67,12 +67,11 @@ struct VDir {
|
|||
struct VFile* VFileOpen(const char* path, int flags);
|
||||
|
||||
struct VFile* VFileOpenFD(const char* path, int flags);
|
||||
struct VFile* VFileFOpen(const char* path, const char* mode);
|
||||
struct VFile* VFileFromFD(int fd);
|
||||
|
||||
struct VFile* VFileFromMemory(void* mem, size_t size);
|
||||
struct VFile* VFileFromConstMemory(const void* mem, size_t size);
|
||||
struct VFile* VFileMemChunk(const void* mem, size_t size);
|
||||
struct VFile* VFileFromFILE(FILE* file);
|
||||
|
||||
struct VDir* VDirOpen(const char* path);
|
||||
struct VDir* VDirOpenArchive(const char* path);
|
||||
|
@ -85,7 +84,11 @@ struct VDir* VDirOpenZip(const char* path, int flags);
|
|||
struct VDir* VDirOpen7z(const char* path, int flags);
|
||||
#endif
|
||||
|
||||
#if defined(WII) || defined(_3DS)
|
||||
struct VFile* VFileFOpen(const char* path, const char* mode);
|
||||
struct VFile* VFileFromFILE(FILE* file);
|
||||
struct VDir* VDeviceList(void);
|
||||
#endif
|
||||
|
||||
void separatePath(const char* path, char* dirname, char* basename, char* extension);
|
||||
|
||||
|
|
Loading…
Reference in New Issue