foxygit / doom Log in
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");
 }