diff --git a/port/fast3d/gfx_pc.cpp b/port/fast3d/gfx_pc.cpp index 54c5ad633..76bc4e1a5 100644 --- a/port/fast3d/gfx_pc.cpp +++ b/port/fast3d/gfx_pc.cpp @@ -48,11 +48,11 @@ using namespace std; #define SCALE_8_3(VAL_) ((VAL_) / 0x24) // SCREEN_WIDTH and SCREEN_HEIGHT are defined in the headerfile -#define HALF_SCREEN_WIDTH (SCREEN_WIDTH / 2) -#define HALF_SCREEN_HEIGHT (SCREEN_HEIGHT / 2) +#define HALF_SCREEN_WIDTH (SCREEN_WIDTH / 2.f) +#define HALF_SCREEN_HEIGHT (SCREEN_HEIGHT / 2.f) -#define RATIO_X (gfx_current_dimensions.width / (2.0f * HALF_SCREEN_WIDTH)) -#define RATIO_Y (gfx_current_dimensions.height / (2.0f * HALF_SCREEN_HEIGHT)) +#define RATIO_X (gfx_current_dimensions.width / (float)SCREEN_WIDTH) +#define RATIO_Y (gfx_current_dimensions.height / (float)SCREEN_HEIGHT) #define MAX_BUFFERED 256 // #define MAX_LIGHTS 2 @@ -124,6 +124,10 @@ static struct RSP { uint32_t extra_geometry_mode; + uint32_t aspect_mode; + float aspect_ofs; + float aspect_scale; + float depth_zfar; struct { @@ -997,12 +1001,11 @@ static void gfx_sp_pop_matrix(uint32_t count) { } } -static float gfx_adjust_x_for_aspect_ratio(float x) { +static float gfx_adjust_x_for_aspect_ratio(float x, float w = 1.f) { if (fbActive) { return x; } else { - return x * ((float)gfx_current_window_dimensions.width / gfx_current_window_dimensions.height) / - ((float)gfx_current_dimensions.width / (float)gfx_current_dimensions.height); + return (rsp.aspect_ofs * w + x) * rsp.aspect_scale / gfx_current_dimensions.aspect_ratio; } } @@ -1029,7 +1032,7 @@ static void gfx_sp_vertex(size_t n_vertices, size_t dest_index, const Vtx* verti float z = v->v[0] * rsp.MP_matrix[0][2] + v->v[1] * rsp.MP_matrix[1][2] + v->v[2] * rsp.MP_matrix[2][2] + rsp.MP_matrix[3][2]; float w = v->v[0] * rsp.MP_matrix[0][3] + v->v[1] * rsp.MP_matrix[1][3] + v->v[2] * rsp.MP_matrix[2][3] + rsp.MP_matrix[3][3]; - x = gfx_adjust_x_for_aspect_ratio(x); + x = gfx_adjust_x_for_aspect_ratio(x, w); short U = v->s * rsp.texture_scaling_factor.s >> 16; short V = v->t * rsp.texture_scaling_factor.t >> 16; @@ -1634,18 +1637,39 @@ static void gfx_sp_geometry_mode(uint32_t clear, uint32_t set) { rsp.geometry_mode |= set; } +static inline void gfx_update_aspect_mode(void) { + rsp.aspect_scale = rsp.aspect_mode ? (4.f / 3.f) : gfx_current_window_dimensions.aspect_ratio; + if (rsp.aspect_mode == G_ASPECT_LEFT_EXT) { + rsp.aspect_ofs = 1.f - 3.f * gfx_current_dimensions.aspect_ratio / 4.f; + } else if (rsp.aspect_mode == G_ASPECT_RIGHT_EXT) { + rsp.aspect_ofs = 3.f * gfx_current_dimensions.aspect_ratio / 4.f - 1.f; + } else { + rsp.aspect_ofs = 0.f; + } +} + static void gfx_sp_extra_geometry_mode(uint32_t clear, uint32_t set) { rsp.extra_geometry_mode &= ~clear; rsp.extra_geometry_mode |= set; + rsp.aspect_mode = (rsp.extra_geometry_mode & G_ASPECT_MODE_EXT); + gfx_update_aspect_mode(); } -static void gfx_adjust_viewport_or_scissor(XYWidthHeight* area) { +static void gfx_adjust_viewport_or_scissor(XYWidthHeight* area, bool preserve_aspect = false) { if (!fbActive) { area->width *= RATIO_X; - area->height *= RATIO_Y; area->x *= RATIO_X; + area->height *= RATIO_Y; area->y = SCREEN_HEIGHT - area->y; area->y *= RATIO_Y; + if (preserve_aspect) { + // preserve 4:3 + const float ratio = (4.f / 3.f) / gfx_current_dimensions.aspect_ratio; + const float midx = gfx_current_dimensions.width * 0.5f; + area->x = midx + (area->x - midx) * ratio; + area->x += rsp.aspect_ofs * gfx_current_dimensions.width * 0.5f; + area->width *= ratio; + } if (!game_renders_to_framebuffer || (gfx_msaa_level > 1 && gfx_current_dimensions.width == gfx_current_game_window_viewport.width && @@ -1771,7 +1795,7 @@ static void gfx_dp_set_scissor(uint32_t mode, uint32_t ulx, uint32_t uly, uint32 rdp.scissor.width = width; rdp.scissor.height = height; - gfx_adjust_viewport_or_scissor(&rdp.scissor); + gfx_adjust_viewport_or_scissor(&rdp.scissor, rsp.aspect_mode != 0); rdp.viewport_or_scissor_changed = true; } @@ -2086,7 +2110,7 @@ static void gfx_draw_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lr ur->w = 1.0f; // The coordinates for texture rectangle shall bypass the viewport setting - struct XYWidthHeight default_viewport = { 0, SCREEN_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT }; + struct XYWidthHeight default_viewport = { 0, (int16_t)SCREEN_HEIGHT, (uint32_t)SCREEN_WIDTH, (uint32_t)SCREEN_HEIGHT }; struct XYWidthHeight viewport_saved = rdp.viewport; uint32_t geometry_mode_saved = rsp.geometry_mode; @@ -2179,7 +2203,7 @@ static void gfx_dp_fill_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t uint32_t mode = (rdp.other_mode_h & (3U << G_MDSFT_CYCLETYPE)); // OTRTODO: This is a bit of a hack for widescreen screen fades, but it'll work for now... - if (ulx == 0 && uly == 0 && lrx == (int32_t)((SCREEN_WIDTH - 1) * 4) && lry == (int32_t)((SCREEN_HEIGHT - 1) * 4)) { + if (ulx == 0 && uly == 0 && lrx == 319 * 4 && lry == 239 * 4) { ulx = -1024; uly = -1024; lrx = 2048; @@ -2348,6 +2372,9 @@ static void gfx_run_dl(Gfx* cmd) { case (uint8_t)G_CLEARGEOMETRYMODE: gfx_sp_geometry_mode(cmd->words.w1, 0); break; + case G_EXTRAGEOMETRYMODE_EXT: + gfx_sp_extra_geometry_mode(~C0(0, 24), cmd->words.w1); + break; #endif case (uint8_t)G_TRI1: #ifdef F3DEX_GBI_2 @@ -2677,6 +2704,9 @@ extern "C" void gfx_start_frame(void) { } fbActive = 0; + + // update aspect scale and offset + gfx_update_aspect_mode(); } uint32_t num_dls = 0; diff --git a/port/fast3d/gfx_pc.h b/port/fast3d/gfx_pc.h index 35e13e736..2700a163b 100644 --- a/port/fast3d/gfx_pc.h +++ b/port/fast3d/gfx_pc.h @@ -12,8 +12,8 @@ extern "C" void sysFatalError(const char *fmt, ...) __attribute__((noreturn)); -#define SCREEN_WIDTH (gfx_current_native_viewport.width) -#define SCREEN_HEIGHT (gfx_current_native_viewport.height) +#define SCREEN_WIDTH ((int32_t)gfx_current_native_viewport.width) +#define SCREEN_HEIGHT ((int32_t)gfx_current_native_viewport.height) extern uintptr_t gfxFramebuffer; diff --git a/src/game/bondgun.c b/src/game/bondgun.c index a61a2c087..81472dbb9 100644 --- a/src/game/bondgun.c +++ b/src/game/bondgun.c @@ -12724,6 +12724,12 @@ Gfx *bgunDrawHud(Gfx *gdl) gdl = text0f153628(gdl); +#ifndef PLATFORM_N64 + if (playercount < 2) { + gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, G_ASPECT_RIGHT_EXT); + } +#endif + if (playercount >= 2) { barwidth = 5; reserveheight = 26; @@ -12944,6 +12950,9 @@ Gfx *bgunDrawHud(Gfx *gdl) } if (ammoindex == -1) { +#ifndef PLATFORM_N64 + gSPClearExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT); +#endif gdl = text0f153780(gdl); g_ScaleX = 1; return gdl; @@ -12969,6 +12978,12 @@ Gfx *bgunDrawHud(Gfx *gdl) xpos -= 14; } +#ifndef PLATFORM_N64 + if (playercount < 2) { + gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, G_ASPECT_LEFT_EXT); + } +#endif + if (lefthand->clipsizes[ammoindex] > 0 && (weapon->ammos[ammoindex]->flags & AMMOFLAG_EQUIPPEDISRESERVE) == 0) { gdl = bgunDrawHudGauge(gdl, xpos, bottom - reserveheight - clipheight - 3, xpos + barwidth, bottom - reserveheight - 3, @@ -13003,6 +13018,12 @@ Gfx *bgunDrawHud(Gfx *gdl) xpos += 15; } +#ifndef PLATFORM_N64 + if (playercount < 2) { + gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, G_ASPECT_RIGHT_EXT); + } +#endif + // Mag ammoheld = player->ammoheldarr[ammotype]; @@ -13056,6 +13077,10 @@ Gfx *bgunDrawHud(Gfx *gdl) } } +#ifndef PLATFORM_N64 + gSPClearExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT); +#endif + gdl = text0f153780(gdl); g_ScaleX = 1; diff --git a/src/game/credits.c b/src/game/credits.c index 5de55450d..54ad8cf8c 100644 --- a/src/game/credits.c +++ b/src/game/credits.c @@ -1777,6 +1777,10 @@ Gfx *creditsDraw(Gfx *gdl) g_ScaleX = 1; +#ifndef PLATFORM_N64 + gSPClearExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT); +#endif + gdl = viPrepareZbuf(gdl); gdl = vi0000b1d0(gdl); gdl = creditsFillFramebuffer(gdl, 0x000000ff); diff --git a/src/game/hudmsg.c b/src/game/hudmsg.c index f497c88ed..b6d927b22 100644 --- a/src/game/hudmsg.c +++ b/src/game/hudmsg.c @@ -189,8 +189,18 @@ Gfx *hudmsgRenderMissionTimer(Gfx *gdl, u32 alpha) x = viewleft + g_HudPaddingX + 3; y = timery; +#ifndef PLATFORM_N64 + if (PLAYERCOUNT() < 2) { + gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, G_ASPECT_LEFT_EXT); + } +#endif + gdl = textRender(gdl, &x, &y, buffer, g_CharsNumeric, g_FontNumeric, textcolour, 0x000000a0, viGetWidth(), viGetHeight_hack(), 0, 0); +#ifndef PLATFORM_N64 + gSPClearExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT); +#endif + return gdl; } @@ -1362,6 +1372,9 @@ Gfx *hudmsgsRender(Gfx *gdl) s32 y; s32 timerthing = 255; s32 spdc = true; +#ifndef PLATFORM_N64 + const s32 playercount = PLAYERCOUNT(); +#endif #if PAL g_ScaleX = 1; @@ -1426,6 +1439,18 @@ Gfx *hudmsgsRender(Gfx *gdl) y += (s32)(16.0f * playerGetHealthBarHeightFrac()); } +#ifndef PLATFORM_N64 + if (playercount < 2 && msg->state >= HUDMSGSTATE_FADINGIN) { + if (msg->alignh == HUDMSGALIGN_SCREENLEFT || msg->alignh == HUDMSGALIGN_LEFT) { + gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, G_ASPECT_LEFT_EXT); + } else if (msg->alignh == HUDMSGALIGN_RIGHT) { + gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, G_ASPECT_RIGHT_EXT); + } else { + gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, G_ASPECT_CENTER_EXT); + } + } +#endif + if (msg->type == HUDMSGTYPE_CUTSCENESUBTITLE) { #if VERSION >= VERSION_NTSC_1_0 gDPSetScissor(gdl++, 0, @@ -1582,6 +1607,10 @@ Gfx *hudmsgsRender(Gfx *gdl) break; } +#ifndef PLATFORM_N64 + gSPClearExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT); +#endif + if (msg->type == HUDMSGTYPE_CUTSCENESUBTITLE) { gDPSetScissor(gdl++, 0, viGetViewLeft(), viGetViewTop(), diff --git a/src/game/menu.c b/src/game/menu.c index e48c3b9d2..98de1156c 100644 --- a/src/game/menu.c +++ b/src/game/menu.c @@ -2185,9 +2185,7 @@ Gfx *menuRenderModel(Gfx *gdl, struct menumodel *menumodel, s32 modeltype) gSPMatrix(gdl++, osVirtualToPhysical(camGetPerspectiveMtxL()), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); } else { f32 aspect = (f32) (g_MenuScissorX2 - g_MenuScissorX1) / (f32) (g_MenuScissorY2 - g_MenuScissorY1); -#ifndef PLATFORM_N64 - aspect *= videoGetAspect() / (4.0f / 3.0f); -#endif + static u32 znear = 10; static u32 zfar = 300; @@ -5182,6 +5180,10 @@ Gfx *menuRender(Gfx *gdl) gdl = menuRenderBackgroundLayer1(gdl, g_MenuData.bg, 1.0f); } +#ifndef PLATFORM_N64 + gSPSetExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT); +#endif + // Calculate hudpiece things then render it if (g_MenuData.unk5d5_05) { g_MenuData.hudpiece.curanimnum = 0; @@ -5279,7 +5281,13 @@ Gfx *menuRender(Gfx *gdl) if ((g_MenuData.bg || g_MenuData.nextbg != 255) && (!g_Vars.currentplayer->eyespy || !g_Vars.currentplayer->eyespy->active)) { gdl = func0f0d49c8(gdl); +#ifndef PLATFORM_N64 + gSPClearExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT); +#endif gdl = playerRenderHealthBar(gdl); +#ifndef PLATFORM_N64 + gSPSetExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT); +#endif gdl = func0f0d479c(gdl); } @@ -5491,6 +5499,10 @@ Gfx *menuRender(Gfx *gdl) #endif } +#ifndef PLATFORM_N64 + gSPClearExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT); +#endif + gdl = func0f0d49c8(gdl); g_ScaleX = 1; diff --git a/src/game/radar.c b/src/game/radar.c index 0d184bc57..e13aa5e45 100644 --- a/src/game/radar.c +++ b/src/game/radar.c @@ -322,6 +322,9 @@ Gfx *radarRender(Gfx *gdl) if (optionsGetEffectiveScreenSize() != SCREENSIZE_FULL) { g_RadarY -= 6; } +#ifndef PLATFORM_N64 + gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, G_ASPECT_RIGHT_EXT); +#endif } gdl = radarRenderBackground(gdl, tconfig, g_RadarX, g_RadarY, 0x10); @@ -412,6 +415,10 @@ Gfx *radarRender(Gfx *gdl) gdl = radarDrawDot(gdl, g_Vars.currentplayer->prop, &pos, colour, 0, 0); } +#ifndef PLATFORM_N64 + gSPClearExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT); +#endif + g_ScaleX = 1; return gdl; diff --git a/src/game/title.c b/src/game/title.c index baa7184a9..1ccd3bf0b 100644 --- a/src/game/title.c +++ b/src/game/title.c @@ -345,6 +345,10 @@ Gfx *titleRenderLegal(Gfx *gdl) #endif gdl = text0f153628(gdl); +#ifndef PLATFORM_N64 + gSPSetExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT); +#endif + elem = g_LegalElements; end = &g_LegalElements[ARRAYCOUNT(g_LegalElements)]; @@ -511,6 +515,10 @@ Gfx *titleRenderLegal(Gfx *gdl) } } +#ifndef PLATFORM_N64 + gSPClearExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT); +#endif + gdl = text0f153780(gdl); } diff --git a/src/game/trainingmenus.c b/src/game/trainingmenus.c index db90ba2a8..b942b0361 100644 --- a/src/game/trainingmenus.c +++ b/src/game/trainingmenus.c @@ -22,6 +22,9 @@ #include "lib/main.h" #include "data.h" #include "types.h" +#ifndef PLATFORM_N64 +#include "video.h" +#endif #define NUM_BIO_LOCATIONS 14 @@ -1583,6 +1586,10 @@ MenuDialogHandlerResult ciCharacterProfileMenuDialog(s32 operation, struct menud scale = 0.8f; } +#ifndef PLATFORM_N64 + x = (float)x * (4.f / 3.f) / videoGetAspect(); +#endif + menuConfigureModel(&g_Menus[g_MpPlayerNum].menumodel, x, y, 0, 0, 0, 0, scale, MENUMODELFLAG_HASSCALE | MENUMODELFLAG_HASPOSITION | MENUMODELFLAG_HASROTATION); diff --git a/src/include/gbiex.h b/src/include/gbiex.h index a7805cd34..1bbef5a8b 100644 --- a/src/include/gbiex.h +++ b/src/include/gbiex.h @@ -184,14 +184,23 @@ /* Extended commands */ -#define G_SETFB_EXT 0x21 -#define G_SETTIMG_FB_EXT 0x23 -#define G_INVALTEXCACHE_EXT 0x34 -#define G_TEXRECT_WIDE_EXT 0x37 -#define G_FILLRECT_WIDE_EXT 0x38 -#define G_SETGRAYSCALE_EXT 0x39 -#define G_SETINTENSITY_EXT 0x40 -#define G_COPYFB_EXT 0x41 +#define G_SETFB_EXT 0x21 +#define G_SETTIMG_FB_EXT 0x23 +#define G_INVALTEXCACHE_EXT 0x34 +#define G_TEXRECT_WIDE_EXT 0x37 +#define G_FILLRECT_WIDE_EXT 0x38 +#define G_SETGRAYSCALE_EXT 0x39 +#define G_EXTRAGEOMETRYMODE_EXT 0x3a +#define G_SETINTENSITY_EXT 0x40 +#define G_COPYFB_EXT 0x41 + +/* G_EXTRAGEOMETRYMODE flags */ + +#define G_INVERT_CULLING_EXT 0x00000001 +#define G_ASPECT_LEFT_EXT 0x00000010 +#define G_ASPECT_RIGHT_EXT 0x00000020 +#define G_ASPECT_CENTER_EXT (G_ASPECT_LEFT_EXT | G_ASPECT_RIGHT_EXT) +#define G_ASPECT_MODE_EXT G_ASPECT_CENTER_EXT /* Extended command macros */ @@ -252,6 +261,17 @@ _g2->words.w1 = (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)); \ } +#define gSPExtraGeometryModeEXT(pkt, c, s) \ +{ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_EXTRAGEOMETRYMODE_EXT, 24, 8) | _SHIFTL(~(u32)(c), 0, 24); \ + _g->words.w1 = (u32)(s); \ +} + +#define gSPSetExtraGeometryModeEXT(pkt, word) gSPExtraGeometryModeEXT((pkt), 0, word) +#define gSPClearExtraGeometryModeEXT(pkt, word) gSPExtraGeometryModeEXT((pkt), word, 0) + #define gDPFillRectangleEXT gDPFillRectangleWideEXT #define gSPTextureRectangleEXT gSPTextureRectangleWideEXT