From 66042ef8a189c02c5c370d0ccfdd685fc0f2a2ca Mon Sep 17 00:00:00 2001 From: spherallic Date: Thu, 9 Mar 2023 11:20:26 +0100 Subject: [PATCH] Improved handling of multi-line strings: - Centered/right-aligned string drawing now properly handles newlines - Measuring string width/height takes newlines into account - String height also takes V_RETURN8 into account - Cleaned up menu message code, removed now-redundant M_StringHeight --- src/m_menu.c | 149 +++----------------------------------------------- src/v_video.c | 114 +++++++++++++++++++++++++------------- src/v_video.h | 6 +- 3 files changed, 87 insertions(+), 182 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index a866654a4..a6d4d8b63 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -4957,22 +4957,6 @@ static void M_DrawCenteredMenu(void) } } -// -// M_StringHeight -// -// Find string height from hu_font chars -// -static inline size_t M_StringHeight(const char *string) -{ - size_t h = 8, i; - - for (i = 0; i < strlen(string); i++) - if (string[i] == '\n') - h += 8; - - return h; -} - // ========================================================================== // Extraneous menu patching functions // ========================================================================== @@ -6099,56 +6083,16 @@ menu_t MessageDef = NULL }; - -void M_StartMessage(const char *string, void *routine, - menumessagetype_t itemtype) +void M_StartMessage(const char *string, void *routine, menumessagetype_t itemtype) { - size_t max = 0, start = 0, i, strlines; - static char *message = NULL; + static char *message; Z_Free(message); - message = Z_StrDup(string); + message = V_WordWrap(0,0,V_ALLOWLOWERCASE,string); DEBFILE(message); - // Rudementary word wrapping. - // Simple and effective. Does not handle nonuniform letter sizes, colors, etc. but who cares. - strlines = 0; - for (i = 0; message[i]; i++) - { - if (message[i] == ' ') - { - start = i; - max += 4; - } - else if (message[i] == '\n') - { - strlines = i; - start = 0; - max = 0; - continue; - } - else - max += 8; - - // Start trying to wrap if presumed length exceeds the screen width. - if (max >= BASEVIDWIDTH && start > 0) - { - message[start] = '\n'; - max -= (start-strlines)*8; - strlines = start; - start = 0; - } - } - - start = 0; - max = 0; - M_StartControlPanel(); // can't put menuactive to true - if (currentMenu == &MessageDef) // Prevent recursion - MessageDef.prevMenu = &MainDef; - else - MessageDef.prevMenu = currentMenu; - + MessageDef.prevMenu = (currentMenu == &MessageDef) ? &MainDef : currentMenu; // Prevent recursion MessageDef.menuitems[0].text = message; MessageDef.menuitems[0].alphaKey = (UINT8)itemtype; if (!routine && itemtype != MM_NOTHING) itemtype = MM_NOTHING; @@ -6167,51 +6111,17 @@ void M_StartMessage(const char *string, void *routine, MessageDef.menuitems[0].itemaction = routine; break; } - //added : 06-02-98: now draw a textbox around the message - // compute lenght max and the numbers of lines - for (strlines = 0; *(message+start); strlines++) - { - for (i = 0;i < strlen(message+start);i++) - { - if (*(message+start+i) == '\n') - { - if (i > max) - max = i; - start += i; - i = (size_t)-1; //added : 07-02-98 : damned! - start++; - break; - } - } + MessageDef.x = (INT16)((BASEVIDWIDTH - V_StringWidth(message, 0)-32)/2); + MessageDef.y = (INT16)((BASEVIDHEIGHT - V_StringHeight(message, V_RETURN8))/2); - if (i == strlen(message+start)) - start += i; - } - - MessageDef.x = (INT16)((BASEVIDWIDTH - 8*max-16)/2); - MessageDef.y = (INT16)((BASEVIDHEIGHT - M_StringHeight(message))/2); - - MessageDef.lastOn = (INT16)((strlines<<8)+max); - - //M_SetupNextMenu(); currentMenu = &MessageDef; itemOn = 0; } -#define MAXMSGLINELEN 256 - static void M_DrawMessageMenu(void) { - INT32 y = currentMenu->y; - size_t i, start = 0; - INT16 max; - char string[MAXMSGLINELEN]; - INT32 mlines; const char *msg = currentMenu->menuitems[0].text; - mlines = currentMenu->lastOn>>8; - max = (INT16)((UINT8)(currentMenu->lastOn & 0xFF)*8); - // hack: draw RA background in RA menus if (gamestate == GS_TIMEATTACK) { @@ -6235,51 +6145,8 @@ static void M_DrawMessageMenu(void) V_DrawFadeScreen(0xFF00, curfadevalue); } - M_DrawTextBox(currentMenu->x, y - 8, (max+7)>>3, mlines); - - while (*(msg+start)) - { - size_t len = strlen(msg+start); - - for (i = 0; i < len; i++) - { - if (*(msg+start+i) == '\n') - { - memset(string, 0, MAXMSGLINELEN); - if (i >= MAXMSGLINELEN) - { - CONS_Printf("M_DrawMessageMenu: too long segment in %s\n", msg); - return; - } - else - { - strncpy(string,msg+start, i); - string[i] = '\0'; - start += i; - i = (size_t)-1; //added : 07-02-98 : damned! - start++; - } - break; - } - } - - if (i == strlen(msg+start)) - { - if (i >= MAXMSGLINELEN) - { - CONS_Printf("M_DrawMessageMenu: too long segment in %s\n", msg); - return; - } - else - { - strcpy(string, msg + start); - start += i; - } - } - - V_DrawString((BASEVIDWIDTH - V_StringWidth(string, 0))/2,y,V_ALLOWLOWERCASE,string); - y += 8; //hu_font.chars[0]->height; - } + M_DrawTextBox(currentMenu->x, currentMenu->y - 8, 2+V_StringWidth(msg, 0)/8, V_StringHeight(msg, V_RETURN8)/8); + V_DrawCenteredString(BASEVIDWIDTH/2, currentMenu->y, V_ALLOWLOWERCASE|V_RETURN8, msg); } // default message handler diff --git a/src/v_video.c b/src/v_video.c index a9fbceb3d..922b7f7d4 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1990,10 +1990,7 @@ void V_DrawFontCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed, fi flags = c & ~(V_CHARCOLORMASK | V_PARAMMASK); c &= 0x7f; - if (lowercaseallowed) - c -= FONTSTART; - else - c = toupper(c) - FONTSTART; + c = (lowercaseallowed ? c : toupper(c)) - FONTSTART; if (c < 0 || c >= FONTSIZE || !font.chars[c]) return; @@ -2009,8 +2006,7 @@ void V_DrawFontCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed, fi char *V_FontWordWrap(INT32 x, INT32 w, INT32 option, fixed_t scale, const char *string, fontdef_t font) { int c; - size_t chw, i, lastusablespace = 0; - size_t slen; + size_t slen, chw, i, lastusablespace = 0; char *newstring = Z_StrDup(string); INT32 spacewidth = font.spacewidth, charwidth = 0; @@ -2048,10 +2044,7 @@ char *V_FontWordWrap(INT32 x, INT32 w, INT32 option, fixed_t scale, const char * continue; } - if (!(option & V_ALLOWLOWERCASE)) - c = toupper(c); - c -= FONTSTART; - + c = (option & V_ALLOWLOWERCASE ? c : toupper(c)) - FONTSTART; if (c < 0 || c >= FONTSIZE || !font.chars[c]) { chw = spacewidth; @@ -2148,20 +2141,11 @@ void V_DrawFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, if (*ch == '\n') { cx = x; - - if (option & V_RETURN8) - cy += FixedMul((8<= FONTSIZE || !font.chars[c]) { cx += FixedMul((spacewidth<= MAXLINELEN) + { + CONS_Printf("V_DrawAlignedFontStringAtFixed: a line exceeds max. length %d (string: %s)\n", MAXLINELEN, string); + return; + } + strncpy(line,string + start, i); + line[i] = '\0'; + start += i + 1; + i = (size_t)-1; //added : 07-02-98 : damned! + break; + } + } + + if (i == strlen(string + start)) + { + if (i >= MAXLINELEN) + { + CONS_Printf("V_DrawAlignedFontStringAtFixed: a line exceeds max. length %d (string: %s)\n", MAXLINELEN, string); + return; + } + strcpy(line, string + start); + start += i; + } + + lx = x - (V_FontStringWidth(line, option, font)*pscale) / (center ? 2 : 1); + V_DrawFontStringAtFixed(lx, ly, option, pscale, vscale, line, font); + ly += FixedMul(((option & V_RETURN8) ? 8 : font.linespacing)<= FONTSIZE || !ntb_font.chars[c] || !nto_font.chars[c]) { cx += FixedMul((ntb_font.spacewidth * dupx)*FRACUNIT, scale); @@ -2464,9 +2487,8 @@ INT32 V_CountNameTagLines(const char *string) // INT32 V_FontStringWidth(const char *string, INT32 option, fontdef_t font) { - INT32 c, w = 0; + INT32 c, w = 0, wline = 0; INT32 spacewidth = font.spacewidth, charwidth = 0; - size_t i; switch (option & V_SPACINGMASK) { @@ -2482,16 +2504,24 @@ INT32 V_FontStringWidth(const char *string, INT32 option, fontdef_t font) break; } - for (i = 0; i < strlen(string); i++) + for (size_t i = 0; i < strlen(string); i++) { + if (string[i] == '\n') + { + if (wline < w) wline = w; + w = 0; + continue; + } if (string[i] & 0x80) continue; - c = ((option & V_ALLOWLOWERCASE ? string[i] : toupper(string[i])) - FONTSTART); + + c = (option & V_ALLOWLOWERCASE ? string[i] : toupper(string[i])) - FONTSTART; if (c < 0 || c >= FONTSIZE || !font.chars[c]) w += spacewidth; else w += (charwidth ? charwidth : (font.chars[c]->width)) + font.kerning; } + w = max(wline, w); if (option & (V_NOSCALESTART|V_NOSCALEPATCH)) w *= vid.dupx; @@ -2501,22 +2531,28 @@ INT32 V_FontStringWidth(const char *string, INT32 option, fontdef_t font) // Find max string height from supplied font characters // -INT32 V_FontStringHeight(const char *string, fontdef_t font) +INT32 V_FontStringHeight(const char *string, INT32 option, fontdef_t font) { - INT32 c, h = 0; - size_t i; + INT32 c, h = 0, result = 0; - for (i = 0; i < strlen(string); i++) + for (size_t i = 0; i < strlen(string); i++) { - c = string[i] - FONTSTART; + c = (option & V_ALLOWLOWERCASE ? string[i] : toupper(string[i])) - FONTSTART; if (c < 0 || c >= FONTSIZE || !font.chars[c]) + { + if (string[i] == '\n') + { + result += (option & V_RETURN8) ? 8 : font.linespacing; + h = 0; + } continue; + } if (font.chars[c]->height > h) h = font.chars[c]->height; } - return h; + return result + h; } boolean *heatshifter = NULL; diff --git a/src/v_video.h b/src/v_video.h index 0a5bbfc51..83a911db6 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -213,6 +213,7 @@ void V_DrawCenteredFontString(INT32 x, INT32 y, INT32 option, fixed_t pscale, fi void V_DrawRightAlignedFontString(INT32 x, INT32 y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font); // Draw a string, using a supplied font and scale, at fixed_t coordinates. void V_DrawFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font); +void V_DrawAlignedFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font, boolean center); void V_DrawCenteredFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font); void V_DrawRightAlignedFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font); @@ -266,7 +267,7 @@ INT32 V_CountNameTagLines(const char *string); // Find string width or height from supplied font chars INT32 V_FontStringWidth(const char *string, INT32 option, fontdef_t font); -INT32 V_FontStringHeight(const char *string, fontdef_t font); +INT32 V_FontStringHeight(const char *string, INT32 option, fontdef_t font); // Defines for old string width functions. #define V_StringWidth(str,o) V_FontStringWidth(str,o,hu_font) @@ -276,7 +277,8 @@ INT32 V_FontStringHeight(const char *string, fontdef_t font); #define V_CreditStringWidth(str) V_FontStringWidth(str,0,cred_font) #define V_NameTagWidth(str) V_FontStringWidth(str,0,ntb_font) #define V_LevelNameWidth(str) V_FontStringWidth(str,V_ALLOWLOWERCASE,lt_font) -#define V_LevelNameHeight(str) V_FontStringHeight(str,lt_font) +#define V_LevelNameHeight(str) V_FontStringHeight(str,0,lt_font) +#define V_StringHeight(str,o) V_FontStringHeight(str,o,hu_font) void V_DoPostProcessor(INT32 view, postimg_t type, INT32 param);