aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichieSams2015-02-11 14:57:05 -0600
committerRichieSams2015-02-11 15:13:19 -0600
commita851fa8e1aef50334402fec65bf89ee8b582ea62 (patch)
tree13f17fa8bf1603c7b08376791592d523ef13adef
parent55be1b82a84454ae838419e22ce15cade5298665 (diff)
downloadscummvm-rg350-a851fa8e1aef50334402fec65bf89ee8b582ea62.tar.gz
scummvm-rg350-a851fa8e1aef50334402fec65bf89ee8b582ea62.tar.bz2
scummvm-rg350-a851fa8e1aef50334402fec65bf89ee8b582ea62.zip
ZVISION: Refactor text rendering code in order to fix word wrapping
and clarify the logic. Fixes bug #6801
-rw-r--r--engines/zvision/graphics/render_manager.cpp2
-rw-r--r--engines/zvision/scripting/controls/input_control.cpp8
-rw-r--r--engines/zvision/scripting/controls/input_control.h4
-rw-r--r--engines/zvision/scripting/controls/titler_control.cpp2
-rw-r--r--engines/zvision/scripting/effects/ttytext_effect.cpp40
-rw-r--r--engines/zvision/scripting/effects/ttytext_effect.h2
-rw-r--r--engines/zvision/text/text.cpp425
-rw-r--r--engines/zvision/text/text.h52
-rw-r--r--engines/zvision/text/truetype_font.cpp60
-rw-r--r--engines/zvision/text/truetype_font.h14
10 files changed, 308 insertions, 301 deletions
diff --git a/engines/zvision/graphics/render_manager.cpp b/engines/zvision/graphics/render_manager.cpp
index 3cd9701b7c..8758097c93 100644
--- a/engines/zvision/graphics/render_manager.cpp
+++ b/engines/zvision/graphics/render_manager.cpp
@@ -755,7 +755,7 @@ void RenderManager::processSubs(uint16 deltatime) {
if (sub->txt.size()) {
Graphics::Surface *rndr = new Graphics::Surface();
rndr->create(sub->r.width(), sub->r.height(), _engine->_resourcePixelFormat);
- _engine->getTextRenderer()->drawTxtInOneLine(sub->txt, *rndr);
+ _engine->getTextRenderer()->drawTextWithWordWrapping(sub->txt, *rndr);
Common::Rect empty;
blitSurfaceToSurface(*rndr, empty, _subtitleSurface, sub->r.left - _subtitleArea.left + _workingWindow.left, sub->r.top - _subtitleArea.top + _workingWindow.top);
rndr->free();
diff --git a/engines/zvision/scripting/controls/input_control.cpp b/engines/zvision/scripting/controls/input_control.cpp
index 20c8e7ccbc..df0c77ba96 100644
--- a/engines/zvision/scripting/controls/input_control.cpp
+++ b/engines/zvision/scripting/controls/input_control.cpp
@@ -79,13 +79,13 @@ InputControl::InputControl(ZVision *engine, uint32 key, Common::SeekableReadStre
sscanf(values.c_str(), "%u", &fontFormatNumber);
- _stringInit.readAllStyle(_engine->getStringManager()->getTextLine(fontFormatNumber));
+ _stringInit.readAllStyles(_engine->getStringManager()->getTextLine(fontFormatNumber));
} else if (param.matchString("chooser_init_string", true)) {
uint fontFormatNumber;
sscanf(values.c_str(), "%u", &fontFormatNumber);
- _stringChooserInit.readAllStyle(_engine->getStringManager()->getTextLine(fontFormatNumber));
+ _stringChooserInit.readAllStyles(_engine->getStringManager()->getTextLine(fontFormatNumber));
} else if (param.matchString("next_tabstop", true)) {
sscanf(values.c_str(), "%u", &_nextTabstop);
} else if (param.matchString("cursor_dimensions", true)) {
@@ -215,9 +215,9 @@ bool InputControl::process(uint32 deltaTimeInMillis) {
int32 oldTxtWidth = _txtWidth;
if (!_readOnly || !_focused)
- _txtWidth = _engine->getTextRenderer()->drawTxt(_currentInputText, _stringInit, txt);
+ _txtWidth = _engine->getTextRenderer()->drawText(_currentInputText, _stringInit, txt);
else
- _txtWidth = _engine->getTextRenderer()->drawTxt(_currentInputText, _stringChooserInit, txt);
+ _txtWidth = _engine->getTextRenderer()->drawText(_currentInputText, _stringChooserInit, txt);
if (_readOnly || _txtWidth <= _maxTxtWidth)
_engine->getRenderManager()->blitSurfaceToBkg(txt, _textRectangle.left, _textRectangle.top);
diff --git a/engines/zvision/scripting/controls/input_control.h b/engines/zvision/scripting/controls/input_control.h
index 7f272e8d81..9b48514e16 100644
--- a/engines/zvision/scripting/controls/input_control.h
+++ b/engines/zvision/scripting/controls/input_control.h
@@ -44,8 +44,8 @@ private:
Graphics::Surface *_background;
Common::Rect _textRectangle;
Common::Rect _headerRectangle;
- cTxtStyle _stringInit;
- cTxtStyle _stringChooserInit;
+ TextStyleState _stringInit;
+ TextStyleState _stringChooserInit;
uint32 _nextTabstop;
bool _focused;
diff --git a/engines/zvision/scripting/controls/titler_control.cpp b/engines/zvision/scripting/controls/titler_control.cpp
index 542e0a0b67..683d6660af 100644
--- a/engines/zvision/scripting/controls/titler_control.cpp
+++ b/engines/zvision/scripting/controls/titler_control.cpp
@@ -82,7 +82,7 @@ TitlerControl::~TitlerControl() {
void TitlerControl::setString(int strLine) {
if (strLine != _curString && strLine >= 0 && strLine < (int)_strings.size()) {
_surface->fillRect(Common::Rect(_surface->w, _surface->h), 0);
- _engine->getTextRenderer()->drawTxtInOneLine(_strings[strLine], *_surface);
+ _engine->getTextRenderer()->drawTextWithWordWrapping(_strings[strLine], *_surface);
_engine->getRenderManager()->blitSurfaceToBkg(*_surface, _rectangle.left, _rectangle.top);
_curString = strLine;
}
diff --git a/engines/zvision/scripting/effects/ttytext_effect.cpp b/engines/zvision/scripting/effects/ttytext_effect.cpp
index c60b3aa8c5..8d340dae39 100644
--- a/engines/zvision/scripting/effects/ttytext_effect.cpp
+++ b/engines/zvision/scripting/effects/ttytext_effect.cpp
@@ -57,9 +57,9 @@ ttyTextNode::ttyTextNode(ZVision *engine, uint32 key, const Common::String &file
delete infile;
}
_img.create(_r.width(), _r.height(), _engine->_resourcePixelFormat);
- _style._sharp = true;
- _style.readAllStyle(_txtbuf);
- _style.setFont(_fnt);
+ _state._sharp = true;
+ _state.readAllStyles(_txtbuf);
+ _state.updateFontWithTextState(_fnt);
_engine->getScriptManager()->setStateValue(_key, 1);
}
@@ -74,29 +74,27 @@ bool ttyTextNode::process(uint32 deltaTimeInMillis) {
if (_nexttime < 0) {
if (_txtpos < _txtbuf.size()) {
if (_txtbuf[_txtpos] == '<') {
- int32 strt = _txtpos;
- int32 endt = 0;
+ int32 start = _txtpos;
+ int32 end = 0;
int16 ret = 0;
while (_txtbuf[_txtpos] != '>' && _txtpos < _txtbuf.size())
_txtpos++;
- endt = _txtpos;
- if (strt != -1)
- if ((endt - strt - 1) > 0)
- ret = _style.parseStyle(_txtbuf.c_str() + strt + 1, endt - strt - 1);
-
- if (ret & (TXT_RET_FNTCHG | TXT_RET_FNTSTL | TXT_RET_NEWLN)) {
- if (ret & TXT_RET_FNTCHG)
- _style.setFont(_fnt);
- if (ret & TXT_RET_FNTSTL)
- _style.setFontStyle(_fnt);
-
- if (ret & TXT_RET_NEWLN)
- newline();
+ end = _txtpos;
+ if (start != -1) {
+ if ((end - start - 1) > 0) {
+ ret = _state.parseStyle(_txtbuf.c_str() + start + 1, end - start - 1);
+ }
+ }
+
+ if (ret & (TEXT_CHANGE_FONT_TYPE | TEXT_CHANGE_FONT_STYLE)) {
+ _state.updateFontWithTextState(_fnt);
+ } else if (ret & TEXT_CHANGE_NEWLINE) {
+ newline();
}
- if (ret & TXT_RET_HASSTBOX) {
+ if (ret & TEXT_CHANGE_HAS_STATE_BOX) {
Common::String buf;
- buf = Common::String::format("%d", _engine->getScriptManager()->getStateValue(_style._statebox));
+ buf = Common::String::format("%d", _engine->getScriptManager()->getStateValue(_state._statebox));
for (uint8 j = 0; j < buf.size(); j++)
outchar(buf[j]);
@@ -158,7 +156,7 @@ void ttyTextNode::newline() {
}
void ttyTextNode::outchar(uint16 chr) {
- uint32 clr = _engine->_resourcePixelFormat.RGBToColor(_style._red, _style._green, _style._blue);
+ uint32 clr = _engine->_resourcePixelFormat.RGBToColor(_state._red, _state._green, _state._blue);
if (_dx + _fnt.getCharWidth(chr) > _r.width())
newline();
diff --git a/engines/zvision/scripting/effects/ttytext_effect.h b/engines/zvision/scripting/effects/ttytext_effect.h
index 8d8a2518c7..18cbbbaee3 100644
--- a/engines/zvision/scripting/effects/ttytext_effect.h
+++ b/engines/zvision/scripting/effects/ttytext_effect.h
@@ -51,7 +51,7 @@ public:
private:
Common::Rect _r;
- cTxtStyle _style;
+ TextStyleState _state;
StyledTTFont _fnt;
Common::String _txtbuf;
uint32 _txtpos;
diff --git a/engines/zvision/text/text.cpp b/engines/zvision/text/text.cpp
index 4af3b967f3..868ee4f1ae 100644
--- a/engines/zvision/text/text.cpp
+++ b/engines/zvision/text/text.cpp
@@ -38,7 +38,7 @@
namespace ZVision {
-cTxtStyle::cTxtStyle() {
+TextStyleState::TextStyleState() {
_fontname = "Arial";
_blue = 255;
_green = 255;
@@ -49,7 +49,7 @@ cTxtStyle::cTxtStyle() {
_escapement = 0;
#endif
_italic = false;
- _justify = TXT_JUSTIFY_LEFT;
+ _justification = TEXT_JUSTIFY_LEFT;
_size = 12;
#if 0
_skipcolor = false;
@@ -60,10 +60,10 @@ cTxtStyle::cTxtStyle() {
_sharp = false;
}
-txtReturn cTxtStyle::parseStyle(const Common::String &strin, int16 ln) {
- Common::String buf = Common::String(strin.c_str(), ln);
+TextChange TextStyleState::parseStyle(const Common::String &str, int16 len) {
+ Common::String buf = Common::String(str.c_str(), len);
- int8 retval = TXT_RET_NOTHING;
+ uint retval = TEXT_CHANGE_NONE;
Common::StringTokenizer tokenizer(buf, " ");
Common::String token;
@@ -89,7 +89,7 @@ txtReturn cTxtStyle::parseStyle(const Common::String &strin, int16 ln) {
if (!tokenizer.empty())
_fontname = token;
}
- retval |= TXT_RET_FNTCHG;
+ retval |= TEXT_CHANGE_FONT_TYPE;
} else if (token.matchString("blue", true)) {
if (!tokenizer.empty()) {
@@ -97,7 +97,7 @@ txtReturn cTxtStyle::parseStyle(const Common::String &strin, int16 ln) {
int32 tmp = atoi(token.c_str());
if (_blue != tmp) {
_blue = tmp;
- retval |= TXT_RET_FNTSTL;
+ retval |= TEXT_CHANGE_FONT_STYLE;
}
}
} else if (token.matchString("red", true)) {
@@ -106,7 +106,7 @@ txtReturn cTxtStyle::parseStyle(const Common::String &strin, int16 ln) {
int32 tmp = atoi(token.c_str());
if (_red != tmp) {
_red = tmp;
- retval |= TXT_RET_FNTSTL;
+ retval |= TEXT_CHANGE_FONT_STYLE;
}
}
} else if (token.matchString("green", true)) {
@@ -115,7 +115,7 @@ txtReturn cTxtStyle::parseStyle(const Common::String &strin, int16 ln) {
int32 tmp = atoi(token.c_str());
if (_green != tmp) {
_green = tmp;
- retval |= TXT_RET_FNTSTL;
+ retval |= TEXT_CHANGE_FONT_STYLE;
}
}
} else if (token.matchString("newline", true)) {
@@ -125,14 +125,14 @@ txtReturn cTxtStyle::parseStyle(const Common::String &strin, int16 ln) {
_newline++;
#endif
- retval |= TXT_RET_NEWLN;
+ retval |= TEXT_CHANGE_NEWLINE;
} else if (token.matchString("point", true)) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
int32 tmp = atoi(token.c_str());
if (_size != tmp) {
_size = tmp;
- retval |= TXT_RET_FNTCHG;
+ retval |= TEXT_CHANGE_FONT_TYPE;
}
}
} else if (token.matchString("escapement", true)) {
@@ -149,12 +149,12 @@ txtReturn cTxtStyle::parseStyle(const Common::String &strin, int16 ln) {
if (token.matchString("on", true)) {
if (_italic != true) {
_italic = true;
- retval |= TXT_RET_FNTSTL;
+ retval |= TEXT_CHANGE_FONT_STYLE;
}
} else if (token.matchString("off", true)) {
if (_italic != false) {
_italic = false;
- retval |= TXT_RET_FNTSTL;
+ retval |= TEXT_CHANGE_FONT_STYLE;
}
}
}
@@ -164,12 +164,12 @@ txtReturn cTxtStyle::parseStyle(const Common::String &strin, int16 ln) {
if (token.matchString("on", true)) {
if (_underline != true) {
_underline = true;
- retval |= TXT_RET_FNTSTL;
+ retval |= TEXT_CHANGE_FONT_STYLE;
}
} else if (token.matchString("off", true)) {
if (_underline != false) {
_underline = false;
- retval |= TXT_RET_FNTSTL;
+ retval |= TEXT_CHANGE_FONT_STYLE;
}
}
}
@@ -179,12 +179,12 @@ txtReturn cTxtStyle::parseStyle(const Common::String &strin, int16 ln) {
if (token.matchString("on", true)) {
if (_strikeout != true) {
_strikeout = true;
- retval |= TXT_RET_FNTSTL;
+ retval |= TEXT_CHANGE_FONT_STYLE;
}
} else if (token.matchString("off", true)) {
if (_strikeout != false) {
_strikeout = false;
- retval |= TXT_RET_FNTSTL;
+ retval |= TEXT_CHANGE_FONT_STYLE;
}
}
}
@@ -194,12 +194,12 @@ txtReturn cTxtStyle::parseStyle(const Common::String &strin, int16 ln) {
if (token.matchString("on", true)) {
if (_bold != true) {
_bold = true;
- retval |= TXT_RET_FNTSTL;
+ retval |= TEXT_CHANGE_FONT_STYLE;
}
} else if (token.matchString("off", true)) {
if (_bold != false) {
_bold = false;
- retval |= TXT_RET_FNTSTL;
+ retval |= TEXT_CHANGE_FONT_STYLE;
}
}
}
@@ -220,24 +220,24 @@ txtReturn cTxtStyle::parseStyle(const Common::String &strin, int16 ln) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
_statebox = atoi(token.c_str());
- retval |= TXT_RET_HASSTBOX;
+ retval |= TEXT_CHANGE_HAS_STATE_BOX;
}
} else if (token.matchString("justify", true)) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
if (token.matchString("center", true))
- _justify = TXT_JUSTIFY_CENTER;
+ _justification = TEXT_JUSTIFY_CENTER;
else if (token.matchString("left", true))
- _justify = TXT_JUSTIFY_LEFT;
+ _justification = TEXT_JUSTIFY_LEFT;
else if (token.matchString("right", true))
- _justify = TXT_JUSTIFY_RIGHT;
+ _justification = TEXT_JUSTIFY_RIGHT;
}
}
}
- return (txtReturn)retval;
+ return (TextChange)retval;
}
-void cTxtStyle::readAllStyle(const Common::String &txt) {
+void TextStyleState::readAllStyles(const Common::String &txt) {
int16 startTextPosition = -1;
int16 endTextPosition = -1;
@@ -246,243 +246,264 @@ void cTxtStyle::readAllStyle(const Common::String &txt) {
startTextPosition = i;
else if (txt[i] == '>') {
endTextPosition = i;
- if (startTextPosition != -1)
- if ((endTextPosition - startTextPosition - 1) > 0)
+ if (startTextPosition != -1) {
+ if ((endTextPosition - startTextPosition - 1) > 0) {
parseStyle(Common::String(txt.c_str() + startTextPosition + 1), endTextPosition - startTextPosition - 1);
+ }
+ }
}
}
}
-void cTxtStyle::setFontStyle(StyledTTFont &font) {
+void TextStyleState::updateFontWithTextState(StyledTTFont &font) {
uint tempStyle = 0;
- if (_bold)
- tempStyle |= StyledTTFont::STTF_BOLD;
-
- if (_italic)
- tempStyle |= StyledTTFont::STTF_ITALIC;
-
- if (_underline)
- tempStyle |= StyledTTFont::STTF_UNDERLINE;
-
- if (_strikeout)
- tempStyle |= StyledTTFont::STTF_STRIKEOUT;
-
- if (_sharp)
- tempStyle |= StyledTTFont::STTF_SHARP;
+ if (_bold) {
+ tempStyle |= StyledTTFont::TTF_STYLE_BOLD;
+ }
+ if (_italic) {
+ tempStyle |= StyledTTFont::TTF_STYLE_ITALIC;
+ }
+ if (_underline) {
+ tempStyle |= StyledTTFont::TTF_STYLE_UNDERLINE;
+ }
+ if (_strikeout) {
+ tempStyle |= StyledTTFont::TTF_STYLE_STRIKETHROUGH;
+ }
+ if (_sharp) {
+ tempStyle |= StyledTTFont::TTF_STYLE_SHARP;
+ }
- font.setStyle(tempStyle);
+ font.loadFont(_fontname, _size, tempStyle);
}
-void cTxtStyle::setFont(StyledTTFont &font) {
- uint tempStyle = 0;
-
- if (_bold)
- tempStyle |= StyledTTFont::STTF_BOLD;
+void TextRenderer::drawTextWithJustification(const Common::String &text, StyledTTFont &font, uint32 color, Graphics::Surface &dest, int lineY, TextJustification justify) {
+ if (justify == TEXT_JUSTIFY_LEFT)
+ font.drawString(&dest, text, 0, lineY, dest.w, color, Graphics::kTextAlignLeft);
+ else if (justify == TEXT_JUSTIFY_CENTER)
+ font.drawString(&dest, text, 0, lineY, dest.w, color, Graphics::kTextAlignCenter);
+ else if (justify == TEXT_JUSTIFY_RIGHT)
+ font.drawString(&dest, text, 0, lineY, dest.w, color, Graphics::kTextAlignRight);
+}
- if (_italic)
- tempStyle |= StyledTTFont::STTF_ITALIC;
+int32 TextRenderer::drawText(const Common::String &text, TextStyleState &state, Graphics::Surface &dest) {
+ StyledTTFont font(_engine);
+ state.updateFontWithTextState(font);
- if (_underline)
- tempStyle |= StyledTTFont::STTF_UNDERLINE;
+ uint32 color = _engine->_resourcePixelFormat.RGBToColor(state._red, state._green, state._blue);
+ drawTextWithJustification(text, font, color, dest, 0, state._justification);
- if (_strikeout)
- tempStyle |= StyledTTFont::STTF_STRIKEOUT;
+ return font.getStringWidth(text);
+}
- if (_sharp)
- tempStyle |= StyledTTFont::STTF_SHARP;
+struct TextSurface {
+ TextSurface(Graphics::Surface *surface, Common::Point surfaceOffset, uint lineNumber)
+ : _surface(surface),
+ _surfaceOffset(surfaceOffset),
+ _lineNumber(lineNumber) {
+ }
- font.loadFont(_fontname, _size, tempStyle);
-}
+ Graphics::Surface *_surface;
+ Common::Point _surfaceOffset;
+ uint _lineNumber;
+};
-Graphics::Surface *TextRenderer::render(StyledTTFont &fnt, const Common::String &txt, cTxtStyle &style) {
- style.setFontStyle(fnt);
- uint32 clr = _engine->_resourcePixelFormat.RGBToColor(style._red, style._green, style._blue);
- return fnt.renderSolidText(txt, clr);
-}
+void TextRenderer::drawTextWithWordWrapping(const Common::String &text, Graphics::Surface &dest) {
+ Common::Array<TextSurface> textSurfaces;
+ Common::Array<uint> lineWidths;
+ Common::Array<TextJustification> lineJustifications;
-void TextRenderer::drawTxtWithJustify(const Common::String &txt, StyledTTFont &fnt, uint32 color, Graphics::Surface &dst, int lineY, txtJustify justify) {
- if (justify == TXT_JUSTIFY_LEFT)
- fnt.drawString(&dst, txt, 0, lineY, dst.w, color, Graphics::kTextAlignLeft);
- else if (justify == TXT_JUSTIFY_CENTER)
- fnt.drawString(&dst, txt, 0, lineY, dst.w, color, Graphics::kTextAlignCenter);
- else if (justify == TXT_JUSTIFY_RIGHT)
- fnt.drawString(&dst, txt, 0, lineY, dst.w, color, Graphics::kTextAlignRight);
-}
+ // Create the initial text state
+ TextStyleState currentState;
-int32 TextRenderer::drawTxt(const Common::String &txt, cTxtStyle &fontStyle, Graphics::Surface &dst) {
+ // Create an empty font and bind it to the state
StyledTTFont font(_engine);
- fontStyle.setFont(font);
+ currentState.updateFontWithTextState(font);
- uint32 clr = _engine->_resourcePixelFormat.RGBToColor(fontStyle._red, fontStyle._green, fontStyle._blue);
+ Common::String currentSentence; // Not a true 'grammatical' sentence. Rather, it's just a collection of words
+ Common::String currentWord;
+ int sentenceWidth = 0;
+ int wordWidth = 0;
+ int lineWidth = 0;
+ int lineHeight = font.getFontHeight();
- int16 w;
+ uint currentLineNumber = 0u;
- w = font.getStringWidth(txt);
+ uint numSpaces = 0u;
+ int spaceWidth = 0;
- drawTxtWithJustify(txt, font, clr, dst, 0, fontStyle._justify);
+ // The pixel offset to the currentSentence
+ Common::Point sentencePixelOffset;
- return w;
-}
+ uint i = 0u;
+ uint stringlen = text.size();
-void TextRenderer::drawTxtInOneLine(const Common::String &text, Graphics::Surface &dst) {
- const int16 TXT_CFG_TEXTURES_LINES = 256; // For now I don't want remake it
- const int TXT_CFG_TEXTURES_PER_LINE = 6;
- cTxtStyle style, style2;
- int16 startTextPosition = -1;
- int16 endTextPosition = -1;
- int16 i = 0;
- int16 dx = 0, dy = 0;
- int16 textPixelWidth;
- int16 textPosition = 0;
- Common::String buf;
- Common::String buf2;
-
- Graphics::Surface *TxtSurfaces[TXT_CFG_TEXTURES_LINES][TXT_CFG_TEXTURES_PER_LINE];
- int16 currentline = 0, currentlineitm = 0;
-
- int TxtJustify[TXT_CFG_TEXTURES_LINES];
- int TxtPoint[TXT_CFG_TEXTURES_LINES];
-
- for (int16 k = 0; k < TXT_CFG_TEXTURES_LINES; k++) {
- TxtPoint[k] = 0;
- for (int j = 0; j < TXT_CFG_TEXTURES_PER_LINE; j++)
- TxtSurfaces[k][j] = NULL;
- }
-
- int16 stringlen = text.size();
+ while (i < stringlen) {
+ if (text[i] == '<') {
+ // Flush the currentWord to the currentSentence
+ currentSentence += currentWord;
+ sentenceWidth += wordWidth;
+
+ // Reset the word variables
+ currentWord.clear();
+ wordWidth = 0;
+
+ // Parse the style tag
+ uint startTextPosition = i;
+ while (i < stringlen && text[i] != '>') {
+ ++i;
+ }
+ uint endTextPosition = i;
- StyledTTFont font(_engine);
+ uint32 textColor = currentState.getTextColor(_engine);
- style.setFont(font);
+ uint stateChanges = 0u;
+ if ((endTextPosition - startTextPosition - 1) > 0) {
+ stateChanges = currentState.parseStyle(Common::String(text.c_str() + startTextPosition + 1), endTextPosition - startTextPosition - 1);
+ }
- int16 prevbufspace = 0, prevtxtspace = 0;
+ if (stateChanges & (TEXT_CHANGE_FONT_TYPE | TEXT_CHANGE_FONT_STYLE)) {
+ // Use the last state to render out the current sentence
+ // Styles apply to the text 'after' them
+ if (!currentSentence.empty()) {
+ textSurfaces.push_back(TextSurface(font.renderSolidText(currentSentence, textColor), sentencePixelOffset, currentLineNumber));
- while (i < stringlen) {
- TxtJustify[currentline] = style._justify;
- if (text[i] == '<') {
- int16 ret = 0;
+ lineWidth += sentenceWidth;
+ sentencePixelOffset.x += sentenceWidth;
- startTextPosition = i;
- while (i < stringlen && text[i] != '>')
- i++;
- endTextPosition = i;
- if (startTextPosition != -1)
- if ((endTextPosition - startTextPosition - 1) > 0) {
- style2 = style;
- ret = style.parseStyle(Common::String(text.c_str() + startTextPosition + 1), endTextPosition - startTextPosition - 1);
+ // Reset the sentence variables
+ currentSentence.clear();
+ sentenceWidth = 0;
}
- if (ret & (TXT_RET_FNTCHG | TXT_RET_FNTSTL | TXT_RET_NEWLN)) {
- if (buf.size() > 0) {
- textPixelWidth = font.getStringWidth(buf);
+ // Update the current state with the style information
+ currentState.updateFontWithTextState(font);
+
+ lineHeight = MAX(lineHeight, font.getFontHeight());
+ spaceWidth = font.getCharWidth(' ');
+ }
+ if (stateChanges & TEXT_CHANGE_NEWLINE) {
+ // If the current sentence has content, render it out
+ if (!currentSentence.empty()) {
+ textSurfaces.push_back(TextSurface(font.renderSolidText(currentSentence, textColor), sentencePixelOffset, currentLineNumber));
+ }
+
+ // Set line width
+ lineWidths.push_back(lineWidth + sentenceWidth - (numSpaces * spaceWidth));
+
+ currentSentence.clear();
+ sentenceWidth = 0;
+
+ // Update the offsets
+ sentencePixelOffset.x = 0u;
+ sentencePixelOffset.y += lineHeight;
+
+ // Reset the line variables
+ lineHeight = font.getFontHeight();
+ lineWidth = 0;
+ ++currentLineNumber;
+ lineJustifications.push_back(currentState._justification);
+ }
+ if (stateChanges & TEXT_CHANGE_HAS_STATE_BOX) {
+ Common::String temp = Common::String::format("%d", _engine->getScriptManager()->getStateValue(currentState._statebox));
+ wordWidth += font.getStringWidth(temp);
- TxtSurfaces[currentline][currentlineitm] = render(font, buf, style2);
- TxtPoint[currentline] = MAX(font.getFontHeight(), TxtPoint[currentline]);
+ // If the word causes the line to overflow, render the sentence and start a new line
+ if (lineWidth + sentenceWidth + wordWidth > dest.w) {
+ textSurfaces.push_back(TextSurface(font.renderSolidText(currentSentence, textColor), sentencePixelOffset, currentLineNumber));
- currentlineitm++;
+ // Set line width
+ lineWidths.push_back(lineWidth + sentenceWidth - (numSpaces * spaceWidth));
- buf.clear();
- prevbufspace = 0;
- textPosition = 0;
- dx += textPixelWidth;
+ currentSentence.clear();
+ sentenceWidth = 0;
- }
- if (ret & TXT_RET_FNTCHG) {
- style.setFont(font);
- }
- if (ret & TXT_RET_FNTSTL)
- style.setFontStyle(font);
+ // Update the offsets
+ sentencePixelOffset.x = 0u;
+ sentencePixelOffset.y += lineHeight;
- if (ret & TXT_RET_NEWLN) {
- currentline++;
- currentlineitm = 0;
- dx = 0;
+ // Reset the line variables
+ lineHeight = font.getFontHeight();
+ lineWidth = 0;
+ ++currentLineNumber;
+ lineJustifications.push_back(currentState._justification);
}
}
-
- if (ret & TXT_RET_HASSTBOX) {
- Common::String buf3;
- buf3 = Common::String::format("%d", _engine->getScriptManager()->getStateValue(style._statebox));
- buf += buf3;
- textPosition += buf3.size();
- }
-
} else {
-
- buf += text[i];
- textPosition++;
+ currentWord += text[i];
+ wordWidth += font.getCharWidth(text[i]);
if (text[i] == ' ') {
- prevbufspace = textPosition - 1;
- prevtxtspace = i;
- }
+ // When we hit the first space, flush the current word to the sentence
+ if (!currentWord.empty()) {
+ currentSentence += currentWord;
+ sentenceWidth += wordWidth;
- if (font.isLoaded()) {
- textPixelWidth = font.getStringWidth(buf);
- if (textPixelWidth + dx > dst.w) {
- if (prevbufspace == 0) {
- prevtxtspace = i;
- prevbufspace = textPosition - 1;
- }
- buf2 = Common::String(buf.c_str(), prevbufspace + 1);
+ currentWord.clear();
+ wordWidth = 0;
+ }
- if (buf2.size() > 0) {
- TxtSurfaces[currentline][currentlineitm] = render(font, buf2, style);
- TxtPoint[currentline] = MAX(font.getFontHeight(), TxtPoint[currentline]);
+ // We track the number of spaces so we can disregard their width in lineWidth calculations
+ ++numSpaces;
+ } else {
+ // If the word causes the line to overflow, render the sentence and start a new line
+ if (lineWidth + sentenceWidth + wordWidth > dest.w) {
+ // Only render out content
+ if (!currentSentence.empty()) {
+ textSurfaces.push_back(TextSurface(font.renderSolidText(currentSentence, currentState.getTextColor(_engine)), sentencePixelOffset, currentLineNumber));
}
- buf.clear();
- i = prevtxtspace;
- prevbufspace = 0;
- textPosition = 0;
- currentline++;
- currentlineitm = 0;
- dx = 0;
+ // Set line width
+ lineWidths.push_back(lineWidth + sentenceWidth - (numSpaces * spaceWidth));
+
+ currentSentence.clear();
+ sentenceWidth = 0;
+
+ // Update the offsets
+ sentencePixelOffset.x = 0u;
+ sentencePixelOffset.y += lineHeight;
+
+ // Reset the line variables
+ lineHeight = font.getFontHeight();
+ lineWidth = 0;
+ ++currentLineNumber;
+ lineJustifications.push_back(currentState._justification);
}
+
+ numSpaces = 0u;
}
}
+
i++;
}
- if (buf.size() > 0) {
- TxtSurfaces[currentline][currentlineitm] = render(font, buf, style);
- TxtPoint[currentline] = MAX(font.getFontHeight(), TxtPoint[currentline]);
+ // Render out any remaining words/sentences
+ if (!currentWord.empty() || !currentSentence.empty()) {
+ currentSentence += currentWord;
+ sentenceWidth += wordWidth;
+
+ textSurfaces.push_back(TextSurface(font.renderSolidText(currentSentence, currentState.getTextColor(_engine)), sentencePixelOffset, currentLineNumber));
}
- dy = 0;
- for (i = 0; i <= currentline; i++) {
- int16 j = 0;
- int16 width = 0;
- while (TxtSurfaces[i][j] != NULL) {
- width += TxtSurfaces[i][j]->w;
- j++;
- }
- dx = 0;
- Common::Rect empty;
- for (int32 jj = 0; jj < j; jj++) {
- if (TxtJustify[i] == TXT_JUSTIFY_LEFT)
- _engine->getRenderManager()->blitSurfaceToSurface(*TxtSurfaces[i][jj], empty, dst, dx, dy + TxtPoint[i] - TxtSurfaces[i][jj]->h, 0);
-
- else if (TxtJustify[i] == TXT_JUSTIFY_CENTER)
- _engine->getRenderManager()->blitSurfaceToSurface(*TxtSurfaces[i][jj], empty, dst, ((dst.w - width) / 2) + dx, dy + TxtPoint[i] - TxtSurfaces[i][jj]->h, 0);
+ lineWidths.push_back(lineWidth + sentenceWidth);
+ lineJustifications.push_back(currentState._justification);
- else if (TxtJustify[i] == TXT_JUSTIFY_RIGHT)
- _engine->getRenderManager()->blitSurfaceToSurface(*TxtSurfaces[i][jj], empty, dst, dst.w - width + dx, dy + TxtPoint[i] - TxtSurfaces[i][jj]->h, 0);
+ for (Common::Array<TextSurface>::iterator iter = textSurfaces.begin(); iter != textSurfaces.end(); ++iter) {
+ Common::Rect empty;
- dx += TxtSurfaces[i][jj]->w;
+ if (lineJustifications[iter->_lineNumber] == TEXT_JUSTIFY_LEFT) {
+ _engine->getRenderManager()->blitSurfaceToSurface(*iter->_surface, empty, dest, iter->_surfaceOffset.x, iter->_surfaceOffset.y, 0);
+ } else if (lineJustifications[iter->_lineNumber] == TEXT_JUSTIFY_CENTER) {
+ _engine->getRenderManager()->blitSurfaceToSurface(*iter->_surface, empty, dest, ((dest.w - lineWidths[iter->_lineNumber]) / 2) + iter->_surfaceOffset.x, iter->_surfaceOffset.y, 0);
+ } else if (lineJustifications[iter->_lineNumber] == TEXT_JUSTIFY_RIGHT) {
+ _engine->getRenderManager()->blitSurfaceToSurface(*iter->_surface, empty, dest, dest.w - lineWidths[iter->_lineNumber] + iter->_surfaceOffset.x, iter->_surfaceOffset.y, 0);
}
- dy += TxtPoint[i];
+ // Release memory
+ iter->_surface->free();
+ delete iter->_surface;
}
-
- for (i = 0; i < TXT_CFG_TEXTURES_LINES; i++)
- for (int32 j = 0; j < TXT_CFG_TEXTURES_PER_LINE; j++)
- if (TxtSurfaces[i][j] != NULL) {
- TxtSurfaces[i][j]->free();
- delete TxtSurfaces[i][j];
- }
}
Common::String readWideLine(Common::SeekableReadStream &stream) {
diff --git a/engines/zvision/text/text.h b/engines/zvision/text/text.h
index c942b8141a..d35b90499d 100644
--- a/engines/zvision/text/text.h
+++ b/engines/zvision/text/text.h
@@ -32,59 +32,53 @@ namespace ZVision {
class ZVision;
-enum txtJustify {
- TXT_JUSTIFY_CENTER = 0,
- TXT_JUSTIFY_LEFT = 1,
- TXT_JUSTIFY_RIGHT = 2
+enum TextJustification {
+ TEXT_JUSTIFY_CENTER = 0,
+ TEXT_JUSTIFY_LEFT = 1,
+ TEXT_JUSTIFY_RIGHT = 2
};
-enum txtReturn {
- TXT_RET_NOTHING = 0x0,
- TXT_RET_FNTCHG = 0x1,
- TXT_RET_FNTSTL = 0x2,
- TXT_RET_NEWLN = 0x4,
- TXT_RET_HASSTBOX = 0x8
+enum TextChange {
+ TEXT_CHANGE_NONE = 0x0,
+ TEXT_CHANGE_FONT_TYPE = 0x1,
+ TEXT_CHANGE_FONT_STYLE = 0x2,
+ TEXT_CHANGE_NEWLINE = 0x4,
+ TEXT_CHANGE_HAS_STATE_BOX = 0x8
};
-class cTxtStyle {
+class TextStyleState {
public:
- cTxtStyle();
- txtReturn parseStyle(const Common::String &strin, int16 len);
- void readAllStyle(const Common::String &txt);
- void setFontStyle(StyledTTFont &font);
- void setFont(StyledTTFont &font);
+ TextStyleState();
+ TextChange parseStyle(const Common::String &str, int16 len);
+ void readAllStyles(const Common::String &txt);
+ void updateFontWithTextState(StyledTTFont &font);
+
+ uint32 getTextColor(ZVision *engine) {
+ return engine->_resourcePixelFormat.RGBToColor(_red, _green, _blue);
+ }
public:
Common::String _fontname;
- txtJustify _justify; // 0 - center, 1-left, 2-right
+ TextJustification _justification; // 0 - center, 1-left, 2-right
int16 _size;
uint8 _red; // 0-255
uint8 _green; // 0-255
uint8 _blue; // 0-255
-#if 0
- int8 _newline;
- int8 _escapement;
-#endif
bool _italic;
bool _bold;
bool _underline;
bool _strikeout;
-#if 0
- bool _skipcolor;
-#endif
int32 _statebox;
bool _sharp;
- // char image ??
};
class TextRenderer {
public:
TextRenderer(ZVision *engine): _engine(engine) {};
- void drawTxtWithJustify(const Common::String &txt, StyledTTFont &fnt, uint32 color, Graphics::Surface &dst, int lineY, txtJustify justify);
- int32 drawTxt(const Common::String &txt, cTxtStyle &fontStyle, Graphics::Surface &dst);
- Graphics::Surface *render(StyledTTFont &fnt, const Common::String &txt, cTxtStyle &style);
- void drawTxtInOneLine(const Common::String &txt, Graphics::Surface &dst);
+ void drawTextWithJustification(const Common::String &text, StyledTTFont &font, uint32 color, Graphics::Surface &dest, int lineY, TextJustification jusification);
+ int32 drawText(const Common::String &text, TextStyleState &state, Graphics::Surface &dest);
+ void drawTextWithWordWrapping(const Common::String &text, Graphics::Surface &dest);
private:
ZVision *_engine;
diff --git a/engines/zvision/text/truetype_font.cpp b/engines/zvision/text/truetype_font.cpp
index f7580fb553..8e402efc08 100644
--- a/engines/zvision/text/truetype_font.cpp
+++ b/engines/zvision/text/truetype_font.cpp
@@ -56,21 +56,23 @@ const FontStyle getSystemFont(int fontIndex) {
StyledTTFont::StyledTTFont(ZVision *engine) {
_engine = engine;
_style = 0;
- _font = NULL;
+ _font = nullptr;
_lineHeight = 0;
}
StyledTTFont::~StyledTTFont() {
- if (_font)
- delete _font;
+ delete _font;
}
bool StyledTTFont::loadFont(const Common::String &fontName, int32 point, uint style) {
_style = style;
- return loadFont(fontName, point);
-}
-bool StyledTTFont::loadFont(const Common::String &fontName, int32 point) {
+ // Don't re-load the font if we've already loaded it
+ // We have to check for empty so we can default to Arial
+ if (!fontName.empty() && _fontName.equalsIgnoreCase(fontName)) {
+ return true;
+ }
+
Common::String newFontName;
Common::String freeFontName;
Common::String liberationFontName;
@@ -82,16 +84,16 @@ bool StyledTTFont::loadFont(const Common::String &fontName, int32 point) {
freeFontName = curFont.freeFontBase;
liberationFontName = curFont.liberationFontBase;
- if ((_style & STTF_BOLD) && (_style & STTF_ITALIC)) {
+ if ((_style & TTF_STYLE_BOLD) && (_style & TTF_STYLE_ITALIC)) {
newFontName += "bi";
freeFontName += "Bold";
freeFontName += curFont.freeFontItalicName;
liberationFontName += "-BoldItalic";
- } else if (_style & STTF_BOLD) {
+ } else if (_style & TTF_STYLE_BOLD) {
newFontName += "bd";
freeFontName += "Bold";
liberationFontName += "-Bold";
- } else if (_style & STTF_ITALIC) {
+ } else if (_style & TTF_STYLE_ITALIC) {
newFontName += "i";
freeFontName += curFont.freeFontItalicName;
liberationFontName += "-Italic";
@@ -113,7 +115,7 @@ bool StyledTTFont::loadFont(const Common::String &fontName, int32 point) {
liberationFontName = "LiberationSans-Regular.ttf";
}
- bool sharp = (_style & STTF_SHARP) == STTF_SHARP;
+ bool sharp = (_style & TTF_STYLE_SHARP) == TTF_STYLE_SHARP;
Common::File file;
if (!file.open(newFontName) && !_engine->getSearchManager()->openFile(file, newFontName) &&
@@ -121,51 +123,45 @@ bool StyledTTFont::loadFont(const Common::String &fontName, int32 point) {
!file.open(freeFontName) && !_engine->getSearchManager()->openFile(file, freeFontName))
error("Unable to open font file %s (Liberation Font alternative: %s, FreeFont alternative: %s)", newFontName.c_str(), liberationFontName.c_str(), freeFontName.c_str());
- Graphics::Font *_newFont = Graphics::loadTTFFont(file, point, 60, (sharp ? Graphics::kTTFRenderModeMonochrome : Graphics::kTTFRenderModeNormal)); // 66 dpi for 640 x 480 on 14" display
- if (_newFont) {
- if (!_font)
- delete _font;
- _font = _newFont;
+ Graphics::Font *newFont = Graphics::loadTTFFont(file, point, 60, (sharp ? Graphics::kTTFRenderModeMonochrome : Graphics::kTTFRenderModeNormal)); // 66 dpi for 640 x 480 on 14" display
+ if (newFont == nullptr) {
+ return false;
}
- _fntName = fontName;
- _lineHeight = point;
+ delete _font;
+ _font = newFont;
- if (_font)
- return true;
- return false;
-}
+ _fontName = fontName;
+ _lineHeight = point;
-void StyledTTFont::setStyle(uint newStyle) {
- if ((_style & (STTF_BOLD | STTF_ITALIC | STTF_SHARP)) != (newStyle & (STTF_BOLD | STTF_ITALIC | STTF_SHARP))) {
- _style = newStyle;
- loadFont(_fntName, _lineHeight);
- } else {
- _style = newStyle;
- }
+ return true;
}
int StyledTTFont::getFontHeight() {
if (_font)
return _font->getFontHeight();
+
return 0;
}
int StyledTTFont::getMaxCharWidth() {
if (_font)
return _font->getMaxCharWidth();
+
return 0;
}
int StyledTTFont::getCharWidth(byte chr) {
if (_font)
return _font->getCharWidth(chr);
+
return 0;
}
int StyledTTFont::getKerningOffset(byte left, byte right) {
if (_font)
return _font->getKerningOffset(left, right);
+
return 0;
}
@@ -202,12 +198,12 @@ Common::U32String StyledTTFont::convertUtf8ToUtf32(const Common::String &str) {
void StyledTTFont::drawChar(Graphics::Surface *dst, byte chr, int x, int y, uint32 color) {
if (_font) {
_font->drawChar(dst, chr, x, y, color);
- if (_style & STTF_UNDERLINE) {
+ if (_style & TTF_STYLE_UNDERLINE) {
int16 pos = floor(_font->getFontHeight() * 0.87);
int thk = MAX((int)(_font->getFontHeight() * 0.05), 1);
dst->fillRect(Common::Rect(x, y + pos, x + _font->getCharWidth(chr), y + pos + thk), color);
}
- if (_style & STTF_STRIKEOUT) {
+ if (_style & TTF_STYLE_STRIKETHROUGH) {
int16 pos = floor(_font->getFontHeight() * 0.60);
int thk = MAX((int)(_font->getFontHeight() * 0.05), 1);
dst->fillRect(Common::Rect(x, y + pos, x + _font->getCharWidth(chr), y + pos + thk), color);
@@ -219,7 +215,7 @@ void StyledTTFont::drawString(Graphics::Surface *dst, const Common::String &str,
if (_font) {
Common::U32String u32str = convertUtf8ToUtf32(str);
_font->drawString(dst, u32str, x, y, w, color, align);
- if (_style & STTF_UNDERLINE) {
+ if (_style & TTF_STYLE_UNDERLINE) {
int16 pos = floor(_font->getFontHeight() * 0.87);
int16 wd = MIN(_font->getStringWidth(u32str), w);
int16 stX = x;
@@ -232,7 +228,7 @@ void StyledTTFont::drawString(Graphics::Surface *dst, const Common::String &str,
dst->fillRect(Common::Rect(stX, y + pos, stX + wd, y + pos + thk), color);
}
- if (_style & STTF_STRIKEOUT) {
+ if (_style & TTF_STYLE_STRIKETHROUGH) {
int16 pos = floor(_font->getFontHeight() * 0.60);
int16 wd = MIN(_font->getStringWidth(u32str), w);
int16 stX = x;
diff --git a/engines/zvision/text/truetype_font.h b/engines/zvision/text/truetype_font.h
index caa9c09a76..6abe05cda6 100644
--- a/engines/zvision/text/truetype_font.h
+++ b/engines/zvision/text/truetype_font.h
@@ -53,11 +53,11 @@ public:
~StyledTTFont();
enum {
- STTF_BOLD = 1,
- STTF_ITALIC = 2,
- STTF_UNDERLINE = 4,
- STTF_STRIKEOUT = 8,
- STTF_SHARP = 16
+ TTF_STYLE_BOLD = 0x01,
+ TTF_STYLE_ITALIC = 0x02,
+ TTF_STYLE_UNDERLINE = 0x04,
+ TTF_STYLE_STRIKETHROUGH = 0x08,
+ TTF_STYLE_SHARP = 0x10
};
private:
@@ -65,12 +65,10 @@ private:
Graphics::Font *_font;
int _lineHeight;
uint _style;
- Common::String _fntName;
+ Common::String _fontName;
public:
- bool loadFont(const Common::String &fontName, int32 point);
bool loadFont(const Common::String &fontName, int32 point, uint style);
- void setStyle(uint newStyle);
int getFontHeight();
int getMaxCharWidth();