From 0c01ab76cf0397313bab9e26684931a0fc434db7 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 15 Aug 2023 21:45:23 +0200 Subject: [PATCH] port: add simple config file includes an option to disable vsync and enable cpu-side frame limiter --- port/fast3d/gfx_sdl2.cpp | 14 +++++-- port/fast3d/gfx_window_manager_api.h | 1 + port/include/config.h | 15 +++++++ port/include/{ => external}/minimp3.h | 0 port/include/fs.h | 12 +++--- port/include/system.h | 2 + port/src/audio.c | 8 +++- port/src/fs.c | 58 +++++++++++++++++++++------ port/src/input.c | 43 +++++++++++++++----- port/src/libultra.c | 11 ++--- port/src/main.c | 4 ++ port/src/mixer.c | 2 +- port/src/system.c | 19 +++++++++ port/src/video.c | 13 +++++- 14 files changed, 162 insertions(+), 40 deletions(-) create mode 100644 port/include/config.h rename port/include/{ => external}/minimp3.h (100%) diff --git a/port/fast3d/gfx_sdl2.cpp b/port/fast3d/gfx_sdl2.cpp index 9f1bdcad0..770aaa3ca 100644 --- a/port/fast3d/gfx_sdl2.cpp +++ b/port/fast3d/gfx_sdl2.cpp @@ -27,7 +27,7 @@ static void (*on_fullscreen_changed_callback)(bool is_now_fullscreen); static uint64_t previous_time; -static int target_fps = 60; +static int target_fps = 120; // above 60 since vsync is enabled by default static uint64_t qpc_freq; @@ -190,7 +190,9 @@ static inline void sync_framerate_with_timer(void) { } static void gfx_sdl_swap_buffers_begin(void) { - //sync_framerate_with_timer(); + if (target_fps) { + sync_framerate_with_timer(); + } SDL_GL_SwapWindow(wnd); } @@ -218,6 +220,11 @@ static void gfx_sdl_set_window_title(const char *title) { SDL_SetWindowTitle(wnd, title); } +static void gfx_sdl_set_swap_interval(int interval) { + SDL_GL_SetSwapInterval(interval); + vsync_enabled = (interval != 0); +} + struct GfxWindowManagerAPI gfx_sdl = { gfx_sdl_init, gfx_sdl_close, @@ -234,5 +241,6 @@ struct GfxWindowManagerAPI gfx_sdl = { gfx_sdl_set_target_fps, gfx_sdl_can_disable_vsync, gfx_sdl_get_window_handle, - gfx_sdl_set_window_title + gfx_sdl_set_window_title, + gfx_sdl_set_swap_interval, }; diff --git a/port/fast3d/gfx_window_manager_api.h b/port/fast3d/gfx_window_manager_api.h index d3334ec74..f4070f782 100644 --- a/port/fast3d/gfx_window_manager_api.h +++ b/port/fast3d/gfx_window_manager_api.h @@ -22,6 +22,7 @@ struct GfxWindowManagerAPI { bool (*can_disable_vsync)(void); void *(*get_window_handle)(void); void (*set_window_title)(const char *); + void (*set_swap_interval)(int); }; #endif diff --git a/port/include/config.h b/port/include/config.h new file mode 100644 index 000000000..6c814782c --- /dev/null +++ b/port/include/config.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +void configInit(void); +s32 configLoad(const char *fname); +s32 configSave(const char *fname); + +s32 configGetInt(const char *key, s32 defval); +f32 configGetFloat(const char *key, f32 defval); +const char *configGetString(const char *key, const char *defval); + +void configSetInt(const char *key, s32 val); +void configSetFloat(const char *key, f32 val); +void configSetString(const char *key, const char *val); diff --git a/port/include/minimp3.h b/port/include/external/minimp3.h similarity index 100% rename from port/include/minimp3.h rename to port/include/external/minimp3.h diff --git a/port/include/fs.h b/port/include/fs.h index c117b4d69..dc299cf57 100644 --- a/port/include/fs.h +++ b/port/include/fs.h @@ -1,18 +1,20 @@ #ifndef _IN_FS_H #define _IN_FS_H -#include +#include #include -#ifdef PATH_MAX -#define FS_MAXPATH PATH_MAX -#else #define FS_MAXPATH 1024 -#endif s32 fsInit(void); +const char *fsFullPath(const char *relPath); + void *fsFileLoad(const char *name, u32 *outSize); s32 fsFileSize(const char *name); +FILE *fsFileOpenWrite(const char *name); +FILE *fsFileOpenRead(const char *name); +void fsFileClose(FILE *f); + #endif diff --git a/port/include/system.h b/port/include/system.h index 257ac1f9d..be03e0621 100644 --- a/port/include/system.h +++ b/port/include/system.h @@ -8,4 +8,6 @@ u64 sysGetTicksPerSecond(void); void sysFatalError(const char *fmt, ...) __attribute__((noreturn)); +void sysGetExecutablePath(char *outPath, const u32 outLen); + #endif diff --git a/port/src/audio.c b/port/src/audio.c index a363228ec..75067efa7 100644 --- a/port/src/audio.c +++ b/port/src/audio.c @@ -1,11 +1,13 @@ #include #include #include +#include "config.h" #include "audio.h" static SDL_AudioDeviceID dev; static const s16 *nextBuf; static u32 nextSize = 0; +static u32 queueLimit = 8192; s32 audioInit(void) { @@ -19,7 +21,7 @@ s32 audioInit(void) want.freq = 22020; // TODO: this might cause trouble for some platforms want.format = AUDIO_S16SYS; want.channels = 2; - want.samples = 512; + want.samples = configGetInt("Audio.BufferSize", 512); want.callback = NULL; nextBuf = NULL; @@ -30,6 +32,8 @@ s32 audioInit(void) return -1; } + queueLimit = configGetInt("Audio.QueueLimit", 8192); + SDL_PauseAudioDevice(dev, 0); return 0; @@ -54,7 +58,7 @@ void audioSetNextBuffer(const s16 *buf, u32 len) void audioEndFrame(void) { if (nextBuf && nextSize) { - if (audioGetSamplesBuffered() < 8192) { + if (audioGetSamplesBuffered() < queueLimit) { SDL_QueueAudio(dev, nextBuf, nextSize); } nextBuf = NULL; diff --git a/port/src/fs.c b/port/src/fs.c index 61f267465..50be2d2c9 100644 --- a/port/src/fs.c +++ b/port/src/fs.c @@ -4,18 +4,14 @@ #include #include #include +#include "config.h" +#include "system.h" #include "fs.h" -#ifdef PATH_MAX -#define FS_MAXPATH PATH_MAX -#else -#define FS_MAXPATH 1024 -#endif - -#define FS_BASEDIR "data" #define FS_MAX_FILES 2048 static char baseDir[FS_MAXPATH + 1]; +static char exeDir[FS_MAXPATH + 1]; static struct { char *name[FS_MAXPATH + 1]; @@ -23,17 +19,40 @@ static struct { void *data; } fileSlots[FS_MAX_FILES]; -static const char *fsFullPath(const char *relPath) +const char *fsFullPath(const char *relPath) { - static char pathBuf[FS_MAXPATH]; - snprintf(pathBuf, sizeof(pathBuf), "%s/%s", baseDir, relPath); + static char pathBuf[FS_MAXPATH + 1]; + + if (relPath[0] == '!') { + // path relative to the exe + const u32 len = strlen(exeDir); + if (len > 0) { + memcpy(pathBuf, exeDir, len); + strncpy(pathBuf + len, relPath + 1, FS_MAXPATH - len); + return pathBuf; + } + } else if (relPath[0] == '.') { + // user explicitly wants working directory + return relPath; + } + + // path relative to basedir + snprintf(pathBuf, FS_MAXPATH, "%s/%s", baseDir, relPath); return pathBuf; } s32 fsInit(void) { - // TODO: support appdata/home/whatever - strcpy(baseDir, FS_BASEDIR); + sysGetExecutablePath(exeDir, FS_MAXPATH); + + // get path to data dir and expand it if needed + const char *path = configGetString("Game.BaseDir", "./data"); + if (path[0] == '!') { + strncpy(baseDir, fsFullPath(path), FS_MAXPATH); + } else { + strncpy(baseDir, path, FS_MAXPATH); + } + return 0; } @@ -87,3 +106,18 @@ s32 fsFileSize(const char *name) return st.st_size; } } + +FILE *fsFileOpenWrite(const char *name) +{ + return fopen(fsFullPath(name), "wb"); +} + +FILE *fsFileOpenRead(const char *name) +{ + return fopen(fsFullPath(name), "rb"); +} + +void fsFileClose(FILE *f) +{ + fclose(f); +} diff --git a/port/src/input.c b/port/src/input.c index b720ffcb8..8835f586e 100644 --- a/port/src/input.c +++ b/port/src/input.c @@ -4,6 +4,7 @@ #include #include "input.h" #include "video.h" +#include "config.h" #define MAX_BINDS 4 #define TRIG_THRESHOLD (30 * 256) @@ -15,6 +16,7 @@ static u32 binds[MAXCONTROLLERS][CK_TOTAL_COUNT][MAX_BINDS]; // [i][CK_][b] = [V static s32 connectedMask = 0; +static s32 mouseEnabled = 1; static s32 mouseLocked = 0; static s32 mouseX, mouseY; static s32 mouseDX, mouseDY; @@ -23,16 +25,13 @@ static u32 mouseButtons; static f32 mouseSensX = 1.5f; static f32 mouseSensY = 1.5f; -// NOTE: default is inverted for 1.2 +// NOTE: by default this gets inverted for 1.2 static u32 axisMap[2][2] = { - { SDL_CONTROLLER_AXIS_RIGHTX, SDL_CONTROLLER_AXIS_RIGHTY }, // stick x/y - { SDL_CONTROLLER_AXIS_LEFTX, SDL_CONTROLLER_AXIS_LEFTY }, // cbuttons x/y + { SDL_CONTROLLER_AXIS_LEFTX, SDL_CONTROLLER_AXIS_LEFTY }, + { SDL_CONTROLLER_AXIS_RIGHTX, SDL_CONTROLLER_AXIS_RIGHTY }, }; -static u32 deadzone[2][2] = { - { DEFAULT_DEADZONE, DEFAULT_DEADZONE }, - { DEFAULT_DEADZONE, DEFAULT_DEADZONE }, -}; +static u32 deadzone[2] = { DEFAULT_DEADZONE, DEFAULT_DEADZONE }; void inputSetDefaultKeyBinds(void) { // TODO: make VK constants for all these @@ -114,6 +113,21 @@ s32 inputInit(void) inputSetDefaultKeyBinds(); + mouseEnabled = configGetInt("Input.MouseEnabled", 1); + mouseSensX = configGetFloat("Input.MouseSpeedX", 1.5f); + mouseSensY = configGetFloat("Input.MouseSpeedY", 1.5f); + + deadzone[0] = configGetInt("Input.LStickDeadzone", DEFAULT_DEADZONE); + deadzone[1] = configGetInt("Input.RStickDeadzone", DEFAULT_DEADZONE); + + if (configGetInt("Input.SwapSticks", 1)) { + // invert axis map + axisMap[0][0] = SDL_CONTROLLER_AXIS_RIGHTX; + axisMap[0][1] = SDL_CONTROLLER_AXIS_RIGHTY; + axisMap[1][0] = SDL_CONTROLLER_AXIS_LEFTX; + axisMap[1][1] = SDL_CONTROLLER_AXIS_LEFTY; + } + connectedMask = ret; return ret; @@ -165,7 +179,7 @@ s32 inputReadController(s32 idx, OSContPad *npad) if (rightY > +0x4000) npad->button |= D_CBUTTONS; const s32 leftMag = leftX * leftX + leftY * leftY; - const s32 deadzoneMag = deadzone[0][0] * deadzone[0][0] + deadzone[0][1] * deadzone[0][1]; + const s32 deadzoneMag = deadzone[0] * deadzone[0] + deadzone[0] * deadzone[0]; if (leftMag > deadzoneMag) { const s32 stickY = -leftY / 0x100; if (!npad->stick_x) { @@ -179,10 +193,8 @@ s32 inputReadController(s32 idx, OSContPad *npad) return 0; } -void inputUpdate(void) +static inline void inputUpdateMouse(void) { - SDL_GameControllerUpdate(); - s32 mx, my; mouseButtons = SDL_GetMouseState(&mx, &my); @@ -201,6 +213,15 @@ void inputUpdate(void) } else if (mouseLocked && inputKeyPressed(VK_ESCAPE)) { inputLockMouse(0); } +} + +void inputUpdate(void) +{ + SDL_GameControllerUpdate(); + + if (mouseEnabled) { + inputUpdateMouse(); + } for (s32 i = 0; i < INPUT_MAX_CONTROLLERS; ++i) { if (pads[i] && !SDL_GameControllerGetAttached(pads[i])) { diff --git a/port/src/libultra.c b/port/src/libultra.c index 60ae71eb6..0f179a9d0 100644 --- a/port/src/libultra.c +++ b/port/src/libultra.c @@ -9,9 +9,10 @@ #include "input.h" #include "video.h" #include "audio.h" +#include "fs.h" #define EEPROM_SIZE (EEP16K_MAXBLOCKS * 8) -#define EEPROM_FNAME "eeprom.bin" +#define EEPROM_FNAME "./eeprom.bin" #define OS_COUNTER_RATE 46875000ULL u64 osClockRate = OS_CLOCK_RATE; @@ -252,7 +253,7 @@ s32 osEepromLongRead(OSMesgQueue *mq, u8 address, u8 *buffer, int nbytes) { u8 content[EEPROM_SIZE]; s32 ret = -1; - FILE *fp = fopen(EEPROM_FNAME, "rb"); + FILE *fp = fsFileOpenRead(EEPROM_FNAME); if (fp == NULL) { return -1; } @@ -260,7 +261,7 @@ s32 osEepromLongRead(OSMesgQueue *mq, u8 address, u8 *buffer, int nbytes) memcpy(buffer, content + address * 8, nbytes); ret = 0; } - fclose(fp); + fsFileClose(fp); return ret; } @@ -271,12 +272,12 @@ s32 osEepromLongWrite(OSMesgQueue *mq, u8 address, u8 *buffer, int nbytes) osEepromLongRead(mq, 0, content, EEPROM_SIZE); } memcpy(content + address * 8, buffer, nbytes); - FILE* fp = fopen(EEPROM_FNAME, "wb"); + FILE* fp = fsFileOpenWrite(EEPROM_FNAME); if (fp == NULL) { return -1; } s32 ret = fwrite(content, 1, EEPROM_SIZE, fp) == EEPROM_SIZE ? 0 : -1; - fclose(fp); + fsFileClose(fp); return ret; } diff --git a/port/src/main.c b/port/src/main.c index 3b56fd02d..5ac513609 100644 --- a/port/src/main.c +++ b/port/src/main.c @@ -12,6 +12,7 @@ #include "input.h" #include "fs.h" #include "romdata.h" +#include "config.h" #include "system.h" u32 g_OsMemSize = 0; @@ -54,6 +55,7 @@ void bootCreateSched(void) int main(int argc, const char **argv) { fsInit(); + configInit(); videoInit(); inputInit(); audioInit(); @@ -61,6 +63,8 @@ int main(int argc, const char **argv) bootCreateSched(); + osMemSize = configGetInt("Game.MemorySize", 16) * 1024 * 1024; + g_OsMemSize = osGetMemSize(); g_MempHeapSize = g_OsMemSize; diff --git a/port/src/mixer.c b/port/src/mixer.c index 653499735..9fff8538a 100644 --- a/port/src/mixer.c +++ b/port/src/mixer.c @@ -7,7 +7,7 @@ #include "platform.h" #define MINIMP3_IMPLEMENTATION -#include "minimp3.h" +#include "external/minimp3.h" #ifdef __SSE4_1__ #include diff --git a/port/src/system.c b/port/src/system.c index aedfaa7ba..33cc89c8f 100644 --- a/port/src/system.c +++ b/port/src/system.c @@ -46,3 +46,22 @@ void sysFatalError(const char *fmt, ...) SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal error", errmsg, NULL); exit(1); } + +void sysGetExecutablePath(char *outPath, const u32 outLen) +{ + // try asking SDL + char *sdlPath = SDL_GetBasePath(); + if (sdlPath && *sdlPath) { + // -1 to trim trailing slash + const u32 len = strlen(sdlPath) - 1; + if (len < outLen) { + memcpy(outPath, sdlPath, len); + outPath[len] = '\0'; + } + } else if (outLen > 1) { + // give up, use working directory instead + outPath[0] = '.'; + outPath[1] = '\0'; + } + SDL_free(sdlPath); +} diff --git a/port/src/video.c b/port/src/video.c index 195e98772..e88a9b0b1 100644 --- a/port/src/video.c +++ b/port/src/video.c @@ -4,6 +4,8 @@ #include #include #include +#include "config.h" +#include "video.h" #include "../fast3d/gfx_api.h" #include "../fast3d/gfx_sdl.h" @@ -25,7 +27,16 @@ s32 videoInit(void) renderingAPI = &gfx_opengl_api; gfx_current_native_viewport.width = 320; gfx_current_native_viewport.height = 240; - gfx_init(wmAPI, renderingAPI, "PD", false, 640, 480, 100, 100); + + const s32 w = configGetInt("Video.DefaultWidth", 640); + const s32 h = configGetInt("Video.DefaultHeight", 480); + const bool fs = configGetInt("Video.DefaultFullscreen", false); + + gfx_init(wmAPI, renderingAPI, "PD", fs, w, h, 100, 100); + + wmAPI->set_swap_interval(configGetInt("Video.VSync", 1)); + wmAPI->set_target_fps(configGetInt("Video.FramerateLimit", 0)); // disabled because vsync is on + initDone = true; return 0; }