Merge branch 'master' into medusa
jump to
@@ -43,6 +43,8 @@ - Qt: Spanish translation (by Kevin López)
- Add option for whether rewinding restores save games - Qt: German translation (by Lothar Serra Mari) - 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: - LR35902: Fix core never exiting with certain event patterns - GB Timer: Improve DIV reset behavior@@ -118,6 +120,8 @@ - FFmpeg: Force MP4 files to YUV420P
- Qt: Make "Mute" able to be bound to a key - Core: Restore sleep callback - 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) Features:
@@ -92,6 +92,8 @@ memcpy(dest->vector, src->vector, src->size * sizeof(TYPE)); \
dest->size = src->size; \ } \ +DECLARE_VECTOR(StringList, char*); + CXX_GUARD_END #endif
@@ -48,7 +48,6 @@
mLOG_DECLARE_CATEGORY(CHEATS); DECLARE_VECTOR(mCheatList, struct mCheat); -DECLARE_VECTOR(StringList, char*); struct mCheatDevice; struct mCheatSet {
@@ -147,11 +147,19 @@ struct mCheatDevice* (*cheatDevice)(struct mCore*);
size_t (*savedataClone)(struct mCore*, void** sram); 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 struct mCore* mCoreFind(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 mCoreAutoloadPatch(struct mCore* core);
@@ -105,6 +105,13 @@ struct mRumble {
void (*setRumble)(struct mRumble*, int enable); }; +struct mCoreChannelInfo { + size_t id; + const char* internalName; + const char* visibleName; + const char* visibleType; +}; + CXX_GUARD_END #endif
@@ -17,7 +17,6 @@ mLOG_DEFINE_CATEGORY(CHEATS, "Cheats", "core.cheats");
DEFINE_VECTOR(mCheatList, struct mCheat); DEFINE_VECTOR(mCheatSets, struct mCheatSet*); -DEFINE_VECTOR(StringList, char*); static int32_t _readMem(struct mCore* core, uint32_t address, int width) { switch (width) {
@@ -122,6 +122,35 @@ }
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) { return core->loadSave(core, mDirectorySetOpenSuffix(&core->dirs, core->dirs.save, ".sav", O_CREAT | O_RDWR)); }
@@ -18,6 +18,38 @@ #include <mgba-util/memory.h>
#include <mgba-util/patch.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 mCore d; struct ARMCore* arm7;@@ -515,6 +547,27 @@ static bool _DSCoreSavedataRestore(struct mCore* core, const void* sram, size_t size, bool writeback) {
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 DSCore* dscore = malloc(sizeof(*dscore)); struct mCore* core = &dscore->d;@@ -584,5 +637,9 @@ #endif
core->cheatDevice = _DSCoreCheatDevice; core->savedataClone = _DSCoreSavedataClone; core->savedataRestore = _DSCoreSavedataRestore; + core->listVideoLayers = _DSCoreListVideoLayers; + core->listAudioChannels = _DSCoreListAudioChannels; + core->enableVideoLayer = _DSCoreEnableVideoLayer; + core->enableAudioChannel = _DSCoreEnableAudioChannel; return core; }
@@ -38,6 +38,7 @@ #ifdef USE_GDB_STUB
{ "gdb", no_argument, 0, 'g' }, #endif { "help", no_argument, 0, 'h' }, + { "log-level", required_argument, 0, 'l' }, { "movie", required_argument, 0, 'v' }, { "patch", required_argument, 0, 'p' }, { "version", no_argument, 0, '\0' },@@ -47,10 +48,27 @@
static bool _parseGraphicsArg(struct mSubParser* parser, int option, const char* arg); 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) { int ch; char options[64] = - "b:c:hl:p:s:v:" + "b:c:C:hl:p:s:v:" #ifdef USE_EDITLINE "d" #endif@@ -61,6 +79,7 @@ ;
memset(args, 0, sizeof(*args)); args->frameskip = -1; args->logLevel = INT_MIN; + HashTableInit(&args->configOverrides, 0, free); if (subparser && subparser->extraOptions) { // TODO: modularize options to subparsers strncat(options, subparser->extraOptions, sizeof(options) - strlen(options) - 1);@@ -82,6 +101,9 @@ break;
case 'c': args->cheatsFile = strdup(optarg); break; + case 'C': + _tableInsert(&args->configOverrides, optarg); + break; #ifdef USE_EDITLINE case 'd': if (args->debuggerType != DEBUGGER_NONE) {@@ -144,6 +166,7 @@ }
if (args->bios) { mCoreConfigSetOverrideValue(config, "bios", args->bios); } + HashTableEnumerate(&args->configOverrides, _tableApply, config); if (subparser) { subparser->apply(subparser, config); }@@ -164,6 +187,8 @@ args->cheatsFile = 0;
free(args->bios); args->bios = 0; + + HashTableDeinit(&args->configOverrides); } void initParserForGraphics(struct mSubParser* parser, struct mGraphicsOpts* opts) {@@ -209,18 +234,20 @@
void usage(const char* arg0, const char* extraOptions) { printf("usage: %s [option ...] file\n", arg0); puts("\nGeneric options:"); - puts(" -b, --bios FILE GBA BIOS file to use"); - puts(" -c, --cheats FILE Apply cheat codes from a file"); + puts(" -b, --bios FILE GBA BIOS file to use"); + puts(" -c, --cheats FILE Apply cheat codes from a file"); + puts(" -C, --config OPTION=VALUE Override config value"); #ifdef USE_EDITLINE - puts(" -d, --debug Use command-line debugger"); + puts(" -d, --debug Use command-line debugger"); #endif #ifdef USE_GDB_STUB - puts(" -g, --gdb Start GDB session (default port 2345)"); + puts(" -g, --gdb Start GDB session (default port 2345)"); #endif - puts(" -v, --movie FILE Play back a movie of recorded input"); - puts(" -p, --patch FILE Apply a specified patch file when running"); - puts(" -s, --frameskip N Skip every N frames"); - puts(" --version Print version and exit"); + puts(" -l, --log-level N Log level mask"); + puts(" -v, --movie FILE Play back a movie of recorded input"); + puts(" -p, --patch FILE Apply a specified patch file when running"); + puts(" -s, --frameskip N Skip every N frames"); + puts(" --version Print version and exit"); if (extraOptions) { puts(extraOptions); }
@@ -10,6 +10,8 @@ #include <mgba-util/common.h>
CXX_GUARD_START +#include <mgba-util/table.h> + #include <mgba/internal/debugger/debugger.h> struct mArguments {@@ -20,6 +22,8 @@ char* movie;
char* bios; int logLevel; int frameskip; + + struct Table configOverrides; enum mDebuggerType debuggerType; bool debugAtStart;
@@ -25,6 +25,19 @@ #ifndef MINIMAL_CORE
#include <mgba/internal/gba/input.h> #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 mCore d; struct GBVideoSoftwareRenderer renderer;@@ -599,6 +612,37 @@ memcpy(gb->memory.sram, sram, size);
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 GBCore* gbcore = malloc(sizeof(*gbcore)); struct mCore* core = &gbcore->d;@@ -669,5 +713,9 @@ #endif
core->cheatDevice = _GBCoreCheatDevice; core->savedataClone = _GBCoreSavedataClone; core->savedataRestore = _GBCoreSavedataRestore; + core->listVideoLayers = _GBCoreListVideoLayers; + core->listAudioChannels = _GBCoreListAudioChannels; + core->enableVideoLayer = _GBCoreEnableVideoLayer; + core->enableAudioChannel = _GBCoreEnableAudioChannel; return core; }
@@ -26,6 +26,23 @@ #ifndef MINIMAL_CORE
#include <mgba/internal/gba/input.h> #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 mCore d; struct GBAVideoSoftwareRenderer renderer;@@ -600,6 +617,54 @@ }
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 GBACore* gbacore = malloc(sizeof(*gbacore)); struct mCore* core = &gbacore->d;@@ -670,5 +735,9 @@ #endif
core->cheatDevice = _GBACoreCheatDevice; core->savedataClone = _GBACoreSavedataClone; core->savedataRestore = _GBACoreSavedataRestore; + core->listVideoLayers = _GBACoreListVideoLayers; + core->listAudioChannels = _GBACoreListAudioChannels; + core->enableVideoLayer = _GBACoreEnableVideoLayer; + core->enableAudioChannel = _GBACoreEnableAudioChannel; return core; }
@@ -92,7 +92,7 @@ QString ConfigController::s_configDir;
ConfigController::ConfigController(QObject* parent) : QObject(parent) - , m_opts() + , m_opts{} { QString fileName = configDir(); fileName.append(QDir::separator());
@@ -57,8 +57,8 @@ , m_turbo(false)
, m_turboForced(false) , m_turboSpeed(-1) , m_wasPaused(false) - , m_audioChannels{ true, true, true, true, true, true } - , m_videoLayers{ true, true, true, true, true } + , m_audioChannels() + , m_videoLayers() , m_autofire{} , m_autofireStatus{} , m_inputController(nullptr)@@ -69,6 +69,7 @@ , m_backupLoadState(nullptr)
, m_backupSaveState(nullptr) , m_saveStateFlags(SAVESTATE_SCREENSHOT | SAVESTATE_SAVEDATA | SAVESTATE_CHEATS | SAVESTATE_RTC) , m_loadStateFlags(SAVESTATE_SCREENSHOT | SAVESTATE_RTC) + , m_preload(false) , m_override(nullptr) { #ifdef M_CORE_GBA@@ -90,35 +91,17 @@ GameController* controller = static_cast<GameController*>(context->userData);
context->core->setPeripheral(context->core, mPERIPH_ROTATION, controller->m_inputController->rotationSource()); context->core->setPeripheral(context->core, mPERIPH_RUMBLE, controller->m_inputController->rumble()); -#ifdef M_CORE_GBA - GBA* gba = static_cast<GBA*>(context->core->board); -#endif -#ifdef M_CORE_GB - GB* gb = static_cast<GB*>(context->core->board); -#endif + for (size_t i = 0; i < controller->m_audioChannels.size(); ++i) { + context->core->enableAudioChannel(context->core, i, controller->m_audioChannels[i]); + } + for (size_t i = 0; i < controller->m_videoLayers.size(); ++i) { + context->core->enableVideoLayer(context->core, i, controller->m_videoLayers[i]); + } + switch (context->core->platform(context->core)) { #ifdef M_CORE_GBA case PLATFORM_GBA: 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; #endif default:@@ -476,11 +459,20 @@
QByteArray bytes; if (!biosOnly) { bytes = m_fname.toUtf8(); - if (m_vf) { - m_threadContext.core->loadROM(m_threadContext.core, m_vf); + 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 { - mCoreLoadFile(m_threadContext.core, bytes.constData()); - mDirectorySetDetachBase(&m_threadContext.core->dirs); + if (m_vf) { + m_threadContext.core->loadROM(m_threadContext.core, m_vf); + } else { + mCoreLoadFile(m_threadContext.core, bytes.constData()); + mDirectorySetDetachBase(&m_threadContext.core->dirs); + } } } else { bytes = m_bios.toUtf8();@@ -880,47 +872,13 @@ void GameController::setAudioChannelEnabled(int channel, bool enable) {
if (channel > 5 || channel < 0) { return; } -#ifdef M_CORE_GBA - GBA* gba = static_cast<GBA*>(m_threadContext.core->board); -#endif -#ifdef M_CORE_GB - GB* gb = static_cast<GB*>(m_threadContext.core->board); -#endif + m_audioChannels.reserve(channel + 1); + while (m_audioChannels.size() <= channel) { + m_audioChannels.append(true); + } m_audioChannels[channel] = enable; if (isLoaded()) { - switch (channel) { - 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 - } + m_threadContext.core->enableAudioChannel(m_threadContext.core, channel, enable); } }@@ -939,23 +897,14 @@ void GameController::setVideoLayerEnabled(int layer, bool enable) {
if (layer > 4 || layer < 0) { return; } + m_videoLayers.reserve(layer + 1); + while (m_videoLayers.size() <= layer) { + m_videoLayers.append(true); + } m_videoLayers[layer] = enable; -#ifdef M_CORE_GBA - if (isLoaded() && m_threadContext.core->platform(m_threadContext.core) == PLATFORM_GBA) { - 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; - } + if (isLoaded()) { + m_threadContext.core->enableVideoLayer(m_threadContext.core, layer, enable); } -#endif } void GameController::setFPSTarget(float fps) {@@ -1180,6 +1129,10 @@ }
void GameController::setLoadStateExtdata(int flags) { m_loadStateFlags = flags; +} + +void GameController::setPreload(bool preload) { + m_preload = preload; } void GameController::setLuminanceValue(uint8_t value) {
@@ -156,6 +156,7 @@ void clearAVStream();
void reloadAudioDriver(); void setSaveStateExtdata(int flags); void setLoadStateExtdata(int flags); + void setPreload(bool); #ifdef USE_PNG void screenshot();@@ -224,8 +225,8 @@ bool m_wasPaused;
std::shared_ptr<mTileCache> m_tileCache; - bool m_audioChannels[6]; - bool m_videoLayers[5]; + QList<bool> m_audioChannels; + QList<bool> m_videoLayers; bool m_autofire[GBA_KEY_MAX]; int m_autofireStatus[GBA_KEY_MAX];@@ -235,6 +236,8 @@ struct VFile* m_backupLoadState;
QByteArray m_backupSaveState; int m_saveStateFlags; int m_loadStateFlags; + + bool m_preload; InputController* m_inputController; MultiplayerController* m_multiplayer;
@@ -191,6 +191,7 @@ saveSetting("savestatePath", m_ui.savestatePath);
saveSetting("screenshotPath", m_ui.screenshotPath); saveSetting("patchPath", m_ui.patchPath); saveSetting("showLibrary", m_ui.showLibrary); + saveSetting("preload", m_ui.preload); if (m_ui.fastForwardUnbounded->isChecked()) { saveSetting("fastForwardRatio", "-1");@@ -273,6 +274,7 @@ loadSetting("savestatePath", m_ui.savestatePath);
loadSetting("screenshotPath", m_ui.screenshotPath); loadSetting("patchPath", m_ui.patchPath); loadSetting("showLibrary", m_ui.showLibrary); + loadSetting("preload", m_ui.preload); double fastForwardRatio = loadSetting("fastForwardRatio").toDouble(); if (fastForwardRatio <= 0) {
@@ -568,21 +568,21 @@ </property>
</item> </widget> </item> - <item row="7" column="0" colspan="2"> + <item row="8" column="0" colspan="2"> <widget class="Line" name="line_2"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> </widget> </item> - <item row="8" column="0"> + <item row="9" column="0"> <widget class="QLabel" name="label_24"> <property name="text"> <string>Savestate extra data:</string> </property> </widget> </item> - <item row="8" column="1"> + <item row="9" column="1"> <widget class="QCheckBox" name="saveStateScreenshot"> <property name="text"> <string>Screenshot</string>@@ -592,7 +592,7 @@ <bool>true</bool>
</property> </widget> </item> - <item row="9" column="1"> + <item row="10" column="1"> <widget class="QCheckBox" name="saveStateSave"> <property name="text"> <string>Save data</string>@@ -602,7 +602,7 @@ <bool>true</bool>
</property> </widget> </item> - <item row="10" column="1"> + <item row="11" column="1"> <widget class="QCheckBox" name="saveStateCheats"> <property name="text"> <string>Cheat codes</string>@@ -612,14 +612,14 @@ <bool>true</bool>
</property> </widget> </item> - <item row="12" column="0"> + <item row="13" column="0"> <widget class="QLabel" name="label_25"> <property name="text"> <string>Load extra data:</string> </property> </widget> </item> - <item row="12" column="1"> + <item row="13" column="1"> <widget class="QCheckBox" name="loadStateScreenshot"> <property name="text"> <string>Screenshot</string>@@ -629,21 +629,21 @@ <bool>true</bool>
</property> </widget> </item> - <item row="13" column="1"> + <item row="14" column="1"> <widget class="QCheckBox" name="loadStateSave"> <property name="text"> <string>Save data</string> </property> </widget> </item> - <item row="14" column="1"> + <item row="15" column="1"> <widget class="QCheckBox" name="loadStateCheats"> <property name="text"> <string>Cheat codes</string> </property> </widget> </item> - <item row="11" column="0" colspan="2"> + <item row="12" column="0" colspan="2"> <widget class="Line" name="line_9"> <property name="orientation"> <enum>Qt::Horizontal</enum>@@ -657,6 +657,13 @@ <string>Rewind affects save data</string>
</property> <property name="checked"> <bool>true</bool> + </property> + </widget> + </item> + <item row="7" column="1"> + <widget class="QCheckBox" name="preload"> + <property name="text"> + <string>Preload entire ROM into memory</string> </property> </widget> </item>
@@ -335,19 +335,6 @@ const mCoreOptions* opts = m_config->options();
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_display->lockAspectRatio(opts->lockAspectRatio); m_display->filter(opts->resampleVideo);@@ -1547,11 +1534,19 @@ ConfigOption* saveStateExtdata = m_config->addOption("saveStateExtdata");
saveStateExtdata->connect([this](const QVariant& value) { m_controller->setSaveStateExtdata(value.toInt()); }, this); + m_config->updateOption("saveStateExtdata"); ConfigOption* loadStateExtdata = m_config->addOption("loadStateExtdata"); loadStateExtdata->connect([this](const QVariant& value) { m_controller->setLoadStateExtdata(value.toInt()); }, 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); connect(exitFullScreen, SIGNAL(triggered()), this, SLOT(exitFullScreen()));
@@ -5,7 +5,11 @@ * 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 <mgba-util/string.h> +#include <mgba-util/vector.h> + #include <string.h> + +DEFINE_VECTOR(StringList, char*); #ifndef HAVE_STRNDUP char* strndup(const char* start, size_t len) {