diff --git a/port/include/video.h b/port/include/video.h index f5bb2b52e..c15cdbf69 100644 --- a/port/include/video.h +++ b/port/include/video.h @@ -19,6 +19,7 @@ s32 videoGetNativeHeight(void); s32 videoGetWidth(void); s32 videoGetHeight(void); f32 videoGetAspect(void); +f32 videoGetPlayerFovY(void); void videoResetTextureCache(void); diff --git a/port/src/config.c b/port/src/config.c index 0404ddbb6..c1f6d64d0 100644 --- a/port/src/config.c +++ b/port/src/config.c @@ -32,6 +32,7 @@ struct configentry { { "Video.DefaultHeight", CONFIG_S32, { .s32val = 480 } }, { "Video.VSync", CONFIG_S32, { .s32val = 1 } }, { "Video.FramerateLimit", CONFIG_S32, { .s32val = 0 } }, + { "Video.FovY", CONFIG_F32, { .f32val = 60.f } }, /* Audio */ { "Audio.BufferSize", CONFIG_S32, { .s32val = 512 } }, { "Audio.QueueLimit", CONFIG_S32, { .s32val = 8192 } }, diff --git a/port/src/video.c b/port/src/video.c index 07e0fbf5d..eed3cb355 100644 --- a/port/src/video.c +++ b/port/src/video.c @@ -19,7 +19,9 @@ static bool initDone = false; static u32 dlcount = 0; static u32 frames = 0; static u32 framesPerSec = 0; -static double startTime, endTime, fpsTime; +static f64 startTime, endTime, fpsTime; + +static f32 playerFovY = 60.f; s32 videoInit(void) { @@ -28,6 +30,8 @@ s32 videoInit(void) gfx_current_native_viewport.width = 320; gfx_current_native_viewport.height = 240; + playerFovY = configGetFloat("Video.FovY", 60.f); + const s32 w = configGetInt("Video.DefaultWidth", 640); const s32 h = configGetInt("Video.DefaultHeight", 480); const bool fs = configGetInt("Video.DefaultFullscreen", false); @@ -125,6 +129,11 @@ f32 videoGetAspect(void) return gfx_current_dimensions.aspect_ratio; } +f32 videoGetPlayerFovY(void) +{ + return playerFovY; +} + void videoResetTextureCache(void) { gfx_texture_cache_clear(); diff --git a/src/game/bondgun.c b/src/game/bondgun.c index 04e828d79..c4d77fcf9 100644 --- a/src/game/bondgun.c +++ b/src/game/bondgun.c @@ -7491,6 +7491,32 @@ void bgunCreateFx(struct hand *hand, s32 handnum, struct weaponfunc *funcdef, s3 } } +#ifndef PLATFORM_N64 + +// offset calculation from NeonNyan/perfect-dark + +static inline f32 bgunGetFovOffsetZ(void) +{ + const f32 fovdelta = videoGetPlayerFovY() - 60.f; + if (fovdelta < -0.01f || fovdelta > 0.01f) { + return fovdelta / 3.f; + } else { + return 0.f; + } +} + +static inline f32 bgunGetFovOffsetY(void) +{ + const f32 fovdelta = videoGetPlayerFovY() - 60.f; + if (fovdelta < -0.01f || fovdelta > 0.01f) { + return fovdelta / (2.75f * 4.f); + } else { + return 0.f; + } +} + +#endif + void bgun0f0a5550(s32 handnum) { u8 *mtxallocation; @@ -7582,6 +7608,12 @@ void bgun0f0a5550(s32 handnum) sp274.y += player->guncloseroffset * 5.0f / -90.0f * 50.0f; sp274.z -= player->guncloseroffset * 15.0f / -90.0f * 50.0f; +#ifndef PLATFORM_N64 + // adjust viewmodel position for different FOVs + sp274.y -= bgunGetFovOffsetY(); + sp274.z += bgunGetFovOffsetZ(); +#endif + if (hand->firing && shootfunc && g_Vars.lvupdate240 != 0 && shootfunc->recoilsettings != NULL) { sp274.x += (RANDOMFRAC() - 0.5f) * shootfunc->recoilsettings->xrange * hand->finalmult[0]; sp274.y += (RANDOMFRAC() - 0.5f) * shootfunc->recoilsettings->yrange * hand->finalmult[0]; diff --git a/src/game/bondmove.c b/src/game/bondmove.c index dfc60e294..256e60a82 100644 --- a/src/game/bondmove.c +++ b/src/game/bondmove.c @@ -1517,7 +1517,11 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i } if (g_Vars.currentplayer->pausemode == PAUSEMODE_UNPAUSED && !g_MainIsEndscreen) { +#ifdef PLATFORM_N64 zoomfov = 60; +#else + zoomfov = videoGetPlayerFovY(); +#endif // FarSight in secondary function if (bgunGetWeaponNum(HAND_RIGHT) == WEAPON_FARSIGHT @@ -1526,9 +1530,15 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i && g_Vars.currentplayer->autoeraserdist > 0) { eraserfov = cam0f0b49b8(500.0f / g_Vars.currentplayer->autoeraserdist); +#ifdef PLATFORM_N64 if (eraserfov > 60) { eraserfov = 60; } +#else + if (eraserfov > videoGetPlayerFovY()) { + eraserfov = videoGetPlayerFovY(); + } +#endif if (eraserfov < 2) { eraserfov = 2; @@ -1562,9 +1572,15 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i zoomfov = currentPlayerGetGunZoomFov(); } +#ifdef PLATFORM_N64 if (zoomfov <= 0) { zoomfov = 60; } +#else + if (zoomfov <= 0) { + zoomfov = videoGetPlayerFovY(); + } +#endif playerTweenFovY(zoomfov); playerUpdateZoom(); diff --git a/src/game/player.c b/src/game/player.c index 7756e9d71..5cd0dacb3 100644 --- a/src/game/player.c +++ b/src/game/player.c @@ -3125,14 +3125,22 @@ void playerConfigureVi(void) var800800f0jf = 0; #endif +#ifdef PLATFORM_N64 playermgrSetFovY(60); +#else + playermgrSetFovY(videoGetPlayerFovY()); +#endif playermgrSetAspectRatio(ratio); playermgrSetViewSize(playerGetViewportWidth(), playerGetViewportHeight()); playermgrSetViewPosition(playerGetViewportLeft(), playerGetViewportTop()); viSetMode(g_ViModes[g_ViRes].xscale); +#ifdef PLATFORM_N64 viSetFovAspectAndSize(60, ratio, playerGetViewportWidth(), playerGetViewportHeight()); +#else + viSetFovAspectAndSize(videoGetPlayerFovY(), ratio, playerGetViewportWidth(), playerGetViewportHeight()); +#endif viSetViewPosition(playerGetViewportLeft(), playerGetViewportTop()); viSetSize(playerGetFbWidth(), playerGetFbHeight()); @@ -3195,13 +3203,21 @@ void playerTick(bool arg0) return; } +#ifdef PLATFORM_N64 playermgrSetFovY(60); +#else + playermgrSetFovY(videoGetPlayerFovY()); +#endif playermgrSetAspectRatio(aspectratio); playermgrSetViewSize(playerGetViewportWidth(), playerGetViewportHeight()); playermgrSetViewPosition(playerGetViewportLeft(), playerGetViewportTop()); viSetMode(g_ViModes[g_ViRes].xscale); +#ifdef PLATFORM_N64 viSetFovAspectAndSize(60, aspectratio, playerGetViewportWidth(), playerGetViewportHeight()); +#else + viSetFovAspectAndSize(videoGetPlayerFovY(), aspectratio, playerGetViewportWidth(), playerGetViewportHeight()); +#endif viSetViewPosition(playerGetViewportLeft(), playerGetViewportTop()); viSetSize(playerGetFbWidth(), playerGetFbHeight()); viSetBufSize(playerGetFbWidth(), playerGetFbHeight());