1
0
Fork 0
mirror of https://github.com/TerryCavanagh/VVVVVV.git synced 2024-12-23 01:59:43 +01:00

Add graphics wrapping functions

This will wrap text on-the-fly, since I will be introducing text that
needs to be wrapped whose length we can't know in advance. (Or we can,
but, that'd be stupid.)

I took the algorithm from Dav999's localization branch, but it's not
like it's a complicated algorithm in the first place. Plus I think it
actually handles words that get too long to fit on a single line better
than his localization branch. The only difference is that I removed all
the STL, and made it more memory efficient (unlike his localization
branch, it does not copy the entire string to make a version with
newline separator characters).
This commit is contained in:
Misa 2021-08-06 20:55:09 -07:00 committed by Ethan Lee
parent ee02aa0499
commit ed9cb4ca6d
2 changed files with 119 additions and 0 deletions

View file

@ -515,6 +515,119 @@ void Graphics::PrintAlpha( int _x, int _y, std::string _s, int r, int g, int b,
} }
} }
bool Graphics::next_wrap(
size_t* start,
size_t* len,
const char* str,
const int maxwidth
) {
/* This function is UTF-8 aware. But start/len still are bytes. */
size_t idx = 0;
size_t lenfromlastspace = 0;
size_t lastspace = 0;
int linewidth = 0;
*len = 0;
if (str[idx] == '\0')
{
return false;
}
while (true)
{
/* FIXME: This only checks one byte, not multiple! */
if ((str[idx] & 0xC0) == 0x80)
{
/* Skip continuation byte. */
goto next;
}
linewidth += bfontlen(str[idx]);
switch (str[idx])
{
case ' ':
lenfromlastspace = idx;
lastspace = *start;
break;
case '\n':
*start += 1;
VVV_fallthrough;
case '\0':
return true;
}
if (linewidth > maxwidth)
{
if (lenfromlastspace != 0)
{
*len = lenfromlastspace;
*start = lastspace + 1;
}
return true;
}
next:
idx += 1;
*start += 1;
*len += 1;
}
}
bool Graphics::next_wrap_s(
char buffer[],
const size_t buffer_size,
size_t* start,
const char* str,
const int maxwidth
) {
size_t len = 0;
const size_t prev_start = *start;
const bool retval = next_wrap(start, &len, &str[*start], maxwidth);
if (retval)
{
/* Like next_split_s(), don't use SDL_strlcpy() here. */
const size_t length = VVV_min(buffer_size - 1, len);
SDL_memcpy(buffer, &str[prev_start], length);
buffer[length] = '\0';
}
return retval;
}
void Graphics::PrintWrap(
const int x,
int y,
const char* str,
const int r,
const int g,
const int b,
const bool cen,
const int linespacing,
const int maxwidth
) {
/* Screen width is 320 pixels. The shortest a char can be is 6 pixels wide.
* 320 / 6 is 54, rounded up. 4 bytes per char. */
char buffer[54*4 + 1];
size_t start = 0;
while (next_wrap_s(buffer, sizeof(buffer), &start, str, maxwidth))
{
Print(x, y, buffer, r, g, b, cen);
if (flipmode)
{
y -= linespacing;
}
else
{
y += linespacing;
}
}
}
void Graphics::bigprint( int _x, int _y, std::string _s, int r, int g, int b, bool cen, int sc ) void Graphics::bigprint( int _x, int _y, std::string _s, int r, int g, int b, bool cen, int sc )
{ {

View file

@ -136,6 +136,12 @@ public:
void PrintAlpha(int _x, int _y, std::string _s, int r, int g, int b, int a, bool cen = false); void PrintAlpha(int _x, int _y, std::string _s, int r, int g, int b, int a, bool cen = false);
bool next_wrap(size_t* start, size_t* len, const char* str, int maxwidth);
bool next_wrap_s(char buffer[], size_t buffer_size, size_t* start, const char* str, int maxwidth);
void PrintWrap(int x, int y, const char* str, int r, int g, int b, bool cen, int linespacing, int maxwidth);
void PrintOffAlpha(int _x, int _y, std::string _s, int r, int g, int b, int a, bool cen = false); void PrintOffAlpha(int _x, int _y, std::string _s, int r, int g, int b, int a, bool cen = false);
void bprint(int x, int y, std::string t, int r, int g, int b, bool cen = false); void bprint(int x, int y, std::string t, int r, int g, int b, bool cen = false);