From 298bfc3d109110b8f4332083b4f9aca850f43eea Mon Sep 17 00:00:00 2001 From: Miroslav Remák Date: Mon, 23 Jul 2018 19:49:08 +0200 Subject: MUTATIONOFJB: Subclass Graphics::Font to reuse existing code. --- engines/mutationofjb/font.cpp | 109 ++++++++++----------- engines/mutationofjb/font.h | 20 ++-- engines/mutationofjb/tasks/saytask.cpp | 28 ++---- .../mutationofjb/widgets/conversationwidget.cpp | 2 +- 4 files changed, 77 insertions(+), 82 deletions(-) (limited to 'engines') diff --git a/engines/mutationofjb/font.cpp b/engines/mutationofjb/font.cpp index 4f4a0ee82b..f87f25ba63 100644 --- a/engines/mutationofjb/font.cpp +++ b/engines/mutationofjb/font.cpp @@ -29,7 +29,8 @@ namespace MutationOfJB { Font::Font(const Common::String &fileName, int horizSpacing, int lineHeight) : _horizSpacing(horizSpacing), - _lineHeight(lineHeight) { + _lineHeight(lineHeight), + _maxCharWidth(0) { load(fileName); } @@ -62,6 +63,10 @@ bool Font::load(const Common::String &fileName) { file.read(surf.getBasePtr(0, h), width); } + if (width > _maxCharWidth) { + _maxCharWidth = width; + } + if (height > maxHeight) { maxHeight = height; } @@ -74,75 +79,69 @@ bool Font::load(const Common::String &fileName) { return true; } -void Font::drawGlyph(uint8 glyph, uint8 baseColor, int16 &x, int16 &y, Graphics::ManagedSurface &surf) const { - GlyphMap::iterator it = _glyphs.find(glyph); +int Font::getFontHeight() const { + return _lineHeight; +} + +int Font::getMaxCharWidth() const { + return _maxCharWidth; +} + +int Font::getCharWidth(uint32 chr) const { + GlyphMap::iterator it = _glyphs.find(chr); if (it == _glyphs.end()) { - // Missing glyph is a common situation in the game and it's okay to ignore it. - return; + return 0; } + return it->_value.w; +} - Graphics::ManagedSurface &glyphSurface = it->_value; +int Font::getKerningOffset(uint32 left, uint32 right) const { + if (left == 0) { + // Do not displace the first character. + return 0; + } - Graphics::ManagedSurface tmp(glyphSurface); - for (int h = 0; h < tmp.h; ++h) { - uint8 *ptr = reinterpret_cast(tmp.getBasePtr(0, h)); - for (int w = 0; w < tmp.w; ++w) { - if (*ptr != 0) { - *ptr = transformColor(baseColor, *ptr); - } - ptr++; - } + if (_glyphs.find(left) == _glyphs.end()) { + // Missing glyphs must not create extra displacement. + // FIXME: This way is not completely correct, as if the last character is + // missing a glyph, it will still create extra displacement. This should + // not affect the visuals but it might affect getStringWidth() / getBoundingBox(). + return 0; } - surf.transBlitFrom(tmp.rawSurface(), Common::Point(x, y)); - x += glyphSurface.w + _horizSpacing; + return _horizSpacing; } -int16 Font::getWidth(const Common::String &str) const { - int16 width = 0; - for (uint i = 0; i < str.size(); ++i) { - GlyphMap::iterator it = _glyphs.find(str[i]); - if (it == _glyphs.end()) { - continue; +class FontBlitOperation { +public: + FontBlitOperation(const Font &font, const byte baseColor) + : _font(font), + _baseColor(baseColor) {} + + byte operator()(const byte srcColor, const byte destColor) { + if (srcColor == 0) { + // Transparency - keep destination color. + return destColor; } - width += it->_value.w + _horizSpacing; + // Replace destination with transformed source color. + return _font.transformColor(_baseColor, srcColor); } - return width; -} -int Font::getLineHeight() const { - return _lineHeight; -} +private: + const Font &_font; + const byte _baseColor; +}; -void Font::drawString(const Common::String &str, uint8 baseColor, int16 x, int16 y, Graphics::ManagedSurface &surf) const { - for (uint i = 0; i < str.size(); ++i) { - drawGlyph(str[i], baseColor, x, y, surf); // "x" is updated. +void Font::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const { + GlyphMap::iterator it = _glyphs.find(chr); + if (it == _glyphs.end()) { + // Missing glyph is a common situation in the game and it's okay to ignore it. + return; } -} -void Font::wordWrap(const Common::String &str, int16 maxLineWidth, Common::Array &lines) const { - lines.push_back(""); - - for (Common::String::const_iterator it = str.begin(); it != str.end();) { - Common::String::const_iterator partStart = it; - it = Common::find(partStart, str.end(), ' '); - if (it != str.end()) { - while (*it == ' ' && it != str.end()) { - ++it; - } - } - - Common::String part(partStart, it); // Word + following whitespace - Common::String line = lines.back() + part; - if (getWidth(line) <= maxLineWidth) { - // The part fits in the current line - lines.back() = line; - } else { - // The part must go to the next line - lines.push_back(part); - } - } + Graphics::ManagedSurface &glyphSurface = it->_value; + blit_if(glyphSurface, *dst, Common::Point(x, y), FontBlitOperation(*this, color)); } uint8 Font::transformColor(uint8 baseColor, uint8 glyphColor) const { diff --git a/engines/mutationofjb/font.h b/engines/mutationofjb/font.h index a27303eb0d..51825dbe13 100644 --- a/engines/mutationofjb/font.h +++ b/engines/mutationofjb/font.h @@ -25,7 +25,9 @@ #include "common/scummsys.h" #include "common/hashmap.h" +#include "graphics/font.h" #include "graphics/managed_surface.h" +#include "graphics/surface.h" namespace Common { class String; @@ -33,24 +35,26 @@ class String; namespace MutationOfJB { -class Font { +class Font : public Graphics::Font { + friend class FontBlitOperation; public: - Font(const Common::String &fileName, int horizSpacing, int vertSpacing); - virtual ~Font() {} - int getLineHeight() const; - int16 getWidth(const Common::String &text) const; - void drawString(const Common::String &str, uint8 baseColor, int16 x, int16 y, Graphics::ManagedSurface &surf) const; - void wordWrap(const Common::String &str, int16 maxLineWidth, Common::Array &lines) const; + Font(const Common::String &fileName, int horizSpacing, int lineHeight); + + virtual int getFontHeight() const override; + virtual int getMaxCharWidth() const override; + virtual int getCharWidth(uint32 chr) const override; + virtual int getKerningOffset(uint32 left, uint32 right) const override; + virtual void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override; protected: virtual uint8 transformColor(uint8 baseColor, uint8 glyphColor) const; private: - void drawGlyph(uint8 glyph, uint8 baseColor, int16 &x, int16 &y, Graphics::ManagedSurface &surf) const; bool load(const Common::String &fileName); int _horizSpacing; int _lineHeight; + int _maxCharWidth; typedef Common::HashMap GlyphMap; GlyphMap _glyphs; }; diff --git a/engines/mutationofjb/tasks/saytask.cpp b/engines/mutationofjb/tasks/saytask.cpp index cfa412b3b1..21a7dea8e3 100644 --- a/engines/mutationofjb/tasks/saytask.cpp +++ b/engines/mutationofjb/tasks/saytask.cpp @@ -68,35 +68,27 @@ void SayTask::drawSubtitle(const Common::String &text, int16 talkX, int16 talkY, const Font &font = getTaskManager()->getGame().getAssets().getSpeechFont(); Common::Array lines; - font.wordWrap(text, MAX_LINE_WIDTH, lines); + const int16 actualMaxWidth = font.wordWrapText(text, MAX_LINE_WIDTH, lines); // Get the x, y coordinates of the top center point of the text's bounding box // from the (rather strange) talk coordinates coming from scripts. int16 x = talkX; - int16 y = talkY - (lines.size() - 1) * font.getLineHeight() - 15; + int16 y = talkY - (lines.size() - 1) * font.getFontHeight() - 15; // Clamp to screen edges. + x = CLIP(x, 3 + actualMaxWidth / 2, 317 - actualMaxWidth / 2); y = MAX(y, 3); - int16 maxWidth = 0; - for (uint i = 0; i < lines.size(); i++) { - int16 lineWidth = font.getWidth(lines[i]); - if (lineWidth > maxWidth) { - maxWidth = lineWidth; - } - x = MAX(x, 3 + lineWidth / 2); - x = MIN(x, 317 - lineWidth / 2); - } + + // Remember the area occupied by the text. + _boundingBox.left = x - actualMaxWidth / 2; + _boundingBox.top = y; + _boundingBox.setWidth(actualMaxWidth); + _boundingBox.setHeight(lines.size() * font.getFontHeight()); // Draw lines. for (uint i = 0; i < lines.size(); i++) { - font.drawString(lines[i], color, x - font.getWidth(lines[i]) / 2, y + i * font.getLineHeight(), getTaskManager()->getGame().getScreen()); + font.drawString(&getTaskManager()->getGame().getScreen(), lines[i], _boundingBox.left, _boundingBox.top + i * font.getFontHeight(), _boundingBox.width(), color, Graphics::kTextAlignCenter); } - - // Remember the area occupied by the text. - _boundingBox.top = x - maxWidth / 2; - _boundingBox.left = y; - _boundingBox.setWidth(maxWidth); - _boundingBox.setHeight(lines.size() * font.getLineHeight()); } void SayTask::finish() { diff --git a/engines/mutationofjb/widgets/conversationwidget.cpp b/engines/mutationofjb/widgets/conversationwidget.cpp index a46b9c50f8..24bb5e1d25 100644 --- a/engines/mutationofjb/widgets/conversationwidget.cpp +++ b/engines/mutationofjb/widgets/conversationwidget.cpp @@ -69,7 +69,7 @@ void ConversationWidget::_draw(Graphics::ManagedSurface &surface) { } // TODO: Active line should be WHITE. - _gui.getGame().getAssets().getSystemFont().drawString(str, LIGHTGRAY, CONVERSATION_LINES_X, CONVERSATION_LINES_Y + i * CONVERSATION_LINE_HEIGHT, surface); + _gui.getGame().getAssets().getSystemFont().drawString(&surface, str, CONVERSATION_LINES_X, CONVERSATION_LINES_Y + i * CONVERSATION_LINE_HEIGHT, _area.width(), LIGHTGRAY); } } -- cgit v1.2.3