mirror of https://github.com/mgba-emu/mgba.git
Merge branch 'master' into medusa
This commit is contained in:
commit
f85a18737e
4
CHANGES
4
CHANGES
|
@ -43,6 +43,8 @@ Features:
|
||||||
- Add option for whether rewinding restores save games
|
- Add option for whether rewinding restores save games
|
||||||
- Qt: German translation (by Lothar Serra Mari)
|
- Qt: German translation (by Lothar Serra Mari)
|
||||||
- Savestates now contain any RTC override data
|
- Savestates now contain any RTC override data
|
||||||
|
- Command line ability to override configuration values
|
||||||
|
- Add option to allow preloading the entire ROM before running
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
- LR35902: Fix core never exiting with certain event patterns
|
- LR35902: Fix core never exiting with certain event patterns
|
||||||
- GB Timer: Improve DIV reset behavior
|
- GB Timer: Improve DIV reset behavior
|
||||||
|
@ -118,6 +120,8 @@ Misc:
|
||||||
- Qt: Make "Mute" able to be bound to a key
|
- Qt: Make "Mute" able to be bound to a key
|
||||||
- Core: Restore sleep callback
|
- Core: Restore sleep callback
|
||||||
- Qt: Add .gb/.gbc files to the extension list in Info.plist
|
- Qt: Add .gb/.gbc files to the extension list in Info.plist
|
||||||
|
- Feature: Make -l option explicit
|
||||||
|
- Core: Ability to enumerate and modify video and audio channels
|
||||||
|
|
||||||
medusa alpha 1: (2017-04-08)
|
medusa alpha 1: (2017-04-08)
|
||||||
Features:
|
Features:
|
||||||
|
|
|
@ -92,6 +92,8 @@ CXX_GUARD_START
|
||||||
dest->size = src->size; \
|
dest->size = src->size; \
|
||||||
} \
|
} \
|
||||||
|
|
||||||
|
DECLARE_VECTOR(StringList, char*);
|
||||||
|
|
||||||
CXX_GUARD_END
|
CXX_GUARD_END
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -48,7 +48,6 @@ struct mCheat {
|
||||||
mLOG_DECLARE_CATEGORY(CHEATS);
|
mLOG_DECLARE_CATEGORY(CHEATS);
|
||||||
|
|
||||||
DECLARE_VECTOR(mCheatList, struct mCheat);
|
DECLARE_VECTOR(mCheatList, struct mCheat);
|
||||||
DECLARE_VECTOR(StringList, char*);
|
|
||||||
|
|
||||||
struct mCheatDevice;
|
struct mCheatDevice;
|
||||||
struct mCheatSet {
|
struct mCheatSet {
|
||||||
|
|
|
@ -147,12 +147,20 @@ struct mCore {
|
||||||
|
|
||||||
size_t (*savedataClone)(struct mCore*, void** sram);
|
size_t (*savedataClone)(struct mCore*, void** sram);
|
||||||
bool (*savedataRestore)(struct mCore*, const void* sram, size_t size, bool writeback);
|
bool (*savedataRestore)(struct mCore*, const void* sram, size_t size, bool writeback);
|
||||||
|
|
||||||
|
size_t (*listVideoLayers)(const struct mCore*, const struct mCoreChannelInfo**);
|
||||||
|
size_t (*listAudioChannels)(const struct mCore*, const struct mCoreChannelInfo**);
|
||||||
|
void (*enableVideoLayer)(struct mCore*, size_t id, bool enable);
|
||||||
|
void (*enableAudioChannel)(struct mCore*, size_t id, bool enable);
|
||||||
};
|
};
|
||||||
|
|
||||||
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
|
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
|
||||||
struct mCore* mCoreFind(const char* path);
|
struct mCore* mCoreFind(const char* path);
|
||||||
bool mCoreLoadFile(struct mCore* core, const char* path);
|
bool mCoreLoadFile(struct mCore* core, const char* path);
|
||||||
|
|
||||||
|
bool mCorePreloadVF(struct mCore* core, struct VFile* vf);
|
||||||
|
bool mCorePreloadFile(struct mCore* core, const char* path);
|
||||||
|
|
||||||
bool mCoreAutoloadSave(struct mCore* core);
|
bool mCoreAutoloadSave(struct mCore* core);
|
||||||
bool mCoreAutoloadPatch(struct mCore* core);
|
bool mCoreAutoloadPatch(struct mCore* core);
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,13 @@ struct mRumble {
|
||||||
void (*setRumble)(struct mRumble*, int enable);
|
void (*setRumble)(struct mRumble*, int enable);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mCoreChannelInfo {
|
||||||
|
size_t id;
|
||||||
|
const char* internalName;
|
||||||
|
const char* visibleName;
|
||||||
|
const char* visibleType;
|
||||||
|
};
|
||||||
|
|
||||||
CXX_GUARD_END
|
CXX_GUARD_END
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -17,7 +17,6 @@ mLOG_DEFINE_CATEGORY(CHEATS, "Cheats", "core.cheats");
|
||||||
|
|
||||||
DEFINE_VECTOR(mCheatList, struct mCheat);
|
DEFINE_VECTOR(mCheatList, struct mCheat);
|
||||||
DEFINE_VECTOR(mCheatSets, struct mCheatSet*);
|
DEFINE_VECTOR(mCheatSets, struct mCheatSet*);
|
||||||
DEFINE_VECTOR(StringList, char*);
|
|
||||||
|
|
||||||
static int32_t _readMem(struct mCore* core, uint32_t address, int width) {
|
static int32_t _readMem(struct mCore* core, uint32_t address, int width) {
|
||||||
switch (width) {
|
switch (width) {
|
||||||
|
|
|
@ -122,6 +122,35 @@ bool mCoreLoadFile(struct mCore* core, const char* path) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool mCorePreloadVF(struct mCore* core, struct VFile* vf) {
|
||||||
|
struct VFile* vfm = VFileMemChunk(NULL, vf->size(vf));
|
||||||
|
uint8_t buffer[2048];
|
||||||
|
ssize_t read;
|
||||||
|
vf->seek(vf, 0, SEEK_SET);
|
||||||
|
while ((read = vf->read(vf, buffer, sizeof(buffer))) > 0) {
|
||||||
|
vfm->write(vfm, buffer, read);
|
||||||
|
}
|
||||||
|
vf->close(vf);
|
||||||
|
bool ret = core->loadROM(core, vfm);
|
||||||
|
if (!ret) {
|
||||||
|
vfm->close(vfm);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mCorePreloadFile(struct mCore* core, const char* path) {
|
||||||
|
struct VFile* rom = mDirectorySetOpenPath(&core->dirs, path, core->isROM);
|
||||||
|
if (!rom) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ret = mCorePreloadVF(core, rom);
|
||||||
|
if (!ret) {
|
||||||
|
rom->close(rom);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
bool mCoreAutoloadSave(struct mCore* core) {
|
bool mCoreAutoloadSave(struct mCore* core) {
|
||||||
return core->loadSave(core, mDirectorySetOpenSuffix(&core->dirs, core->dirs.save, ".sav", O_CREAT | O_RDWR));
|
return core->loadSave(core, mDirectorySetOpenSuffix(&core->dirs, core->dirs.save, ".sav", O_CREAT | O_RDWR));
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,38 @@
|
||||||
#include <mgba-util/patch.h>
|
#include <mgba-util/patch.h>
|
||||||
#include <mgba-util/vfs.h>
|
#include <mgba-util/vfs.h>
|
||||||
|
|
||||||
|
const static struct mCoreChannelInfo _DSVideoLayers[] = {
|
||||||
|
{ 0, "abg0", "A BG0", "2D/3D" },
|
||||||
|
{ 1, "abg1", "A BG1", NULL },
|
||||||
|
{ 2, "abg2", "A BG2", NULL },
|
||||||
|
{ 3, "abg3", "A BG3", NULL },
|
||||||
|
{ 4, "aobj", "A OBJ", NULL },
|
||||||
|
{ 5, "bbg0", "B BG0", "2D/3D" },
|
||||||
|
{ 6, "bbg1", "B BG1", NULL },
|
||||||
|
{ 7, "bbg2", "B BG2", NULL },
|
||||||
|
{ 8, "bbg3", "B BG3", NULL },
|
||||||
|
{ 9, "bobj", "B OBJ", NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
const static struct mCoreChannelInfo _DSAudioChannels[] = {
|
||||||
|
{ 0, "ch00", "Channel 0", NULL },
|
||||||
|
{ 1, "ch01", "Channel 1", NULL },
|
||||||
|
{ 2, "ch02", "Channel 2", NULL },
|
||||||
|
{ 3, "ch03", "Channel 3", NULL },
|
||||||
|
{ 4, "ch04", "Channel 4", NULL },
|
||||||
|
{ 5, "ch05", "Channel 5", NULL },
|
||||||
|
{ 6, "ch06", "Channel 6", NULL },
|
||||||
|
{ 7, "ch07", "Channel 7", NULL },
|
||||||
|
{ 8, "ch08", "Channel 8", NULL },
|
||||||
|
{ 9, "ch09", "Channel 9", NULL },
|
||||||
|
{ 10, "ch10", "Channel 10", NULL },
|
||||||
|
{ 11, "ch11", "Channel 11", NULL },
|
||||||
|
{ 12, "ch12", "Channel 12", NULL },
|
||||||
|
{ 13, "ch13", "Channel 13", NULL },
|
||||||
|
{ 14, "ch14", "Channel 14", NULL },
|
||||||
|
{ 15, "ch15", "Channel 15", NULL },
|
||||||
|
};
|
||||||
|
|
||||||
struct DSCore {
|
struct DSCore {
|
||||||
struct mCore d;
|
struct mCore d;
|
||||||
struct ARMCore* arm7;
|
struct ARMCore* arm7;
|
||||||
|
@ -515,6 +547,27 @@ static bool _DSCoreSavedataRestore(struct mCore* core, const void* sram, size_t
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t _DSCoreListVideoLayers(const struct mCore* core, const struct mCoreChannelInfo** info) {
|
||||||
|
UNUSED(core);
|
||||||
|
*info = _DSVideoLayers;
|
||||||
|
return sizeof(_DSVideoLayers) / sizeof(*_DSVideoLayers);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t _DSCoreListAudioChannels(const struct mCore* core, const struct mCoreChannelInfo** info) {
|
||||||
|
UNUSED(core);
|
||||||
|
*info = _DSAudioChannels;
|
||||||
|
return sizeof(_DSAudioChannels) / sizeof(*_DSAudioChannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _DSCoreEnableVideoLayer(struct mCore* core, size_t id, bool enable) {
|
||||||
|
struct DS* ds = core->board;
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _DSCoreEnableAudioChannel(struct mCore* core, size_t id, bool enable) {
|
||||||
|
struct DS* ds = core->board;
|
||||||
|
}
|
||||||
|
|
||||||
struct mCore* DSCoreCreate(void) {
|
struct mCore* DSCoreCreate(void) {
|
||||||
struct DSCore* dscore = malloc(sizeof(*dscore));
|
struct DSCore* dscore = malloc(sizeof(*dscore));
|
||||||
struct mCore* core = &dscore->d;
|
struct mCore* core = &dscore->d;
|
||||||
|
@ -584,5 +637,9 @@ struct mCore* DSCoreCreate(void) {
|
||||||
core->cheatDevice = _DSCoreCheatDevice;
|
core->cheatDevice = _DSCoreCheatDevice;
|
||||||
core->savedataClone = _DSCoreSavedataClone;
|
core->savedataClone = _DSCoreSavedataClone;
|
||||||
core->savedataRestore = _DSCoreSavedataRestore;
|
core->savedataRestore = _DSCoreSavedataRestore;
|
||||||
|
core->listVideoLayers = _DSCoreListVideoLayers;
|
||||||
|
core->listAudioChannels = _DSCoreListAudioChannels;
|
||||||
|
core->enableVideoLayer = _DSCoreEnableVideoLayer;
|
||||||
|
core->enableAudioChannel = _DSCoreEnableAudioChannel;
|
||||||
return core;
|
return core;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@ static const struct option _options[] = {
|
||||||
{ "gdb", no_argument, 0, 'g' },
|
{ "gdb", no_argument, 0, 'g' },
|
||||||
#endif
|
#endif
|
||||||
{ "help", no_argument, 0, 'h' },
|
{ "help", no_argument, 0, 'h' },
|
||||||
|
{ "log-level", required_argument, 0, 'l' },
|
||||||
{ "movie", required_argument, 0, 'v' },
|
{ "movie", required_argument, 0, 'v' },
|
||||||
{ "patch", required_argument, 0, 'p' },
|
{ "patch", required_argument, 0, 'p' },
|
||||||
{ "version", no_argument, 0, '\0' },
|
{ "version", no_argument, 0, '\0' },
|
||||||
|
@ -47,10 +48,27 @@ static const struct option _options[] = {
|
||||||
static bool _parseGraphicsArg(struct mSubParser* parser, int option, const char* arg);
|
static bool _parseGraphicsArg(struct mSubParser* parser, int option, const char* arg);
|
||||||
static void _applyGraphicsArgs(struct mSubParser* parser, struct mCoreConfig* config);
|
static void _applyGraphicsArgs(struct mSubParser* parser, struct mCoreConfig* config);
|
||||||
|
|
||||||
|
static void _tableInsert(struct Table* table, const char* pair) {
|
||||||
|
char* eq = strchr(pair, '=');
|
||||||
|
if (eq) {
|
||||||
|
char option[128] = "";
|
||||||
|
strncpy(option, pair, eq - pair);
|
||||||
|
option[sizeof(option) - 1] = '\0';
|
||||||
|
HashTableInsert(table, option, strdup(&eq[1]));
|
||||||
|
} else {
|
||||||
|
HashTableInsert(table, pair, strdup("1"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _tableApply(const char* key, void* value, void* user) {
|
||||||
|
struct mCoreConfig* config = user;
|
||||||
|
mCoreConfigSetOverrideValue(config, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
bool parseArguments(struct mArguments* args, int argc, char* const* argv, struct mSubParser* subparser) {
|
bool parseArguments(struct mArguments* args, int argc, char* const* argv, struct mSubParser* subparser) {
|
||||||
int ch;
|
int ch;
|
||||||
char options[64] =
|
char options[64] =
|
||||||
"b:c:hl:p:s:v:"
|
"b:c:C:hl:p:s:v:"
|
||||||
#ifdef USE_EDITLINE
|
#ifdef USE_EDITLINE
|
||||||
"d"
|
"d"
|
||||||
#endif
|
#endif
|
||||||
|
@ -61,6 +79,7 @@ bool parseArguments(struct mArguments* args, int argc, char* const* argv, struct
|
||||||
memset(args, 0, sizeof(*args));
|
memset(args, 0, sizeof(*args));
|
||||||
args->frameskip = -1;
|
args->frameskip = -1;
|
||||||
args->logLevel = INT_MIN;
|
args->logLevel = INT_MIN;
|
||||||
|
HashTableInit(&args->configOverrides, 0, free);
|
||||||
if (subparser && subparser->extraOptions) {
|
if (subparser && subparser->extraOptions) {
|
||||||
// TODO: modularize options to subparsers
|
// TODO: modularize options to subparsers
|
||||||
strncat(options, subparser->extraOptions, sizeof(options) - strlen(options) - 1);
|
strncat(options, subparser->extraOptions, sizeof(options) - strlen(options) - 1);
|
||||||
|
@ -82,6 +101,9 @@ bool parseArguments(struct mArguments* args, int argc, char* const* argv, struct
|
||||||
case 'c':
|
case 'c':
|
||||||
args->cheatsFile = strdup(optarg);
|
args->cheatsFile = strdup(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 'C':
|
||||||
|
_tableInsert(&args->configOverrides, optarg);
|
||||||
|
break;
|
||||||
#ifdef USE_EDITLINE
|
#ifdef USE_EDITLINE
|
||||||
case 'd':
|
case 'd':
|
||||||
if (args->debuggerType != DEBUGGER_NONE) {
|
if (args->debuggerType != DEBUGGER_NONE) {
|
||||||
|
@ -144,6 +166,7 @@ void applyArguments(const struct mArguments* args, struct mSubParser* subparser,
|
||||||
if (args->bios) {
|
if (args->bios) {
|
||||||
mCoreConfigSetOverrideValue(config, "bios", args->bios);
|
mCoreConfigSetOverrideValue(config, "bios", args->bios);
|
||||||
}
|
}
|
||||||
|
HashTableEnumerate(&args->configOverrides, _tableApply, config);
|
||||||
if (subparser) {
|
if (subparser) {
|
||||||
subparser->apply(subparser, config);
|
subparser->apply(subparser, config);
|
||||||
}
|
}
|
||||||
|
@ -164,6 +187,8 @@ void freeArguments(struct mArguments* args) {
|
||||||
|
|
||||||
free(args->bios);
|
free(args->bios);
|
||||||
args->bios = 0;
|
args->bios = 0;
|
||||||
|
|
||||||
|
HashTableDeinit(&args->configOverrides);
|
||||||
}
|
}
|
||||||
|
|
||||||
void initParserForGraphics(struct mSubParser* parser, struct mGraphicsOpts* opts) {
|
void initParserForGraphics(struct mSubParser* parser, struct mGraphicsOpts* opts) {
|
||||||
|
@ -211,12 +236,14 @@ void usage(const char* arg0, const char* extraOptions) {
|
||||||
puts("\nGeneric options:");
|
puts("\nGeneric options:");
|
||||||
puts(" -b, --bios FILE GBA BIOS file to use");
|
puts(" -b, --bios FILE GBA BIOS file to use");
|
||||||
puts(" -c, --cheats FILE Apply cheat codes from a file");
|
puts(" -c, --cheats FILE Apply cheat codes from a file");
|
||||||
|
puts(" -C, --config OPTION=VALUE Override config value");
|
||||||
#ifdef USE_EDITLINE
|
#ifdef USE_EDITLINE
|
||||||
puts(" -d, --debug Use command-line debugger");
|
puts(" -d, --debug Use command-line debugger");
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_GDB_STUB
|
#ifdef USE_GDB_STUB
|
||||||
puts(" -g, --gdb Start GDB session (default port 2345)");
|
puts(" -g, --gdb Start GDB session (default port 2345)");
|
||||||
#endif
|
#endif
|
||||||
|
puts(" -l, --log-level N Log level mask");
|
||||||
puts(" -v, --movie FILE Play back a movie of recorded input");
|
puts(" -v, --movie FILE Play back a movie of recorded input");
|
||||||
puts(" -p, --patch FILE Apply a specified patch file when running");
|
puts(" -p, --patch FILE Apply a specified patch file when running");
|
||||||
puts(" -s, --frameskip N Skip every N frames");
|
puts(" -s, --frameskip N Skip every N frames");
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
CXX_GUARD_START
|
CXX_GUARD_START
|
||||||
|
|
||||||
|
#include <mgba-util/table.h>
|
||||||
|
|
||||||
#include <mgba/internal/debugger/debugger.h>
|
#include <mgba/internal/debugger/debugger.h>
|
||||||
|
|
||||||
struct mArguments {
|
struct mArguments {
|
||||||
|
@ -21,6 +23,8 @@ struct mArguments {
|
||||||
int logLevel;
|
int logLevel;
|
||||||
int frameskip;
|
int frameskip;
|
||||||
|
|
||||||
|
struct Table configOverrides;
|
||||||
|
|
||||||
enum mDebuggerType debuggerType;
|
enum mDebuggerType debuggerType;
|
||||||
bool debugAtStart;
|
bool debugAtStart;
|
||||||
bool showHelp;
|
bool showHelp;
|
||||||
|
|
|
@ -25,6 +25,19 @@
|
||||||
#include <mgba/internal/gba/input.h>
|
#include <mgba/internal/gba/input.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
const static struct mCoreChannelInfo _GBVideoLayers[] = {
|
||||||
|
{ 0, "bg", "Background", NULL },
|
||||||
|
{ 1, "obj", "Objects", NULL },
|
||||||
|
{ 2, "win", "Window", NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
const static struct mCoreChannelInfo _GBAudioChannels[] = {
|
||||||
|
{ 0, "ch0", "Channel 0", "Square/Sweep" },
|
||||||
|
{ 1, "ch1", "Channel 1", "Square" },
|
||||||
|
{ 2, "ch2", "Channel 2", "PCM" },
|
||||||
|
{ 3, "ch3", "Channel 3", "Noise" },
|
||||||
|
};
|
||||||
|
|
||||||
struct GBCore {
|
struct GBCore {
|
||||||
struct mCore d;
|
struct mCore d;
|
||||||
struct GBVideoSoftwareRenderer renderer;
|
struct GBVideoSoftwareRenderer renderer;
|
||||||
|
@ -599,6 +612,37 @@ static bool _GBCoreSavedataRestore(struct mCore* core, const void* sram, size_t
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t _GBCoreListVideoLayers(const struct mCore* core, const struct mCoreChannelInfo** info) {
|
||||||
|
UNUSED(core);
|
||||||
|
*info = _GBVideoLayers;
|
||||||
|
return sizeof(_GBVideoLayers) / sizeof(*_GBVideoLayers);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t _GBCoreListAudioChannels(const struct mCore* core, const struct mCoreChannelInfo** info) {
|
||||||
|
UNUSED(core);
|
||||||
|
*info = _GBAudioChannels;
|
||||||
|
return sizeof(_GBAudioChannels) / sizeof(*_GBAudioChannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _GBCoreEnableVideoLayer(struct mCore* core, size_t id, bool enable) {
|
||||||
|
struct GB* gb = core->board;
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _GBCoreEnableAudioChannel(struct mCore* core, size_t id, bool enable) {
|
||||||
|
struct GB* gb = core->board;
|
||||||
|
switch (id) {
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
gb->audio.forceDisableCh[id] = !enable;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct mCore* GBCoreCreate(void) {
|
struct mCore* GBCoreCreate(void) {
|
||||||
struct GBCore* gbcore = malloc(sizeof(*gbcore));
|
struct GBCore* gbcore = malloc(sizeof(*gbcore));
|
||||||
struct mCore* core = &gbcore->d;
|
struct mCore* core = &gbcore->d;
|
||||||
|
@ -669,5 +713,9 @@ struct mCore* GBCoreCreate(void) {
|
||||||
core->cheatDevice = _GBCoreCheatDevice;
|
core->cheatDevice = _GBCoreCheatDevice;
|
||||||
core->savedataClone = _GBCoreSavedataClone;
|
core->savedataClone = _GBCoreSavedataClone;
|
||||||
core->savedataRestore = _GBCoreSavedataRestore;
|
core->savedataRestore = _GBCoreSavedataRestore;
|
||||||
|
core->listVideoLayers = _GBCoreListVideoLayers;
|
||||||
|
core->listAudioChannels = _GBCoreListAudioChannels;
|
||||||
|
core->enableVideoLayer = _GBCoreEnableVideoLayer;
|
||||||
|
core->enableAudioChannel = _GBCoreEnableAudioChannel;
|
||||||
return core;
|
return core;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,23 @@
|
||||||
#include <mgba/internal/gba/input.h>
|
#include <mgba/internal/gba/input.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
const static struct mCoreChannelInfo _GBAVideoLayers[] = {
|
||||||
|
{ 0, "bg0", "Background 0", NULL },
|
||||||
|
{ 1, "bg1", "Background 1", NULL },
|
||||||
|
{ 2, "bg2", "Background 2", NULL },
|
||||||
|
{ 3, "bg3", "Background 3", NULL },
|
||||||
|
{ 4, "obj", "Objects", NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
const static struct mCoreChannelInfo _GBAAudioChannels[] = {
|
||||||
|
{ 0, "ch0", "PSG Channel 0", "Square/Sweep" },
|
||||||
|
{ 1, "ch1", "PSG Channel 1", "Square" },
|
||||||
|
{ 2, "ch2", "PSG Channel 2", "PCM" },
|
||||||
|
{ 3, "ch3", "PSG Channel 3", "Noise" },
|
||||||
|
{ 4, "chA", "FIFO Channel A", NULL },
|
||||||
|
{ 5, "chB", "FIFO Channel B", NULL },
|
||||||
|
};
|
||||||
|
|
||||||
struct GBACore {
|
struct GBACore {
|
||||||
struct mCore d;
|
struct mCore d;
|
||||||
struct GBAVideoSoftwareRenderer renderer;
|
struct GBAVideoSoftwareRenderer renderer;
|
||||||
|
@ -600,6 +617,54 @@ static bool _GBACoreSavedataRestore(struct mCore* core, const void* sram, size_t
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t _GBACoreListVideoLayers(const struct mCore* core, const struct mCoreChannelInfo** info) {
|
||||||
|
UNUSED(core);
|
||||||
|
*info = _GBAVideoLayers;
|
||||||
|
return sizeof(_GBAVideoLayers) / sizeof(*_GBAVideoLayers);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t _GBACoreListAudioChannels(const struct mCore* core, const struct mCoreChannelInfo** info) {
|
||||||
|
UNUSED(core);
|
||||||
|
*info = _GBAAudioChannels;
|
||||||
|
return sizeof(_GBAAudioChannels) / sizeof(*_GBAAudioChannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _GBACoreEnableVideoLayer(struct mCore* core, size_t id, bool enable) {
|
||||||
|
struct GBA* gba = core->board;
|
||||||
|
switch (id) {
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
gba->video.renderer->disableBG[id] = !enable;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
gba->video.renderer->disableOBJ = !enable;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _GBACoreEnableAudioChannel(struct mCore* core, size_t id, bool enable) {
|
||||||
|
struct GBA* gba = core->board;
|
||||||
|
switch (id) {
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
gba->audio.psg.forceDisableCh[id] = !enable;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
gba->audio.forceDisableChA = !enable;
|
||||||
|
case 5:
|
||||||
|
gba->audio.forceDisableChB = !enable;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct mCore* GBACoreCreate(void) {
|
struct mCore* GBACoreCreate(void) {
|
||||||
struct GBACore* gbacore = malloc(sizeof(*gbacore));
|
struct GBACore* gbacore = malloc(sizeof(*gbacore));
|
||||||
struct mCore* core = &gbacore->d;
|
struct mCore* core = &gbacore->d;
|
||||||
|
@ -670,5 +735,9 @@ struct mCore* GBACoreCreate(void) {
|
||||||
core->cheatDevice = _GBACoreCheatDevice;
|
core->cheatDevice = _GBACoreCheatDevice;
|
||||||
core->savedataClone = _GBACoreSavedataClone;
|
core->savedataClone = _GBACoreSavedataClone;
|
||||||
core->savedataRestore = _GBACoreSavedataRestore;
|
core->savedataRestore = _GBACoreSavedataRestore;
|
||||||
|
core->listVideoLayers = _GBACoreListVideoLayers;
|
||||||
|
core->listAudioChannels = _GBACoreListAudioChannels;
|
||||||
|
core->enableVideoLayer = _GBACoreEnableVideoLayer;
|
||||||
|
core->enableAudioChannel = _GBACoreEnableAudioChannel;
|
||||||
return core;
|
return core;
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,7 @@ QString ConfigController::s_configDir;
|
||||||
|
|
||||||
ConfigController::ConfigController(QObject* parent)
|
ConfigController::ConfigController(QObject* parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, m_opts()
|
, m_opts{}
|
||||||
{
|
{
|
||||||
QString fileName = configDir();
|
QString fileName = configDir();
|
||||||
fileName.append(QDir::separator());
|
fileName.append(QDir::separator());
|
||||||
|
|
|
@ -57,8 +57,8 @@ GameController::GameController(QObject* parent)
|
||||||
, m_turboForced(false)
|
, m_turboForced(false)
|
||||||
, m_turboSpeed(-1)
|
, m_turboSpeed(-1)
|
||||||
, m_wasPaused(false)
|
, m_wasPaused(false)
|
||||||
, m_audioChannels{ true, true, true, true, true, true }
|
, m_audioChannels()
|
||||||
, m_videoLayers{ true, true, true, true, true }
|
, m_videoLayers()
|
||||||
, m_autofire{}
|
, m_autofire{}
|
||||||
, m_autofireStatus{}
|
, m_autofireStatus{}
|
||||||
, m_inputController(nullptr)
|
, m_inputController(nullptr)
|
||||||
|
@ -69,6 +69,7 @@ GameController::GameController(QObject* parent)
|
||||||
, m_backupSaveState(nullptr)
|
, m_backupSaveState(nullptr)
|
||||||
, m_saveStateFlags(SAVESTATE_SCREENSHOT | SAVESTATE_SAVEDATA | SAVESTATE_CHEATS | SAVESTATE_RTC)
|
, m_saveStateFlags(SAVESTATE_SCREENSHOT | SAVESTATE_SAVEDATA | SAVESTATE_CHEATS | SAVESTATE_RTC)
|
||||||
, m_loadStateFlags(SAVESTATE_SCREENSHOT | SAVESTATE_RTC)
|
, m_loadStateFlags(SAVESTATE_SCREENSHOT | SAVESTATE_RTC)
|
||||||
|
, m_preload(false)
|
||||||
, m_override(nullptr)
|
, m_override(nullptr)
|
||||||
{
|
{
|
||||||
#ifdef M_CORE_GBA
|
#ifdef M_CORE_GBA
|
||||||
|
@ -90,35 +91,17 @@ GameController::GameController(QObject* parent)
|
||||||
context->core->setPeripheral(context->core, mPERIPH_ROTATION, controller->m_inputController->rotationSource());
|
context->core->setPeripheral(context->core, mPERIPH_ROTATION, controller->m_inputController->rotationSource());
|
||||||
context->core->setPeripheral(context->core, mPERIPH_RUMBLE, controller->m_inputController->rumble());
|
context->core->setPeripheral(context->core, mPERIPH_RUMBLE, controller->m_inputController->rumble());
|
||||||
|
|
||||||
#ifdef M_CORE_GBA
|
for (size_t i = 0; i < controller->m_audioChannels.size(); ++i) {
|
||||||
GBA* gba = static_cast<GBA*>(context->core->board);
|
context->core->enableAudioChannel(context->core, i, controller->m_audioChannels[i]);
|
||||||
#endif
|
}
|
||||||
#ifdef M_CORE_GB
|
for (size_t i = 0; i < controller->m_videoLayers.size(); ++i) {
|
||||||
GB* gb = static_cast<GB*>(context->core->board);
|
context->core->enableVideoLayer(context->core, i, controller->m_videoLayers[i]);
|
||||||
#endif
|
}
|
||||||
|
|
||||||
switch (context->core->platform(context->core)) {
|
switch (context->core->platform(context->core)) {
|
||||||
#ifdef M_CORE_GBA
|
#ifdef M_CORE_GBA
|
||||||
case PLATFORM_GBA:
|
case PLATFORM_GBA:
|
||||||
context->core->setPeripheral(context->core, mPERIPH_GBA_LUMINANCE, &controller->m_lux);
|
context->core->setPeripheral(context->core, mPERIPH_GBA_LUMINANCE, &controller->m_lux);
|
||||||
gba->audio.psg.forceDisableCh[0] = !controller->m_audioChannels[0];
|
|
||||||
gba->audio.psg.forceDisableCh[1] = !controller->m_audioChannels[1];
|
|
||||||
gba->audio.psg.forceDisableCh[2] = !controller->m_audioChannels[2];
|
|
||||||
gba->audio.psg.forceDisableCh[3] = !controller->m_audioChannels[3];
|
|
||||||
gba->audio.forceDisableChA = !controller->m_audioChannels[4];
|
|
||||||
gba->audio.forceDisableChB = !controller->m_audioChannels[5];
|
|
||||||
gba->video.renderer->disableBG[0] = !controller->m_videoLayers[0];
|
|
||||||
gba->video.renderer->disableBG[1] = !controller->m_videoLayers[1];
|
|
||||||
gba->video.renderer->disableBG[2] = !controller->m_videoLayers[2];
|
|
||||||
gba->video.renderer->disableBG[3] = !controller->m_videoLayers[3];
|
|
||||||
gba->video.renderer->disableOBJ = !controller->m_videoLayers[4];
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef M_CORE_GB
|
|
||||||
case PLATFORM_GB:
|
|
||||||
gb->audio.forceDisableCh[0] = !controller->m_audioChannels[0];
|
|
||||||
gb->audio.forceDisableCh[1] = !controller->m_audioChannels[1];
|
|
||||||
gb->audio.forceDisableCh[2] = !controller->m_audioChannels[2];
|
|
||||||
gb->audio.forceDisableCh[3] = !controller->m_audioChannels[3];
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
|
@ -476,12 +459,21 @@ void GameController::openGame(bool biosOnly) {
|
||||||
QByteArray bytes;
|
QByteArray bytes;
|
||||||
if (!biosOnly) {
|
if (!biosOnly) {
|
||||||
bytes = m_fname.toUtf8();
|
bytes = m_fname.toUtf8();
|
||||||
|
if (m_preload) {
|
||||||
|
if (m_vf) {
|
||||||
|
mCorePreloadVF(m_threadContext.core, m_vf);
|
||||||
|
} else {
|
||||||
|
mCorePreloadFile(m_threadContext.core, bytes.constData());
|
||||||
|
mDirectorySetDetachBase(&m_threadContext.core->dirs);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (m_vf) {
|
if (m_vf) {
|
||||||
m_threadContext.core->loadROM(m_threadContext.core, m_vf);
|
m_threadContext.core->loadROM(m_threadContext.core, m_vf);
|
||||||
} else {
|
} else {
|
||||||
mCoreLoadFile(m_threadContext.core, bytes.constData());
|
mCoreLoadFile(m_threadContext.core, bytes.constData());
|
||||||
mDirectorySetDetachBase(&m_threadContext.core->dirs);
|
mDirectorySetDetachBase(&m_threadContext.core->dirs);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
bytes = m_bios.toUtf8();
|
bytes = m_bios.toUtf8();
|
||||||
}
|
}
|
||||||
|
@ -880,47 +872,13 @@ void GameController::setAudioChannelEnabled(int channel, bool enable) {
|
||||||
if (channel > 5 || channel < 0) {
|
if (channel > 5 || channel < 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#ifdef M_CORE_GBA
|
m_audioChannels.reserve(channel + 1);
|
||||||
GBA* gba = static_cast<GBA*>(m_threadContext.core->board);
|
while (m_audioChannels.size() <= channel) {
|
||||||
#endif
|
m_audioChannels.append(true);
|
||||||
#ifdef M_CORE_GB
|
}
|
||||||
GB* gb = static_cast<GB*>(m_threadContext.core->board);
|
|
||||||
#endif
|
|
||||||
m_audioChannels[channel] = enable;
|
m_audioChannels[channel] = enable;
|
||||||
if (isLoaded()) {
|
if (isLoaded()) {
|
||||||
switch (channel) {
|
m_threadContext.core->enableAudioChannel(m_threadContext.core, channel, enable);
|
||||||
case 0:
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
switch (m_threadContext.core->platform(m_threadContext.core)) {
|
|
||||||
#ifdef M_CORE_GBA
|
|
||||||
case PLATFORM_GBA:
|
|
||||||
gba->audio.psg.forceDisableCh[channel] = !enable;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef M_CORE_GB
|
|
||||||
case PLATFORM_GB:
|
|
||||||
gb->audio.forceDisableCh[channel] = !enable;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#ifdef M_CORE_GBA
|
|
||||||
case 4:
|
|
||||||
if (m_threadContext.core->platform(m_threadContext.core) == PLATFORM_GBA) {
|
|
||||||
gba->audio.forceDisableChA = !enable;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
if (m_threadContext.core->platform(m_threadContext.core) == PLATFORM_GBA) {
|
|
||||||
gba->audio.forceDisableChB = !enable;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -939,24 +897,15 @@ void GameController::setVideoLayerEnabled(int layer, bool enable) {
|
||||||
if (layer > 4 || layer < 0) {
|
if (layer > 4 || layer < 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
m_videoLayers.reserve(layer + 1);
|
||||||
|
while (m_videoLayers.size() <= layer) {
|
||||||
|
m_videoLayers.append(true);
|
||||||
|
}
|
||||||
m_videoLayers[layer] = enable;
|
m_videoLayers[layer] = enable;
|
||||||
#ifdef M_CORE_GBA
|
if (isLoaded()) {
|
||||||
if (isLoaded() && m_threadContext.core->platform(m_threadContext.core) == PLATFORM_GBA) {
|
m_threadContext.core->enableVideoLayer(m_threadContext.core, layer, enable);
|
||||||
GBA* gba = static_cast<GBA*>(m_threadContext.core->board);
|
|
||||||
switch (layer) {
|
|
||||||
case 0:
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
gba->video.renderer->disableBG[layer] = !enable;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
gba->video.renderer->disableOBJ = !enable;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameController::setFPSTarget(float fps) {
|
void GameController::setFPSTarget(float fps) {
|
||||||
Interrupter interrupter(this);
|
Interrupter interrupter(this);
|
||||||
|
@ -1182,6 +1131,10 @@ void GameController::setLoadStateExtdata(int flags) {
|
||||||
m_loadStateFlags = flags;
|
m_loadStateFlags = flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameController::setPreload(bool preload) {
|
||||||
|
m_preload = preload;
|
||||||
|
}
|
||||||
|
|
||||||
void GameController::setLuminanceValue(uint8_t value) {
|
void GameController::setLuminanceValue(uint8_t value) {
|
||||||
m_luxValue = value;
|
m_luxValue = value;
|
||||||
value = std::max<int>(value - 0x16, 0);
|
value = std::max<int>(value - 0x16, 0);
|
||||||
|
|
|
@ -156,6 +156,7 @@ public slots:
|
||||||
void reloadAudioDriver();
|
void reloadAudioDriver();
|
||||||
void setSaveStateExtdata(int flags);
|
void setSaveStateExtdata(int flags);
|
||||||
void setLoadStateExtdata(int flags);
|
void setLoadStateExtdata(int flags);
|
||||||
|
void setPreload(bool);
|
||||||
|
|
||||||
#ifdef USE_PNG
|
#ifdef USE_PNG
|
||||||
void screenshot();
|
void screenshot();
|
||||||
|
@ -224,8 +225,8 @@ private:
|
||||||
|
|
||||||
std::shared_ptr<mTileCache> m_tileCache;
|
std::shared_ptr<mTileCache> m_tileCache;
|
||||||
|
|
||||||
bool m_audioChannels[6];
|
QList<bool> m_audioChannels;
|
||||||
bool m_videoLayers[5];
|
QList<bool> m_videoLayers;
|
||||||
|
|
||||||
bool m_autofire[GBA_KEY_MAX];
|
bool m_autofire[GBA_KEY_MAX];
|
||||||
int m_autofireStatus[GBA_KEY_MAX];
|
int m_autofireStatus[GBA_KEY_MAX];
|
||||||
|
@ -236,6 +237,8 @@ private:
|
||||||
int m_saveStateFlags;
|
int m_saveStateFlags;
|
||||||
int m_loadStateFlags;
|
int m_loadStateFlags;
|
||||||
|
|
||||||
|
bool m_preload;
|
||||||
|
|
||||||
InputController* m_inputController;
|
InputController* m_inputController;
|
||||||
MultiplayerController* m_multiplayer;
|
MultiplayerController* m_multiplayer;
|
||||||
|
|
||||||
|
|
|
@ -191,6 +191,7 @@ void SettingsView::updateConfig() {
|
||||||
saveSetting("screenshotPath", m_ui.screenshotPath);
|
saveSetting("screenshotPath", m_ui.screenshotPath);
|
||||||
saveSetting("patchPath", m_ui.patchPath);
|
saveSetting("patchPath", m_ui.patchPath);
|
||||||
saveSetting("showLibrary", m_ui.showLibrary);
|
saveSetting("showLibrary", m_ui.showLibrary);
|
||||||
|
saveSetting("preload", m_ui.preload);
|
||||||
|
|
||||||
if (m_ui.fastForwardUnbounded->isChecked()) {
|
if (m_ui.fastForwardUnbounded->isChecked()) {
|
||||||
saveSetting("fastForwardRatio", "-1");
|
saveSetting("fastForwardRatio", "-1");
|
||||||
|
@ -273,6 +274,7 @@ void SettingsView::reloadConfig() {
|
||||||
loadSetting("screenshotPath", m_ui.screenshotPath);
|
loadSetting("screenshotPath", m_ui.screenshotPath);
|
||||||
loadSetting("patchPath", m_ui.patchPath);
|
loadSetting("patchPath", m_ui.patchPath);
|
||||||
loadSetting("showLibrary", m_ui.showLibrary);
|
loadSetting("showLibrary", m_ui.showLibrary);
|
||||||
|
loadSetting("preload", m_ui.preload);
|
||||||
|
|
||||||
double fastForwardRatio = loadSetting("fastForwardRatio").toDouble();
|
double fastForwardRatio = loadSetting("fastForwardRatio").toDouble();
|
||||||
if (fastForwardRatio <= 0) {
|
if (fastForwardRatio <= 0) {
|
||||||
|
|
|
@ -568,21 +568,21 @@
|
||||||
</item>
|
</item>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="7" column="0" colspan="2">
|
<item row="8" column="0" colspan="2">
|
||||||
<widget class="Line" name="line_2">
|
<widget class="Line" name="line_2">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="8" column="0">
|
<item row="9" column="0">
|
||||||
<widget class="QLabel" name="label_24">
|
<widget class="QLabel" name="label_24">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Savestate extra data:</string>
|
<string>Savestate extra data:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="8" column="1">
|
<item row="9" column="1">
|
||||||
<widget class="QCheckBox" name="saveStateScreenshot">
|
<widget class="QCheckBox" name="saveStateScreenshot">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Screenshot</string>
|
<string>Screenshot</string>
|
||||||
|
@ -592,7 +592,7 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="9" column="1">
|
<item row="10" column="1">
|
||||||
<widget class="QCheckBox" name="saveStateSave">
|
<widget class="QCheckBox" name="saveStateSave">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Save data</string>
|
<string>Save data</string>
|
||||||
|
@ -602,7 +602,7 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="10" column="1">
|
<item row="11" column="1">
|
||||||
<widget class="QCheckBox" name="saveStateCheats">
|
<widget class="QCheckBox" name="saveStateCheats">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Cheat codes</string>
|
<string>Cheat codes</string>
|
||||||
|
@ -612,14 +612,14 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="12" column="0">
|
<item row="13" column="0">
|
||||||
<widget class="QLabel" name="label_25">
|
<widget class="QLabel" name="label_25">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Load extra data:</string>
|
<string>Load extra data:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="12" column="1">
|
<item row="13" column="1">
|
||||||
<widget class="QCheckBox" name="loadStateScreenshot">
|
<widget class="QCheckBox" name="loadStateScreenshot">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Screenshot</string>
|
<string>Screenshot</string>
|
||||||
|
@ -629,21 +629,21 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="13" column="1">
|
<item row="14" column="1">
|
||||||
<widget class="QCheckBox" name="loadStateSave">
|
<widget class="QCheckBox" name="loadStateSave">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Save data</string>
|
<string>Save data</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="14" column="1">
|
<item row="15" column="1">
|
||||||
<widget class="QCheckBox" name="loadStateCheats">
|
<widget class="QCheckBox" name="loadStateCheats">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Cheat codes</string>
|
<string>Cheat codes</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="11" column="0" colspan="2">
|
<item row="12" column="0" colspan="2">
|
||||||
<widget class="Line" name="line_9">
|
<widget class="Line" name="line_9">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
|
@ -660,6 +660,13 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="7" column="1">
|
||||||
|
<widget class="QCheckBox" name="preload">
|
||||||
|
<property name="text">
|
||||||
|
<string>Preload entire ROM into memory</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="bios">
|
<widget class="QWidget" name="bios">
|
||||||
|
|
|
@ -335,19 +335,6 @@ void Window::reloadConfig() {
|
||||||
|
|
||||||
m_log.setLevels(opts->logLevel);
|
m_log.setLevels(opts->logLevel);
|
||||||
|
|
||||||
QString saveStateExtdata = m_config->getOption("saveStateExtdata");
|
|
||||||
bool ok;
|
|
||||||
int flags = saveStateExtdata.toInt(&ok);
|
|
||||||
if (ok) {
|
|
||||||
m_controller->setSaveStateExtdata(flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString loadStateExtdata = m_config->getOption("loadStateExtdata");
|
|
||||||
flags = loadStateExtdata.toInt(&ok);
|
|
||||||
if (ok) {
|
|
||||||
m_controller->setLoadStateExtdata(flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_controller->setConfig(m_config->config());
|
m_controller->setConfig(m_config->config());
|
||||||
m_display->lockAspectRatio(opts->lockAspectRatio);
|
m_display->lockAspectRatio(opts->lockAspectRatio);
|
||||||
m_display->filter(opts->resampleVideo);
|
m_display->filter(opts->resampleVideo);
|
||||||
|
@ -1547,11 +1534,19 @@ void Window::setupMenu(QMenuBar* menubar) {
|
||||||
saveStateExtdata->connect([this](const QVariant& value) {
|
saveStateExtdata->connect([this](const QVariant& value) {
|
||||||
m_controller->setSaveStateExtdata(value.toInt());
|
m_controller->setSaveStateExtdata(value.toInt());
|
||||||
}, this);
|
}, this);
|
||||||
|
m_config->updateOption("saveStateExtdata");
|
||||||
|
|
||||||
ConfigOption* loadStateExtdata = m_config->addOption("loadStateExtdata");
|
ConfigOption* loadStateExtdata = m_config->addOption("loadStateExtdata");
|
||||||
loadStateExtdata->connect([this](const QVariant& value) {
|
loadStateExtdata->connect([this](const QVariant& value) {
|
||||||
m_controller->setLoadStateExtdata(value.toInt());
|
m_controller->setLoadStateExtdata(value.toInt());
|
||||||
}, this);
|
}, this);
|
||||||
|
m_config->updateOption("loadStateExtdata");
|
||||||
|
|
||||||
|
ConfigOption* preload = m_config->addOption("preload");
|
||||||
|
preload->connect([this](const QVariant& value) {
|
||||||
|
m_controller->setPreload(value.toBool());
|
||||||
|
}, this);
|
||||||
|
m_config->updateOption("preload");
|
||||||
|
|
||||||
QAction* exitFullScreen = new QAction(tr("Exit fullscreen"), frameMenu);
|
QAction* exitFullScreen = new QAction(tr("Exit fullscreen"), frameMenu);
|
||||||
connect(exitFullScreen, SIGNAL(triggered()), this, SLOT(exitFullScreen()));
|
connect(exitFullScreen, SIGNAL(triggered()), this, SLOT(exitFullScreen()));
|
||||||
|
|
|
@ -5,8 +5,12 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
#include <mgba-util/string.h>
|
#include <mgba-util/string.h>
|
||||||
|
|
||||||
|
#include <mgba-util/vector.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
DEFINE_VECTOR(StringList, char*);
|
||||||
|
|
||||||
#ifndef HAVE_STRNDUP
|
#ifndef HAVE_STRNDUP
|
||||||
char* strndup(const char* start, size_t len) {
|
char* strndup(const char* start, size_t len) {
|
||||||
// This is suboptimal, but anything recent should have strndup
|
// This is suboptimal, but anything recent should have strndup
|
||||||
|
|
Loading…
Reference in New Issue