Merge branch 'master' (early part) into medusa

This commit is contained in:
Vicki Pfau 2022-05-30 17:35:42 -07:00
commit 6c75f9b08c
40 changed files with 481 additions and 192 deletions

View File

@ -59,6 +59,7 @@ Emulation fixes:
- ARM7: Fix unsigned multiply timing
- GB: Copy logo from ROM if not running the BIOS intro (fixes mgba.io/i/2378)
- GB Audio: Fix channel 1/2 reseting edge cases (fixes mgba.io/i/1925)
- GB Audio: Properly apply per-model audio differences
- GB Memory: Add cursory cartridge open bus emulation (fixes mgba.io/i/2032)
- GB Serialize: Fix loading MBC1 states that affect bank 0 (fixes mgba.io/i/2402)
- GB Video: Draw SGB border pieces that overlap GB graphics (fixes mgba.io/i/1339)
@ -77,6 +78,7 @@ Emulation fixes:
Other fixes:
- Core: Don't attempt to restore rewind diffs past start of rewind
- Core: Fix the runloop resuming after a game has crashed (fixes mgba.io/i/2451)
- Core: Fix crash if library can't be opened
- FFmpeg: Fix crash when encoding audio with some containers
- FFmpeg: Fix GIF recording (fixes mgba.io/i/2393)
- GB: Fix temporary saves
@ -89,6 +91,7 @@ Misc:
- Core: Suspend runloop when a core crashes
- Debugger: Save and restore CLI history
- Debugger: GDB now works while the game is paused
- Debugger: Add command to load external symbol file (fixes mgba.io/i/2480)
- GB MBC: Filter out MBC errors when cartridge is yanked (fixes mgba.io/i/2488)
- GB Video: Add default SGB border
- GBA: Automatically skip BIOS if ROM has invalid logo
@ -109,6 +112,8 @@ Misc:
- Qt: Enable -b for Boot BIOS menu option (fixes mgba.io/i/2074)
- Qt: Add tile range selection to tile viewer (closes mgba.io/i/2455)
- Qt: Show warning if XQ audio is toggled while loaded (fixes mgba.io/i/2295)
- Qt: Add e-Card passing to the command line (closes mgba.io/i/2474)
- Qt: Boot both a multiboot image and ROM with CLI args (closes mgba.io/i/1941)
- Windows: Attach to console if present
- Vita: Add bilinear filtering option (closes mgba.io/i/344)

View File

@ -85,7 +85,7 @@ Supported Platforms
-------------------
- Windows 7 or newer
- OS X 10.8 (Mountain Lion)[<sup>[4]</sup>](#osxver) or newer
- OS X 10.9 (Mavericks)[<sup>[4]</sup>](#osxver) or newer
- Linux
- FreeBSD
@ -292,7 +292,7 @@ Missing features on DS are
<a name="flashdetect">[3]</a> Flash memory size detection does not work in some cases. These can be configured at runtime, but filing a bug is recommended if such a case is encountered.
<a name="osxver">[4]</a> 10.8 is only needed for the Qt port. It may be possible to build or running the Qt port on 10.7 or older, but this is not officially supported. The SDL port is known to work on 10.5, and may work on older.
<a name="osxver">[4]</a> 10.9 is only needed for the Qt port. It may be possible to build or running the Qt port on 10.7 or older, but this is not officially supported. The SDL port is known to work on 10.5, and may work on older.
[downloads]: http://mgba.io/downloads.html
[source]: https://github.com/mgba-emu/mgba/

View File

@ -80,7 +80,7 @@ Unterstützte Plattformen
------------------------
- Windows 7 oder neuer
- OS X 10.8 (Mountain Lion)[<sup>[3]</sup>](#osxver) oder neuer
- OS X 10.9 (Mavericks)[<sup>[3]</sup>](#osxver) oder neuer
- Linux
- FreeBSD
- Nintendo 3DS
@ -234,7 +234,7 @@ Fußnoten
<a name="flashdetect">[2]</a> In manchen Fällen ist es nicht möglich, die Größe des Flash-Speichers automatisch zu ermitteln. Diese kann dann zur Laufzeit konfiguriert werden, es wird jedoch empfohlen, den Fehler zu melden.
<a name="osxver">[3]</a> 10.8 wird nur für die Qt-Portierung benötigt. Es ist wahrscheinlich möglich, die Qt-Portierung unter macOS 10.7 und älter zu bauen und zu nutzen, aber das wird nicht offiziell unterstützt. Die SDL-Portierung ist dafür bekannt, mit 10.7 und möglicherweise auf älteren Versionen zu funktionieren.
<a name="osxver">[3]</a> 10.9 wird nur für die Qt-Portierung benötigt. Es ist wahrscheinlich möglich, die Qt-Portierung unter macOS 10.7 und älter zu bauen und zu nutzen, aber das wird nicht offiziell unterstützt. Die SDL-Portierung ist dafür bekannt, mit 10.7 und möglicherweise auf älteren Versionen zu funktionieren.
[downloads]: http://mgba.io/downloads.html
[source]: https://github.com/mgba-emu/mgba/

View File

@ -80,7 +80,7 @@ Plataformas soportadas
-------------------
- Windows 7 o más reciente
- OS X 10.8 (Mountain Lion)[<sup>[3]</sup>](#osxver) o más reciente
- OS X 10.9 (Mavericks)[<sup>[3]</sup>](#osxver) o más reciente
- Linux
- FreeBSD
- Nintendo 3DS
@ -234,7 +234,7 @@ Notas a pie
<a name="flashdetect">[2]</a> La detección del tamaño de la memoria flash no funciona en algunos casos. Se pueden configurar en tiempo de ejecución, pero se recomienda ingresar un bug si se encuentra un caso así.
<a name="osxver">[3]</a> 10.8 sólo se necesita para la versión con Qt. Puede ser posible compilar o hacer funcionar la versión Qt en 10.7 o versiones más antigas, pero esto no está oficialmente soportado. La versión SDL funciona en 10.5, y puede funcionar en versiones anteriores.
<a name="osxver">[3]</a> 10.9 sólo se necesita para la versión con Qt. Puede ser posible compilar o hacer funcionar la versión Qt en 10.7 o versiones más antigas, pero esto no está oficialmente soportado. La versión SDL funciona en 10.5, y puede funcionar en versiones anteriores.
[downloads]: http://mgba.io/downloads.html
[source]: https://github.com/mgba-emu/mgba/

View File

@ -78,7 +78,7 @@ mGBA 是一个运行 Game Boy Advance 游戏的模拟器。mGBA 的目标是比
-------------------
- Windows 7 或更新
- OS X 10.8山狮 / Mountain Lion[<sup>[3]</sup>](#osxver) 或更新
- OS X 10.9Mavericks[<sup>[3]</sup>](#osxver) 或更新
- Linux
- FreeBSD
- Nintendo 3DS
@ -232,7 +232,7 @@ Footnotes
<a name="flashdetect">[2]</a> 闪存大小检测在某些情况下不起作用。 这些可以在运行时中进行配置,但如果遇到此类情况,建议提交错误。
<a name="osxver">[3]</a> 仅 Qt 端口需要 10.8。应该可以在 10.7 或更早版本上构建或运行 Qt 端口,但这类操作不受官方支持。已知 SDL 端口可以在 10.5 上运行,并且可能能够在旧版本上运行。
<a name="osxver">[3]</a> 仅 Qt 端口需要 10.9。应该可以在 10.7 或更早版本上构建或运行 Qt 端口,但这类操作不受官方支持。已知 SDL 端口可以在 10.5 上运行,并且可能能够在旧版本上运行。
[downloads]: http://mgba.io/downloads.html
[source]: https://github.com/mgba-emu/mgba/

View File

@ -31,12 +31,20 @@ struct mArguments {
bool showVersion;
};
struct mOption {
const char* name;
bool arg;
char shortEquiv;
};
struct mCoreConfig;
struct mSubParser {
const char* usage;
bool (*parse)(struct mSubParser* parser, int option, const char* arg);
bool (*parseLong)(struct mSubParser* parser, const char* option, const char* arg);
void (*apply)(struct mSubParser* parser, struct mCoreConfig* config);
const char* extraOptions;
const struct mOption* longOptions;
void* opts;
};
@ -45,15 +53,14 @@ struct mGraphicsOpts {
bool fullscreen;
};
bool parseArguments(struct mArguments* args, int argc, char* const* argv,
struct mSubParser* subparser);
void applyArguments(const struct mArguments* args, struct mSubParser* subparser, struct mCoreConfig* config);
void freeArguments(struct mArguments* args);
void usage(const char* arg0, const char* extraOptions);
void usage(const char* arg0, const char* prologue, const char* epilogue, const struct mSubParser* subparsers, int nSubparsers);
void version(const char* arg0);
void initParserForGraphics(struct mSubParser* parser, struct mGraphicsOpts* opts);
bool mArgumentsParse(struct mArguments* args, int argc, char* const* argv, struct mSubParser* subparsers, int nSubparsers);
void mArgumentsApply(const struct mArguments* args, struct mSubParser* subparsers, int nSubparsers, struct mCoreConfig* config);
void mArgumentsDeinit(struct mArguments* args);
void mSubParserGraphicsInit(struct mSubParser* parser, struct mGraphicsOpts* opts);
CXX_GUARD_END

View File

@ -98,6 +98,7 @@ struct GBA {
uint32_t romCrc32;
struct VFile* romVf;
struct VFile* biosVf;
struct VFile* mbVf;
struct mAVStream* stream;
struct mKeyCallback* keyCallback;
@ -171,6 +172,8 @@ void GBALoadBIOS(struct GBA* gba, struct VFile* vf);
void GBAApplyPatch(struct GBA* gba, struct Patch* patch);
bool GBALoadMB(struct GBA* gba, struct VFile* vf);
void GBAUnloadMB(struct GBA* gba);
bool GBALoadNull(struct GBA* gba);
void GBAGetGameCode(const struct GBA* gba, char* out);

View File

@ -199,6 +199,10 @@ error:
}
void mLibraryDestroy(struct mLibrary* library) {
if (!library) {
return;
}
sqlite3_finalize(library->insertPath);
sqlite3_finalize(library->insertRom);
sqlite3_finalize(library->insertRoot);

View File

@ -8,15 +8,17 @@
#include <mgba/internal/debugger/symbols.h>
#include <mgba/core/core.h>
#include <mgba/core/timing.h>
#include <mgba/core/version.h>
#include <mgba/internal/debugger/parser.h>
#include <mgba-util/string.h>
#include <mgba-util/vfs.h>
#ifdef ENABLE_SCRIPTING
#include <mgba/core/scripting.h>
#endif
#include <mgba/core/timing.h>
#include <mgba/core/version.h>
#include <mgba/internal/debugger/parser.h>
#ifdef USE_ELF
#include <mgba-util/elf-read.h>
#endif
#include <mgba-util/string.h>
#include <mgba-util/vfs.h>
#if !defined(NDEBUG) && !defined(_WIN32)
#include <signal.h>
@ -74,6 +76,7 @@ static void _source(struct CLIDebugger*, struct CLIDebugVector*);
static void _backtrace(struct CLIDebugger*, struct CLIDebugVector*);
static void _finish(struct CLIDebugger*, struct CLIDebugVector*);
static void _setStackTraceMode(struct CLIDebugger*, struct CLIDebugVector*);
static void _loadSymbols(struct CLIDebugger*, struct CLIDebugVector*);
static void _setSymbol(struct CLIDebugger*, struct CLIDebugVector*);
static void _findSymbol(struct CLIDebugger*, struct CLIDebugVector*);
@ -101,6 +104,7 @@ static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
{ "stack", _setStackTraceMode, "S", "Change the stack tracing mode" },
{ "status", _printStatus, "", "Print the current status" },
{ "symbol", _findSymbol, "I", "Find the symbol name for an address" },
{ "load-symbols", _loadSymbols, "S", "Load symbols from an external file" },
{ "trace", _trace, "Is", "Trace a number of instructions" },
{ "w/1", _writeByte, "II", "Write a byte at a specified offset" },
{ "w/2", _writeHalfword, "II", "Write a halfword at a specified offset" },
@ -133,6 +137,7 @@ static struct CLIDebuggerCommandAlias _debuggerCommandAliases[] = {
{ "h", "help" },
{ "i", "status" },
{ "info", "status" },
{ "loadsyms", "load-symbols" },
{ "lb", "listb" },
{ "lw", "listw" },
{ "n", "next" },
@ -1291,6 +1296,40 @@ static void _setStackTraceMode(struct CLIDebugger* debugger, struct CLIDebugVect
}
}
static void _loadSymbols(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
struct mDebuggerSymbols* symbolTable = debugger->d.core->symbolTable;
if (!symbolTable) {
debugger->backend->printf(debugger->backend, "No symbol table available.\n");
return;
}
if (!dv || dv->next) {
debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
return;
}
if (dv->type != CLIDV_CHAR_TYPE) {
debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
return;
}
struct VFile* vf = VFileOpen(dv->charValue, O_RDONLY);
if (!vf) {
debugger->backend->printf(debugger->backend, "%s\n", "Could not open symbol file");
return;
}
#ifdef USE_ELF
struct ELF* elf = ELFOpen(vf);
if (elf) {
#ifdef USE_DEBUGGERS
mCoreLoadELFSymbols(symbolTable, elf);
#endif
ELFClose(elf);
} else
#endif
{
mDebuggerLoadARMIPSSymbols(symbolTable, vf);
}
vf->close(vf);
}
static void _setSymbol(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
struct mDebuggerSymbols* symbolTable = debugger->d.core->symbolTable;
if (!symbolTable) {

View File

@ -16,16 +16,12 @@
#include <getopt.h>
#endif
#define GRAPHICS_OPTIONS "123456f"
#define GRAPHICS_OPTIONS "12345678f"
#define GRAPHICS_USAGE \
"\nGraphics options:\n" \
" -1 1x viewport\n" \
" -2 2x viewport\n" \
" -3 3x viewport\n" \
" -4 4x viewport\n" \
" -5 5x viewport\n" \
" -6 6x viewport\n" \
" -f Start full-screen"
"Graphics options:\n" \
" -1, -2, -3, -4, -5, -6, -7, -8 Scale viewport by 1-8 times\n" \
" -f, --fullscreen Start full-screen\n" \
" --scale X Scale viewport by X times"
static const struct option _options[] = {
{ "bios", required_argument, 0, 'b' },
@ -45,7 +41,14 @@ static const struct option _options[] = {
{ 0, 0, 0, 0 }
};
static const struct mOption _graphicsLongOpts[] = {
{ "fullscreen", false, 'f' },
{ "scale", true, '\0' },
{ 0, 0, 0 }
};
static bool _parseGraphicsArg(struct mSubParser* parser, int option, const char* arg);
static bool _parseLongGraphicsArg(struct mSubParser* parser, const char* option, const char* arg);
static void _applyGraphicsArgs(struct mSubParser* parser, struct mCoreConfig* config);
static void _tableInsert(struct Table* table, const char* pair) {
@ -65,9 +68,9 @@ static void _tableApply(const char* key, void* value, void* user) {
mCoreConfigSetOverrideValue(config, key, value);
}
bool parseArguments(struct mArguments* args, int argc, char* const* argv, struct mSubParser* subparser) {
bool mArgumentsParse(struct mArguments* args, int argc, char* const* argv, struct mSubParser* subparsers, int nSubparsers) {
int ch;
char options[64] =
char options[128] =
"b:c:C:hl:p:s:t:"
#ifdef USE_EDITLINE
"d"
@ -76,23 +79,51 @@ bool parseArguments(struct mArguments* args, int argc, char* const* argv, struct
"g"
#endif
;
struct option longOptions[128] = {0};
memcpy(longOptions, _options, sizeof(_options));
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);
int lastLongOpt;
int i, j;
for (i = 0; _options[i].name; ++i); // Seek to end
lastLongOpt = i;
for (i = 0; i < nSubparsers; ++i) {
if (subparsers[i].extraOptions) {
strncat(options, subparsers[i].extraOptions, sizeof(options) - strlen(options) - 1);
}
if (subparsers[i].longOptions) {
for (j = 0; subparsers[i].longOptions[j].name; ++j) {
longOptions[lastLongOpt].name = subparsers[i].longOptions[j].name;
longOptions[lastLongOpt].has_arg = subparsers[i].longOptions[j].arg ? required_argument : no_argument;
longOptions[lastLongOpt].flag = NULL;
longOptions[lastLongOpt].val = subparsers[i].longOptions[j].shortEquiv;
++lastLongOpt;
}
}
}
bool ok = false;
int index = 0;
while ((ch = getopt_long(argc, argv, options, _options, &index)) != -1) {
const struct option* opt = &_options[index];
while ((ch = getopt_long(argc, argv, options, longOptions, &index)) != -1) {
const struct option* opt = &longOptions[index];
switch (ch) {
case '\0':
if (strcmp(opt->name, "version") == 0) {
args->showVersion = true;
} else {
return false;
for (i = 0; i < nSubparsers; ++i) {
if (subparsers[i].parseLong) {
ok = subparsers[i].parseLong(&subparsers[i], opt->name, optarg) || ok;
}
}
if (!ok) {
return false;
}
}
break;
case 'b':
@ -136,11 +167,14 @@ bool parseArguments(struct mArguments* args, int argc, char* const* argv, struct
args->savestate = strdup(optarg);
break;
default:
if (subparser) {
if (!subparser->parse(subparser, ch, optarg)) {
return false;
for (i = 0; i < nSubparsers; ++i) {
if (subparsers[i].parse) {
ok = subparsers[i].parse(&subparsers[i], ch, optarg) || ok;
}
}
if (!ok) {
return false;
}
break;
}
}
@ -156,7 +190,7 @@ bool parseArguments(struct mArguments* args, int argc, char* const* argv, struct
return true;
}
void applyArguments(const struct mArguments* args, struct mSubParser* subparser, struct mCoreConfig* config) {
void mArgumentsApply(const struct mArguments* args, struct mSubParser* subparsers, int nSubparsers, struct mCoreConfig* config) {
if (args->frameskip >= 0) {
mCoreConfigSetOverrideIntValue(config, "frameskip", args->frameskip);
}
@ -168,12 +202,15 @@ void applyArguments(const struct mArguments* args, struct mSubParser* subparser,
mCoreConfigSetOverrideIntValue(config, "useBios", true);
}
HashTableEnumerate(&args->configOverrides, _tableApply, config);
if (subparser) {
subparser->apply(subparser, config);
int i;
for (i = 0; i < nSubparsers; ++i) {
if (subparsers[i].apply) {
subparsers[i].apply(&subparsers[i], config);
}
}
}
void freeArguments(struct mArguments* args) {
void mArgumentsDeinit(struct mArguments* args) {
free(args->fname);
args->fname = 0;
@ -192,12 +229,14 @@ void freeArguments(struct mArguments* args) {
HashTableDeinit(&args->configOverrides);
}
void initParserForGraphics(struct mSubParser* parser, struct mGraphicsOpts* opts) {
void mSubParserGraphicsInit(struct mSubParser* parser, struct mGraphicsOpts* opts) {
parser->usage = GRAPHICS_USAGE;
parser->opts = opts;
parser->parse = _parseGraphicsArg;
parser->parseLong = _parseLongGraphicsArg;
parser->apply = _applyGraphicsArgs;
parser->extraOptions = GRAPHICS_OPTIONS;
parser->longOptions = _graphicsLongOpts;
opts->multiplier = 0;
opts->fullscreen = false;
}
@ -215,6 +254,8 @@ bool _parseGraphicsArg(struct mSubParser* parser, int option, const char* arg) {
case '4':
case '5':
case '6':
case '7':
case '8':
if (graphicsOpts->multiplier) {
return false;
}
@ -225,6 +266,18 @@ bool _parseGraphicsArg(struct mSubParser* parser, int option, const char* arg) {
}
}
bool _parseLongGraphicsArg(struct mSubParser* parser, const char* option, const char* arg) {
struct mGraphicsOpts* graphicsOpts = parser->opts;
if (strcmp(option, "scale") == 0) {
if (graphicsOpts->multiplier) {
return false;
}
graphicsOpts->multiplier = atoi(arg);
return graphicsOpts->multiplier != 0;
}
return false;
}
void _applyGraphicsArgs(struct mSubParser* parser, struct mCoreConfig* config) {
struct mGraphicsOpts* graphicsOpts = parser->opts;
if (graphicsOpts->fullscreen) {
@ -232,25 +285,36 @@ void _applyGraphicsArgs(struct mSubParser* parser, struct mCoreConfig* config) {
}
}
void usage(const char* arg0, const char* extraOptions) {
void usage(const char* arg0, const char* prologue, const char* epilogue, const struct mSubParser* subparsers, int nSubparsers) {
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(" -C, --config OPTION=VALUE Override config value");
if (prologue) {
puts(prologue);
}
puts("\nGeneric options:\n"
" -b, --bios FILE GBA BIOS file to use\n"
" -c, --cheats FILE Apply cheat codes from a file\n"
" -C, --config OPTION=VALUE Override config value\n"
#ifdef USE_EDITLINE
puts(" -d, --debug Use command-line debugger");
" -d, --debug Use command-line debugger\n"
#endif
#ifdef USE_GDB_STUB
puts(" -g, --gdb Start GDB session (default port 2345)");
" -g, --gdb Start GDB session (default port 2345)\n"
#endif
puts(" -l, --log-level N Log level mask");
puts(" -t, --savestate FILE Load savestate when starting");
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);
" -l, --log-level N Log level mask\n"
" -t, --savestate FILE Load savestate when starting\n"
" -p, --patch FILE Apply a specified patch file when running\n"
" -s, --frameskip N Skip every N frames\n"
" --version Print version and exit"
);
int i;
for (i = 0; i < nSubparsers; ++i) {
if (subparsers[i].usage) {
puts("");
puts(subparsers[i].usage);
}
}
if (epilogue) {
puts(epilogue);
}
}

View File

@ -556,6 +556,23 @@ void GBReset(struct SM83Core* cpu) {
}
}
switch (gb->model) {
case GB_MODEL_DMG:
case GB_MODEL_SGB:
case GB_MODEL_AUTODETECT: //Silence warnings
gb->audio.style = GB_AUDIO_DMG;
break;
case GB_MODEL_MGB:
case GB_MODEL_SGB2:
gb->audio.style = GB_AUDIO_MGB;
break;
case GB_MODEL_AGB:
case GB_MODEL_CGB:
case GB_MODEL_SCGB:
gb->audio.style = GB_AUDIO_CGB;
break;
}
GBVideoReset(&gb->video);
GBTimerReset(&gb->timer);
GBIOReset(gb);
@ -779,23 +796,6 @@ void GBDetectModel(struct GB* gb) {
gb->model = GB_MODEL_DMG;
}
}
switch (gb->model) {
case GB_MODEL_DMG:
case GB_MODEL_SGB:
case GB_MODEL_AUTODETECT: //Silence warnings
gb->audio.style = GB_AUDIO_DMG;
break;
case GB_MODEL_MGB:
case GB_MODEL_SGB2:
gb->audio.style = GB_AUDIO_MGB;
break;
case GB_MODEL_AGB:
case GB_MODEL_CGB:
case GB_MODEL_SCGB:
gb->audio.style = GB_AUDIO_CGB;
break;
}
}
int GBValidModels(const uint8_t* bank0) {

View File

@ -627,7 +627,7 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
if (startX == 0) {
_cleanOAM(softwareRenderer, y);
}
if (GBRegisterLCDCIsObjEnable(softwareRenderer->lcdc) && !softwareRenderer->d.disableOBJ) {
if (GBRegisterLCDCIsObjEnable(softwareRenderer->lcdc) && !softwareRenderer->d.disableOBJ && (softwareRenderer->model != GB_MODEL_SCGB || softwareRenderer->sgbTransfer != 1)) {
int i;
for (i = 0; i < softwareRenderer->objMax; ++i) {
GBVideoSoftwareRendererDrawObj(softwareRenderer, &softwareRenderer->obj[i], startX, endX, y);
@ -917,7 +917,7 @@ static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer
bgTile = ((int8_t*) maps)[topX + topY];
}
int p = highlight ? PAL_HIGHLIGHT_BG : PAL_BG;
if (renderer->model >= GB_MODEL_CGB) {
if (renderer->model >= GB_MODEL_CGB && (!(renderer->model & GB_MODEL_SGB) || renderer->sgbTransfer != 1)) {
GBObjAttributes attrs = attr[topX + topY];
p |= GBObjAttributesGetCGBPalette(attrs) * 4;
if (GBObjAttributesIsPriority(attrs) && GBRegisterLCDCIsBgEnable(renderer->lcdc)) {
@ -952,7 +952,7 @@ static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer
bgTile = ((int8_t*) maps)[topX + topY];
}
int p = highlight ? PAL_HIGHLIGHT_BG : PAL_BG;
if (renderer->model >= GB_MODEL_CGB) {
if (renderer->model >= GB_MODEL_CGB && (!(renderer->model & GB_MODEL_SGB) || renderer->sgbTransfer != 1)) {
GBObjAttributes attrs = attr[topX + topY];
p |= GBObjAttributesGetCGBPalette(attrs) * 4;
if (GBObjAttributesIsPriority(attrs) && GBRegisterLCDCIsBgEnable(renderer->lcdc)) {

View File

@ -92,13 +92,14 @@ static void GBAInit(void* cpu, struct mCPUComponent* component) {
gba->keysActive = 0;
gba->keysLast = 0x400;
gba->rotationSource = 0;
gba->luminanceSource = 0;
gba->rtcSource = 0;
gba->rumble = 0;
gba->rotationSource = NULL;
gba->luminanceSource = NULL;
gba->rtcSource = NULL;
gba->rumble = NULL;
gba->romVf = 0;
gba->biosVf = 0;
gba->romVf = NULL;
gba->mbVf = NULL;
gba->biosVf = NULL;
gba->stream = NULL;
gba->keyCallback = NULL;
@ -139,7 +140,7 @@ void GBAUnloadROM(struct GBA* gba) {
if (gba->romVf) {
#ifndef FIXED_ROM_BUFFER
if (gba->isPristine) {
if (gba->isPristine && gba->memory.rom) {
gba->romVf->unmap(gba->romVf, gba->memory.rom, gba->pristineRomSize);
}
#endif
@ -147,6 +148,8 @@ void GBAUnloadROM(struct GBA* gba) {
gba->romVf = NULL;
}
gba->memory.rom = NULL;
gba->memory.romSize = 0;
gba->memory.romMask = 0;
gba->isPristine = false;
if (!gba->memory.savedata.dirty) {
@ -163,6 +166,7 @@ void GBAUnloadROM(struct GBA* gba) {
void GBADestroy(struct GBA* gba) {
GBAUnloadROM(gba);
GBAUnloadMB(gba);
if (gba->biosVf) {
gba->biosVf->unmap(gba->biosVf, gba->memory.bios, SIZE_BIOS);
@ -228,16 +232,18 @@ void GBAReset(struct ARMCore* cpu) {
bool isELF = false;
#ifdef USE_ELF
struct ELF* elf = ELFOpen(gba->romVf);
if (elf) {
isELF = true;
ELFClose(elf);
if (gba->mbVf) {
struct ELF* elf = ELFOpen(gba->mbVf);
if (elf) {
isELF = true;
ELFClose(elf);
}
}
#endif
if (GBAIsMB(gba->romVf) && !isELF) {
gba->romVf->seek(gba->romVf, 0, SEEK_SET);
gba->romVf->read(gba->romVf, gba->memory.wram, gba->pristineRomSize);
if (GBAIsMB(gba->mbVf) && !isELF) {
gba->mbVf->seek(gba->mbVf, 0, SEEK_SET);
gba->mbVf->read(gba->mbVf, gba->memory.wram, SIZE_WORKING_RAM);
}
gba->lastJump = 0;
@ -367,25 +373,24 @@ bool GBALoadNull(struct GBA* gba) {
}
bool GBALoadMB(struct GBA* gba, struct VFile* vf) {
GBAUnloadROM(gba);
gba->romVf = vf;
gba->pristineRomSize = vf->size(vf);
GBAUnloadMB(gba);
gba->mbVf = vf;
vf->seek(vf, 0, SEEK_SET);
if (gba->pristineRomSize > SIZE_WORKING_RAM) {
gba->pristineRomSize = SIZE_WORKING_RAM;
}
gba->isPristine = true;
memset(gba->memory.wram, 0, SIZE_WORKING_RAM);
gba->yankedRomSize = 0;
gba->memory.romSize = 0;
gba->memory.romMask = 0;
gba->romCrc32 = doCrc32(gba->memory.wram, gba->pristineRomSize);
vf->read(vf, gba->memory.wram, SIZE_WORKING_RAM);
if (gba->cpu && gba->memory.activeRegion == REGION_WORKING_RAM) {
gba->cpu->memory.setActiveRegion(gba->cpu, gba->cpu->gprs[ARM_PC]);
}
return true;
}
void GBAUnloadMB(struct GBA* gba) {
if (gba->mbVf) {
gba->mbVf->close(gba->mbVf);
gba->mbVf = NULL;
}
}
bool GBALoadROM(struct GBA* gba, struct VFile* vf) {
if (!vf) {
return false;

View File

@ -5,8 +5,8 @@
const uint8_t hleBios[SIZE_BIOS] = {
0x06, 0x00, 0x00, 0xea, 0x66, 0x00, 0x00, 0xea, 0x0c, 0x00, 0x00, 0xea,
0xfe, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x00, 0x00, 0xa0, 0xe1,
0x59, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x02, 0x03, 0xa0, 0xe3,
0x03, 0x10, 0xd0, 0xe5, 0xea, 0x00, 0x51, 0xe3, 0x4c, 0x01, 0x9f, 0x15,
0x59, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x58, 0x01, 0x9f, 0xe5,
0x00, 0x10, 0x90, 0xe5, 0x00, 0x00, 0x51, 0xe3, 0x02, 0x03, 0xa0, 0x03,
0x10, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x29, 0xe1,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0xe3, 0x01, 0xd3, 0xa0, 0x03,
0x20, 0xd0, 0x4d, 0x02, 0x00, 0x58, 0x2d, 0xe9, 0x02, 0xc0, 0x5e, 0xe5,

View File

@ -17,10 +17,10 @@ b irqBase
b fiqBase
resetBase:
mov r0, #0x8000000
ldrb r1, [r0, #3]
cmp r1, #0xEA
ldrne r0, =0x20000C0
ldr r0, =0x20000C0
ldr r1, [r0]
cmp r1, #0
moveq r0, #0x8000000
bx r0
.word 0
.word 0xE129F000

View File

@ -16,14 +16,14 @@ int main(int argc, char** argv) {
// Arguments from the command line are parsed by the parseArguments function.
// The NULL here shows that we don't give it any arguments beyond the default ones.
struct mArguments args = {};
bool parsed = parseArguments(&args, argc, argv, NULL);
bool parsed = mArgumentsParse(&args, argc, argv, NULL, 0);
// Parsing can succeed without finding a filename, but we need one.
if (!args.fname) {
parsed = false;
}
if (!parsed || args.showHelp) {
// If parsing failed, or the user passed --help, show usage.
usage(argv[0], NULL);
usage(argv[0], NULL, NULL, NULL, 0);
didFail = !parsed;
goto cleanup;
}
@ -65,7 +65,7 @@ int main(int argc, char** argv) {
SocketSubsystemDeinit();
cleanup:
freeArguments(&args);
mArgumentsDeinit(&args);
return didFail;
}
@ -114,7 +114,7 @@ bool _mExampleRun(const struct mArguments* args, Socket client) {
// loaded into the config system, as well as manually overriding the
// "idleOptimization" setting to ensure cores that can detect idle loops
// will attempt the detection.
applyArguments(args, NULL, &core->config);
mArgumentsApply(args, NULL, 0, &core->config);
mCoreConfigSetDefaultValue(&core->config, "idleOptimization", "detect");
// Tell the core to apply the configuration in the associated config object.

View File

@ -24,6 +24,7 @@ set(OS_LIB -lvita2d -l${M_LIBRARY}
-lSceGxm_stub
-lSceIme_stub
-lSceMotion_stub
-lSceNetCtl_stub
-lScePgf_stub
-lScePhotoExport_stub
-lScePower_stub

View File

@ -6,6 +6,7 @@
#include <mgba-util/platform/psp2/sce-vfs.h>
#include <psp2/io/dirent.h>
#include <psp2/io/stat.h>
#include <mgba-util/vfs.h>
#include <mgba-util/memory.h>

View File

@ -42,10 +42,18 @@ if(APPLE)
list(APPEND QT_DEFINES USE_SHARE_WIDGET)
endif()
if(Qt5Widgets_VERSION MATCHES "^5.1[0-9]")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.8")
if(Qt5Widgets_VERSION MATCHES "^5.15")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.13")
elseif(Qt5Widgets_VERSION MATCHES "^5.1[234]")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.12")
elseif(Qt5Widgets_VERSION MATCHES "^5.11")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.11")
elseif(Qt5Widgets_VERSION MATCHES "^5.(9|10)")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.10")
elseif(Qt5Widgets_VERSION MATCHES "^5.8")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.9")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.7")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.8")
endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
@ -275,7 +283,11 @@ if(BUILD_GL OR BUILD_GLES2 OR BUILD_EPOXY)
endif()
install(FILES ${CMAKE_SOURCE_DIR}/res/nointro.dat DESTINATION ${DATADIR} COMPONENT ${BINARY_NAME}-qt)
if(NOT WIN32 AND NOT APPLE)
list(APPEND QT_DEFINES DATADIR="${CMAKE_INSTALL_PREFIX}/${DATADIR}")
if(DATADIR MATCHES "^\\.[.\\]")
list(APPEND QT_DEFINES DATADIR="${DATADIR}")
else()
list(APPEND QT_DEFINES DATADIR="${CMAKE_INSTALL_PREFIX}/${DATADIR}")
endif()
endif()
find_package(Qt5LinguistTools)
@ -340,11 +352,10 @@ if(QT_STATIC)
elseif(APPLE)
find_package(Cups)
find_package(Qt5PrintSupport)
find_library(QTFREETYPE NAMES qtfreetype)
find_library(QTHARFBUZZ NAMES qtharfbuzzng qtharfbuzz)
find_library(QTPLATFORMSUPPORT NAMES Qt5PlatformSupport)
list(APPEND QT_LIBRARIES Cups Qt5::PrintSupport Qt5::QCocoaIntegrationPlugin Qt5::CoreAudioPlugin Qt5::AVFServicePlugin Qt5::QCocoaPrinterSupportPlugin ${QTPLATFORMSUPPORT} "-framework AVFoundation" "-framework CoreMedia" "-framework SystemConfiguration" "-framework Security")
set_target_properties(Qt5::Core PROPERTIES INTERFACE_LINK_LIBRARIES "${QTPCRE};${QTHARFBUZZ};${QTFREETYPE}")
list(APPEND QT_LIBRARIES Cups Qt5::PrintSupport Qt5::QCocoaIntegrationPlugin Qt5::CoreAudioPlugin Qt5::AVFServicePlugin Qt5::QCocoaPrinterSupportPlugin)
list(APPEND QT_LIBRARIES Qt5AccessibilitySupport Qt5CglSupport Qt5ClipboardSupport Qt5FontDatabaseSupport Qt5GraphicsSupport Qt5ThemeSupport)
list(APPEND QT_LIBRARIES "-framework AVFoundation" "-framework CoreMedia" "-framework SystemConfiguration" "-framework Security")
set_target_properties(Qt5::Core PROPERTIES INTERFACE_LINK_LIBRARIES "${QTPCRE}")
elseif(UNIX)
list(APPEND QT_LIBRARIES Qt5::FontDatabaseSupport Qt5::XcbQpa)
endif()

View File

@ -149,7 +149,11 @@ void CheatsView::enterCheat() {
index = m_model.index(m_model.rowCount() - 1, 0, QModelIndex());
m_ui.cheatList->selectionModel()->select(index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
}
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
QStringList cheats = m_ui.codeEntry->toPlainText().split('\n', Qt::SkipEmptyParts);
#else
QStringList cheats = m_ui.codeEntry->toPlainText().split('\n', QString::SkipEmptyParts);
#endif
for (const QString& string : cheats) {
m_model.beginAppendRow(index);
mCheatAddLine(set, string.toUtf8().constData(), m_codeType);

View File

@ -13,6 +13,12 @@
#include <mgba/feature/commandline.h>
static const mOption s_frontendOptions[] = {
{ "ecard", true, '\0' },
{ "mb", true, '\0' },
{ 0 }
};
using namespace QGBA;
ConfigOption::ConfigOption(const QString& name, QObject* parent)
@ -125,18 +131,57 @@ ConfigController::ConfigController(QObject* parent)
mCoreConfigSetDefaultIntValue(&m_config, "sgb.borders", 1);
mCoreConfigSetDefaultIntValue(&m_config, "useCgbColors", 1);
mCoreConfigMap(&m_config, &m_opts);
mSubParserGraphicsInit(&m_subparsers[0], &m_graphicsOpts);
m_subparsers[1].usage = "Frontend options:\n"
" --ecard FILE Scan an e-Reader card in the first loaded game\n"
" Can be paassed multiple times for multiple cards\n"
" --mb FILE Boot a multiboot image with FILE inserted into the ROM slot";
m_subparsers[1].parse = nullptr;
m_subparsers[1].parseLong = [](struct mSubParser* parser, const char* option, const char* arg) {
ConfigController* self = static_cast<ConfigController*>(parser->opts);
QString optionName(QString::fromUtf8(option));
if (optionName == QLatin1String("ecard")) {
QStringList ecards;
if (self->m_argvOptions.contains(optionName)) {
ecards = self->m_argvOptions[optionName].toStringList();
}
ecards.append(QString::fromUtf8(arg));
self->m_argvOptions[optionName] = ecards;
return true;
}
if (optionName == QLatin1String("mb")) {
self->m_argvOptions[optionName] = QString::fromUtf8(arg);
return true;
}
return false;
};
m_subparsers[1].apply = nullptr;
m_subparsers[1].extraOptions = nullptr;
m_subparsers[1].longOptions = s_frontendOptions;
m_subparsers[1].opts = this;
}
ConfigController::~ConfigController() {
mCoreConfigDeinit(&m_config);
mCoreConfigFreeOpts(&m_opts);
if (m_parsed) {
mArgumentsDeinit(&m_args);
}
}
bool ConfigController::parseArguments(mArguments* args, int argc, char* argv[], mSubParser* subparser) {
if (::parseArguments(args, argc, argv, subparser)) {
bool ConfigController::parseArguments(int argc, char* argv[]) {
if (m_parsed) {
return false;
}
if (mArgumentsParse(&m_args, argc, argv, m_subparsers.data(), m_subparsers.size())) {
mCoreConfigFreeOpts(&m_opts);
applyArguments(args, subparser, &m_config);
mArgumentsApply(&m_args, m_subparsers.data(), m_subparsers.size(), &m_config);
mCoreConfigMap(&m_config, &m_opts);
m_parsed = true;
return true;
}
return false;
@ -192,6 +237,14 @@ QVariant ConfigController::getQtOption(const QString& key, const QString& group)
return value;
}
QVariant ConfigController::getArgvOption(const QString& key) const {
return m_argvOptions.value(key);
}
QVariant ConfigController::takeArgvOption(const QString& key) {
return m_argvOptions.take(key);
}
void ConfigController::saveOverride(const Override& override) {
override.save(overrides());
write();
@ -299,6 +352,10 @@ void ConfigController::makePortable() {
m_settings = std::move(settings2);
}
void ConfigController::usage(const char* arg0) const {
::usage(arg0, nullptr, nullptr, m_subparsers.data(), m_subparsers.size());
}
bool ConfigController::isPortable() {
return mCoreConfigIsPortable();
}

View File

@ -12,6 +12,7 @@
#include <QSettings>
#include <QVariant>
#include <array>
#include <functional>
#include <memory>
@ -70,7 +71,7 @@ public:
~ConfigController();
const mCoreOptions* options() const { return &m_opts; }
bool parseArguments(mArguments* args, int argc, char* argv[], mSubParser* subparser = nullptr);
bool parseArguments(int argc, char* argv[]);
ConfigOption* addOption(const char* key);
void updateOption(const char* key);
@ -80,6 +81,9 @@ public:
QVariant getQtOption(const QString& key, const QString& group = QString()) const;
QVariant getArgvOption(const QString& key) const;
QVariant takeArgvOption(const QString& key);
QList<QString> getMRU() const;
void setMRU(const QList<QString>& mru);
@ -91,6 +95,10 @@ public:
const mCoreConfig* config() const { return &m_config; }
mCoreConfig* config() { return &m_config; }
const mArguments* args() const { return &m_args; }
const mGraphicsOpts* graphicsOpts() const { return &m_graphicsOpts; }
void usage(const char* arg0) const;
static const QString& configDir();
static bool isPortable();
@ -106,11 +114,18 @@ public slots:
void write();
private:
void addArgvOption(const QString& key, const QVariant& value);
Configuration* defaults() { return &m_config.defaultsTable; }
mCoreConfig m_config;
mCoreOptions m_opts{};
mArguments m_args{};
mGraphicsOpts m_graphicsOpts{};
std::array<mSubParser, 2> m_subparsers;
bool m_parsed = false;
QHash<QString, QVariant> m_argvOptions;
QHash<QString, ConfigOption*> m_optionSet;
std::unique_ptr<QSettings> m_settings;
static QString s_configDir;

View File

@ -194,11 +194,11 @@ CoreController::CoreController(mCore* core, QObject* parent)
}
va_list argc;
va_copy(argc, args);
message = QString().vsprintf(format, argc);
message = QString::vasprintf(format, argc);
va_end(argc);
QMetaObject::invokeMethod(controller, "statusPosted", Q_ARG(const QString&, message));
}
message = QString().vsprintf(format, args);
message = QString::vasprintf(format, args);
QMetaObject::invokeMethod(controller, "logPosted", Q_ARG(int, level), Q_ARG(int, category), Q_ARG(const QString&, message));
if (level == mLOG_FATAL) {
mCoreThreadMarkCrashed(controller->thread());
@ -885,8 +885,31 @@ void CoreController::scanCard(const QString& path) {
QImage image(path);
if (image.isNull()) {
QFile file(path);
file.open(QIODevice::ReadOnly);
if (!file.open(QIODevice::ReadOnly)) {
return;
}
m_eReaderData = file.read(2912);
file.seek(0);
QStringList lines;
QDir basedir(QFileInfo(path).dir());
while (true) {
QByteArray line = file.readLine().trimmed();
if (line.isEmpty()) {
break;
}
QString filepath(QString::fromUtf8(line));
if (filepath.isEmpty() || filepath[0] == QChar('#')) {
continue;
}
if (QFileInfo(filepath).isRelative()) {
lines.append(basedir.filePath(filepath));
} else {
lines.append(filepath);
}
}
scanCards(lines);
} else if (image.size() == QSize(989, 44) || image.size() == QSize(639, 44)) {
const uchar* bits = image.constBits();
size_t size;
@ -905,6 +928,11 @@ void CoreController::scanCard(const QString& path) {
#endif
}
void CoreController::scanCards(const QStringList& paths) {
for (const QString& path : paths) {
scanCard(path);
}
}
void CoreController::importSharkport(const QString& path) {
#ifdef M_CORE_GBA

View File

@ -160,6 +160,7 @@ public slots:
void loadSave(VFile*, bool temporary);
void loadPatch(const QString&);
void scanCard(const QString&);
void scanCards(const QStringList&);
void replaceGame(const QString&);
void yankPak();

View File

@ -69,7 +69,7 @@ void DebuggerConsoleController::printf(struct CLIDebuggerBackend* be, const char
DebuggerConsoleController* self = consoleBe->self;
va_list args;
va_start(args, fmt);
self->log(QString().vsprintf(fmt, args));
self->log(QString::vasprintf(fmt, args));
va_end(args);
}

View File

@ -97,7 +97,11 @@ private:
int m_glowFrame;
QTimer m_glowTimer;
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
QRecursiveMutex m_mutex;
#else
QMutex m_mutex{QMutex::Recursive};
#endif
VFile* m_currentFrame = nullptr;
VFile* m_nextFrame = nullptr;
mCore* m_vl = nullptr;

View File

@ -207,6 +207,9 @@ QString GBAApp::getOpenDirectoryName(QWidget* owner, const QString& title, const
QString GBAApp::dataDir() {
#ifdef DATADIR
QString path = QString::fromUtf8(DATADIR);
if (path.startsWith("./") || path.startsWith("../")) {
path = QCoreApplication::applicationDirPath() + "/" + path;
}
#else
QString path = QCoreApplication::applicationDirPath();
#ifdef Q_OS_MAC

View File

@ -11,6 +11,12 @@
using namespace QGBA;
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
#define endl Qt::endl
#else
#define endl std::endl
#endif
LogController LogController::s_global(mLOG_ALL);
int LogController::s_qtCat{-1};

View File

@ -80,7 +80,12 @@ MemoryModel::MemoryModel(QWidget* parent)
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
m_margins = QMargins(metrics.width("0FFFFFF0 ") + 3, m_cellHeight + 1, metrics.width(" AAAAAAAAAAAAAAAA") + 3, 0);
m_margins = QMargins(3, m_cellHeight + 1, 3, 0);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
m_margins += QMargins(metrics.horizontalAdvance("0FFFFFF0 "), 0, metrics.horizontalAdvance(" AAAAAAAAAAAAAAAA"), 0);
#else
m_margins += QMargins(metrics.width("0FFFFFF0 "), 0, metrics.width(" AAAAAAAAAAAAAAAA"), 0);
#endif
m_cellSize = QSizeF((viewport()->size().width() - (m_margins.left() + m_margins.right())) / 16.0, m_cellHeight);
connect(verticalScrollBar(), &QSlider::sliderMoved, [this](int position) {

View File

@ -84,7 +84,11 @@ void MessagePainter::paint(QPainter* painter) {
painter->setRenderHint(QPainter::Antialiasing);
painter->setFont(m_frameFont);
painter->setPen(Qt::black);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
painter->translate(-metrics.horizontalAdvance(frame), 0);
#else
painter->translate(-metrics.width(frame), 0);
#endif
const static int ITERATIONS = 11;
for (int i = 0; i < ITERATIONS; ++i) {
painter->save();

View File

@ -137,7 +137,11 @@ void ShortcutView::closeEvent(QCloseEvent*) {
void ShortcutView::showEvent(QShowEvent*) {
QString longString("Ctrl+Alt+Shift+Tab");
#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
int width = QFontMetrics(QFont()).horizontalAdvance(longString);
#else
int width = QFontMetrics(QFont()).width(longString);
#endif
QHeaderView* header = m_ui.shortcutTable->header();
header->resizeSection(0, header->length() - width * 2);
header->resizeSection(1, width);

View File

@ -212,8 +212,8 @@ Window::~Window() {
#endif
}
void Window::argumentsPassed(mArguments* args) {
loadConfig();
void Window::argumentsPassed() {
const mArguments* args = m_config->args();
if (args->patch) {
m_pendingPatch = args->patch;
@ -236,9 +236,24 @@ void Window::argumentsPassed(mArguments* args) {
}
#endif
if (m_config->graphicsOpts()->multiplier) {
m_savedScale = m_config->graphicsOpts()->multiplier;
#if defined(M_CORE_GBA)
QSize size(GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
#elif defined(M_CORE_GB)
QSize size(GB_VIDEO_HORIZONTAL_PIXELS, GB_VIDEO_VERTICAL_PIXELS);
#endif
resizeFrame(size * m_savedScale);
}
if (args->fname) {
setController(m_manager->loadGame(args->fname), args->fname);
}
if (m_config->graphicsOpts()->fullscreen) {
enterFullScreen();
}
}
void Window::resizeFrame(const QSize& size) {
@ -975,8 +990,19 @@ void Window::gameStarted() {
action->setActive(true);
}
}
interrupter.resume();
m_actions.rebuildMenu(menuBar(), this, *m_shortcutController);
#ifdef M_CORE_GBA
if (m_controller->platform() == mPLATFORM_GBA) {
QVariant eCardList = m_config->takeArgvOption(QString("ecard"));
if (eCardList.canConvert(QMetaType::QStringList)) {
m_controller->scanCards(eCardList.toStringList());
}
}
#endif
#ifdef USE_DISCORD_RPC
DiscordCoordinator::gameStarted(m_controller);
#endif
@ -2071,6 +2097,15 @@ void Window::setController(CoreController* controller, const QString& fname) {
connect(m_controller.get(), &CoreController::failed, this, &Window::gameFailed);
connect(m_controller.get(), &CoreController::unimplementedBiosCall, this, &Window::unimplementedBiosCall);
#ifdef M_CORE_GBA
if (m_controller->platform() == mPLATFORM_GBA) {
QVariant mb = m_config->takeArgvOption(QString("mb"));
if (mb.canConvert(QMetaType::QString)) {
m_controller->replaceGame(mb.toString());
}
}
#endif
#ifdef USE_GDB_STUB
if (m_gdbController) {
m_gdbController->setController(m_controller);

View File

@ -24,8 +24,6 @@
#include "LogController.h"
#include "SettingsView.h"
struct mArguments;
namespace QGBA {
class AudioProcessor;
@ -59,7 +57,7 @@ public:
void setConfig(ConfigController*);
ConfigController* config() { return m_config; }
void argumentsPassed(mArguments*);
void argumentsPassed();
void resizeFrame(const QSize& size);

View File

@ -68,22 +68,18 @@ int main(int argc, char* argv[]) {
QLocale::setDefault(locale);
}
mArguments args;
mGraphicsOpts graphicsOpts;
mSubParser subparser;
initParserForGraphics(&subparser, &graphicsOpts);
bool loaded = configController.parseArguments(&args, argc, argv, &subparser);
if (loaded) {
if (args.showHelp) {
usage(argv[0], subparser.usage);
freeArguments(&args);
if (configController.parseArguments(argc, argv)) {
if (configController.args()->showHelp) {
configController.usage(argv[0]);
return 0;
}
if (args.showVersion) {
if (configController.args()->showVersion) {
version(argv[0]);
freeArguments(&args);
return 0;
}
} else {
configController.usage(argv[0]);
return 1;
}
QApplication::setApplicationName(projectName);
@ -117,19 +113,8 @@ int main(int argc, char* argv[]) {
application.installTranslator(&langTranslator);
Window* w = application.newWindow();
if (loaded) {
w->argumentsPassed(&args);
} else {
w->loadConfig();
}
freeArguments(&args);
if (graphicsOpts.multiplier) {
w->resizeFrame(QSize(GBA_VIDEO_HORIZONTAL_PIXELS * graphicsOpts.multiplier, GBA_VIDEO_VERTICAL_PIXELS * graphicsOpts.multiplier));
}
if (graphicsOpts.fullscreen) {
w->enterFullScreen();
}
w->loadConfig();
w->argumentsPassed();
w->show();

View File

@ -65,7 +65,7 @@ endif()
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libsdl${SDL_VERSION_DEBIAN}" PARENT_SCOPE)
file(GLOB PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/sdl-*.c)
set(PLATFORM_LIBRARY ${SDL_LIBRARY} ${SDLMAIN_LIBRARY} ${PIXMAN-1_LIBRARIES})
set(PLATFORM_LIBRARY ${SDL_LIBRARY} ${SDLMAIN_LIBRARY} ${SDL_LIBRARY} ${PIXMAN-1_LIBRARIES})
include_directories(${CMAKE_SOURCE_DIR}/src/platform/sdl ${PIXMAN-1_INCLUDE_DIRS} ${SDL_INCLUDE_DIR})
set(SDL_INCLUDE_DIR "${SDL_INCLUDE_DIR}" PARENT_SCOPE)

View File

@ -80,37 +80,37 @@ int main(int argc, char** argv) {
struct mSubParser subparser;
initParserForGraphics(&subparser, &graphicsOpts);
bool parsed = parseArguments(&args, argc, argv, &subparser);
mSubParserGraphicsInit(&subparser, &graphicsOpts);
bool parsed = mArgumentsParse(&args, argc, argv, &subparser, 1);
if (!args.fname && !args.showVersion) {
parsed = false;
}
if (!parsed || args.showHelp) {
usage(argv[0], subparser.usage);
freeArguments(&args);
usage(argv[0], NULL, NULL, &subparser, 1);
mArgumentsDeinit(&args);
return !parsed;
}
if (args.showVersion) {
version(argv[0]);
freeArguments(&args);
mArgumentsDeinit(&args);
return 0;
}
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
printf("Could not initialize video: %s\n", SDL_GetError());
freeArguments(&args);
mArgumentsDeinit(&args);
return 1;
}
renderer.core = mCoreFind(args.fname);
if (!renderer.core) {
printf("Could not run game. Are you sure the file exists and is a compatible game?\n");
freeArguments(&args);
mArgumentsDeinit(&args);
return 1;
}
if (!renderer.core->init(renderer.core)) {
freeArguments(&args);
mArgumentsDeinit(&args);
return 1;
}
@ -134,7 +134,7 @@ int main(int argc, char** argv) {
mInputMapInit(&renderer.core->inputMap, renderer.core->inputInfo);
mCoreInitConfig(renderer.core, PORT);
applyArguments(&args, &subparser, &renderer.core->config);
mArgumentsApply(&args, &subparser, 1, &renderer.core->config);
mCoreConfigLoadDefaults(&renderer.core->config, &opts);
mCoreLoadConfig(renderer.core);
@ -168,7 +168,7 @@ int main(int argc, char** argv) {
}
if (!renderer.init(&renderer)) {
freeArguments(&args);
mArgumentsDeinit(&args);
mCoreConfigDeinit(&renderer.core->config);
renderer.core->deinit(renderer.core);
return 1;
@ -199,7 +199,7 @@ int main(int argc, char** argv) {
mSDLDeinit(&renderer);
freeArguments(&args);
mArgumentsDeinit(&args);
mCoreConfigFreeOpts(&opts);
mCoreConfigDeinit(&renderer.core->config);
renderer.core->deinit(renderer.core);

View File

@ -22,7 +22,7 @@
#define FUZZ_OPTIONS "F:NO:S:V:"
#define FUZZ_USAGE \
"\nAdditional options:\n" \
"Additional options:\n" \
" -F FRAMES Run for the specified number of FRAMES before exiting\n" \
" -N Disable video rendering entirely\n" \
" -O OFFSET Offset to apply savestate overlay\n" \
@ -53,12 +53,12 @@ int main(int argc, char** argv) {
};
struct mArguments args;
bool parsed = parseArguments(&args, argc, argv, &subparser);
bool parsed = mArgumentsParse(&args, argc, argv, &subparser, 1);
if (!args.fname) {
parsed = false;
}
if (!parsed || args.showHelp) {
usage(argv[0], FUZZ_USAGE);
usage(argv[0], NULL, NULL, &subparser, 1);
return !parsed;
}
if (args.showVersion) {
@ -71,7 +71,7 @@ int main(int argc, char** argv) {
}
core->init(core);
mCoreInitConfig(core, "fuzz");
applyArguments(&args, NULL, &core->config);
mArgumentsApply(&args, NULL, 0, &core->config);
mCoreConfigSetDefaultValue(&core->config, "idleOptimization", "remove");
@ -161,7 +161,7 @@ int main(int argc, char** argv) {
}
loadError:
freeArguments(&args);
mArgumentsDeinit(&args);
if (outputBuffer) {
free(outputBuffer);
}

View File

@ -44,7 +44,7 @@ size_t romBufferSize;
#define PERF_OPTIONS "DF:L:NPS:T"
#define PERF_USAGE \
"\nBenchmark options:\n" \
"Benchmark options:\n" \
" -F FRAMES Run for the specified number of FRAMES before exiting\n" \
" -N Disable video rendering entirely\n" \
" -T Use threaded video rendering\n" \
@ -131,12 +131,12 @@ int main(int argc, char** argv) {
};
struct mArguments args = {};
bool parsed = parseArguments(&args, argc, argv, &subparser);
bool parsed = mArgumentsParse(&args, argc, argv, &subparser, 1);
if (!args.fname && !perfOpts.server) {
parsed = false;
}
if (!parsed || args.showHelp) {
usage(argv[0], PERF_USAGE);
usage(argv[0], NULL, NULL, &subparser, 1);
didFail = !parsed;
goto cleanup;
}
@ -171,7 +171,7 @@ int main(int argc, char** argv) {
_savestate->close(_savestate);
}
cleanup:
freeArguments(&args);
mArgumentsDeinit(&args);
#ifdef __3DS__
gfxExit();
@ -217,7 +217,7 @@ bool _mPerfRunCore(const char* fname, const struct mArguments* args, const struc
mCoreConfigMap(&core->config, &opts);
opts.audioSync = false;
opts.videoSync = false;
applyArguments(args, NULL, &core->config);
mArgumentsApply(args, NULL, 0, &core->config);
mCoreConfigLoadDefaults(&core->config, &opts);
mCoreConfigSetDefaultValue(&core->config, "idleOptimization", "detect");
mCoreLoadConfig(core);

View File

@ -24,7 +24,7 @@
#define ROM_TEST_OPTIONS "S:R:"
#define ROM_TEST_USAGE \
"\nAdditional options:\n" \
"Additional options:\n" \
" -S SWI Run until specified SWI call before exiting\n" \
" -R REGISTER General purpose register to return as exit code\n" \
@ -81,12 +81,12 @@ int main(int argc, char * argv[]) {
};
struct mArguments args;
bool parsed = parseArguments(&args, argc, argv, &subparser);
bool parsed = mArgumentsParse(&args, argc, argv, &subparser, 1);
if (!args.fname) {
parsed = false;
}
if (!parsed || args.showHelp) {
usage(argv[0], ROM_TEST_USAGE);
usage(argv[0], NULL, NULL, &subparser, 1);
return !parsed;
}
if (args.showVersion) {
@ -99,7 +99,7 @@ int main(int argc, char * argv[]) {
}
core->init(core);
mCoreInitConfig(core, "romTest");
applyArguments(&args, NULL, &core->config);
mArgumentsApply(&args, NULL, 0, &core->config);
mCoreConfigSetDefaultValue(&core->config, "idleOptimization", "remove");
@ -184,7 +184,7 @@ int main(int argc, char * argv[]) {
cleanExit = true;
loadError:
freeArguments(&args);
mArgumentsDeinit(&args);
mCoreConfigDeinit(&core->config);
core->deinit(core);

View File

@ -52,10 +52,10 @@ OutputBaseFilename={#AppName}-setup-{#CleanVersionString}-win{#WinBits}
UsePreviousLanguage=False
DisableWelcomePage=False
VersionInfoDescription={#AppName} is an open-source Game Boy Advance emulator
VersionInfoCopyright=© 20132020 Jeffrey Pfau
VersionInfoCopyright=© 20132022 Jeffrey Pfau
VersionInfoProductName={#AppName}
VersionInfoVersion={#AppVer}
Compression=lzma2/ultra64
Compression=lzma2/ultra
SolidCompression=True
VersionInfoTextVersion={#VersionString}
VersionInfoProductVersion={#AppVer}