From 6b468f44f62cca6224eb8eb2d384640f43205b0b Mon Sep 17 00:00:00 2001 From: uncletrunks Date: Sun, 17 May 2020 11:03:02 -0500 Subject: [PATCH 1/4] fix for issue #149 --- src/game/spawn_object.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/game/spawn_object.c b/src/game/spawn_object.c index 5e416584..cc15c8e9 100644 --- a/src/game/spawn_object.c +++ b/src/game/spawn_object.c @@ -196,6 +196,7 @@ void unload_object(struct Object *obj) { geo_add_child(&gObjParentGraphNode, &obj->header.gfx.node); obj->header.gfx.node.flags &= ~GRAPH_RENDER_BILLBOARD; + obj->header.gfx.node.flags &= ~GRAPH_RENDER_CYLBOARD; obj->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE; deallocate_object(&gFreeObjectList, &obj->header); From 58dbb04f97ba1d418f5f05adad177221b26888e3 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sun, 17 May 2020 19:42:46 +0300 Subject: [PATCH 2/4] update gfx_sdl2.c with the latest stuff from Emill/n64-fast3d-engine --- src/pc/gfx/gfx_sdl2.c | 121 +++++++++++++++++++++++++++++------------- 1 file changed, 83 insertions(+), 38 deletions(-) diff --git a/src/pc/gfx/gfx_sdl2.c b/src/pc/gfx/gfx_sdl2.c index 846ce383..9c51e710 100644 --- a/src/pc/gfx/gfx_sdl2.c +++ b/src/pc/gfx/gfx_sdl2.c @@ -24,17 +24,28 @@ #include "gfx_window_manager_api.h" #include "gfx_screen_config.h" +#include "../pc_main.h" #include "../configfile.h" #include "../cliopts.h" #include "src/pc/controller/controller_keyboard.h" +// TODO: figure out if this shit even works +#ifdef VERSION_EU +# define FRAMERATE 25 +#else +# define FRAMERATE 30 +#endif + static SDL_Window *wnd; static SDL_GLContext ctx = NULL; static int inverted_scancode_table[512]; -static bool cur_fullscreen; -static uint32_t cur_width, cur_height; +static bool window_fullscreen; +static bool window_vsync; +static int window_width, window_height; + +static Uint64 frame_time = 0; const SDL_Scancode windows_scancode_table[] = { @@ -88,22 +99,42 @@ const SDL_Scancode scancode_rmapping_nonextended[][2] = { }; static void gfx_sdl_set_fullscreen(bool fullscreen) { - if (fullscreen == cur_fullscreen) return; + if (fullscreen == window_fullscreen) return; if (fullscreen) { SDL_SetWindowFullscreen(wnd, SDL_WINDOW_FULLSCREEN_DESKTOP); SDL_ShowCursor(SDL_DISABLE); + SDL_GetWindowSize(wnd, &window_width, &window_height); } else { SDL_SetWindowFullscreen(wnd, 0); SDL_ShowCursor(SDL_ENABLE); + window_width = DESIRED_SCREEN_WIDTH; + window_height = DESIRED_SCREEN_HEIGHT; + SDL_SetWindowSize(wnd, window_width, window_height); } - cur_fullscreen = fullscreen; + window_fullscreen = fullscreen; +} + +static bool 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. + // If it takes less than 12 milliseconds, assume that VSync is not working. + // SDL_GetTicks() probably does not offer enough precision for this kind of shit. + Uint32 start, end; + + // do an extra swap, sometimes the first one takes longer (maybe creates buffers?) + SDL_GL_SwapWindow(wnd); + + SDL_GL_SwapWindow(wnd); + start = SDL_GetTicks(); + SDL_GL_SwapWindow(wnd); + end = SDL_GetTicks(); + + return (end - start >= 12); } static void gfx_sdl_init(void) { - Uint32 window_flags = 0; - SDL_Init(SDL_INIT_VIDEO); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); @@ -118,47 +149,47 @@ static void gfx_sdl_init(void) { //SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); //SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); - window_flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE; - - if (gCLIOpts.FullScreen) { + if (gCLIOpts.FullScreen) configFullscreen = true; - } - if (configFullscreen) { - window_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; - } - - SDL_DisplayMode sdl_displaymode; - SDL_GetCurrentDisplayMode(0, &sdl_displaymode); - - const char* window_title = + const char* window_title = #ifndef USE_GLES "Super Mario 64 PC port (OpenGL)"; #else "Super Mario 64 PC port (OpenGL_ES2)"; #endif + Uint32 window_flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE; + + window_width = DESIRED_SCREEN_WIDTH; + window_height = DESIRED_SCREEN_HEIGHT; + window_fullscreen = configFullscreen; + if (configFullscreen) { - wnd = SDL_CreateWindow(window_title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - sdl_displaymode.w, sdl_displaymode.h, window_flags); + window_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; SDL_ShowCursor(SDL_DISABLE); } else { - wnd = SDL_CreateWindow(window_title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - DESIRED_SCREEN_WIDTH, DESIRED_SCREEN_HEIGHT, window_flags); SDL_ShowCursor(SDL_ENABLE); } - SDL_GL_CreateContext(wnd); - SDL_GL_SetSwapInterval(1); // We have a double buffered GL context, it makes no sense to want tearing. + wnd = SDL_CreateWindow(window_title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, + window_width, window_height, window_flags); + + ctx = SDL_GL_CreateContext(wnd); + SDL_GL_SetSwapInterval(2); + + window_vsync = test_vsync(); + if (!window_vsync) + printf("Warning: VSync is not enabled or not working. Falling back to timer for synchronization\n"); for (size_t i = 0; i < sizeof(windows_scancode_table) / sizeof(SDL_Scancode); i++) { inverted_scancode_table[windows_scancode_table[i]] = i; } - + for (size_t i = 0; i < sizeof(scancode_rmapping_extended) / sizeof(scancode_rmapping_extended[0]); i++) { inverted_scancode_table[scancode_rmapping_extended[i][0]] = inverted_scancode_table[scancode_rmapping_extended[i][1]] + 0x100; } - + for (size_t i = 0; i < sizeof(scancode_rmapping_nonextended) / sizeof(scancode_rmapping_nonextended[0]); i++) { inverted_scancode_table[scancode_rmapping_nonextended[i][0]] = inverted_scancode_table[scancode_rmapping_nonextended[i][1]]; inverted_scancode_table[scancode_rmapping_nonextended[i][1]] += 0x100; @@ -166,20 +197,13 @@ static void gfx_sdl_init(void) { } static void gfx_sdl_main_loop(void (*run_one_game_iter)(void)) { - int t; - while (1) { - t = SDL_GetTicks(); + while (1) run_one_game_iter(); - t = SDL_GetTicks() - t; - - if (t < 1000 / 30) { - SDL_Delay ((1000 / 30) - t); - } - } } static void gfx_sdl_get_dimensions(uint32_t *width, uint32_t *height) { - SDL_GetWindowSize(wnd, width, height); + *width = window_width; + *height = window_height; } static int translate_scancode(int scancode) { @@ -218,12 +242,19 @@ static void gfx_sdl_handle_events(void) { gfx_sdl_onkeyup(event.key.keysym.scancode); break; #endif + case SDL_WINDOWEVENT: + if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { + window_width = event.window.data1; + window_height = event.window.data2; + } + break; case SDL_QUIT: - exit(0); + game_exit(); + break; } } // just check if the fullscreen value has changed and toggle fullscreen if it has - if (configFullscreen != cur_fullscreen) + if (configFullscreen != window_fullscreen) gfx_sdl_set_fullscreen(configFullscreen); } @@ -231,7 +262,21 @@ static bool gfx_sdl_start_frame(void) { return true; } +static void sync_framerate_with_timer(void) { + // Number of milliseconds a frame should take (30 fps) + const Uint32 FRAME_TIME = 1000 / FRAMERATE; + static Uint32 last_time; + + Uint32 elapsed = SDL_GetTicks() - last_time; + if (elapsed < FRAME_TIME) + SDL_Delay(FRAME_TIME - elapsed); + + last_time = SDL_GetTicks(); +} + static void gfx_sdl_swap_buffers_begin(void) { + if (!window_vsync) + sync_framerate_with_timer(); SDL_GL_SwapWindow(wnd); } From 62cc4620ec75a1395398515189f5e9d1f050d01e Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sun, 17 May 2020 19:56:17 +0300 Subject: [PATCH 3/4] no need for that, window resize events happen when fullscreen state changes --- src/pc/gfx/gfx_sdl2.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/pc/gfx/gfx_sdl2.c b/src/pc/gfx/gfx_sdl2.c index 9c51e710..b73b6aeb 100644 --- a/src/pc/gfx/gfx_sdl2.c +++ b/src/pc/gfx/gfx_sdl2.c @@ -45,8 +45,6 @@ static bool window_fullscreen; static bool window_vsync; static int window_width, window_height; -static Uint64 frame_time = 0; - const SDL_Scancode windows_scancode_table[] = { /* 0 1 2 3 4 5 6 7 */ @@ -104,10 +102,10 @@ static void gfx_sdl_set_fullscreen(bool fullscreen) { if (fullscreen) { SDL_SetWindowFullscreen(wnd, SDL_WINDOW_FULLSCREEN_DESKTOP); SDL_ShowCursor(SDL_DISABLE); - SDL_GetWindowSize(wnd, &window_width, &window_height); } else { SDL_SetWindowFullscreen(wnd, 0); SDL_ShowCursor(SDL_ENABLE); + // reset back to small window just in case window_width = DESIRED_SCREEN_WIDTH; window_height = DESIRED_SCREEN_HEIGHT; SDL_SetWindowSize(wnd, window_width, window_height); @@ -161,8 +159,6 @@ static void gfx_sdl_init(void) { Uint32 window_flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE; - window_width = DESIRED_SCREEN_WIDTH; - window_height = DESIRED_SCREEN_HEIGHT; window_fullscreen = configFullscreen; if (configFullscreen) { @@ -173,11 +169,14 @@ static void gfx_sdl_init(void) { } wnd = SDL_CreateWindow(window_title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - window_width, window_height, window_flags); + DESIRED_SCREEN_WIDTH, DESIRED_SCREEN_HEIGHT, window_flags); ctx = SDL_GL_CreateContext(wnd); SDL_GL_SetSwapInterval(2); + // in case FULLSCREEN_DESKTOP set our size to god knows what + SDL_GetWindowSize(wnd, &window_width, &window_height); + window_vsync = test_vsync(); if (!window_vsync) printf("Warning: VSync is not enabled or not working. Falling back to timer for synchronization\n"); From ece7649b4bfb175d1fc0a54060c276259805414d Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sun, 17 May 2020 19:46:30 +0300 Subject: [PATCH 4/4] use a wrapper for exiting instead of just calling exit() this might also fix the webgl build issue --- src/game/level_update.c | 42 ++++++++++++------------------- src/game/mario_actions_cutscene.c | 17 ++++--------- src/game/options_menu.c | 3 ++- src/pc/pc_main.c | 39 ++++++++++++++-------------- src/pc/pc_main.h | 7 ++++++ 5 files changed, 50 insertions(+), 58 deletions(-) create mode 100644 src/pc/pc_main.h diff --git a/src/game/level_update.c b/src/game/level_update.c index 3fa795f9..052959c4 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -29,8 +29,7 @@ #include "course_table.h" #include "thread6.h" #include "../../include/libc/stdlib.h" -#include "../pc/configfile.h" -#define CONFIG_FILE "sm64config.txt" +#include "../pc/pc_main.h" #include "pc/cliopts.h" @@ -1020,36 +1019,27 @@ s32 play_mode_normal(void) { s32 play_mode_paused(void) { if (gPauseScreenMode == 0) { set_menu_mode(RENDER_PAUSE_SCREEN); - } else if (gPauseScreenMode == 1) { + } else if (gPauseScreenMode == 1) { raise_background_noise(1); gCameraMovementFlags &= ~CAM_MOVE_PAUSE_SCREEN; set_play_mode(PLAY_MODE_NORMAL); - } + } else if (gPauseScreenMode == 2) { // Exit level - else if (gPauseScreenMode == 2) { - - if (gDebugLevelSelect) { - fade_into_special_warp(-9, 1); - } - - else { - initiate_warp(LEVEL_CASTLE, 1, 0x1F, 0); - fade_into_special_warp(0, 0); - gSavedCourseNum = COURSE_NONE; - } - - } // end of gPauseScreenMode == 2 for "EXIT COURSE" option - - if (gPauseScreenMode == 3) { // We should only be getting "int 3" to here - initiate_warp(LEVEL_CASTLE, 1, 0x1F, 0); + if (gDebugLevelSelect) { + fade_into_special_warp(-9, 1); + } else { + initiate_warp(LEVEL_CASTLE, 1, 0x1F, 0); fade_into_special_warp(0, 0); + gSavedCourseNum = COURSE_NONE; + } + } else if (gPauseScreenMode == 3) { + // We should only be getting "int 3" to here + initiate_warp(LEVEL_CASTLE, 1, 0x1F, 0); + fade_into_special_warp(0, 0); + game_exit(); + } - //configfile_save(CONFIG_FILE); - exit(0); // Appears to automatically save config on exit! - } - - gCameraMovementFlags &= ~CAM_MOVE_PAUSE_SCREEN; - // } + gCameraMovementFlags &= ~CAM_MOVE_PAUSE_SCREEN; return 0; } diff --git a/src/game/mario_actions_cutscene.c b/src/game/mario_actions_cutscene.c index cf623f91..6c3a8b0a 100644 --- a/src/game/mario_actions_cutscene.c +++ b/src/game/mario_actions_cutscene.c @@ -29,8 +29,7 @@ #include "dialog_ids.h" #include "thread6.h" #include "../../include/libc/stdlib.h" -#include "../pc/configfile.h" -#define CONFIG_FILE "sm64config.txt" +#include "../pc/pc_main.h" // TODO: put this elsewhere enum SaveOption { SAVE_OPT_SAVE_AND_CONTINUE = 1, SAVE_OPT_SAVE_AND_QUIT, SAVE_OPT_SAVE_EXIT_GAME, SAVE_OPT_CONTINUE_DONT_SAVE }; @@ -263,17 +262,11 @@ void handle_save_menu(struct MarioState *m) { if (gSaveOptSelectIndex == SAVE_OPT_SAVE_AND_QUIT) { fade_into_special_warp(-2, 0); // reset game + } else if (gSaveOptSelectIndex == SAVE_OPT_SAVE_EXIT_GAME) { + //initiate_warp(LEVEL_CASTLE, 1, 0x1F, 0); + fade_into_special_warp(0, 0); + game_exit(); } - - if (gSaveOptSelectIndex == SAVE_OPT_SAVE_EXIT_GAME) { - //configfile_save(CONFIG_FILE); //Redundant, save_file implies save_config? Save config file before fully exiting - //initiate_warp(LEVEL_CASTLE, 1, 0x1F, 0); - fade_into_special_warp(0, 0); - - //fade_into_special_warp(-2, 0); // do the reset game thing - exit(0); // exit after saving game - } - } // not quitting diff --git a/src/game/options_menu.c b/src/game/options_menu.c index 59dfc23e..752a5396 100644 --- a/src/game/options_menu.c +++ b/src/game/options_menu.c @@ -16,6 +16,7 @@ #include "game/game_init.h" #include "game/ingame_menu.h" #include "game/options_menu.h" +#include "pc/pc_main.h" #include "pc/cliopts.h" #include "pc/configfile.h" #include "pc/controller/controller_api.h" @@ -161,7 +162,7 @@ struct SubMenu { /* button action functions */ static void optmenu_act_exit(UNUSED struct Option *self, s32 arg) { - if (!arg) exit(0); // only exit on A press and not directions + if (!arg) game_exit(); // only exit on A press and not directions } /* submenu option lists */ diff --git a/src/pc/pc_main.c b/src/pc/pc_main.c index c198f210..c4162c32 100644 --- a/src/pc/pc_main.c +++ b/src/pc/pc_main.c @@ -18,6 +18,7 @@ #include "audio/audio_sdl.h" #include "audio/audio_null.h" +#include "pc_main.h" #include "cliopts.h" #include "configfile.h" #include "controller/controller_api.h" @@ -46,13 +47,11 @@ void dispatch_audio_sptask(struct SPTask *spTask) { void set_vblank_handler(s32 index, struct VblankHandler *handler, OSMesgQueue *queue, OSMesg *msg) { } -static uint8_t inited = 0; +static bool inited = false; #include "game/display.h" // for gGlobalTimer void send_display_list(struct SPTask *spTask) { - if (!inited) { - return; - } + if (!inited) return; gfx_run((Gfx *)spTask->task.t.data_ptr); } @@ -92,11 +91,19 @@ void audio_shutdown(void) { } } -void game_shutdown(void) { +void game_deinit(void) { configfile_save(gCLIOpts.ConfigFile);; controller_shutdown(); audio_shutdown(); gfx_shutdown(); + inited = false; +} + +void game_exit(void) { + game_deinit(); +#ifndef TARGET_WEB + exit(0); +#endif } #ifdef TARGET_WEB @@ -128,7 +135,8 @@ static void on_anim_frame(double time) { } } - request_anim_frame(on_anim_frame); + if (inited) // only continue if the init flag is still set + request_anim_frame(on_anim_frame); } #endif @@ -138,12 +146,7 @@ void main_func(void) { gEffectsMemoryPool = mem_pool_init(0x4000, MEMORY_POOL_LEFT); configfile_load(gCLIOpts.ConfigFile); - atexit(game_shutdown); -#ifdef TARGET_WEB - emscripten_set_main_loop(em_main_loop, 0, 0); - request_anim_frame(on_anim_frame); -#endif wm_api = &gfx_sdl; rendering_api = &gfx_opengl_api; gfx_init(wm_api, rendering_api); @@ -159,16 +162,14 @@ void main_func(void) { sound_init(); thread5_game_loop(NULL); + + inited = true; + #ifdef TARGET_WEB - /*for (int i = 0; i < atoi(argv[1]); i++) { - game_loop_one_iteration(); - }*/ - inited = 1; + emscripten_set_main_loop(em_main_loop, 0, 0); + request_anim_frame(on_anim_frame); #else - inited = 1; - while (1) { - wm_api->main_loop(produce_one_frame); - } + wm_api->main_loop(produce_one_frame); #endif } diff --git a/src/pc/pc_main.h b/src/pc/pc_main.h new file mode 100644 index 00000000..00ab34be --- /dev/null +++ b/src/pc/pc_main.h @@ -0,0 +1,7 @@ +#ifndef _PC_MAIN_H +#define _PC_MAIN_H + +void game_deinit(void); +void game_exit(void); + +#endif // _PC_MAIN_H