commit 2788d67e3ce3592f198b42bb1bf9a8a83830f976
Author: jens <jens.se@icloud.com>
AuthorDate: Sat Aug 22 09:46:43 2026 +0200
Commit: jens <jens.se@icloud.com>
CommitDate: Sat Aug 22 09:46:43 2026 +0200
Fix Multiplayer menu label: wrong size, then wrong position
First pass made the label bigger by calling V_DrawPatchDirectScaled
with a bigger scale than this file's usual 2x - but that function
multiplies position by scale too (see V_DrawPatchScaledCore in
v_video.c), so passing the same native coordinates at scale 3 instead
of 2 didn't just enlarge the glyphs, it also dragged the whole label a
row and a half further down the screen than intended, overlapping Load
Game/Save Game instead of sitting between New Game and Options.
Added V_DrawPatchBlockScaled, which takes real-screen coordinates
directly and enlarges glyph content independently of position, so the
label can be sized up without its position scaling along with it.
M_WriteMenuLabel and its one caller now work in real-screen space
instead of native coordinates (unlike M_WriteText) for exactly this
reason. Verified in-game: MULTIPLAYER now sits correctly between New
Game and Options, at a size much closer to the other (WAD graphic)
items, with correct skull-cursor alignment.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
---
src/doom/m_menu.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 86 insertions(+), 2 deletions(-)
diff --git a/src/doom/m_menu.c b/src/doom/m_menu.c
index 6f8d57a7..1810b99e 100644
--- a/src/doom/m_menu.c
+++ b/src/doom/m_menu.c
@@ -887,14 +887,98 @@ void M_MusicVol(int choice)
//
// M_DrawMainMenu
//
+// Draws one hu_font glyph with each source pixel enlarged to a
+// blocksize x blocksize block, at literal real-screen coordinates (x,
+// y is the patch's own top-left before any offset/size scaling, same
+// as V_DrawPatch). Unlike V_DrawPatchScaled, x/y are NOT themselves
+// multiplied by blocksize - position and glyph size are independent -
+// which is the point: M_WriteMenuLabel below needs to land each label
+// at the same real position this file's normal (native times its
+// usual V_DrawPatchDirect scale) item positions do, while still
+// drawing noticeably bigger than that scale alone would.
+static void V_DrawPatchBlockScaled(int x, int y, patch_t *patch, int blocksize)
+{
+ column_t *column;
+ byte *source;
+ pixel_t *dest;
+ int count, i, dx, dy;
+ int w, col;
+ int srcx, srcy;
+
+ y -= SHORT(patch->topoffset) * blocksize;
+ x -= SHORT(patch->leftoffset) * blocksize;
+
+ w = SHORT(patch->width);
+
+ for (col = 0 ; col < w ; col++)
+ {
+ column = (column_t *)((byte *)patch + LONG(patch->columnofs[col]));
+ srcx = x + col * blocksize;
+
+ while (column->topdelta != 0xff)
+ {
+ source = (byte *)column + 3;
+ count = column->length;
+
+ for (i = 0 ; i < count ; i++)
+ {
+ srcy = y + (column->topdelta + i) * blocksize;
+ for (dy = 0 ; dy < blocksize ; dy++)
+ {
+ // The menu never draws while V_UseBuffer has
+ // redirected output elsewhere, so I_VideoBuffer -
+ // the real screen - is always the right target here.
+ dest = I_VideoBuffer + (srcy+dy)*SCREENWIDTH + srcx;
+ for (dx = 0 ; dx < blocksize ; dx++)
+ dest[dx] = source[i];
+ }
+ }
+ column = (column_t *)((byte *)column + column->length + 4);
+ }
+ }
+}
+
+// Draws str at real-screen position (x, y) - see V_DrawPatchBlockScaled
+// above for why that's real rather than native coordinates here, unlike
+// M_WriteText. Noticeably bigger than M_WriteText's usual size: hu_font
+// reads much smaller/thinner than the stylized WAD graphics (M_NGAME,
+// M_OPTION, ...) every other menu item uses, so at M_WriteText's size a
+// text-label item looks visibly out of place next to them. Only for
+// menu items with no matching WAD graphic - see their blank name in
+// MainMenu/OptionsMenu.
+static void M_WriteMenuLabel(int x, int y, const char *string)
+{
+ int blocksize = (SCREENWIDTH / ORIGWIDTH) * 3 / 2;
+ int cx = x;
+ const char *ch;
+ int c;
+
+ for (ch = string; *ch != '\0'; ch++)
+ {
+ c = toupper(*ch) - HU_FONTSTART;
+ if (c < 0 || c >= HU_FONTSIZE)
+ {
+ cx += 4 * (SCREENWIDTH / ORIGWIDTH);
+ continue;
+ }
+ V_DrawPatchBlockScaled(cx, y, hu_font[c], blocksize);
+ cx += SHORT(hu_font[c]->width) * blocksize;
+ }
+}
+
void M_DrawMainMenu(void)
{
V_DrawPatchDirect(94, 2,
W_CacheLumpName(DEH_String("M_DOOM"), PU_CACHE));
// No WAD graphic for this item - see its blank name in MainMenu.
- M_WriteText(MainDef.x, MainDef.y + LINEHEIGHT * multiplayer + 4,
- "MULTIPLAYER");
+ // Real-screen position matching where this row's other items land
+ // (native times this file's usual scale), plus a few real pixels
+ // down to roughly center the taller glyphs within the row - see
+ // M_WriteMenuLabel/V_DrawPatchBlockScaled above.
+ M_WriteMenuLabel(MainDef.x * (SCREENWIDTH / ORIGWIDTH),
+ (MainDef.y + LINEHEIGHT * multiplayer) * (SCREENWIDTH / ORIGWIDTH) + 4,
+ "MULTIPLAYER");
}