diff --git a/port/fast3d/gfx_api.h b/port/fast3d/gfx_api.h index 1f53f0ed4..3bf8427ad 100644 --- a/port/fast3d/gfx_api.h +++ b/port/fast3d/gfx_api.h @@ -31,7 +31,7 @@ extern float gfx_current_native_aspect; // The aspect ratio of the above mode extern bool gfx_framebuffers_enabled; void gfx_init(struct GfxWindowManagerAPI* wapi, struct GfxRenderingAPI* rapi, const char* game_name, - bool start_in_fullscreen, uint32_t width, uint32_t height, + bool start_in_fullscreen, bool start_maximized, uint32_t width, uint32_t height, uint32_t posX, uint32_t posY); void gfx_destroy(void); struct GfxRenderingAPI* gfx_get_current_rendering_api(void); diff --git a/port/fast3d/gfx_pc.cpp b/port/fast3d/gfx_pc.cpp index a5c997a31..cdd0d3e3c 100644 --- a/port/fast3d/gfx_pc.cpp +++ b/port/fast3d/gfx_pc.cpp @@ -2699,10 +2699,10 @@ extern "C" void gfx_get_dimensions(uint32_t* width, uint32_t* height, int32_t* p } extern "C" void gfx_init(struct GfxWindowManagerAPI* wapi, struct GfxRenderingAPI* rapi, const char* game_name, - bool start_in_fullscreen, uint32_t width, uint32_t height, uint32_t posX, uint32_t posY) { + bool start_in_fullscreen, bool start_maximized, uint32_t width, uint32_t height, uint32_t posX, uint32_t posY) { gfx_wapi = wapi; gfx_rapi = rapi; - gfx_wapi->init(game_name, rapi->get_name(), start_in_fullscreen, width, height, posX, posY); + gfx_wapi->init(game_name, rapi->get_name(), start_in_fullscreen, start_maximized, width, height, posX, posY); gfx_rapi->init(); gfx_rapi->update_framebuffer_parameters(0, width, height, 1, false, true, true, true); gfx_current_dimensions.internal_mul = 1; diff --git a/port/fast3d/gfx_sdl2.cpp b/port/fast3d/gfx_sdl2.cpp index 07128bfcf..8e9dcfaf7 100644 --- a/port/fast3d/gfx_sdl2.cpp +++ b/port/fast3d/gfx_sdl2.cpp @@ -36,6 +36,7 @@ static bool vsync_enabled = true; static int window_width = DESIRED_SCREEN_WIDTH; static int window_height = DESIRED_SCREEN_HEIGHT; static bool fullscreen_state; +static bool maximized_state; static bool is_running = true; static void (*on_fullscreen_changed_callback)(bool is_now_fullscreen); @@ -76,6 +77,18 @@ static void set_fullscreen(bool on, bool call_callback) { } } +static void set_maximize_window(bool on) { + if (maximized_state == on) { + return; + } + maximized_state = on; + if (on) { + SDL_MaximizeWindow(wnd); + } else { + SDL_RestoreWindow (wnd); + } +} + static void gfx_sdl_get_active_window_refresh_rate(uint32_t* refresh_rate) { int display_in_use = SDL_GetWindowDisplayIndex(wnd); @@ -84,7 +97,7 @@ static void gfx_sdl_get_active_window_refresh_rate(uint32_t* refresh_rate) { *refresh_rate = mode.refresh_rate; } -static void gfx_sdl_init(const char* game_name, const char* gfx_api_name, bool start_in_fullscreen, uint32_t width, +static void gfx_sdl_init(const char* game_name, const char* gfx_api_name, bool start_in_fullscreen, bool start_maximized, uint32_t width, uint32_t height, int32_t posX, int32_t posY) { window_width = width; window_height = height; @@ -111,6 +124,7 @@ static void gfx_sdl_init(const char* game_name, const char* gfx_api_name, bool s } const Uint32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_OPENGL; + wnd = SDL_CreateWindow(title, posX, posY, window_width, window_height, flags); if (!wnd) { sysFatalError("Could not open SDL window:\n%s", SDL_GetError()); @@ -181,6 +195,7 @@ static void gfx_sdl_init(const char* game_name, const char* gfx_api_name, bool s } #endif + set_maximize_window(start_maximized); set_fullscreen(start_in_fullscreen, false); } @@ -196,6 +211,10 @@ static void gfx_sdl_set_fullscreen(bool enable) { set_fullscreen(enable, true); } +static void gfx_sdl_set_maximize_window(bool enable) { + set_maximize_window(enable); +} + static void gfx_sdl_set_cursor_visibility(bool visible) { if (visible) { SDL_ShowCursor(SDL_ENABLE); @@ -316,6 +335,7 @@ struct GfxWindowManagerAPI gfx_sdl = { gfx_sdl_close, gfx_sdl_set_fullscreen_changed_callback, gfx_sdl_set_fullscreen, + gfx_sdl_set_maximize_window, gfx_sdl_get_active_window_refresh_rate, gfx_sdl_set_cursor_visibility, gfx_sdl_get_dimensions, diff --git a/port/fast3d/gfx_window_manager_api.h b/port/fast3d/gfx_window_manager_api.h index 71886547e..44eda4160 100644 --- a/port/fast3d/gfx_window_manager_api.h +++ b/port/fast3d/gfx_window_manager_api.h @@ -5,11 +5,12 @@ #include struct GfxWindowManagerAPI { - void (*init)(const char* game_name, const char* gfx_api_name, bool start_in_fullscreen, uint32_t width, + void (*init)(const char* game_name, const char* gfx_api_name, bool start_in_fullscreen, bool start_maximized, uint32_t width, uint32_t height, int32_t posX, int32_t posY); void (*close)(void); void (*set_fullscreen_changed_callback)(void (*on_fullscreen_changed)(bool is_now_fullscreen)); void (*set_fullscreen)(bool enable); + void (*set_maximize)(bool enable); void (*get_active_window_refresh_rate)(uint32_t* refresh_rate); void (*set_cursor_visibility)(bool visible); void (*get_dimensions)(uint32_t* width, uint32_t* height, int32_t* posX, int32_t* posY); diff --git a/port/src/config.c b/port/src/config.c index b10c5e5df..b37c2e955 100644 --- a/port/src/config.c +++ b/port/src/config.c @@ -16,6 +16,7 @@ typedef enum { CFG_NONE, CFG_S32, CFG_F32, + CFG_U32, CFG_STR } configtype; @@ -27,6 +28,7 @@ struct configentry { union { struct { f32 min_f32, max_f32; }; struct { s32 min_s32, max_s32; }; + struct { u32 min_u32, max_u32; }; u32 max_str; }; } settings[CONFIG_MAX_SETTINGS]; @@ -38,11 +40,15 @@ static inline s32 configClampInt(s32 val, s32 min, s32 max) return (val < min) ? min : ((val > max) ? max : val); } -static inline f32 configClampFloat(f32 val, f32 min, f32 max) +static inline u32 configClampUInt(u32 val, u32 min, u32 max) { return (val < min) ? min : ((val > max) ? max : val); } +static inline f32 configClampFloat(f32 val, f32 min, f32 max) +{ + return (val < min) ? min : ((val > max) ? max : val); +} static inline struct configentry *configFindEntry(const char *key) { @@ -101,6 +107,17 @@ void configRegisterInt(const char *key, s32 *var, s32 min, s32 max) } } +void configRegisterUInt(const char* key, u32* var, u32 min, u32 max) +{ + struct configentry* cfg = configFindOrAddEntry(key); + if (cfg) { + cfg->type = CFG_U32; + cfg->ptr = var; + cfg->min_u32 = min; + cfg->max_u32 = max; + } +} + void configRegisterFloat(const char *key, f32 *var, f32 min, f32 max) { struct configentry *cfg = configFindOrAddEntry(key); @@ -129,21 +146,29 @@ static void configSetFromString(const char *key, const char *val) s32 tmp_s32; f32 tmp_f32; + u32 tmp_u32; switch (cfg->type) { case CFG_S32: - tmp_s32 = atoi(val); + tmp_s32 = strtol(val, NULL, 0); if (cfg->min_s32 < cfg->max_s32) { tmp_s32 = configClampInt(tmp_s32, cfg->min_s32, cfg->max_s32); } *(s32 *)cfg->ptr = tmp_s32; break; case CFG_F32: - tmp_f32 = atof(val); + tmp_f32 = strtof(val, NULL); if (cfg->min_f32 < cfg->max_f32) { tmp_f32 = configClampFloat(tmp_f32, cfg->min_f32, cfg->max_f32); } *(f32 *)cfg->ptr = tmp_f32; break; + case CFG_U32: + tmp_u32 = strtoul(val, NULL, 0); + if (cfg->min_u32 < cfg->max_u32) { + tmp_u32 = configClampUInt(tmp_u32, cfg->min_u32, cfg->max_u32); + } + *(u32*)cfg->ptr = tmp_u32; + break; case CFG_STR: strncpy(cfg->ptr, val, cfg->max_str ? cfg->max_str - 1 : 4096); break; @@ -167,6 +192,12 @@ static void configSaveEntry(struct configentry *cfg, FILE *f) } fprintf(f, "%s=%f\n", cfg->key + cfg->seclen + 1, *(f32 *)cfg->ptr); break; + case CFG_U32: + if (cfg->min_u32 < cfg->max_u32) { + *(u32*)cfg->ptr = configClampUInt(*(u32*)cfg->ptr, cfg->min_u32, cfg->max_u32); + } + fprintf(f, "%s=%u\n", cfg->key + cfg->seclen + 1, *(u32 *)cfg->ptr); + break; case CFG_STR: fprintf(f, "%s=%s\n", cfg->key + cfg->seclen + 1, (char *)cfg->ptr); break; diff --git a/port/src/main.c b/port/src/main.c index b13ddf0c1..263ef1c37 100644 --- a/port/src/main.c +++ b/port/src/main.c @@ -157,6 +157,7 @@ PD_CONSTRUCTOR static void gameConfigInit(void) configRegisterInt("Game.TickRateDivisor", &g_TickRateDiv, 0, 10); configRegisterInt("Game.SkipIntro", &g_SkipIntro, 0, 1); configRegisterInt("Game.DisableMpDeathMusic", &g_MusicDisableMpDeath, 0, 1); + configRegisterInt("Game.GEMuzzleFlashes", &g_BgunGeMuzzleFlashes, 0, 1); for (s32 j = 0; j < MAX_PLAYERS; ++j) { const s32 i = j + 1; configRegisterFloat(strFmt("Game.Player%d.FovY", i), &g_PlayerExtCfg[j].fovy, 5.f, 175.f); diff --git a/port/src/optionsmenu.c b/port/src/optionsmenu.c index e77e95322..3a22069b9 100644 --- a/port/src/optionsmenu.c +++ b/port/src/optionsmenu.c @@ -652,6 +652,19 @@ static MenuItemHandlerResult menuhandlerFullScreen(s32 operation, struct menuite return 0; } +static MenuItemHandlerResult menuhandlerMaximizeWindow(s32 operation, struct menuitem *item, union handlerdata *data) +{ + switch (operation) { + case MENUOP_GET: + return videoGetMaximizeWindow(); + case MENUOP_SET: + videoSetMaximizeWindow(data->checkbox.value); + break; + } + + return 0; +} + static MenuItemHandlerResult menuhandlerTexFilter(s32 operation, struct menuitem *item, union handlerdata *data) { switch (operation) { @@ -678,6 +691,19 @@ static MenuItemHandlerResult menuhandlerTexFilter2D(s32 operation, struct menuit return 0; } +static MenuItemHandlerResult menuhandlerGeMuzzleFlashes(s32 operation, struct menuitem *item, union handlerdata *data) +{ + switch (operation) { + case MENUOP_GET: + return g_BgunGeMuzzleFlashes; + case MENUOP_SET: + g_BgunGeMuzzleFlashes = data->checkbox.value; + break; + } + + return 0; +} + static MenuItemHandlerResult menuhandlerCenterHUD(s32 operation, struct menuitem *item, union handlerdata *data) { static const char *opts[] = { @@ -735,6 +761,14 @@ struct menuitem g_ExtendedVideoMenuItems[] = { 0, menuhandlerFullScreen, }, + { + MENUITEMTYPE_CHECKBOX, + 0, + MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)"Maximize Window", + 0, + menuhandlerMaximizeWindow, + }, { MENUITEMTYPE_CHECKBOX, 0, @@ -751,6 +785,14 @@ struct menuitem g_ExtendedVideoMenuItems[] = { 0, menuhandlerTexFilter2D, }, + { + MENUITEMTYPE_CHECKBOX, + 0, + MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)"GE64-style Muzzle Flashes", + 0, + menuhandlerGeMuzzleFlashes, + }, { MENUITEMTYPE_DROPDOWN, 0, diff --git a/port/src/video.c b/port/src/video.c index c0c2fb642..18da94fc0 100644 --- a/port/src/video.c +++ b/port/src/video.c @@ -21,6 +21,7 @@ static s32 vidWidth = 640; static s32 vidHeight = 480; static s32 vidFramebuffers = true; static s32 vidFullscreen = false; +static s32 vidMaximize = false; static s32 vidVsync = 1; static s32 vidMSAA = 1; static s32 vidFramerateLimit = 0; @@ -44,7 +45,7 @@ s32 videoInit(void) gfx_framebuffers_enabled = (bool)vidFramebuffers; gfx_msaa_level = vidMSAA; - gfx_init(wmAPI, renderingAPI, "PD", vidFullscreen, vidWidth, vidHeight, 100, 100); + gfx_init(wmAPI, renderingAPI, "PD", vidFullscreen, vidMaximize, vidWidth, vidHeight, 100, 100); if (!wmAPI->set_swap_interval(vidVsync)) { vidVsync = 0; @@ -147,6 +148,11 @@ s32 videoGetFullscreen(void) return vidFullscreen; } +s32 videoGetMaximizeWindow(void) +{ + return vidMaximize; +} + f32 videoGetAspect(void) { return gfx_current_dimensions.aspect_ratio; @@ -176,6 +182,14 @@ void videoSetFullscreen(s32 fs) } } +void videoSetMaximizeWindow(s32 fs) +{ + if (fs != vidMaximize) { + vidMaximize = !!fs; + wmAPI->set_maximize(vidMaximize); + } +} + void videoSetTextureFilter(u32 filter) { if (filter > FILTER_THREE_POINT) filter = FILTER_THREE_POINT; @@ -232,6 +246,7 @@ void videoFreeCachedTexture(const void *texptr) PD_CONSTRUCTOR static void videoConfigInit(void) { configRegisterInt("Video.DefaultFullscreen", &vidFullscreen, 0, 1); + configRegisterInt("Video.DefaultMaximize", &vidMaximize, 0, 1); configRegisterInt("Video.DefaultWidth", &vidWidth, 0, 32767); configRegisterInt("Video.DefaultHeight", &vidHeight, 0, 32767); configRegisterInt("Video.VSync", &vidVsync, -1, 10); diff --git a/src/game/activemenu.c b/src/game/activemenu.c index e0477e4b4..52924ab00 100644 --- a/src/game/activemenu.c +++ b/src/game/activemenu.c @@ -1275,7 +1275,8 @@ Gfx *amRender(Gfx *gdl) #endif #ifndef PLATFORM_N64 - if (LOCALPLAYERCOUNT() == 1) { + const s32 playercount = LOCALPLAYERCOUNT(); + if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) { gSPSetExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT); } #endif diff --git a/src/game/bondgun.c b/src/game/bondgun.c index 356952cc7..3fc0fb140 100644 --- a/src/game/bondgun.c +++ b/src/game/bondgun.c @@ -190,6 +190,10 @@ char var800700bc[][10] = { { 'x','x','x' }, // "xxx" }; +#ifndef PLATFORM_N64 +s32 g_BgunGeMuzzleFlashes = false; +#endif + #if !MATCHING || VERSION >= VERSION_NTSC_1_0 void bgunRumble(s32 handnum, s32 weaponnum) { @@ -1911,7 +1915,17 @@ void bgun0f09a6f8(struct handweaponinfo *info, s32 handnum, struct hand *hand, s if (func->flags & FUNCFLAG_NOMUZZLEFLASH) { hand->flashon = false; } else { +#ifdef PLATFORM_N64 hand->flashon = true; +#else + if (g_BgunGeMuzzleFlashes) { + if (func->type == INVENTORYFUNCTYPE_SHOOT_SINGLE || (hand->shotstotake & 1)) { + hand->flashon = true; + } + } else { + hand->flashon = true; + } +#endif } bgunStartSlide(handnum); @@ -12783,7 +12797,7 @@ Gfx *bgunDrawHud(Gfx *gdl) gdl = text0f153628(gdl); #ifndef PLATFORM_N64 - if (playercount < 2) { + if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) { gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, g_HudAlignModeR); } #endif @@ -13037,7 +13051,7 @@ Gfx *bgunDrawHud(Gfx *gdl) } #ifndef PLATFORM_N64 - if (playercount < 2) { + if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) { gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, g_HudAlignModeL); } #endif @@ -13077,7 +13091,7 @@ Gfx *bgunDrawHud(Gfx *gdl) } #ifndef PLATFORM_N64 - if (playercount < 2) { + if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) { gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, g_HudAlignModeR); } #endif diff --git a/src/game/hudmsg.c b/src/game/hudmsg.c index a71f7a4fb..fd0cd30d7 100644 --- a/src/game/hudmsg.c +++ b/src/game/hudmsg.c @@ -190,7 +190,7 @@ Gfx *hudmsgRenderMissionTimer(Gfx *gdl, u32 alpha) y = timery; #ifndef PLATFORM_N64 - if (LOCALPLAYERCOUNT() < 2) { + if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) { gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, g_HudAlignModeL); } #endif @@ -282,7 +282,7 @@ Gfx *hudmsgRenderZoomRange(Gfx *gdl, u32 alpha) y2 = y + textheight; #ifndef PLATFORM_N64 - if (playercount == 1) { + if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) { gSPSetExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT); } #endif @@ -1450,7 +1450,8 @@ Gfx *hudmsgsRender(Gfx *gdl) } #ifndef PLATFORM_N64 - if (playercount < 2 && msg->state >= HUDMSGSTATE_FADINGIN) { + const bool doaspectfix = (playercount < 2) || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL); + if (doaspectfix && msg->state >= HUDMSGSTATE_FADINGIN) { if (msg->alignh == HUDMSGALIGN_SCREENLEFT || msg->alignh == HUDMSGALIGN_LEFT) { gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, g_HudAlignModeL); } else if (msg->alignh == HUDMSGALIGN_RIGHT) { diff --git a/src/game/mplayer/scenarios/holdthebriefcase.inc b/src/game/mplayer/scenarios/holdthebriefcase.inc index 53de09f69..4441a6050 100644 --- a/src/game/mplayer/scenarios/holdthebriefcase.inc +++ b/src/game/mplayer/scenarios/holdthebriefcase.inc @@ -417,7 +417,8 @@ Gfx *htbRenderHud(Gfx *gdl) #endif #ifndef PLATFORM_N64 - if (PLAYERCOUNT() == 1) { + const s32 playercount = PLAYERCOUNT(); + if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) { gSPSetExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT); } #endif diff --git a/src/game/mplayer/scenarios/kingofthehill.inc b/src/game/mplayer/scenarios/kingofthehill.inc index ed53d37f8..050ff36b7 100644 --- a/src/game/mplayer/scenarios/kingofthehill.inc +++ b/src/game/mplayer/scenarios/kingofthehill.inc @@ -583,7 +583,8 @@ Gfx *kohRenderHud(Gfx *gdl) } #ifndef PLATFORM_N64 - if (PLAYERCOUNT() == 1) { + const s32 playercount = PLAYERCOUNT(); + if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) { gSPSetExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT); } #endif diff --git a/src/game/mplayer/scenarios/popacap.inc b/src/game/mplayer/scenarios/popacap.inc index 4e499c87e..d0cc31933 100644 --- a/src/game/mplayer/scenarios/popacap.inc +++ b/src/game/mplayer/scenarios/popacap.inc @@ -312,7 +312,8 @@ Gfx *pacRenderHud(Gfx *gdl) sprintf(text, "%d:%02d", mins, secs); #ifndef PLATFORM_N64 - if (PLAYERCOUNT() == 1) { + const s32 playercount = PLAYERCOUNT(); + if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) { gSPSetExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT); } #endif diff --git a/src/game/propobj.c b/src/game/propobj.c index 297edcbbd..c8385a858 100644 --- a/src/game/propobj.c +++ b/src/game/propobj.c @@ -20996,7 +20996,7 @@ Gfx *countdownTimerRender(Gfx *gdl) ms = (s32)floorf(value60 * 1.6666666269302f) - mins * 6000 - secs * 100; #ifndef PLATFORM_N64 - if (playercount == 1) { + if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) { gSPSetExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT); } #endif diff --git a/src/game/radar.c b/src/game/radar.c index b3366a044..f142b91a7 100644 --- a/src/game/radar.c +++ b/src/game/radar.c @@ -312,6 +312,11 @@ Gfx *radarRender(Gfx *gdl) } else if (optionsGetScreenSplit() != SCREENSPLIT_VERTICAL && playernum == 1) { g_RadarY -= 8; } +#ifndef PLATFORM_N64 + if (optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL) { + gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, g_HudAlignModeR); + } +#endif } else if (playercount >= 3) { if (playernum >= 2) { g_RadarY -= 8; diff --git a/src/include/data.h b/src/include/data.h index b6ddd6691..c2bf3a87d 100644 --- a/src/include/data.h +++ b/src/include/data.h @@ -548,6 +548,8 @@ extern s32 g_BlurFbCapTimer; extern bool g_BlurFbDirty; extern s32 g_TickRateDiv; extern s32 g_MusicDisableMpDeath; +extern s32 g_BgunGeMuzzleFlashes; + extern s32 g_NetMode; #define PLAYER_EXTCFG() g_PlayerExtCfg[g_Vars.currentplayerstats->mpindex & 3]