1
0
Fork 0

(svn r19911) -Codechange: Simplify text drawing by eliminating global variables and side effects. This also fixes the 'colour' parameter of DrawStringMultiLine().

release/1.1
frosch 2010-05-30 15:32:37 +00:00
parent 2224c9b515
commit 4b7afccd46
3 changed files with 56 additions and 55 deletions

View File

@ -59,8 +59,17 @@ byte _colour_gradient[COLOUR_END][8];
static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode, const SubSprite *sub = NULL, SpriteID sprite_id = SPR_CURSOR_MOUSE); static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode, const SubSprite *sub = NULL, SpriteID sprite_id = SPR_CURSOR_MOUSE);
FontSize _cur_fontsize; /**
static FontSize _last_fontsize; * Text drawing parameters, which can change while drawing a line, but are kept between multiple parts
* of the same text, e.g. on line breaks.
**/
struct DrawStringParams {
FontSize fontsize;
TextColour cur_colour, prev_colour;
DrawStringParams(TextColour colour) : fontsize(FS_NORMAL), cur_colour(colour), prev_colour(colour) {}
};
static ReusableBuffer<uint8> _cursor_backup; static ReusableBuffer<uint8> _cursor_backup;
/** /**
@ -331,12 +340,13 @@ static UChar *HandleBiDiAndArabicShapes(UChar *buffer)
* @param *str string that is checked and possibly truncated * @param *str string that is checked and possibly truncated
* @param maxw maximum width in pixels of the string * @param maxw maximum width in pixels of the string
* @param ignore_setxy whether to ignore SETX(Y) or not * @param ignore_setxy whether to ignore SETX(Y) or not
* @param start_fontsize Fontsize to start the text with
* @return new width of (truncated) string * @return new width of (truncated) string
*/ */
static int TruncateString(char *str, int maxw, bool ignore_setxy) static int TruncateString(char *str, int maxw, bool ignore_setxy, FontSize start_fontsize)
{ {
int w = 0; int w = 0;
FontSize size = _cur_fontsize; FontSize size = start_fontsize;
int ddd, ddd_w; int ddd, ddd_w;
WChar c; WChar c;
@ -383,16 +393,17 @@ static int TruncateString(char *str, int maxw, bool ignore_setxy)
return w; return w;
} }
static int ReallyDoDrawString(const UChar *string, int x, int y, TextColour &colour, bool parse_string_also_when_clipped = false); static int ReallyDoDrawString(const UChar *string, int x, int y, DrawStringParams &params, bool parse_string_also_when_clipped = false);
/** /**
* Get the real width of the string. * Get the real width of the string.
* @param str the string to draw * @param str the string to draw
* @param start_fontsize Fontsize to start the text with
* @return the width. * @return the width.
*/ */
static int GetStringWidth(const UChar *str) static int GetStringWidth(const UChar *str, FontSize start_fontsize)
{ {
FontSize size = _cur_fontsize; FontSize size = start_fontsize;
int max_width; int max_width;
int width; int width;
WChar c; WChar c;
@ -430,7 +441,7 @@ static int GetStringWidth(const UChar *str)
* @param top The top most position to draw on. * @param top The top most position to draw on.
* @param str String to draw. * @param str String to draw.
* @param last The end of the string buffer to draw. * @param last The end of the string buffer to draw.
* @param colour Colour used for drawing the string, see DoDrawString() for details * @param params Text drawing parameters.
* @param align The alignment of the string when drawing left-to-right. In the * @param align The alignment of the string when drawing left-to-right. In the
* case a right-to-left language is chosen this is inverted so it * case a right-to-left language is chosen this is inverted so it
* will be drawn in the right direction. * will be drawn in the right direction.
@ -440,7 +451,7 @@ static int GetStringWidth(const UChar *str)
* @return In case of left or center alignment the right most pixel we have drawn to. * @return In case of left or center alignment the right most pixel we have drawn to.
* In case of right alignment the left most pixel we have drawn to. * In case of right alignment the left most pixel we have drawn to.
*/ */
static int DrawString(int left, int right, int top, char *str, const char *last, TextColour colour, StringAlignment align, bool underline = false, bool truncate = true) static int DrawString(int left, int right, int top, char *str, const char *last, DrawStringParams &params, StringAlignment align, bool underline = false, bool truncate = true)
{ {
/* We need the outer limits of both left/right */ /* We need the outer limits of both left/right */
int min_left = INT32_MAX; int min_left = INT32_MAX;
@ -450,7 +461,7 @@ static int DrawString(int left, int right, int top, char *str, const char *last,
int initial_right = right; int initial_right = right;
int initial_top = top; int initial_top = top;
if (truncate) TruncateString(str, right - left + 1, (align & SA_STRIP) == SA_STRIP); if (truncate) TruncateString(str, right - left + 1, (align & SA_STRIP) == SA_STRIP, params.fontsize);
/* /*
* To support SETX and SETXY properly with RTL languages we have to * To support SETX and SETXY properly with RTL languages we have to
@ -530,12 +541,10 @@ static int DrawString(int left, int right, int top, char *str, const char *last,
to_draw++; to_draw++;
offset = *to_draw++; offset = *to_draw++;
if (*to_draw == SCC_SETXY) top = initial_top + *to_draw++; if (*to_draw == SCC_SETXY) top = initial_top + *to_draw++;
_cur_fontsize = _last_fontsize;
} }
to_draw = HandleBiDiAndArabicShapes(to_draw); to_draw = HandleBiDiAndArabicShapes(to_draw);
int w = GetStringWidth(to_draw); int w = GetStringWidth(to_draw, params.fontsize);
/* right is the right most position to draw on. In this case we want to do /* right is the right most position to draw on. In this case we want to do
* calculations with the width of the string. In comparison right can be * calculations with the width of the string. In comparison right can be
@ -566,14 +575,12 @@ static int DrawString(int left, int right, int top, char *str, const char *last,
min_left = min(left, min_left); min_left = min(left, min_left);
max_right = max(right, max_right); max_right = max(right, max_right);
ReallyDoDrawString(to_draw, left, top, colour, !truncate); ReallyDoDrawString(to_draw, left, top, params, !truncate);
if (underline) { if (underline) {
GfxFillRect(left, top + FONT_HEIGHT_NORMAL, right, top + FONT_HEIGHT_NORMAL, _string_colourremap[1]); GfxFillRect(left, top + FONT_HEIGHT_NORMAL, right, top + FONT_HEIGHT_NORMAL, _string_colourremap[1]);
} }
} }
_cur_fontsize = FS_NORMAL;
return align == SA_RIGHT ? min_left : max_right; return align == SA_RIGHT ? min_left : max_right;
} }
@ -594,7 +601,8 @@ int DrawString(int left, int right, int top, const char *str, TextColour colour,
{ {
char buffer[DRAW_STRING_BUFFER]; char buffer[DRAW_STRING_BUFFER];
strecpy(buffer, str, lastof(buffer)); strecpy(buffer, str, lastof(buffer));
return DrawString(left, right, top, buffer, lastof(buffer), colour, align, underline); DrawStringParams params(colour);
return DrawString(left, right, top, buffer, lastof(buffer), params, align, underline);
} }
/** /**
@ -614,7 +622,8 @@ int DrawString(int left, int right, int top, StringID str, TextColour colour, St
{ {
char buffer[DRAW_STRING_BUFFER]; char buffer[DRAW_STRING_BUFFER];
GetString(buffer, str, lastof(buffer)); GetString(buffer, str, lastof(buffer));
return DrawString(left, right, top, buffer, lastof(buffer), colour, align, underline); DrawStringParams params(colour);
return DrawString(left, right, top, buffer, lastof(buffer), params, align, underline);
} }
/** /**
@ -632,13 +641,14 @@ int DrawString(int left, int right, int top, StringID str, TextColour colour, St
* @param str string to check and correct for length restrictions * @param str string to check and correct for length restrictions
* @param last the last valid location (for '\0') in the buffer of str * @param last the last valid location (for '\0') in the buffer of str
* @param maxw the maximum width the string can have on one line * @param maxw the maximum width the string can have on one line
* @param start_fontsize Fontsize to start the text with
* @return return a 32bit wide number consisting of 2 packed values: * @return return a 32bit wide number consisting of 2 packed values:
* 0 - 15 the number of lines ADDED to the string * 0 - 15 the number of lines ADDED to the string
* 16 - 31 the fontsize in which the length calculation was done at * 16 - 31 the fontsize in which the length calculation was done at
*/ */
uint32 FormatStringLinebreaks(char *str, const char *last, int maxw) uint32 FormatStringLinebreaks(char *str, const char *last, int maxw, FontSize start_fontsize)
{ {
FontSize size = _cur_fontsize; FontSize size = start_fontsize;
int num = 0; int num = 0;
assert(maxw > 0); assert(maxw > 0);
@ -729,14 +739,15 @@ end_of_inner_loop:
/** Calculates height of string (in pixels). Accepts multiline string with '\0' as separators. /** Calculates height of string (in pixels). Accepts multiline string with '\0' as separators.
* @param src string to check * @param src string to check
* @param num number of extra lines (output of FormatStringLinebreaks()) * @param num number of extra lines (output of FormatStringLinebreaks())
* @param start_fontsize Fontsize to start the text with
* @note assumes text won't be truncated. FormatStringLinebreaks() is a good way to ensure that. * @note assumes text won't be truncated. FormatStringLinebreaks() is a good way to ensure that.
* @return height of pixels of string when it is drawn * @return height of pixels of string when it is drawn
*/ */
static int GetMultilineStringHeight(const char *src, int num) static int GetMultilineStringHeight(const char *src, int num, FontSize start_fontsize)
{ {
int maxy = 0; int maxy = 0;
int y = 0; int y = 0;
int fh = GetCharacterHeight(_cur_fontsize); int fh = GetCharacterHeight(start_fontsize);
for (;;) { for (;;) {
WChar c = Utf8Consume(&src); WChar c = Utf8Consume(&src);
@ -767,7 +778,7 @@ int GetStringHeight(StringID str, int maxw)
uint32 tmp = FormatStringLinebreaks(buffer, lastof(buffer), maxw); uint32 tmp = FormatStringLinebreaks(buffer, lastof(buffer), maxw);
return GetMultilineStringHeight(buffer, GB(tmp, 0, 16)); return GetMultilineStringHeight(buffer, GB(tmp, 0, 16), FS_NORMAL);
} }
/** Calculate string bounding box for multi-line strings. /** Calculate string bounding box for multi-line strings.
@ -826,18 +837,18 @@ int DrawStringMultiLine(int left, int right, int top, int bottom, StringID str,
int y = (align == SA_CENTER) ? RoundDivSU(bottom + top - total_height, 2) : top; int y = (align == SA_CENTER) ? RoundDivSU(bottom + top - total_height, 2) : top;
const char *src = buffer; const char *src = buffer;
DrawStringParams params(colour);
for (;;) { for (;;) {
char buf2[DRAW_STRING_BUFFER]; char buf2[DRAW_STRING_BUFFER];
strecpy(buf2, src, lastof(buf2)); strecpy(buf2, src, lastof(buf2));
DrawString(left, right, y, buf2, lastof(buf2), colour, align, underline, false); DrawString(left, right, y, buf2, lastof(buf2), params, align, underline, false);
_cur_fontsize = _last_fontsize;
for (;;) { for (;;) {
WChar c = Utf8Consume(&src); WChar c = Utf8Consume(&src);
if (c == 0) { if (c == 0) {
y += mt; y += mt;
if (--num < 0) { if (--num < 0) {
_cur_fontsize = FS_NORMAL;
return y; return y;
} }
break; break;
@ -856,10 +867,11 @@ int DrawStringMultiLine(int left, int right, int top, int bottom, StringID str,
* are therefore a rough estimation correct for all the current strings * are therefore a rough estimation correct for all the current strings
* but not every possible combination * but not every possible combination
* @param str string to calculate pixel-width * @param str string to calculate pixel-width
* @param start_fontsize Fontsize to start the text with
* @return string width and height in pixels */ * @return string width and height in pixels */
Dimension GetStringBoundingBox(const char *str) Dimension GetStringBoundingBox(const char *str, FontSize start_fontsize)
{ {
FontSize size = _cur_fontsize; FontSize size = start_fontsize;
Dimension br; Dimension br;
uint max_width; uint max_width;
WChar c; WChar c;
@ -926,8 +938,7 @@ void DrawCharCentered(WChar c, int x, int y, TextColour colour)
* @param string The string to draw. This is already bidi reordered. * @param string The string to draw. This is already bidi reordered.
* @param x Offset from left side of the screen * @param x Offset from left side of the screen
* @param y Offset from top side of the screen * @param y Offset from top side of the screen
* @param colour Colour of the string, see _string_colourmap in * @param params Text drawing parameters
* table/palettes.h or docs/ottd-colourtext-palette.png or the enum TextColour in gfx_type.h
* @param parse_string_also_when_clipped * @param parse_string_also_when_clipped
* By default, always test the available space where to draw the string. * By default, always test the available space where to draw the string.
* When in multipline drawing, it would already be done, * When in multipline drawing, it would already be done,
@ -937,26 +948,21 @@ void DrawCharCentered(WChar c, int x, int y, TextColour colour)
* @return the x-coordinates where the drawing has finished. * @return the x-coordinates where the drawing has finished.
* If nothing is drawn, the originally passed x-coordinate is returned * If nothing is drawn, the originally passed x-coordinate is returned
*/ */
static int ReallyDoDrawString(const UChar *string, int x, int y, TextColour &colour, bool parse_string_also_when_clipped) static int ReallyDoDrawString(const UChar *string, int x, int y, DrawStringParams &params, bool parse_string_also_when_clipped)
{ {
DrawPixelInfo *dpi = _cur_dpi; DrawPixelInfo *dpi = _cur_dpi;
FontSize size = _cur_fontsize;
UChar c; UChar c;
int xo = x; int xo = x;
TextColour previous_colour = colour;
if (!parse_string_also_when_clipped) { if (!parse_string_also_when_clipped) {
/* in "mode multiline", the available space have been verified. Not in regular one. /* in "mode multiline", the available space have been verified. Not in regular one.
* So if the string cannot be drawn, return the original start to say so.*/ * So if the string cannot be drawn, return the original start to say so.*/
if (x >= dpi->left + dpi->width || y >= dpi->top + dpi->height) return x; if (x >= dpi->left + dpi->width || y >= dpi->top + dpi->height) return x;
if (colour != TC_INVALID) { // the invalid colour flag test should not really occur. But better be safe
switch_colour:;
SetColourRemap(colour);
}
} }
switch_colour:;
SetColourRemap(params.cur_colour);
check_bounds: check_bounds:
if (y + _max_char_height <= dpi->top || dpi->top + dpi->height <= y) { if (y + _max_char_height <= dpi->top || dpi->top + dpi->height <= y) {
skip_char:; skip_char:;
@ -970,33 +976,32 @@ skip_char:;
c = *string++; c = *string++;
skip_cont:; skip_cont:;
if (c == 0) { if (c == 0) {
_last_fontsize = size;
return x; // Nothing more to draw, get out. And here is the new x position return x; // Nothing more to draw, get out. And here is the new x position
} }
if (IsPrintable(c)) { if (IsPrintable(c)) {
if (x >= dpi->left + dpi->width) goto skip_char; if (x >= dpi->left + dpi->width) goto skip_char;
if (x + _max_char_width >= dpi->left) { if (x + _max_char_width >= dpi->left) {
GfxMainBlitter(GetGlyph(size, c), x, y, BM_COLOUR_REMAP); GfxMainBlitter(GetGlyph(params.fontsize, c), x, y, BM_COLOUR_REMAP);
} }
x += GetCharacterWidth(size, c); x += GetCharacterWidth(params.fontsize, c);
} else if (c == '\n') { // newline = {} } else if (c == '\n') { // newline = {}
x = xo; // We require a new line, so the x coordinate is reset x = xo; // We require a new line, so the x coordinate is reset
y += GetCharacterHeight(size); y += GetCharacterHeight(params.fontsize);
goto check_bounds; goto check_bounds;
} else if (c >= SCC_BLUE && c <= SCC_BLACK) { // change colour? } else if (c >= SCC_BLUE && c <= SCC_BLACK) { // change colour?
previous_colour = colour; params.prev_colour = params.cur_colour;
colour = (TextColour)(c - SCC_BLUE); params.cur_colour = (TextColour)(c - SCC_BLUE);
goto switch_colour; goto switch_colour;
} else if (c == SCC_PREVIOUS_COLOUR) { // revert to the previous colour } else if (c == SCC_PREVIOUS_COLOUR) { // revert to the previous colour
Swap(colour, previous_colour); Swap(params.cur_colour, params.prev_colour);
goto switch_colour; goto switch_colour;
} else if (c == SCC_SETX || c == SCC_SETXY) { // {SETX}/{SETXY} } else if (c == SCC_SETX || c == SCC_SETXY) { // {SETX}/{SETXY}
/* The characters are handled before calling this. */ /* The characters are handled before calling this. */
NOT_REACHED(); NOT_REACHED();
} else if (c == SCC_TINYFONT) { // {TINYFONT} } else if (c == SCC_TINYFONT) { // {TINYFONT}
size = FS_SMALL; params.fontsize = FS_SMALL;
} else if (c == SCC_BIGFONT) { // {BIGFONT} } else if (c == SCC_BIGFONT) { // {BIGFONT}
size = FS_LARGE; params.fontsize = FS_LARGE;
} else { } else {
DEBUG(misc, 0, "[utf8] unknown string command character %d", c); DEBUG(misc, 0, "[utf8] unknown string command character %d", c);
} }

View File

@ -112,9 +112,9 @@ void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectM
void GfxDrawLine(int left, int top, int right, int bottom, int colour); void GfxDrawLine(int left, int top, int right, int bottom, int colour);
void DrawBox(int x, int y, int dx1, int dy1, int dx2, int dy2, int dx3, int dy3); void DrawBox(int x, int y, int dx1, int dy1, int dx2, int dy2, int dx3, int dy3);
Dimension GetStringBoundingBox(const char *str); Dimension GetStringBoundingBox(const char *str, FontSize start_fontsize = FS_NORMAL);
Dimension GetStringBoundingBox(StringID strid); Dimension GetStringBoundingBox(StringID strid);
uint32 FormatStringLinebreaks(char *str, const char *last, int maxw); uint32 FormatStringLinebreaks(char *str, const char *last, int maxw, FontSize start_fontsize = FS_NORMAL);
int GetStringHeight(StringID str, int maxw); int GetStringHeight(StringID str, int maxw);
Dimension GetStringMultiLineBoundingBox(StringID str, const Dimension &suggestion); Dimension GetStringMultiLineBoundingBox(StringID str, const Dimension &suggestion);
void LoadStringWidthTable(); void LoadStringWidthTable();
@ -155,8 +155,6 @@ void SortResolutions(int count);
bool ToggleFullScreen(bool fs); bool ToggleFullScreen(bool fs);
/* gfx.cpp */ /* gfx.cpp */
extern FontSize _cur_fontsize; ///< Currently selected font.
byte GetCharacterWidth(FontSize size, uint32 key); byte GetCharacterWidth(FontSize size, uint32 key);
byte GetDigitWidth(FontSize size = FS_NORMAL); byte GetDigitWidth(FontSize size = FS_NORMAL);

View File

@ -1187,9 +1187,7 @@ void ViewportSign::UpdatePosition(int center, int top, StringID str)
this->center = center; this->center = center;
/* zoomed out version */ /* zoomed out version */
_cur_fontsize = FS_SMALL; this->width_small = VPSM_LEFT + Align(GetStringBoundingBox(buffer, FS_SMALL).width, 2) + VPSM_RIGHT;
this->width_small = VPSM_LEFT + Align(GetStringBoundingBox(buffer).width, 2) + VPSM_RIGHT;
_cur_fontsize = FS_NORMAL;
this->MarkDirty(); this->MarkDirty();
} }