From e0d59345c7378949933f13d8110639519952e5f4 Mon Sep 17 00:00:00 2001 From: Matthew Coppola Date: Thu, 24 Oct 2024 01:16:11 -0400 Subject: [PATCH 1/5] Center-align crosshairs and zoom range --- port/fast3d/gfx_pc.cpp | 47 +++++++++++++++--- src/game/bondview.c | 16 +++--- src/game/sight.c | 108 ++++++++++++++++++++++------------------- src/include/gbiex.h | 38 ++++++++++----- 4 files changed, 133 insertions(+), 76 deletions(-) diff --git a/port/fast3d/gfx_pc.cpp b/port/fast3d/gfx_pc.cpp index 571e03f05..43713c67d 100644 --- a/port/fast3d/gfx_pc.cpp +++ b/port/fast3d/gfx_pc.cpp @@ -1573,7 +1573,7 @@ static inline void gfx_sp_tri4(Gfx *cmd) { uint8_t x = C1(0, 4); uint8_t y = C1(4, 4); uint8_t z = C0(0, 4); - + if(x || y || z) { gfx_sp_tri1(x, y, z, false); } @@ -2148,10 +2148,10 @@ static void gfx_dp_image_rectangle(int32_t tile, int32_t w, int32_t h, rdp.combine_mode = saved_combine_mode; } -static void gfx_dp_fill_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry) { +static int gfx_dp_fill_rectangle_common(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry, uint64_t *saved_combine_mode) { if (rdp.color_image_address == rdp.z_buf_address) { // Don't clear Z buffer here since we already did it with glClear - return; + return 1; } uint32_t mode = (rdp.other_mode_h & (3U << G_MDSFT_CYCLETYPE)); @@ -2174,14 +2174,39 @@ static void gfx_dp_fill_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t v->color = rdp.fill_color; } - uint64_t saved_combine_mode = rdp.combine_mode; + *saved_combine_mode = rdp.combine_mode; if (mode == G_CYC_FILL) { gfx_dp_set_combine_mode(color_comb(0, 0, 0, G_CCMUX_SHADE), alpha_comb(0, 0, 0, G_ACMUX_SHADE), 0, 0); } - gfx_draw_rectangle(ulx, uly, lrx, lry); - rdp.combine_mode = saved_combine_mode; + return 0; +} + +static void gfx_dp_fill_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry) { + uint64_t saved_combine_mode; + if (gfx_dp_fill_rectangle_common(ulx, uly, lrx, lry, &saved_combine_mode) == 0) { + gfx_draw_rectangle(ulx, uly, lrx, lry); + rdp.combine_mode = saved_combine_mode; + } +} + +static void gfx_dp_fill_rectangle_centered(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry) { + uint64_t saved_combine_mode; + if (gfx_dp_fill_rectangle_common(ulx, uly, lrx, lry, &saved_combine_mode) == 0) { + // The coordinates of the rect are usually quantized to the default N64 + // resolution (320x220), but adding the rect to the graphics display + // list scales it by four. So, a single pixel at 320x220 becomes four + // pixels at 1280x880. Since the crosshair was misaligned by half a + // native pixel, we need to shift the crosshair by two scaled pixels. + ulx -= 2; + lrx -= 2; + uly -= 2; + lry -= 2; + + gfx_draw_rectangle(ulx, uly, lrx, lry); + rdp.combine_mode = saved_combine_mode; + } } static void gfx_dp_set_z_image(void* z_buf_address) { @@ -2392,6 +2417,16 @@ static void gfx_run_dl(Gfx* cmd) { gfx_dp_fill_rectangle(ulx, uly, lrx, lry); break; } + case G_FILLRECT_CENTERED_WIDE_EXT: { + int32_t lrx, lry, ulx, uly; + lrx = (int32_t)(C0(0, 24) << 8) >> 8; + lry = (int32_t)(C1(0, 24) << 8) >> 8; + ++cmd; + ulx = (int32_t)(C0(0, 24) << 8) >> 8; + uly = (int32_t)(C1(0, 24) << 8) >> 8; + gfx_dp_fill_rectangle_centered(ulx, uly, lrx, lry); + break; + } case G_TEXRECT_WIDE_EXT: { int32_t lrx, lry, tile, ulx, uly; uint32_t uls, ult, dsdx, dtdy; diff --git a/src/game/bondview.c b/src/game/bondview.c index af101fa37..935476d6c 100644 --- a/src/game/bondview.c +++ b/src/game/bondview.c @@ -1109,14 +1109,14 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl) s32 x = viewleft + (viewwidth >> 1); s32 y = viewtop + (viewheight >> 1); - gDPFillRectangle(gdl++, x + 2, y + 0, x + 7, y + 1); - gDPFillRectangle(gdl++, x + 2, y + 0, x + 5, y + 1); - gDPFillRectangle(gdl++, x - 6, y + 0, x - 1, y + 1); - gDPFillRectangle(gdl++, x - 4, y + 0, x - 1, y + 1); - gDPFillRectangle(gdl++, x + 0, y + 2, x + 1, y + 7); - gDPFillRectangle(gdl++, x + 0, y + 2, x + 1, y + 5); - gDPFillRectangle(gdl++, x + 0, y - 6, x + 1, y - 1); - gDPFillRectangle(gdl++, x + 0, y - 4, x + 1, y - 1); + gDPFillRectangleCenteredEXT(gdl++, x + 2, y + 0, x + 7, y + 1); + gDPFillRectangleCenteredEXT(gdl++, x + 2, y + 0, x + 5, y + 1); + gDPFillRectangleCenteredEXT(gdl++, x - 6, y + 0, x - 1, y + 1); + gDPFillRectangleCenteredEXT(gdl++, x - 4, y + 0, x - 1, y + 1); + gDPFillRectangleCenteredEXT(gdl++, x + 0, y + 2, x + 1, y + 7); + gDPFillRectangleCenteredEXT(gdl++, x + 0, y + 2, x + 1, y + 5); + gDPFillRectangleCenteredEXT(gdl++, x + 0, y - 6, x + 1, y - 1); + gDPFillRectangleCenteredEXT(gdl++, x + 0, y - 4, x + 1, y - 1); } if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_CAMSPY) { diff --git a/src/game/sight.c b/src/game/sight.c index 78359c4ef..a3bdd642f 100644 --- a/src/game/sight.c +++ b/src/game/sight.c @@ -519,35 +519,35 @@ Gfx *sightDrawAimer(Gfx *gdl, s32 x, s32 y, s32 radius, s32 cornergap, u32 colou // Draw the lines that span most of the viewport if (PLAYERCOUNT() == 1) { - gDPHudRectangle(gdl++, viewleft + 48, y, x - radius + 2, y); - gDPHudRectangle(gdl++, x + radius - 2, y, viewright - 49, y); - gDPHudRectangle(gdl++, x, viewtop + 10, x, y - radius + 2); - gDPHudRectangle(gdl++, x, y + radius - 2, x, viewbottom - 10); + gDPHudRectangleCentered(gdl++, viewleft + 48, y, x - radius + 2, y); + gDPHudRectangleCentered(gdl++, x + radius - 2, y, viewright - 49, y); + gDPHudRectangleCentered(gdl++, x, viewtop + 10, x, y - radius + 2); + gDPHudRectangleCentered(gdl++, x, y + radius - 2, x, viewbottom - 10); } else { - gDPHudRectangle(gdl++, viewleft, y, x - radius + 2, y); - gDPHudRectangle(gdl++, x + radius - 2, y, viewright, y); - gDPHudRectangle(gdl++, x, viewtop, x, y - radius + 2); - gDPHudRectangle(gdl++, x, y + radius - 2, x, viewbottom); + gDPHudRectangleCentered(gdl++, viewleft, y, x - radius + 2, y); + gDPHudRectangleCentered(gdl++, x + radius - 2, y, viewright, y); + gDPHudRectangleCentered(gdl++, x, viewtop, x, y - radius + 2); + gDPHudRectangleCentered(gdl++, x, y + radius - 2, x, viewbottom); } gdl = text0f153838(gdl); gdl = textSetPrimColour(gdl, colour); // Draw the box - gDPHudRectangle(gdl++, x - radius, y - radius, x - radius, y + radius); - gDPHudRectangle(gdl++, x + radius, y - radius, x + radius, y + radius); - gDPHudRectangle(gdl++, x - radius, y - radius, x + radius, y - radius); - gDPHudRectangle(gdl++, x - radius, y + radius, x + radius, y + radius); + gDPHudRectangleCentered(gdl++, x - radius, y - radius, x - radius, y + radius); + gDPHudRectangleCentered(gdl++, x + radius, y - radius, x + radius, y + radius); + gDPHudRectangleCentered(gdl++, x - radius, y - radius, x + radius, y - radius); + gDPHudRectangleCentered(gdl++, x - radius, y + radius, x + radius, y + radius); // Go over the corners a second time - gDPHudRectangle(gdl++, x - radius, y - radius, x - radius, y - cornergap); - gDPHudRectangle(gdl++, x - radius, y + cornergap, x - radius, y + radius); - gDPHudRectangle(gdl++, x + radius, y - radius, x + radius, y - cornergap); - gDPHudRectangle(gdl++, x + radius, y + cornergap, x + radius, y + radius); - gDPHudRectangle(gdl++, x - radius, y - radius, x - cornergap, y - radius); - gDPHudRectangle(gdl++, x + cornergap, y - radius, x + radius, y - radius); - gDPHudRectangle(gdl++, x - radius, y + radius, x - cornergap, y + radius); - gDPHudRectangle(gdl++, x + cornergap, y + radius, x + radius, y + radius); + gDPHudRectangleCentered(gdl++, x - radius, y - radius, x - radius, y - cornergap); + gDPHudRectangleCentered(gdl++, x - radius, y + cornergap, x - radius, y + radius); + gDPHudRectangleCentered(gdl++, x + radius, y - radius, x + radius, y - cornergap); + gDPHudRectangleCentered(gdl++, x + radius, y + cornergap, x + radius, y + radius); + gDPHudRectangleCentered(gdl++, x - radius, y - radius, x - cornergap, y - radius); + gDPHudRectangleCentered(gdl++, x + cornergap, y - radius, x + radius, y - radius); + gDPHudRectangleCentered(gdl++, x - radius, y + radius, x - cornergap, y + radius); + gDPHudRectangleCentered(gdl++, x + cornergap, y + radius, x + radius, y + radius); #ifndef PLATFORM_N64 gSPClearExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT); @@ -908,7 +908,7 @@ Gfx *sightDrawClassic(Gfx *gdl, bool sighton) f32 spc4[2]; f32 spbc[2]; s32 x = g_Vars.currentplayer->crosspos[0]; - s32 y = g_Vars.currentplayer->crosspos[1]; + s32 y = g_Vars.currentplayer->crosspos[1] + 1; // Plus one, to align with the laser sight. s32 x1; s32 x2; s32 y1; @@ -1331,6 +1331,14 @@ Gfx *sightDrawZoom(Gfx *gdl, bool sighton) marginbottom = viewhalfheight - availablebelow * frac; margintop = viewhalfheight - availableabove * frac; + // Center-align the zoom range. + if (frac != 1.0f) { + viewleft += 1; + viewright += 1; + viewbottom += 1; + viewtop += 1; + } + #define BOXLEFT (viewleft + marginleft) #define BOXRIGHT (viewright - marginright) #define BOXBOTTOM (viewbottom - marginbottom) @@ -1349,40 +1357,40 @@ Gfx *sightDrawZoom(Gfx *gdl, bool sighton) #endif // Top left - gDPHudRectangle(gdl++, BOXLEFT + 1, BOXTOP, BOXLEFT + cornerwidth - 1, BOXTOP); - gDPHudRectangle(gdl++, BOXLEFT, BOXTOP, BOXLEFT, BOXTOP + cornerheight - 1); + gDPHudRectangleCentered(gdl++, BOXLEFT + 1, BOXTOP, BOXLEFT + cornerwidth - 1, BOXTOP); + gDPHudRectangleCentered(gdl++, BOXLEFT, BOXTOP, BOXLEFT, BOXTOP + cornerheight - 1); // Top right - gDPHudRectangle(gdl++, BOXRIGHT - cornerwidth + 2, BOXTOP, BOXRIGHT - 1, BOXTOP); - gDPHudRectangle(gdl++, BOXRIGHT, BOXTOP, BOXRIGHT, BOXTOP + cornerheight - 1); + gDPHudRectangleCentered(gdl++, BOXRIGHT - cornerwidth + 2, BOXTOP, BOXRIGHT - 1, BOXTOP); + gDPHudRectangleCentered(gdl++, BOXRIGHT, BOXTOP, BOXRIGHT, BOXTOP + cornerheight - 1); // Bottom left - gDPHudRectangle(gdl++, BOXLEFT + 1, BOXBOTTOM, BOXLEFT + cornerwidth - 1, BOXBOTTOM); - gDPHudRectangle(gdl++, BOXLEFT, BOXBOTTOM - cornerheight + 1, BOXLEFT, BOXBOTTOM); + gDPHudRectangleCentered(gdl++, BOXLEFT + 1, BOXBOTTOM, BOXLEFT + cornerwidth - 1, BOXBOTTOM); + gDPHudRectangleCentered(gdl++, BOXLEFT, BOXBOTTOM - cornerheight + 1, BOXLEFT, BOXBOTTOM); // Bottom right - gDPHudRectangle(gdl++, BOXRIGHT - cornerwidth + 2, BOXBOTTOM, BOXRIGHT - 1, BOXBOTTOM); - gDPHudRectangle(gdl++, BOXRIGHT, BOXBOTTOM - cornerheight + 1, BOXRIGHT, BOXBOTTOM); + gDPHudRectangleCentered(gdl++, BOXRIGHT - cornerwidth + 2, BOXBOTTOM, BOXRIGHT - 1, BOXBOTTOM); + gDPHudRectangleCentered(gdl++, BOXRIGHT, BOXBOTTOM - cornerheight + 1, BOXRIGHT, BOXBOTTOM); // Draw over the corners again, but only half as wide/high cornerwidth >>= 1; cornerheight >>= 1; // Top left - gDPHudRectangle(gdl++, BOXLEFT, BOXTOP, BOXLEFT + cornerwidth, BOXTOP); - gDPHudRectangle(gdl++, BOXLEFT, BOXTOP, BOXLEFT, BOXTOP + cornerheight); + gDPHudRectangleCentered(gdl++, BOXLEFT, BOXTOP, BOXLEFT + cornerwidth, BOXTOP); + gDPHudRectangleCentered(gdl++, BOXLEFT, BOXTOP, BOXLEFT, BOXTOP + cornerheight); // Top right - gDPHudRectangle(gdl++, BOXRIGHT - cornerwidth, BOXTOP, BOXRIGHT, BOXTOP); - gDPHudRectangle(gdl++, BOXRIGHT, BOXTOP, BOXRIGHT, BOXTOP + cornerheight); + gDPHudRectangleCentered(gdl++, BOXRIGHT - cornerwidth, BOXTOP, BOXRIGHT, BOXTOP); + gDPHudRectangleCentered(gdl++, BOXRIGHT, BOXTOP, BOXRIGHT, BOXTOP + cornerheight); // Bottom left - gDPHudRectangle(gdl++, BOXLEFT, BOXBOTTOM, BOXLEFT + cornerwidth, BOXBOTTOM); - gDPHudRectangle(gdl++, BOXLEFT, BOXBOTTOM - cornerheight, BOXLEFT, BOXBOTTOM); + gDPHudRectangleCentered(gdl++, BOXLEFT, BOXBOTTOM, BOXLEFT + cornerwidth, BOXBOTTOM); + gDPHudRectangleCentered(gdl++, BOXLEFT, BOXBOTTOM - cornerheight, BOXLEFT, BOXBOTTOM); // Bottom right - gDPHudRectangle(gdl++, BOXRIGHT - cornerwidth, BOXBOTTOM, BOXRIGHT, BOXBOTTOM); - gDPHudRectangle(gdl++, BOXRIGHT, BOXBOTTOM - cornerheight, BOXRIGHT, BOXBOTTOM); + gDPHudRectangleCentered(gdl++, BOXRIGHT - cornerwidth, BOXBOTTOM, BOXRIGHT, BOXBOTTOM); + gDPHudRectangleCentered(gdl++, BOXRIGHT, BOXBOTTOM - cornerheight, BOXRIGHT, BOXBOTTOM); #ifndef PLATFORM_N64 @@ -1490,10 +1498,10 @@ Gfx *sightDrawMaian(Gfx *gdl, bool sighton) gdl = textSetPrimColour(gdl, SIGHT_COLOUR); // Draw border over inner points - gDPHudRectangle(gdl++, x - 4, y - 4, x - 4, y + 4); // left - gDPHudRectangle(gdl++, x + 4, y - 4, x + 4, y + 4); // right - gDPHudRectangle(gdl++, x - 4, y - 4, x + 4, y - 4); // top - gDPHudRectangle(gdl++, x - 4, y + 4, x + 4, y + 4); // bottom + gDPHudRectangleCentered(gdl++, x - 4, y - 4, x - 4, y + 4); // left + gDPHudRectangleCentered(gdl++, x + 4, y - 4, x + 4, y + 4); // right + gDPHudRectangleCentered(gdl++, x - 4, y - 4, x + 4, y - 4); // top + gDPHudRectangleCentered(gdl++, x - 4, y + 4, x + 4, y + 4); // bottom gdl = text0f153838(gdl); @@ -1521,18 +1529,18 @@ Gfx *sightDrawTarget(Gfx *gdl) gSPSetExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT); if (SIGHT_SCALE == 0) { // Draw single rectangle to preserve intended opacity - gDPHudRectangle(gdl++, x, y, x, y); + gDPHudRectangleCentered(gdl++, x, y, x, y); } else #endif { - gDPHudRectangle(gdl++, x + 1 * SIGHT_SCALE, y + 0 * SIGHT_SCALE, x + 3 * SIGHT_SCALE, y + 0 * SIGHT_SCALE); - gDPHudRectangle(gdl++, x + 1 * SIGHT_SCALE, y + 0 * SIGHT_SCALE, x + 2 * SIGHT_SCALE, y + 0 * SIGHT_SCALE); - gDPHudRectangle(gdl++, x - 3 * SIGHT_SCALE, y + 0 * SIGHT_SCALE, x - 1 * SIGHT_SCALE, y + 0 * SIGHT_SCALE); - gDPHudRectangle(gdl++, x - 2 * SIGHT_SCALE, y + 0 * SIGHT_SCALE, x - 1 * SIGHT_SCALE, y + 0 * SIGHT_SCALE); - gDPHudRectangle(gdl++, x + 0 * SIGHT_SCALE, y + 1 * SIGHT_SCALE, x + 0 * SIGHT_SCALE, y + 3 * SIGHT_SCALE); - gDPHudRectangle(gdl++, x + 0 * SIGHT_SCALE, y + 1 * SIGHT_SCALE, x + 0 * SIGHT_SCALE, y + 2 * SIGHT_SCALE); - gDPHudRectangle(gdl++, x + 0 * SIGHT_SCALE, y - 3 * SIGHT_SCALE, x + 0 * SIGHT_SCALE, y - 1 * SIGHT_SCALE); - gDPHudRectangle(gdl++, x + 0 * SIGHT_SCALE, y - 2 * SIGHT_SCALE, x + 0 * SIGHT_SCALE, y - 1 * SIGHT_SCALE); + gDPHudRectangleCentered(gdl++, x + 1 * SIGHT_SCALE, y + 0 * SIGHT_SCALE, x + 3 * SIGHT_SCALE, y + 0 * SIGHT_SCALE); + gDPHudRectangleCentered(gdl++, x + 1 * SIGHT_SCALE, y + 0 * SIGHT_SCALE, x + 2 * SIGHT_SCALE, y + 0 * SIGHT_SCALE); + gDPHudRectangleCentered(gdl++, x - 3 * SIGHT_SCALE, y + 0 * SIGHT_SCALE, x - 1 * SIGHT_SCALE, y + 0 * SIGHT_SCALE); + gDPHudRectangleCentered(gdl++, x - 2 * SIGHT_SCALE, y + 0 * SIGHT_SCALE, x - 1 * SIGHT_SCALE, y + 0 * SIGHT_SCALE); + gDPHudRectangleCentered(gdl++, x + 0 * SIGHT_SCALE, y + 1 * SIGHT_SCALE, x + 0 * SIGHT_SCALE, y + 3 * SIGHT_SCALE); + gDPHudRectangleCentered(gdl++, x + 0 * SIGHT_SCALE, y + 1 * SIGHT_SCALE, x + 0 * SIGHT_SCALE, y + 2 * SIGHT_SCALE); + gDPHudRectangleCentered(gdl++, x + 0 * SIGHT_SCALE, y - 3 * SIGHT_SCALE, x + 0 * SIGHT_SCALE, y - 1 * SIGHT_SCALE); + gDPHudRectangleCentered(gdl++, x + 0 * SIGHT_SCALE, y - 2 * SIGHT_SCALE, x + 0 * SIGHT_SCALE, y - 1 * SIGHT_SCALE); } #ifndef PLATFORM_N64 diff --git a/src/include/gbiex.h b/src/include/gbiex.h index 8cc1d50c6..c16107b87 100644 --- a/src/include/gbiex.h +++ b/src/include/gbiex.h @@ -184,18 +184,19 @@ /* 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_EXTRAGEOMETRYMODE_EXT 0x3a -#define G_SETINTENSITY_EXT 0x40 -#define G_COPYFB_EXT 0x41 -#define G_IMAGERECT_EXT 0x42 -#define G_RDPFLUSH_EXT 0x43 -#define G_CLEAR_DEPTH_EXT 0x44 +#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 +#define G_IMAGERECT_EXT 0x42 +#define G_RDPFLUSH_EXT 0x43 +#define G_CLEAR_DEPTH_EXT 0x44 +#define G_FILLRECT_CENTERED_WIDE_EXT 0x45 /* G_EXTRAGEOMETRYMODE flags */ @@ -260,6 +261,16 @@ _g1->words.w1 = _SHIFTL((uly), 2, 22); \ } +#define gDPFillRectangleCenteredWideEXT(pkt, ulx, uly, lrx, lry) \ +{ \ + Gfx *_g0 = (Gfx*)(pkt), *_g1 = (Gfx*)(pkt); \ + \ + _g0->words.w0 = _SHIFTL(G_FILLRECT_CENTERED_WIDE_EXT, 24, 8) | _SHIFTL((lrx), 2, 22); \ + _g0->words.w1 = _SHIFTL((lry), 2, 22); \ + _g1->words.w0 = _SHIFTL((ulx), 2, 22); \ + _g1->words.w1 = _SHIFTL((uly), 2, 22); \ +} + #define gSPTextureRectangleWideEXT(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy, flip) \ { \ Gfx *_g0 = (Gfx*)(pkt), *_g1 = (Gfx*)(pkt), *_g2 = (Gfx*)(pkt); \ @@ -296,6 +307,7 @@ #define gSPClearExtraGeometryModeEXT(pkt, word) gSPExtraGeometryModeEXT((pkt), word, 0) #define gDPFillRectangleEXT gDPFillRectangleWideEXT +#define gDPFillRectangleCenteredEXT gDPFillRectangleCenteredWideEXT #define gSPTextureRectangleEXT(p, xl, yl, xh, yh, tile, s, t, ds, dt) gSPTextureRectangleWideEXT(p, xl, yl, xh, yh, tile, s, t, ds, dt, G_OFF) #define gSPTextureRectangleFlipEXT(p, xl, yl, xh, yh, tile, s, t, ds, dt) gSPTextureRectangleWideEXT(p, xl, yl, xh, yh, tile, s, t, ds, dt, G_ON) @@ -308,10 +320,12 @@ #undef gDPHudRectangle #define gDPHudRectangle(pkt, x1, y1, x2, y2) gDPFillRectangleEXT(pkt, (x1) * g_ScaleX, y1, ((x2 + 1)) * g_ScaleX, (y2) + 1) +#define gDPHudRectangleCentered(pkt, x1, y1, x2, y2) gDPFillRectangleCenteredEXT(pkt, (x1) * g_ScaleX, y1, ((x2 + 1)) * g_ScaleX, (y2) + 1) #else // PLATFORM_N64 #define gDPFillRectangleEXT gDPFillRectangle +#define gDPFillRectangleCenteredEXT gDPFillRectangle #define gSPTextureRectangleEXT gSPTextureRectangle #endif // PLATFORM_N64 From 942c966bf25af2f6256bd6cc65636d6987ca0d14 Mon Sep 17 00:00:00 2001 From: Matthew Coppola Date: Tue, 29 Oct 2024 04:21:10 -0400 Subject: [PATCH 2/5] Replace centered rects with subpixel offsets --- port/fast3d/gfx_pc.cpp | 60 ++++++++--------------- src/game/bondview.c | 24 ++++++---- src/game/sight.c | 106 ++++++++++++++++++++++------------------- src/include/gbiex.h | 23 ++++----- 4 files changed, 103 insertions(+), 110 deletions(-) diff --git a/port/fast3d/gfx_pc.cpp b/port/fast3d/gfx_pc.cpp index 43713c67d..8e701c9fd 100644 --- a/port/fast3d/gfx_pc.cpp +++ b/port/fast3d/gfx_pc.cpp @@ -192,6 +192,9 @@ static struct RDP { bool viewport_or_scissor_changed; void* z_buf_address; void* color_image_address; + + int16_t subpixel_ofs_x; + int16_t subpixel_ofs_y; } rdp; static struct RenderingState { @@ -1969,6 +1972,11 @@ static void gfx_dp_set_fill_color(uint32_t packed_color) { rdp.fill_color.a = a * 255; } +static void gfx_dp_set_subpixel_offset(int16_t x, int16_t y) { + rdp.subpixel_ofs_x = x; + rdp.subpixel_ofs_y = y; +} + static void gfx_draw_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry) { uint32_t saved_other_mode_h = rdp.other_mode_h; uint32_t cycle_type = (rdp.other_mode_h & (3U << G_MDSFT_CYCLETYPE)); @@ -2148,10 +2156,10 @@ static void gfx_dp_image_rectangle(int32_t tile, int32_t w, int32_t h, rdp.combine_mode = saved_combine_mode; } -static int gfx_dp_fill_rectangle_common(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry, uint64_t *saved_combine_mode) { +static void gfx_dp_fill_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry) { if (rdp.color_image_address == rdp.z_buf_address) { // Don't clear Z buffer here since we already did it with glClear - return 1; + return; } uint32_t mode = (rdp.other_mode_h & (3U << G_MDSFT_CYCLETYPE)); @@ -2174,39 +2182,19 @@ static int gfx_dp_fill_rectangle_common(int32_t ulx, int32_t uly, int32_t lrx, i v->color = rdp.fill_color; } - *saved_combine_mode = rdp.combine_mode; + uint64_t saved_combine_mode = rdp.combine_mode; if (mode == G_CYC_FILL) { gfx_dp_set_combine_mode(color_comb(0, 0, 0, G_CCMUX_SHADE), alpha_comb(0, 0, 0, G_ACMUX_SHADE), 0, 0); } - return 0; -} + ulx += rdp.subpixel_ofs_x; + lrx += rdp.subpixel_ofs_x; + uly += rdp.subpixel_ofs_y; + lry += rdp.subpixel_ofs_y; -static void gfx_dp_fill_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry) { - uint64_t saved_combine_mode; - if (gfx_dp_fill_rectangle_common(ulx, uly, lrx, lry, &saved_combine_mode) == 0) { - gfx_draw_rectangle(ulx, uly, lrx, lry); - rdp.combine_mode = saved_combine_mode; - } -} - -static void gfx_dp_fill_rectangle_centered(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry) { - uint64_t saved_combine_mode; - if (gfx_dp_fill_rectangle_common(ulx, uly, lrx, lry, &saved_combine_mode) == 0) { - // The coordinates of the rect are usually quantized to the default N64 - // resolution (320x220), but adding the rect to the graphics display - // list scales it by four. So, a single pixel at 320x220 becomes four - // pixels at 1280x880. Since the crosshair was misaligned by half a - // native pixel, we need to shift the crosshair by two scaled pixels. - ulx -= 2; - lrx -= 2; - uly -= 2; - lry -= 2; - - gfx_draw_rectangle(ulx, uly, lrx, lry); - rdp.combine_mode = saved_combine_mode; - } + gfx_draw_rectangle(ulx, uly, lrx, lry); + rdp.combine_mode = saved_combine_mode; } static void gfx_dp_set_z_image(void* z_buf_address) { @@ -2386,6 +2374,10 @@ static void gfx_run_dl(Gfx* cmd) { break; // G_SETPRIMCOLOR, G_CCMUX_PRIMITIVE, G_ACMUX_PRIMITIVE, is used by Goddard // G_CCMUX_TEXEL1, LOD_FRACTION is used in Bowser room 1 + case G_SETSUBPIXELOFFSET_EXT: { + gfx_dp_set_subpixel_offset(C0(0, 16), C1(0, 16)); + break; + } case G_TEXRECT: case G_TEXRECTFLIP: { int32_t lrx, lry, tile, ulx, uly; @@ -2417,16 +2409,6 @@ static void gfx_run_dl(Gfx* cmd) { gfx_dp_fill_rectangle(ulx, uly, lrx, lry); break; } - case G_FILLRECT_CENTERED_WIDE_EXT: { - int32_t lrx, lry, ulx, uly; - lrx = (int32_t)(C0(0, 24) << 8) >> 8; - lry = (int32_t)(C1(0, 24) << 8) >> 8; - ++cmd; - ulx = (int32_t)(C0(0, 24) << 8) >> 8; - uly = (int32_t)(C1(0, 24) << 8) >> 8; - gfx_dp_fill_rectangle_centered(ulx, uly, lrx, lry); - break; - } case G_TEXRECT_WIDE_EXT: { int32_t lrx, lry, tile, ulx, uly; uint32_t uls, ult, dsdx, dtdy; diff --git a/src/game/bondview.c b/src/game/bondview.c index 935476d6c..f6554a991 100644 --- a/src/game/bondview.c +++ b/src/game/bondview.c @@ -1109,14 +1109,22 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl) s32 x = viewleft + (viewwidth >> 1); s32 y = viewtop + (viewheight >> 1); - gDPFillRectangleCenteredEXT(gdl++, x + 2, y + 0, x + 7, y + 1); - gDPFillRectangleCenteredEXT(gdl++, x + 2, y + 0, x + 5, y + 1); - gDPFillRectangleCenteredEXT(gdl++, x - 6, y + 0, x - 1, y + 1); - gDPFillRectangleCenteredEXT(gdl++, x - 4, y + 0, x - 1, y + 1); - gDPFillRectangleCenteredEXT(gdl++, x + 0, y + 2, x + 1, y + 7); - gDPFillRectangleCenteredEXT(gdl++, x + 0, y + 2, x + 1, y + 5); - gDPFillRectangleCenteredEXT(gdl++, x + 0, y - 6, x + 1, y - 1); - gDPFillRectangleCenteredEXT(gdl++, x + 0, y - 4, x + 1, y - 1); +#ifndef PLATFORM_N64 + gDPSetSubpixelOffsetEXT(gdl++, -2, -2); +#endif + + gDPFillRectangle(gdl++, x + 2, y + 0, x + 7, y + 1); + gDPFillRectangle(gdl++, x + 2, y + 0, x + 5, y + 1); + gDPFillRectangle(gdl++, x - 6, y + 0, x - 1, y + 1); + gDPFillRectangle(gdl++, x - 4, y + 0, x - 1, y + 1); + gDPFillRectangle(gdl++, x + 0, y + 2, x + 1, y + 7); + gDPFillRectangle(gdl++, x + 0, y + 2, x + 1, y + 5); + gDPFillRectangle(gdl++, x + 0, y - 6, x + 1, y - 1); + gDPFillRectangle(gdl++, x + 0, y - 4, x + 1, y - 1); + +#ifndef PLATFORM_N64 + gDPSetSubpixelOffsetEXT(gdl++, 0, 0); +#endif } if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_CAMSPY) { diff --git a/src/game/sight.c b/src/game/sight.c index a3bdd642f..2fe7cc047 100644 --- a/src/game/sight.c +++ b/src/game/sight.c @@ -515,42 +515,44 @@ Gfx *sightDrawAimer(Gfx *gdl, s32 x, s32 y, s32 radius, s32 cornergap, u32 colou #ifndef PLATFORM_N64 x = sightGetAdjustedX(x); gSPSetExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT); + gDPSetSubpixelOffsetEXT(gdl++, -2, -2); #endif // Draw the lines that span most of the viewport if (PLAYERCOUNT() == 1) { - gDPHudRectangleCentered(gdl++, viewleft + 48, y, x - radius + 2, y); - gDPHudRectangleCentered(gdl++, x + radius - 2, y, viewright - 49, y); - gDPHudRectangleCentered(gdl++, x, viewtop + 10, x, y - radius + 2); - gDPHudRectangleCentered(gdl++, x, y + radius - 2, x, viewbottom - 10); + gDPHudRectangle(gdl++, viewleft + 48, y, x - radius + 2, y); + gDPHudRectangle(gdl++, x + radius - 2, y, viewright - 49, y); + gDPHudRectangle(gdl++, x, viewtop + 10, x, y - radius + 2); + gDPHudRectangle(gdl++, x, y + radius - 2, x, viewbottom - 10); } else { - gDPHudRectangleCentered(gdl++, viewleft, y, x - radius + 2, y); - gDPHudRectangleCentered(gdl++, x + radius - 2, y, viewright, y); - gDPHudRectangleCentered(gdl++, x, viewtop, x, y - radius + 2); - gDPHudRectangleCentered(gdl++, x, y + radius - 2, x, viewbottom); + gDPHudRectangle(gdl++, viewleft, y, x - radius + 2, y); + gDPHudRectangle(gdl++, x + radius - 2, y, viewright, y); + gDPHudRectangle(gdl++, x, viewtop, x, y - radius + 2); + gDPHudRectangle(gdl++, x, y + radius - 2, x, viewbottom); } gdl = text0f153838(gdl); gdl = textSetPrimColour(gdl, colour); // Draw the box - gDPHudRectangleCentered(gdl++, x - radius, y - radius, x - radius, y + radius); - gDPHudRectangleCentered(gdl++, x + radius, y - radius, x + radius, y + radius); - gDPHudRectangleCentered(gdl++, x - radius, y - radius, x + radius, y - radius); - gDPHudRectangleCentered(gdl++, x - radius, y + radius, x + radius, y + radius); + gDPHudRectangle(gdl++, x - radius, y - radius, x - radius, y + radius); + gDPHudRectangle(gdl++, x + radius, y - radius, x + radius, y + radius); + gDPHudRectangle(gdl++, x - radius, y - radius, x + radius, y - radius); + gDPHudRectangle(gdl++, x - radius, y + radius, x + radius, y + radius); // Go over the corners a second time - gDPHudRectangleCentered(gdl++, x - radius, y - radius, x - radius, y - cornergap); - gDPHudRectangleCentered(gdl++, x - radius, y + cornergap, x - radius, y + radius); - gDPHudRectangleCentered(gdl++, x + radius, y - radius, x + radius, y - cornergap); - gDPHudRectangleCentered(gdl++, x + radius, y + cornergap, x + radius, y + radius); - gDPHudRectangleCentered(gdl++, x - radius, y - radius, x - cornergap, y - radius); - gDPHudRectangleCentered(gdl++, x + cornergap, y - radius, x + radius, y - radius); - gDPHudRectangleCentered(gdl++, x - radius, y + radius, x - cornergap, y + radius); - gDPHudRectangleCentered(gdl++, x + cornergap, y + radius, x + radius, y + radius); + gDPHudRectangle(gdl++, x - radius, y - radius, x - radius, y - cornergap); + gDPHudRectangle(gdl++, x - radius, y + cornergap, x - radius, y + radius); + gDPHudRectangle(gdl++, x + radius, y - radius, x + radius, y - cornergap); + gDPHudRectangle(gdl++, x + radius, y + cornergap, x + radius, y + radius); + gDPHudRectangle(gdl++, x - radius, y - radius, x - cornergap, y - radius); + gDPHudRectangle(gdl++, x + cornergap, y - radius, x + radius, y - radius); + gDPHudRectangle(gdl++, x - radius, y + radius, x - cornergap, y + radius); + gDPHudRectangle(gdl++, x + cornergap, y + radius, x + radius, y + radius); #ifndef PLATFORM_N64 gSPClearExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT); + gDPSetSubpixelOffsetEXT(gdl++, 0, 0); #endif gdl = text0f153838(gdl); @@ -1354,47 +1356,49 @@ Gfx *sightDrawZoom(Gfx *gdl, bool sighton) #ifndef PLATFORM_N64 gSPSetExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT); + gDPSetSubpixelOffsetEXT(gdl++, -2, -2); #endif // Top left - gDPHudRectangleCentered(gdl++, BOXLEFT + 1, BOXTOP, BOXLEFT + cornerwidth - 1, BOXTOP); - gDPHudRectangleCentered(gdl++, BOXLEFT, BOXTOP, BOXLEFT, BOXTOP + cornerheight - 1); + gDPHudRectangle(gdl++, BOXLEFT + 1, BOXTOP, BOXLEFT + cornerwidth - 1, BOXTOP); + gDPHudRectangle(gdl++, BOXLEFT, BOXTOP, BOXLEFT, BOXTOP + cornerheight - 1); // Top right - gDPHudRectangleCentered(gdl++, BOXRIGHT - cornerwidth + 2, BOXTOP, BOXRIGHT - 1, BOXTOP); - gDPHudRectangleCentered(gdl++, BOXRIGHT, BOXTOP, BOXRIGHT, BOXTOP + cornerheight - 1); + gDPHudRectangle(gdl++, BOXRIGHT - cornerwidth + 2, BOXTOP, BOXRIGHT - 1, BOXTOP); + gDPHudRectangle(gdl++, BOXRIGHT, BOXTOP, BOXRIGHT, BOXTOP + cornerheight - 1); // Bottom left - gDPHudRectangleCentered(gdl++, BOXLEFT + 1, BOXBOTTOM, BOXLEFT + cornerwidth - 1, BOXBOTTOM); - gDPHudRectangleCentered(gdl++, BOXLEFT, BOXBOTTOM - cornerheight + 1, BOXLEFT, BOXBOTTOM); + gDPHudRectangle(gdl++, BOXLEFT + 1, BOXBOTTOM, BOXLEFT + cornerwidth - 1, BOXBOTTOM); + gDPHudRectangle(gdl++, BOXLEFT, BOXBOTTOM - cornerheight + 1, BOXLEFT, BOXBOTTOM); // Bottom right - gDPHudRectangleCentered(gdl++, BOXRIGHT - cornerwidth + 2, BOXBOTTOM, BOXRIGHT - 1, BOXBOTTOM); - gDPHudRectangleCentered(gdl++, BOXRIGHT, BOXBOTTOM - cornerheight + 1, BOXRIGHT, BOXBOTTOM); + gDPHudRectangle(gdl++, BOXRIGHT - cornerwidth + 2, BOXBOTTOM, BOXRIGHT - 1, BOXBOTTOM); + gDPHudRectangle(gdl++, BOXRIGHT, BOXBOTTOM - cornerheight + 1, BOXRIGHT, BOXBOTTOM); // Draw over the corners again, but only half as wide/high cornerwidth >>= 1; cornerheight >>= 1; // Top left - gDPHudRectangleCentered(gdl++, BOXLEFT, BOXTOP, BOXLEFT + cornerwidth, BOXTOP); - gDPHudRectangleCentered(gdl++, BOXLEFT, BOXTOP, BOXLEFT, BOXTOP + cornerheight); + gDPHudRectangle(gdl++, BOXLEFT, BOXTOP, BOXLEFT + cornerwidth, BOXTOP); + gDPHudRectangle(gdl++, BOXLEFT, BOXTOP, BOXLEFT, BOXTOP + cornerheight); // Top right - gDPHudRectangleCentered(gdl++, BOXRIGHT - cornerwidth, BOXTOP, BOXRIGHT, BOXTOP); - gDPHudRectangleCentered(gdl++, BOXRIGHT, BOXTOP, BOXRIGHT, BOXTOP + cornerheight); + gDPHudRectangle(gdl++, BOXRIGHT - cornerwidth, BOXTOP, BOXRIGHT, BOXTOP); + gDPHudRectangle(gdl++, BOXRIGHT, BOXTOP, BOXRIGHT, BOXTOP + cornerheight); // Bottom left - gDPHudRectangleCentered(gdl++, BOXLEFT, BOXBOTTOM, BOXLEFT + cornerwidth, BOXBOTTOM); - gDPHudRectangleCentered(gdl++, BOXLEFT, BOXBOTTOM - cornerheight, BOXLEFT, BOXBOTTOM); + gDPHudRectangle(gdl++, BOXLEFT, BOXBOTTOM, BOXLEFT + cornerwidth, BOXBOTTOM); + gDPHudRectangle(gdl++, BOXLEFT, BOXBOTTOM - cornerheight, BOXLEFT, BOXBOTTOM); // Bottom right - gDPHudRectangleCentered(gdl++, BOXRIGHT - cornerwidth, BOXBOTTOM, BOXRIGHT, BOXBOTTOM); - gDPHudRectangleCentered(gdl++, BOXRIGHT, BOXBOTTOM - cornerheight, BOXRIGHT, BOXBOTTOM); + gDPHudRectangle(gdl++, BOXRIGHT - cornerwidth, BOXBOTTOM, BOXRIGHT, BOXBOTTOM); + gDPHudRectangle(gdl++, BOXRIGHT, BOXBOTTOM - cornerheight, BOXRIGHT, BOXBOTTOM); #ifndef PLATFORM_N64 gSPClearExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT); + gDPSetSubpixelOffsetEXT(gdl++, 0, 0); #endif gdl = text0f153838(gdl); @@ -1433,6 +1437,7 @@ Gfx *sightDrawMaian(Gfx *gdl, bool sighton) #ifndef PLATFORM_N64 x = sightGetAdjustedX(x); gSPSetExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT); + gDPSetSubpixelOffsetEXT(gdl++, -2, -2); #endif vertices = gfxAllocateVertices(8); @@ -1498,15 +1503,16 @@ Gfx *sightDrawMaian(Gfx *gdl, bool sighton) gdl = textSetPrimColour(gdl, SIGHT_COLOUR); // Draw border over inner points - gDPHudRectangleCentered(gdl++, x - 4, y - 4, x - 4, y + 4); // left - gDPHudRectangleCentered(gdl++, x + 4, y - 4, x + 4, y + 4); // right - gDPHudRectangleCentered(gdl++, x - 4, y - 4, x + 4, y - 4); // top - gDPHudRectangleCentered(gdl++, x - 4, y + 4, x + 4, y + 4); // bottom + gDPHudRectangle(gdl++, x - 4, y - 4, x - 4, y + 4); // left + gDPHudRectangle(gdl++, x + 4, y - 4, x + 4, y + 4); // right + gDPHudRectangle(gdl++, x - 4, y - 4, x + 4, y - 4); // top + gDPHudRectangle(gdl++, x - 4, y + 4, x + 4, y + 4); // bottom gdl = text0f153838(gdl); #ifndef PLATFORM_N64 gSPClearExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT); + gDPSetSubpixelOffsetEXT(gdl++, 0, 0); #endif return gdl; @@ -1527,24 +1533,26 @@ Gfx *sightDrawTarget(Gfx *gdl) #ifndef PLATFORM_N64 gSPSetExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT); + gDPSetSubpixelOffsetEXT(gdl++, -2, -2); if (SIGHT_SCALE == 0) { // Draw single rectangle to preserve intended opacity - gDPHudRectangleCentered(gdl++, x, y, x, y); + gDPHudRectangle(gdl++, x, y, x, y); } else #endif { - gDPHudRectangleCentered(gdl++, x + 1 * SIGHT_SCALE, y + 0 * SIGHT_SCALE, x + 3 * SIGHT_SCALE, y + 0 * SIGHT_SCALE); - gDPHudRectangleCentered(gdl++, x + 1 * SIGHT_SCALE, y + 0 * SIGHT_SCALE, x + 2 * SIGHT_SCALE, y + 0 * SIGHT_SCALE); - gDPHudRectangleCentered(gdl++, x - 3 * SIGHT_SCALE, y + 0 * SIGHT_SCALE, x - 1 * SIGHT_SCALE, y + 0 * SIGHT_SCALE); - gDPHudRectangleCentered(gdl++, x - 2 * SIGHT_SCALE, y + 0 * SIGHT_SCALE, x - 1 * SIGHT_SCALE, y + 0 * SIGHT_SCALE); - gDPHudRectangleCentered(gdl++, x + 0 * SIGHT_SCALE, y + 1 * SIGHT_SCALE, x + 0 * SIGHT_SCALE, y + 3 * SIGHT_SCALE); - gDPHudRectangleCentered(gdl++, x + 0 * SIGHT_SCALE, y + 1 * SIGHT_SCALE, x + 0 * SIGHT_SCALE, y + 2 * SIGHT_SCALE); - gDPHudRectangleCentered(gdl++, x + 0 * SIGHT_SCALE, y - 3 * SIGHT_SCALE, x + 0 * SIGHT_SCALE, y - 1 * SIGHT_SCALE); - gDPHudRectangleCentered(gdl++, x + 0 * SIGHT_SCALE, y - 2 * SIGHT_SCALE, x + 0 * SIGHT_SCALE, y - 1 * SIGHT_SCALE); + gDPHudRectangle(gdl++, x + 1 * SIGHT_SCALE, y + 0 * SIGHT_SCALE, x + 3 * SIGHT_SCALE, y + 0 * SIGHT_SCALE); + gDPHudRectangle(gdl++, x + 1 * SIGHT_SCALE, y + 0 * SIGHT_SCALE, x + 2 * SIGHT_SCALE, y + 0 * SIGHT_SCALE); + gDPHudRectangle(gdl++, x - 3 * SIGHT_SCALE, y + 0 * SIGHT_SCALE, x - 1 * SIGHT_SCALE, y + 0 * SIGHT_SCALE); + gDPHudRectangle(gdl++, x - 2 * SIGHT_SCALE, y + 0 * SIGHT_SCALE, x - 1 * SIGHT_SCALE, y + 0 * SIGHT_SCALE); + gDPHudRectangle(gdl++, x + 0 * SIGHT_SCALE, y + 1 * SIGHT_SCALE, x + 0 * SIGHT_SCALE, y + 3 * SIGHT_SCALE); + gDPHudRectangle(gdl++, x + 0 * SIGHT_SCALE, y + 1 * SIGHT_SCALE, x + 0 * SIGHT_SCALE, y + 2 * SIGHT_SCALE); + gDPHudRectangle(gdl++, x + 0 * SIGHT_SCALE, y - 3 * SIGHT_SCALE, x + 0 * SIGHT_SCALE, y - 1 * SIGHT_SCALE); + gDPHudRectangle(gdl++, x + 0 * SIGHT_SCALE, y - 2 * SIGHT_SCALE, x + 0 * SIGHT_SCALE, y - 1 * SIGHT_SCALE); } #ifndef PLATFORM_N64 gSPClearExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT); + gDPSetSubpixelOffsetEXT(gdl++, 0, 0); #endif gdl = text0f153838(gdl); diff --git a/src/include/gbiex.h b/src/include/gbiex.h index c16107b87..687d08d90 100644 --- a/src/include/gbiex.h +++ b/src/include/gbiex.h @@ -196,7 +196,7 @@ #define G_IMAGERECT_EXT 0x42 #define G_RDPFLUSH_EXT 0x43 #define G_CLEAR_DEPTH_EXT 0x44 -#define G_FILLRECT_CENTERED_WIDE_EXT 0x45 +#define G_SETSUBPIXELOFFSET_EXT 0x45 /* G_EXTRAGEOMETRYMODE flags */ @@ -261,16 +261,6 @@ _g1->words.w1 = _SHIFTL((uly), 2, 22); \ } -#define gDPFillRectangleCenteredWideEXT(pkt, ulx, uly, lrx, lry) \ -{ \ - Gfx *_g0 = (Gfx*)(pkt), *_g1 = (Gfx*)(pkt); \ - \ - _g0->words.w0 = _SHIFTL(G_FILLRECT_CENTERED_WIDE_EXT, 24, 8) | _SHIFTL((lrx), 2, 22); \ - _g0->words.w1 = _SHIFTL((lry), 2, 22); \ - _g1->words.w0 = _SHIFTL((ulx), 2, 22); \ - _g1->words.w1 = _SHIFTL((uly), 2, 22); \ -} - #define gSPTextureRectangleWideEXT(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy, flip) \ { \ Gfx *_g0 = (Gfx*)(pkt), *_g1 = (Gfx*)(pkt), *_g2 = (Gfx*)(pkt); \ @@ -303,11 +293,18 @@ _g->words.w1 = (u32)(s); \ } +#define gDPSetSubpixelOffsetEXT(pkt, x, y) \ +{ \ + Gfx *_g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_SETSUBPIXELOFFSET_EXT, 24, 8) | _SHIFTL((s16)(x), 0, 16); \ + _g->words.w1 = _SHIFTL((s16)(y), 0, 16); \ +} + #define gSPSetExtraGeometryModeEXT(pkt, word) gSPExtraGeometryModeEXT((pkt), 0, word) #define gSPClearExtraGeometryModeEXT(pkt, word) gSPExtraGeometryModeEXT((pkt), word, 0) #define gDPFillRectangleEXT gDPFillRectangleWideEXT -#define gDPFillRectangleCenteredEXT gDPFillRectangleCenteredWideEXT #define gSPTextureRectangleEXT(p, xl, yl, xh, yh, tile, s, t, ds, dt) gSPTextureRectangleWideEXT(p, xl, yl, xh, yh, tile, s, t, ds, dt, G_OFF) #define gSPTextureRectangleFlipEXT(p, xl, yl, xh, yh, tile, s, t, ds, dt) gSPTextureRectangleWideEXT(p, xl, yl, xh, yh, tile, s, t, ds, dt, G_ON) @@ -320,12 +317,10 @@ #undef gDPHudRectangle #define gDPHudRectangle(pkt, x1, y1, x2, y2) gDPFillRectangleEXT(pkt, (x1) * g_ScaleX, y1, ((x2 + 1)) * g_ScaleX, (y2) + 1) -#define gDPHudRectangleCentered(pkt, x1, y1, x2, y2) gDPFillRectangleCenteredEXT(pkt, (x1) * g_ScaleX, y1, ((x2 + 1)) * g_ScaleX, (y2) + 1) #else // PLATFORM_N64 #define gDPFillRectangleEXT gDPFillRectangle -#define gDPFillRectangleCenteredEXT gDPFillRectangle #define gSPTextureRectangleEXT gSPTextureRectangle #endif // PLATFORM_N64 From 938223db289d4e1b1e04251a69643c75d7780783 Mon Sep 17 00:00:00 2001 From: Matthew Coppola Date: Tue, 12 Nov 2024 20:31:08 -0500 Subject: [PATCH 3/5] Center Maian and Skedar tri sights --- src/game/sight.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/game/sight.c b/src/game/sight.c index 2fe7cc047..b32e4c87a 100644 --- a/src/game/sight.c +++ b/src/game/sight.c @@ -1036,6 +1036,14 @@ Gfx *sightDrawSkedarTriangle(Gfx *gdl, s32 x, s32 y, s32 dir, u32 colour) vertices[2].y = points[5] * 10; vertices[2].z = -10; +#ifndef PLATFORM_N64 + // Center-align Skedar tris + for (int i = 0; i < 3; ++i) { + vertices[i].x -= 2; + vertices[i].y += 2; + } +#endif + // @bug: This also needs to check for COLOUR_LIGHTRED because the caller can // use two shades of red. The second colour is used when zeroing the sight // in on a new target. Because of this bug, targeting an ally with the @@ -1333,13 +1341,15 @@ Gfx *sightDrawZoom(Gfx *gdl, bool sighton) marginbottom = viewhalfheight - availablebelow * frac; margintop = viewhalfheight - availableabove * frac; - // Center-align the zoom range. +#ifndef PLATFORM_N64 + // Center-align the zoom range if (frac != 1.0f) { viewleft += 1; viewright += 1; viewbottom += 1; viewtop += 1; } +#endif #define BOXLEFT (viewleft + marginleft) #define BOXRIGHT (viewright - marginright) @@ -1482,6 +1492,14 @@ Gfx *sightDrawMaian(Gfx *gdl, bool sighton) vertices[7].y = inner[2] * 10; vertices[7].z = -10; +#ifndef PLATFORM_N64 + // Center-align Maian tris + for (int i = 0; i < 8; ++i) { + vertices[i].x -= 2; + vertices[i].y += 2; + } +#endif + colours[0].word = PD_BE32(0x00ff000f); colours[1].word = PD_BE32(hasprop ? colour : 0x00ff0044); From bc82328353e98ff487a87b95a884363cfbfcf102 Mon Sep 17 00:00:00 2001 From: Matthew Coppola Date: Wed, 13 Nov 2024 02:52:58 -0500 Subject: [PATCH 4/5] Improve crosshair position accuracy by rounding --- src/game/sight.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/game/sight.c b/src/game/sight.c index b32e4c87a..0764caf5d 100644 --- a/src/game/sight.c +++ b/src/game/sight.c @@ -1602,6 +1602,16 @@ Gfx *sightDraw(Gfx *gdl, bool sighton, s32 sight) return gdl; } +#ifndef PLATFORM_N64 + // Rounding the crosshair positions allow them to more accurately follow the + // gun's vector. Without this, the mantissa isn't factored in at all (cast + // to integer), which leads to some awkward behavior, such as the crosshair + // taking a long time to return to the center of the screen when coming from + // an up and/or left direction. + g_Vars.currentplayer->crosspos[0] = roundf(g_Vars.currentplayer->crosspos[0]); + g_Vars.currentplayer->crosspos[1] = roundf(g_Vars.currentplayer->crosspos[1]); +#endif + #if PAL g_ScaleX = 1; #else From fb18da239fbce7bc923eb737a0070986c32542d1 Mon Sep 17 00:00:00 2001 From: Matthew Coppola Date: Fri, 15 Nov 2024 02:59:58 -0500 Subject: [PATCH 5/5] Move subpixel offset code & fix radar UV map The subpixel offset code has been moved into the draw_rectangle function, so it can be applied to more than just the fill_rectangle function. The radar texture was displaced along its V component and has been corrected. It has also been subpixel-adjusted to align with the player's radar dot. --- port/fast3d/gfx_pc.cpp | 10 +++++----- src/game/radar.c | 4 +++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/port/fast3d/gfx_pc.cpp b/port/fast3d/gfx_pc.cpp index 8e701c9fd..0acaff3fc 100644 --- a/port/fast3d/gfx_pc.cpp +++ b/port/fast3d/gfx_pc.cpp @@ -1985,6 +1985,11 @@ static void gfx_draw_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lr rdp.other_mode_h = (rdp.other_mode_h & ~(3U << G_MDSFT_TEXTFILT)) | G_TF_POINT; } + ulx += rdp.subpixel_ofs_x; + lrx += rdp.subpixel_ofs_x; + uly += rdp.subpixel_ofs_y; + lry += rdp.subpixel_ofs_y; + // U10.2 coordinates float ulxf = ulx; float ulyf = uly; @@ -2188,11 +2193,6 @@ static void gfx_dp_fill_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t gfx_dp_set_combine_mode(color_comb(0, 0, 0, G_CCMUX_SHADE), alpha_comb(0, 0, 0, G_ACMUX_SHADE), 0, 0); } - ulx += rdp.subpixel_ofs_x; - lrx += rdp.subpixel_ofs_x; - uly += rdp.subpixel_ofs_y; - lry += rdp.subpixel_ofs_y; - gfx_draw_rectangle(ulx, uly, lrx, lry); rdp.combine_mode = saved_combine_mode; } diff --git a/src/game/radar.c b/src/game/radar.c index 2a449e034..d289a9a04 100644 --- a/src/game/radar.c +++ b/src/game/radar.c @@ -80,7 +80,7 @@ Gfx *radarRenderBackground(Gfx *gdl, struct textureconfig *tconfig, s32 arg2, s3 texSelect(&gdl, tconfig, 2, 0, 0, 1, NULL); func0f0b278c(&gdl, spb0, spa8, tconfig->width, tconfig->height, - 0, 0, 1, 0, 0xff, 0, 40, tconfig->level > 0, 0); + 0, 0, 0, 0, 0xff, 0, 40, tconfig->level > 0, 0); gDPPipeSync(gdl++); gDPSetColorDither(gdl++, G_CD_BAYER); @@ -329,6 +329,7 @@ Gfx *radarRender(Gfx *gdl) } #ifndef PLATFORM_N64 gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, g_HudAlignModeR); + gDPSetSubpixelOffsetEXT(gdl++, -2, 2); #endif } @@ -337,6 +338,7 @@ Gfx *radarRender(Gfx *gdl) // Draw dots for human players #ifndef PLATFORM_N64 + gDPSetSubpixelOffsetEXT(gdl++, 0, 0); if (!(g_MpSetup.options & MPOPTION_NOPLAYERONRADAR)) { #endif for (i = 0; i < playercount; i++) {