diff --git a/.gitignore b/.gitignore index 0caa3e08..6f09a7e9 100644 --- a/.gitignore +++ b/.gitignore @@ -78,3 +78,6 @@ sm64config.txt !/sound/**/*custom*/**/*.aiff !/assets/**/*custom*.bin !/assets/**/*custom*/**/*.bin + +# macOS bullcrap directory settings file thats autocreated +.DS_Store diff --git a/Makefile b/Makefile index 1353aa08..b2797d97 100644 --- a/Makefile +++ b/Makefile @@ -30,6 +30,9 @@ TARGET_WEB ?= 0 # Makeflag to enable OSX fixes OSX_BUILD ?= 0 +# Enable -no-pie linker option +NO_PIE ?= 1 + # Specify the target you are building for, TARGET_BITS=0 means native TARGET_ARCH ?= native TARGET_BITS ?= 0 @@ -555,7 +558,13 @@ else ifeq ($(SDL1_USED),1) endif ifneq ($(SDL1_USED)$(SDL2_USED),00) - BACKEND_CFLAGS += $(shell $(SDLCONFIG) --cflags) + ifeq ($(OSX_BUILD),1) + # on OSX at least the homebrew version of sdl-config gives include path as `.../include/SDL2` instead of `.../include` + OSX_PREFIX := $(shell $(SDLCONFIG) --prefix) + BACKEND_CFLAGS += -I$(OSX_PREFIX)/include $(shell $(SDLCONFIG) --cflags) + else + BACKEND_CFLAGS += $(shell $(SDLCONFIG) --cflags) + endif ifeq ($(WINDOWS_BUILD),1) BACKEND_LDFLAGS += $(shell $(SDLCONFIG) --static-libs) -lsetupapi -luser32 -limm32 -lole32 -loleaut32 -lshell32 -lwinmm -lversion else @@ -662,10 +671,17 @@ else ifeq ($(TARGET_RPI),1) else ifeq ($(OSX_BUILD),1) LDFLAGS := -lm $(PLATFORM_LDFLAGS) $(BACKEND_LDFLAGS) -lpthread +else ifeq ($(HOST_OS),Haiku) + LDFLAGS := $(BACKEND_LDFLAGS) -no-pie + else - LDFLAGS := $(BITS) -march=$(TARGET_ARCH) -lm $(BACKEND_LDFLAGS) -no-pie -lpthread + LDFLAGS := $(BITS) -march=$(TARGET_ARCH) -lm $(BACKEND_LDFLAGS) -lpthread -ldl + ifeq ($(NO_PIE), 1) + LDFLAGS += -no-pie + endif + ifeq ($(DISCORDRPC),1) - LDFLAGS += -ldl -Wl,-rpath . + LDFLAGS += -Wl,-rpath . endif endif # End of LDFLAGS diff --git a/README.md b/README.md index 1a99617f..47a4904a 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Run `./extract_assets.py --clean && make clean` or `make distclean` to remove RO Please contribute **first** to the [nightly branch](https://github.com/sm64pc/sm64ex/tree/nightly/). New functionality will be merged to master once they're considered to be well-tested. -*Read this in other languages: [Español](README_es_ES.md), [Português](README_pt_BR.md) or [简体中文](README_zh_CN.md).* +*Read this in other languages: [Español](README_es_ES.md), [Português](README_pt_BR.md), [简体中文](README_zh_CN.md) or [Bahasa Melayu](README_ms_MY.md).* ## New features diff --git a/README_es_ES.md b/README_es_ES.md index 44a34a1c..1382d88b 100644 --- a/README_es_ES.md +++ b/README_es_ES.md @@ -155,6 +155,11 @@ sudo xbps-install -S base-devel python3 audiofile-devel SDL2-devel glew-devel sudo xbps-install -S base-devel python3 audiofile-devel-32bit SDL2-devel-32bit glew-devel-32bit ``` +##### Alpine Linux - (compilando para 32 bits y 64 bits) +``` +sudo apk add build-base python3 audiofile-dev sdl2-dev glew-dev +``` + #### Compila el ejecutable. Ejecuta `make` para compilar (por defecto `VERSION=us`) diff --git a/README_ms_MY.md b/README_ms_MY.md new file mode 100644 index 00000000..c8709bb6 --- /dev/null +++ b/README_ms_MY.md @@ -0,0 +1,30 @@ +# sm64ex +Fork dari [sm64-port/sm64-port](https://github.com/sm64-port/sm64-port) dengan ciri tambahan. + +Jangan ragu-ragu untuk melaporkan pepijat dan memberi sumbangan, tetapi ingat, tidak boleh **memuat naik aset berhak cipta**. +Jalankan `./extract_assets.py --clean && make clean` atau `make distclean` untuk membuang kandungan yang berasal dari ROM. + +Sila sumbangkan **dahulu** ke [nightly branch](https://github.com/sm64pc/sm64ex/tree/nightly/). Fungsi baru akan digabungkan ke master setelah siap diuji. + +*Baca ini dalam bahasa lain: [Español](README_es_ES.md), [Português](README_pt_BR.md), [简体中文](README_zh_CN.md) atau [Bahasa Melayu](README_ms_MY.md).* + +## Ciri-ciri baru + + * Menu pilihan dengan pelbagai tetapan, termasuk pemetaan semula butang. + * Pilihan untuk pemuatan data luaran (setakat ini hanya tekstur dan papan suara yang dipasang), memberikan sokongan untuk pek tekstur tersuai. + * Pilihan untuk rupa kamera analog dan tetikus (menggunakan [Puppycam](https://github.com/FazanaJ/puppycam)). + * Pilihan untuk perender berasaskan OpenGL1.3 untuk mesin yang lebih tua, serta perender asli GL2.1, D3D11 dan D3D12 dari Emill's [n64-fast3d-engine](https://github.com/Emill/n64-fast3d-engine/). + * Pilihan untuk menyahaktifkan jarak lukisan. + * Pilihan untuk pembaikan model dan tekstur (mis. Tekstur asap). + * Langkau cutscenes pengenalan Peach & Lakitu dengan pilihan CLI `--skip-intro`. + * Menu cheats di Options (aktifkan dengan `--cheats` atau dengan menekan L tiga kali di menu pause). + * Sokongan untuk kedua-dua fail simpanan little-endian dan big-endian (bermaksud anda boleh menggunakan fail simpan dari sm64-port dan kebanyakan emulator), serta format simpanan berasaskan teks pilihan. + +Perubahan terbaru di Nightly telah memindahkan laluan fail simpan dan konfigurasi ke `%HOMEPATH%\AppData\Roaming\sm64pc` pada Windows dan `$HOME/.local/share/sm64pc` di Linux. Tingkah laku ini dapat diubah dengan `--savepath` pilihan CLI. +For example `--savepath .` akan membaca simpanan dari direktori semasa (yang tidak selalu sepadan dengan direktori exe, tetapi selalunya ia berlaku); + `--savepath '!'` akan membaca simpanan dari direktori executable. + +## Pembangunan +Untuk arahan pembangunan, sila rujuk di [wiki](https://github.com/sm64pc/sm64ex/wiki). + +**Pastikan anda mempunyai MXE terlebih dahulu sebelum cuba compile untuk Windows di Linux dan WSL. Ikuti panduan di wiki.** diff --git a/enhancements/60fps_ex.patch b/enhancements/60fps_ex.patch index 5980d9bf..f2f79f22 100644 --- a/enhancements/60fps_ex.patch +++ b/enhancements/60fps_ex.patch @@ -232,18 +232,19 @@ index 1da535b..49a5c03 100644 break; } diff --git a/src/engine/surface_load.c b/src/engine/surface_load.c -index ac2ee50..323b7d0 100644 +index ac2ee50..ce5fd37 100644 --- a/src/engine/surface_load.c +++ b/src/engine/surface_load.c -@@ -14,6 +14,7 @@ +@@ -14,6 +14,8 @@ #include "game/mario.h" #include "game/object_list_processor.h" #include "surface_load.h" +#include "game/game_init.h" ++#include "math_util.h" s32 unused8038BE90; -@@ -359,6 +360,11 @@ static struct Surface *read_surface_data(s16 *vertexData, s16 **vertexIndices) { +@@ -359,6 +361,11 @@ static struct Surface *read_surface_data(s16 *vertexData, s16 **vertexIndices) { surface = alloc_surface(); @@ -388,10 +389,19 @@ index 173ab8a..b1abdc4 100644 // bss order hack to not affect BSS order. if possible, remove me, but it will be hard to match otherwise diff --git a/src/game/envfx_bubbles.c b/src/game/envfx_bubbles.c -index 16a9272..ee1b029 100644 +index 16a9272..500e796 100644 --- a/src/game/envfx_bubbles.c +++ b/src/game/envfx_bubbles.c -@@ -35,6 +35,20 @@ Vtx_t gBubbleTempVtx[3] = { +@@ -11,6 +11,8 @@ + #include "audio/external.h" + #include "textures.h" + ++extern void interpolate_vectors_s16(Vec3s res, Vec3s a, Vec3s b); ++ + /** + * This file implements environment effects that are not snow: + * Flowers (unused), lava bubbles and jet stream/whirlpool bubbles. +@@ -35,6 +37,20 @@ Vtx_t gBubbleTempVtx[3] = { { { 0, 0, 0 }, 0, { -498, 964 }, { 0xFF, 0xFF, 0xFF, 0xFF } }, }; @@ -412,7 +422,7 @@ index 16a9272..ee1b029 100644 /** * Check whether the particle with the given index is * laterally within distance of point (x, z). Used to -@@ -241,6 +255,7 @@ void envfx_update_whirlpool(void) { +@@ -241,6 +257,7 @@ void envfx_update_whirlpool(void) { (gEnvFxBuffer + i)->yPos = (i + gEnvFxBuffer)->bubbleY; (gEnvFxBuffer + i)->unusedBubbleVar = 0; (gEnvFxBuffer + i)->isAlive = 1; @@ -420,7 +430,7 @@ index 16a9272..ee1b029 100644 envfx_rotate_around_whirlpool(&(gEnvFxBuffer + i)->xPos, &(gEnvFxBuffer + i)->yPos, &(gEnvFxBuffer + i)->zPos); -@@ -299,6 +314,7 @@ void envfx_update_jetstream(void) { +@@ -299,6 +316,7 @@ void envfx_update_jetstream(void) { + coss((gEnvFxBuffer + i)->angleAndDist[0]) * (gEnvFxBuffer + i)->angleAndDist[1]; (gEnvFxBuffer + i)->yPos = gEnvFxBubbleConfig[ENVFX_STATE_SRC_Y] + (random_float() * 400.0f - 200.0f); @@ -428,7 +438,7 @@ index 16a9272..ee1b029 100644 } else { (gEnvFxBuffer + i)->angleAndDist[1] += 10; (gEnvFxBuffer + i)->xPos += sins((gEnvFxBuffer + i)->angleAndDist[0]) * 10.0f; -@@ -506,6 +522,12 @@ Gfx *envfx_update_bubble_particles(s32 mode, UNUSED Vec3s marioPos, Vec3s camFro +@@ -506,6 +524,12 @@ Gfx *envfx_update_bubble_particles(s32 mode, UNUSED Vec3s marioPos, Vec3s camFro Vec3s vertex1; Vec3s vertex2; Vec3s vertex3; @@ -441,7 +451,7 @@ index 16a9272..ee1b029 100644 Gfx *gfxStart; -@@ -521,18 +543,52 @@ Gfx *envfx_update_bubble_particles(s32 mode, UNUSED Vec3s marioPos, Vec3s camFro +@@ -521,18 +545,52 @@ Gfx *envfx_update_bubble_particles(s32 mode, UNUSED Vec3s marioPos, Vec3s camFro envfx_bubbles_update_switch(mode, camTo, vertex1, vertex2, vertex3); rotate_triangle_vertices(vertex1, vertex2, vertex3, pitch, yaw); @@ -1821,7 +1831,7 @@ index b49ddaf..d6656af 100644 switch (transType) { case WARP_TRANSITION_FADE_FROM_COLOR: diff --git a/src/menu/intro_geo.c b/src/menu/intro_geo.c -index 37c6752..d823d40 100644 +index 37c6752..7499b1f 100644 --- a/src/menu/intro_geo.c +++ b/src/menu/intro_geo.c @@ -1,5 +1,6 @@ @@ -1831,7 +1841,16 @@ index 37c6752..d823d40 100644 #include "game/memory.h" #include "game/segment2.h" #include "game/segment7.h" -@@ -70,6 +71,18 @@ s8 gameOverBackgroundTable[] = { +@@ -26,6 +27,8 @@ struct GraphNodeMore { + /*0x18*/ u32 unk18; + }; + ++extern void interpolate_vectors(Vec3f res, Vec3f a, Vec3f b); ++ + // intro geo bss + s32 gGameOverFrameCounter; + s32 gGameOverTableIndex; +@@ -70,6 +73,18 @@ s8 gameOverBackgroundTable[] = { s8 gameOverBackgroundFlipOrder[] = { 0x00, 0x01, 0x02, 0x03, 0x07, 0x0B, 0x0a, 0x09, 0x08, 0x04, 0x05, 0x06 }; @@ -1850,7 +1869,7 @@ index 37c6752..d823d40 100644 Gfx *geo_title_screen(s32 sp50, struct GraphNode *sp54, UNUSED void *context) { struct GraphNode *graphNode; // sp4c Gfx *displayList; // sp48 -@@ -80,6 +93,8 @@ Gfx *geo_title_screen(s32 sp50, struct GraphNode *sp54, UNUSED void *context) { +@@ -80,6 +95,8 @@ Gfx *geo_title_screen(s32 sp50, struct GraphNode *sp54, UNUSED void *context) { f32 scaleX; // sp34 f32 scaleY; // sp30 f32 scaleZ; // sp2c @@ -1859,7 +1878,7 @@ index 37c6752..d823d40 100644 graphNode = sp54; displayList = NULL; displayListIter = NULL; -@@ -110,7 +125,11 @@ Gfx *geo_title_screen(s32 sp50, struct GraphNode *sp54, UNUSED void *context) { +@@ -110,7 +127,11 @@ Gfx *geo_title_screen(s32 sp50, struct GraphNode *sp54, UNUSED void *context) { scaleY = 0.0f; scaleZ = 0.0f; } @@ -1890,31 +1909,18 @@ index 0467495..fa4eb33 100644 using namespace Microsoft::WRL; // For ComPtr diff --git a/src/pc/gfx/gfx_sdl2.c b/src/pc/gfx/gfx_sdl2.c -index 0108ca9..28d56ac 100644 +index 243a704..193a245 100644 --- a/src/pc/gfx/gfx_sdl2.c +++ b/src/pc/gfx/gfx_sdl2.c -@@ -150,7 +150,11 @@ static inline void gfx_sdl_set_vsync(const bool enabled) { - if (enabled) { - // try to detect refresh rate - SDL_GL_SetSwapInterval(1); -- const int vblanks = gCLIOpts.SyncFrames ? (int)gCLIOpts.SyncFrames : test_vsync(); -+ int vblanks = test_vsync(); -+ if (vblanks & 1) -+ vblanks = 0; // not divisible by 60, fuck that -+ else -+ vblanks /= 2; - if (vblanks) { - printf("determined swap interval: %d\n", vblanks); - SDL_GL_SetSwapInterval(vblanks); -@@ -233,7 +237,7 @@ static void gfx_sdl_init(const char *window_title) { - gfx_sdl_set_fullscreen(); +@@ -181,7 +181,7 @@ static void gfx_sdl_init(const char *window_title) { perf_freq = SDL_GetPerformanceFrequency(); -- frame_time = perf_freq / FRAMERATE; -+ frame_time = perf_freq / (2 * FRAMERATE); + +- frame_rate = perf_freq / FRAMERATE; ++ frame_rate = perf_freq / (2 * FRAMERATE); + frame_time = SDL_GetPerformanceCounter(); for (size_t i = 0; i < sizeof(windows_scancode_table) / sizeof(SDL_Scancode); i++) { - inverted_scancode_table[windows_scancode_table[i]] = i; diff --git a/src/pc/pc_main.c b/src/pc/pc_main.c index 923e7ea..4fe6161 100644 --- a/src/pc/pc_main.c diff --git a/include/PR/os_libc.h b/include/PR/os_libc.h index 9eb872e7..05ab6682 100644 --- a/include/PR/os_libc.h +++ b/include/PR/os_libc.h @@ -5,7 +5,7 @@ // old bstring functions that aren't present on some platforms -#if defined(__APPLE__) +#if defined(__APPLE__) || defined(__HAIKU__) // macOS libc has them #include diff --git a/src/pc/cliopts.c b/src/pc/cliopts.c index 74a42e86..b01ef685 100644 --- a/src/pc/cliopts.c +++ b/src/pc/cliopts.c @@ -61,9 +61,6 @@ void parse_cli_opts(int argc, char* argv[]) { else if (strcmp(argv[i], "--poolsize") == 0) // Main pool size arg_uint("--poolsize", argv[++i], &gCLIOpts.PoolSize); - else if (strcmp(argv[i], "--syncframes") == 0) // VBlanks to wait - arg_uint("--syncframes", argv[++i], &gCLIOpts.SyncFrames); - else if (strcmp(argv[i], "--configfile") == 0 && (i + 1) < argc) arg_string("--configfile", argv[++i], gCLIOpts.ConfigFile); diff --git a/src/pc/cliopts.h b/src/pc/cliopts.h index 413c2457..a0281e22 100644 --- a/src/pc/cliopts.h +++ b/src/pc/cliopts.h @@ -7,7 +7,6 @@ struct PCCLIOptions { unsigned int SkipIntro; unsigned int FullScreen; unsigned int PoolSize; - unsigned int SyncFrames; char ConfigFile[SYS_MAX_PATH]; char SavePath[SYS_MAX_PATH]; char GameDir[SYS_MAX_PATH]; diff --git a/src/pc/controller/controller_sdl2.c b/src/pc/controller/controller_sdl2.c index a71a82eb..c7e9c7c7 100644 --- a/src/pc/controller/controller_sdl2.c +++ b/src/pc/controller/controller_sdl2.c @@ -89,13 +89,6 @@ static void controller_sdl_bind(void) { } static void controller_sdl_init(void) { - if (SDL_Init(SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS) != 0) { - fprintf(stderr, "SDL init error: %s\n", SDL_GetError()); - return; - } - - haptics_enabled = (SDL_InitSubSystem(SDL_INIT_HAPTIC) == 0); - // try loading an external gamecontroller mapping file uint64_t gcsize = 0; void *gcdata = fs_load_file("gamecontrollerdb.txt", &gcsize); @@ -109,6 +102,13 @@ static void controller_sdl_init(void) { free(gcdata); } + if (SDL_Init(SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS) != 0) { + fprintf(stderr, "SDL init error: %s\n", SDL_GetError()); + return; + } + + haptics_enabled = (SDL_InitSubSystem(SDL_INIT_HAPTIC) == 0); + #ifdef BETTERCAMERA if (newcam_mouse == 1) SDL_SetRelativeMouseMode(SDL_TRUE); diff --git a/src/pc/gfx/gfx_sdl2.c b/src/pc/gfx/gfx_sdl2.c index f808db90..243a7043 100644 --- a/src/pc/gfx/gfx_sdl2.c +++ b/src/pc/gfx/gfx_sdl2.c @@ -54,7 +54,9 @@ static void (*kb_all_keys_up)(void) = NULL; // whether to use timer for frame control static bool use_timer = true; // time between consequtive game frames, in perf counter ticks -static double frame_time = 0.0; // set in init() +static double frame_rate = 0.0; // set in init() +// time in which a frame began, in perf counter ticks +static double frame_time = 0.0; // updated in start_frame() // GetPerformanceFrequency static double perf_freq = 0.0; @@ -110,61 +112,6 @@ const SDL_Scancode scancode_rmapping_nonextended[][2] = { #define IS_FULLSCREEN() ((SDL_GetWindowFlags(wnd) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0) -static inline void sys_sleep(const uint64_t us) { - // TODO: not everything has usleep() - usleep(us); -} - -static int test_vsync(void) { - // Even if SDL_GL_SetSwapInterval succeeds, it doesn't mean that VSync actually works. - // A 60 Hz monitor should have a swap interval of 16.67 milliseconds. - // Try to detect the length of a vsync by swapping buffers some times. - // Since the graphics card may enqueue a fixed number of frames, - // first send in four dummy frames to hopefully fill the queue. - // This method will fail if the refresh rate is changed, which, in - // combination with that we can't control the queue size (i.e. lag) - // is a reason this generic SDL2 backend should only be used as last resort. - - for (int i = 0; i < 8; ++i) - SDL_GL_SwapWindow(wnd); - - Uint32 start = SDL_GetTicks(); - SDL_GL_SwapWindow(wnd); - SDL_GL_SwapWindow(wnd); - SDL_GL_SwapWindow(wnd); - SDL_GL_SwapWindow(wnd); - Uint32 end = SDL_GetTicks(); - - const float average = 4.0 * 1000.0 / (end - start); - - if (average > 27.0f && average < 33.0f) return 1; - if (average > 57.0f && average < 63.0f) return 2; - if (average > 86.0f && average < 94.0f) return 3; - if (average > 115.0f && average < 125.0f) return 4; - if (average > 234.0f && average < 246.0f) return 8; - - return 0; -} - -static inline void gfx_sdl_set_vsync(const bool enabled) { - if (enabled) { - // try to detect refresh rate - SDL_GL_SetSwapInterval(1); - const int vblanks = gCLIOpts.SyncFrames ? (int)gCLIOpts.SyncFrames : test_vsync(); - if (vblanks) { - printf("determined swap interval: %d\n", vblanks); - SDL_GL_SetSwapInterval(vblanks); - use_timer = false; - return; - } else { - printf("could not determine swap interval, falling back to timer sync\n"); - } - } - - use_timer = true; - SDL_GL_SetSwapInterval(0); -} - static void gfx_sdl_set_fullscreen(void) { if (configWindow.reset) configWindow.fullscreen = false; @@ -200,7 +147,7 @@ static void gfx_sdl_reset_dimension_and_pos(void) { SDL_SetWindowSize(wnd, configWindow.w, configWindow.h); SDL_SetWindowPosition(wnd, xpos, ypos); // in case vsync changed - gfx_sdl_set_vsync(configWindow.vsync); + SDL_GL_SetSwapInterval(configWindow.vsync); } static void gfx_sdl_init(const char *window_title) { @@ -228,12 +175,14 @@ static void gfx_sdl_init(const char *window_title) { ); ctx = SDL_GL_CreateContext(wnd); - gfx_sdl_set_vsync(configWindow.vsync); + SDL_GL_SetSwapInterval(configWindow.vsync); gfx_sdl_set_fullscreen(); perf_freq = SDL_GetPerformanceFrequency(); - frame_time = perf_freq / FRAMERATE; + + frame_rate = perf_freq / FRAMERATE; + frame_time = SDL_GetPerformanceCounter(); for (size_t i = 0; i < sizeof(windows_scancode_table) / sizeof(SDL_Scancode); i++) { inverted_scancode_table[windows_scancode_table[i]] = i; @@ -338,35 +287,34 @@ static bool gfx_sdl_start_frame(void) { } static inline void sync_framerate_with_timer(void) { - static double last_time; - static double last_sec; - static int frames_since_last_sec; + // calculate how long it took for the frame to render const double now = SDL_GetPerformanceCounter(); - frames_since_last_sec += 1; - if (last_time) { - const double elapsed = last_sec ? (now - last_sec) : (now - last_time); - if ((elapsed < frame_time && !last_sec) || (elapsed < frames_since_last_sec * frame_time && last_sec)) { - const double delay = last_sec ? frames_since_last_sec * frame_time - elapsed : frame_time - elapsed; - sys_sleep(delay / perf_freq * 1000000.0); - last_time = now + delay; - } else { - last_time = now; - } - if ((int64_t)(now / perf_freq) > (int64_t)(last_sec / perf_freq)) { - last_sec = last_time; - frames_since_last_sec = 0; - } + const double frame_length = now - frame_time; + + if (frame_length < frame_rate) { + // Only sleep if we have time to spare + const double remain = frame_rate - frame_length; + // Sleep remaining time away + sys_sleep(remain / perf_freq * 1000000.0); + // Assume we slept the required amount of time to keep the timer stable + frame_time = now + remain; } else { - last_time = now; + frame_time = now; } } static void gfx_sdl_swap_buffers_begin(void) { - if (use_timer) sync_framerate_with_timer(); + // Swap after we finished rendering, only if this frame wasn't dropped. + // This will wait for vblank if vsync is enabled and then update our window with our render. SDL_GL_SwapWindow(wnd); } static void gfx_sdl_swap_buffers_end(void) { + // The game isn't always going to run at a consistent rate, + // with frame pacing going up and down depending on hardware performance. + // Sleep off any remaining time to make the main loop iteration be called at a consistent frane rate. + // We do this after our swap, because it actually will take the time to swap into account. + sync_framerate_with_timer(); } static double gfx_sdl_get_time(void) { diff --git a/src/pc/platform.c b/src/pc/platform.c index e68370a4..d984ca48 100644 --- a/src/pc/platform.c +++ b/src/pc/platform.c @@ -4,10 +4,12 @@ #include #include #include +#include #include "cliopts.h" #include "fs/fs.h" #include "configfile.h" +#include "platform.h" /* NULL terminated list of platform specific read-only data paths */ /* priority is top first */ @@ -66,6 +68,11 @@ const char *sys_file_name(const char *fpath) { return sep + 1; } +void sys_sleep(const uint64_t us) { + // TODO: figure out which of the platforms we want to support DOESN'T have usleep() + usleep(us); +} + /* this calls a platform-specific impl function after forming the error message */ static void sys_fatal_impl(const char *msg) __attribute__ ((noreturn)); diff --git a/src/pc/platform.h b/src/pc/platform.h index 168333d1..0a26b461 100644 --- a/src/pc/platform.h +++ b/src/pc/platform.h @@ -2,6 +2,7 @@ #define _SM64_PLATFORM_H_ #include +#include #include #include @@ -16,6 +17,7 @@ extern const char *sys_ropaths[]; char *sys_strdup(const char *src); char *sys_strlwr(char *src); int sys_strcasecmp(const char *s1, const char *s2); +void sys_sleep(const uint64_t us); // path stuff const char *sys_user_path(void); diff --git a/tools/aiff_extract_codebook.c b/tools/aiff_extract_codebook.c index 481e3133..6570fa59 100644 --- a/tools/aiff_extract_codebook.c +++ b/tools/aiff_extract_codebook.c @@ -26,6 +26,11 @@ typedef unsigned int u32; #define NORETURN __attribute__((noreturn)) #define UNUSED __attribute__((unused)) +#ifdef __APPLE__ +// even with -std=gnu99 vsnprintf seems to not be defined in stdio.h, why? +extern int vsnprintf(char * __restrict, size_t, const char * __restrict, va_list); +#endif + typedef struct { u32 start;