M-26: [A/E] atexit config+window persistence, --help/--version

- main.c: atexit(portAtExit) = videoSaveWindowState() + configSave(),
  fires on clean exit(0) (SDL_QUIT/ESC/close); abort() paths skip it.
- video.c: new [Window] ini section (Width/Height/X/Y/Maximized);
  sentinels (0 / -1) reproduce native-size + centered. videoSaveWindowState()
  snapshots live geometry via the SDL2 wapi backend. Video.Fullscreen
  now round-trips.
- main.c: --version / --help (-h) before crashInit — build id, usage,
  21-level -level_XX table.
- Verified: -level_09/-level_20 crash-free 6/6 frames, ge007.ini gains
  populated [Window] block on exit.
This commit is contained in:
James Dansereau committed 2026-08-30 12:55:06 -04:00
1 parent 905eebf447
commit db1834ca9b
3 files changed
+112 -6

No files matched your search

+4
View File
@@ -48,6 +48,10 @@ void videoResetTextureCache(void);
/* Current FPS (measured). */
float videoGetFPS(void);
/* Snapshot live window geometry into the config vars (call before configSave
* on a clean exit). No-op if the window isn't up. */
void videoSaveWindowState(void);
#ifdef __cplusplus
}
#endif
+50
View File
@@ -38,10 +38,59 @@
extern void mainproc(void *args);
extern OSThread mainThread; /* src/init.c:75 */
/* name:number pairs for the 21 solo levels (matches tools_pc/level_sweep.sh
* and playtest.sh --list). boss.c decodes -level_XX as d0*10 + d1 - 0x210. */
static const struct { const char *name; const char *num; } kSoloLevels[] = {
{"Dam","33"}, {"Facility","34"}, {"Runway","35"}, {"Surface1","36"},
{"Bunker1","09"}, {"Silo","20"}, {"Frigate","26"}, {"Surface2","43"},
{"Bunker2","27"}, {"Statue","22"}, {"Archives","24"}, {"Streets","29"},
{"Depot","30"}, {"Train","25"}, {"Jungle","37"}, {"Control","23"},
{"Caverns","39"}, {"Cradle","41"}, {"Aztec","28"}, {"Egypt","32"},
{"Cuba","54"},
};
static void portPrintVersion(void)
{
printf("GoldenEye 007 PC port\n"
" rom : %s\n"
" platform : %s\n"
" build : %s\n",
GE007_ROMID, GE007_TARGET_PLATFORM, GE007_VERSION_HASH);
}
static void portPrintHelp(const char *argv0)
{
portPrintVersion();
printf("\nusage: %s [options] [-level_XX]\n\n"
" --help this message\n"
" --version build id only\n"
" -level_XX boot straight into a solo level (per-level\n"
" memory pools are auto-injected)\n\n"
"config: ge007.ini in the data dir (written on first run).\n\n"
"solo levels (-level_XX):\n", argv0 ? argv0 : "ge007");
for (size_t i = 0; i < sizeof(kSoloLevels) / sizeof(kSoloLevels[0]); ++i) {
printf(" %-10s -level_%s\n", kSoloLevels[i].name, kSoloLevels[i].num);
}
}
static void portAtExit(void)
{
/* Clean-exit only (exit(0) from videoPumpEvents). Crash/fatal paths call
* abort(), which does not run atexit handlers. */
videoSaveWindowState();
configSave();
}
int main(int argc, char **argv)
{
sysSetArgs(argc, argv);
if (sysArgCheck("--version")) { portPrintVersion(); return 0; }
if (sysArgCheck("--help") || sysArgCheck("-h")) {
portPrintHelp(argv[0]);
return 0;
}
sysLogPrintf(LOG_INFO, "GoldenEye 007 PC port starting "
"(%s, %s)", GE007_ROMID, GE007_VERSION_HASH);
@@ -50,6 +99,7 @@ int main(int argc, char **argv)
/* 1. Platform + config + filesystem. */
configLoad();
atexit(portAtExit); /* persist config + window geometry on clean exit */
/* 2. Load the ROM and map segments. */
if (romdataInit() != 0) {
+58 -6
View File
@@ -57,6 +57,18 @@ static int cfgMSAA = 1; /* 1/2/4/8 samples; 1 = off
static int cfgTexFilter = 1; /* 0 = nearest (crisp), 1 = bilinear */
static int cfgFullscreen = 0; /* 0 = windowed, 1 = borderless fullscreen */
/*
* [Window] persistence. Defaults are sentinels that reproduce the old
* hardcoded behaviour (native size, centered): W/H = 0 -> native, X/Y = -1 ->
* let SDL centre the window. videoSaveWindowState() writes the live geometry
* back into these on a clean exit (see main.c's atexit handler).
*/
static int cfgWinW = 0;
static int cfgWinH = 0;
static int cfgWinX = -1;
static int cfgWinY = -1;
static int cfgWinMax = 0;
PD_CONSTRUCTOR static void videoConfigInit(void)
{
configRegisterInt("Video.VSync", &cfgVSync, 0, 1);
@@ -64,6 +76,11 @@ PD_CONSTRUCTOR static void videoConfigInit(void)
configRegisterInt("Video.MSAA", &cfgMSAA, 1, 8);
configRegisterInt("Video.TextureFilter", &cfgTexFilter, 0, 1);
configRegisterInt("Video.Fullscreen", &cfgFullscreen, 0, 1);
configRegisterInt("Window.Width", &cfgWinW, 0, 16384);
configRegisterInt("Window.Height", &cfgWinH, 0, 16384);
configRegisterInt("Window.X", &cfgWinX, -1, 16384);
configRegisterInt("Window.Y", &cfgWinY, -1, 16384);
configRegisterInt("Window.Maximized", &cfgWinMax, 0, 1);
}
static u32 frames = 0;
@@ -88,19 +105,23 @@ int videoInit(void)
/* MSAA: snap the requested sample count down to a supported power of two. */
gfx_msaa_level = cfgMSAA >= 8 ? 8 : cfgMSAA >= 4 ? 4 : cfgMSAA >= 2 ? 2 : 1;
int winW = cfgWinW > 0 ? cfgWinW : GE_NATIVE_W;
int winH = cfgWinH > 0 ? cfgWinH : GE_NATIVE_H;
int havePos = (cfgWinX >= 0 && cfgWinY >= 0);
struct GfxInitSettings set = {
.wapi = wmAPI,
.rapi = renderingAPI,
.window_settings = {
.title = "GoldenEye 007",
.width = GE_NATIVE_W,
.height = GE_NATIVE_H,
.x = 100,
.y = 100,
.width = winW,
.height = winH,
.x = havePos ? cfgWinX : 100,
.y = havePos ? cfgWinY : 100,
.fullscreen = cfgFullscreen != 0,
.fullscreen_is_exclusive = false,
.maximized = false,
.centered = true,
.maximized = cfgWinMax != 0,
.centered = !havePos,
.allow_hidpi = false,
},
};
@@ -292,6 +313,37 @@ float videoGetFPS(void)
return vidAvgFPS;
}
/*
* Snapshot the current window geometry into the [Window] / [Video] config
* vars so the next configSave() persists it. Called from main.c's atexit
* handler (runs on the host thread, which owns the window). A maximized or
* fullscreen window keeps its last restored size/pos on disk; only the
* flag is updated.
*/
void videoSaveWindowState(void)
{
if (!initDone || !wmAPI) {
return;
}
int32_t fs = wmAPI->get_fullscreen_state ? wmAPI->get_fullscreen_state() : 0;
int32_t mx = wmAPI->get_maximized_state ? wmAPI->get_maximized_state() : 0;
cfgFullscreen = fs ? 1 : 0;
cfgWinMax = mx ? 1 : 0;
if (!fs && !mx && wmAPI->get_dimensions) {
uint32_t w = 0, h = 0;
int32_t x = 0, y = 0;
wmAPI->get_dimensions(&w, &h, &x, &y);
if (w > 0 && h > 0) {
cfgWinW = (int)w;
cfgWinH = (int)h;
cfgWinX = x < 0 ? 0 : x;
cfgWinY = y < 0 ? 0 : y;
}
}
}
void videoUpdateNativeResolution(s32 w, s32 h)
{
if (w <= 0 || h <= 0) {