From 9e4e996a5e3a1bfbb7a76d4dc32174b575d75e17 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 11 Jul 2023 18:54:06 +0100 Subject: [PATCH] V_ScaledWordWrap API changes - The function is back to producing zone-allocated memory copies, like its precursor V_WordWrap - The author of this commit got rid of that dependency originally because it seemed like a fair part of the API, and meant static buffers could be used in certain circumstances, but it was necessary to revert for the following change. - Newlines can now be inserted mid-word, treating the width provided as ironclad except in the case of single characters wider than the region. - This will be necessary for future work with the in-game chat. - Reserves 8 characters at first, then Z_Reallocs double that every time it runs out. --- src/f_finale.c | 5 +- src/hu_stuff.c | 8 +-- src/m_cond.c | 9 ++- src/menus/extras-challenges.c | 6 ++ src/menus/transient/message-box.c | 7 +- src/v_video.cpp | 111 +++++++++++++++++++----------- src/v_video.h | 4 +- 7 files changed, 93 insertions(+), 57 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index 64945543e..ccb8fbb30 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2283,12 +2283,11 @@ static void F_PreparePageText(char *pagetext) Z_Free(promptpagetext); if (pagetext && pagetext[0]) { - promptpagetext = Z_StrDup(pagetext); - V_ScaledWordWrap( + promptpagetext = V_ScaledWordWrap( (textx - textr)<challengegrid[i]); + if (challengesmenu.unlockcondition) + Z_Free(challengesmenu.unlockcondition); challengesmenu.unlockcondition = M_BuildConditionSetString(challengesmenu.currentunlock); challengesmenu.hilix = challengesmenu.col; diff --git a/src/menus/transient/message-box.c b/src/menus/transient/message-box.c index 2d71bdca4..f69b3ebfe 100644 --- a/src/menus/transient/message-box.c +++ b/src/menus/transient/message-box.c @@ -33,15 +33,14 @@ void M_StartMessage(const char *header, const char *string, void (*routine)(INT3 const UINT8 pid = 0; static char *message = NULL; Z_Free(message); - message = Z_StrDup(string); - DEBFILE(message); + DEBFILE(string); - V_ScaledWordWrap( + message = V_ScaledWordWrap( BASEVIDWIDTH << FRACBITS, FRACUNIT, FRACUNIT, FRACUNIT, 0, HU_FONT, - message + string ); strncpy(menumessage.message, string, MAXMENUMESSAGE); diff --git a/src/v_video.cpp b/src/v_video.cpp index e574e81fb..5b848fcde 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -2610,14 +2610,14 @@ fixed_t V_StringScaledWidth( } // Modify a string to wordwrap at any given width. -void V_ScaledWordWrap( +char * V_ScaledWordWrap( fixed_t w, fixed_t scale, fixed_t spacescale, fixed_t lfscale, INT32 flags, int fontno, - char *newstring) + const char *s) { INT32 hchw;/* half-width for centering */ @@ -2675,11 +2675,19 @@ void V_ScaledWordWrap( cx = 0; right = 0; - size_t i = 0, start = 0; + size_t reader = 0, writer = 0, startwriter = 0; fixed_t cxatstart = 0; - for (; ( c = newstring[i] ); ++i) + size_t len = strlen(s) + 1; + size_t potentialnewlines = 8; + size_t sparenewlines = potentialnewlines; + + char *newstring = static_cast(Z_Malloc(len + sparenewlines, PU_STATIC, NULL)); + + for (; ( c = s[reader] ); ++reader, ++writer) { + newstring[writer] = s[reader]; + right = 0; switch (c) @@ -2687,58 +2695,83 @@ void V_ScaledWordWrap( case '\n': cx = 0; cxatstart = 0; - start = 0; + startwriter = 0; break; default: if (( c & 0x80 )) - continue; - - if (uppercase) + ; + else { - c = toupper(c); - } - else if (V_CharacterValid(font, c - font->start) == false) - { - // Try the other case if it doesn't exist - if (c >= 'A' && c <= 'Z') - { - c = tolower(c); - } - else if (c >= 'a' && c <= 'z') + if (uppercase) { c = toupper(c); } - } + else if (V_CharacterValid(font, c - font->start) == false) + { + // Try the other case if it doesn't exist + if (c >= 'A' && c <= 'Z') + { + c = tolower(c); + } + else if (c >= 'a' && c <= 'z') + { + c = toupper(c); + } + } - c -= font->start; - if (V_CharacterValid(font, c) == true) - { - cw = SHORT (font->font[c]->width) * dupx; + c -= font->start; + if (V_CharacterValid(font, c) == true) + { + cw = SHORT (font->font[c]->width) * dupx; - // How bunched dims work is by incrementing cx slightly less than a full character width. - // This causes the next character to be drawn overlapping the previous. - // We need to count the full width to get the rightmost edge of the string though. - right = cx + (cw * scale); + // How bunched dims work is by incrementing cx slightly less than a full character width. + // This causes the next character to be drawn overlapping the previous. + // We need to count the full width to get the rightmost edge of the string though. + right = cx + (cw * scale); - (*fontspec.dim_fn)(scale, fontspec.chw, hchw, dupx, &cw); - cx += cw; - } - else - { - cx += fontspec.spacew; - cxatstart = cx; - start = i; + (*fontspec.dim_fn)(scale, fontspec.chw, hchw, dupx, &cw); + cx += cw; + } + else + { + cx += fontspec.spacew; + cxatstart = cx; + startwriter = writer; + } } } // Start trying to wrap if presumed length exceeds the space we have on-screen. - if (start != 0 && right > w) + if (right && right > w) { - newstring[start] = '\n'; - cx -= cxatstart; - start = 0; + if (startwriter != 0) + { + newstring[startwriter] = '\n'; + cx -= cxatstart; + cxatstart = 0; + startwriter = 0; + } + else + { + if (sparenewlines == 0) + { + sparenewlines = (potentialnewlines *= 2); + newstring = static_cast(Z_Realloc(newstring, len + sparenewlines, PU_STATIC, NULL)); + } + + sparenewlines--; + len++; + + newstring[writer++] = '\n'; // Over-write previous + cx = cw; // Valid value in the only case right is currently set + newstring[writer] = s[reader]; // Re-add + } } } + + newstring[writer] = '\0'; + + return newstring; } void V_DrawCenteredString(INT32 x, INT32 y, INT32 option, const char *string) diff --git a/src/v_video.h b/src/v_video.h index fc7afac33..7a26591dc 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -293,14 +293,14 @@ fixed_t V_StringScaledWidth( int fontno, const char *s); -void V_ScaledWordWrap( +char * V_ScaledWordWrap( fixed_t w, fixed_t scale, fixed_t spacescale, fixed_t lfscale, INT32 flags, int fontno, - char *newstring); + const char *s); // draw a string using the hu_font #define V_DrawString( x,y,option,string ) \