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.
This commit is contained in:
toaster 2023-07-11 18:54:06 +01:00
parent 4675a9b059
commit 9e4e996a5e
7 changed files with 93 additions and 57 deletions

View file

@ -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)<<FRACBITS,
FRACUNIT, FRACUNIT, FRACUNIT,
0, HU_FONT,
promptpagetext
pagetext
);
}
else

View file

@ -1273,19 +1273,15 @@ boolean HU_Responder(event_t *ev)
// Now a wrapper for the chat drawer.
static char *CHAT_WordWrap(INT32 x, INT32 w, INT32 option, const char *string)
{
char *newstring = Z_StrDup(string);
fixed_t scale = (vid.width < 640) ? FRACUNIT : FRACUNIT/2;
V_ScaledWordWrap(
return V_ScaledWordWrap(
(w - x) << FRACBITS,
scale, scale, scale,
option,
HU_FONT,
newstring
string
);
return newstring;
}

View file

@ -1577,6 +1577,11 @@ char *M_BuildConditionSetString(UINT16 unlockid)
}
}
if (message[0] == '\0')
{
return NULL;
}
// Valid sentence capitalisation handling.
{
// Finds the first : character, indicating the end of the prefix.
@ -1604,15 +1609,13 @@ char *M_BuildConditionSetString(UINT16 unlockid)
}
// Finally, do a clean wordwrap!
V_ScaledWordWrap(
return V_ScaledWordWrap(
DESCRIPTIONWIDTH << FRACBITS,
FRACUNIT, FRACUNIT, FRACUNIT,
0,
HU_FONT,
message
);
return message;
}
static boolean M_CheckUnlockConditions(player_t *player)

View file

@ -104,6 +104,8 @@ static void M_ChallengesAutoFocus(UINT16 unlockid, boolean fresh)
return;
challengesmenu.currentunlock = unlockid;
if (challengesmenu.unlockcondition)
Z_Free(challengesmenu.unlockcondition);
challengesmenu.unlockcondition = M_BuildConditionSetString(challengesmenu.currentunlock);
challengesmenu.unlockanim = (challengesmenu.pending && !challengesmenu.chaokeyadd ? 0 : MAXUNLOCKTIME);
@ -505,6 +507,8 @@ void M_ChallengesTick(void)
M_UpdateUnlockablesAndExtraEmblems(true, true);
// Update shown description just in case..?
if (challengesmenu.unlockcondition)
Z_Free(challengesmenu.unlockcondition);
challengesmenu.unlockcondition = M_BuildConditionSetString(challengesmenu.currentunlock);
challengesmenu.unlockcount[CC_TALLY]++;
@ -787,6 +791,8 @@ boolean M_ChallengesInputs(INT32 ch)
// After movement has been determined, figure out the current selection.
i = (challengesmenu.col * CHALLENGEGRIDHEIGHT) + challengesmenu.row;
challengesmenu.currentunlock = (gamedata->challengegrid[i]);
if (challengesmenu.unlockcondition)
Z_Free(challengesmenu.unlockcondition);
challengesmenu.unlockcondition = M_BuildConditionSetString(challengesmenu.currentunlock);
challengesmenu.hilix = challengesmenu.col;

View file

@ -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);

View file

@ -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<char *>(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<char *>(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)

View file

@ -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 ) \