From 61c106b3307ee2f8aaa579dbc5d7c8f8e62ae41a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=BDubom=C3=ADr=20Rem=C3=A1k?= Date: Sat, 14 Apr 2018 23:04:20 +0200 Subject: [PATCH] MUTATIONOFJB: Add font support and conversation widget. --- engines/mutationofjb/font.cpp | 125 ++++++++++++++++++ engines/mutationofjb/font.h | 70 ++++++++++ engines/mutationofjb/game.cpp | 8 ++ engines/mutationofjb/game.h | 7 + engines/mutationofjb/gui.cpp | 11 ++ engines/mutationofjb/gui.h | 15 +++ engines/mutationofjb/module.mk | 2 + .../widgets/conversationwidget.cpp | 65 +++++++++ .../mutationofjb/widgets/conversationwidget.h | 50 +++++++ engines/mutationofjb/widgets/widget.cpp | 15 ++- engines/mutationofjb/widgets/widget.h | 6 +- 11 files changed, 372 insertions(+), 2 deletions(-) create mode 100644 engines/mutationofjb/font.cpp create mode 100644 engines/mutationofjb/font.h create mode 100644 engines/mutationofjb/widgets/conversationwidget.cpp create mode 100644 engines/mutationofjb/widgets/conversationwidget.h diff --git a/engines/mutationofjb/font.cpp b/engines/mutationofjb/font.cpp new file mode 100644 index 000000000000..235c60a39e15 --- /dev/null +++ b/engines/mutationofjb/font.cpp @@ -0,0 +1,125 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "mutationofjb/font.h" +#include "mutationofjb/encryptedfile.h" +#include "mutationofjb/util.h" +#include "common/debug.h" + +namespace MutationOfJB { + +Font::Font(const Common::String &fileName, int horizSpacing, int vertSpacing) : + _horizSpacing(horizSpacing), + _vertSpacing(vertSpacing) { + + load(fileName); +} + +bool Font::load(const Common::String &fileName) { + EncryptedFile file; + file.open(fileName); + if (!file.isOpen()) { + reportFileMissingError(fileName.c_str()); + return false; + } + + file.seek(0x02D6, SEEK_SET); // Skip header + unknown data (unused palette?). + + uint16 noGlyphs = 0; + noGlyphs = file.readUint16LE(); + + file.seek(7, SEEK_CUR); // Skip unknown data (0s). + + uint8 maxHeight = 0; + + while (noGlyphs--) { + const uint8 character = file.readByte(); + const uint8 width = file.readByte(); + const uint8 height = file.readByte(); + + Graphics::ManagedSurface &surf = _glyphs[character]; + surf.create(width, height); + for (int h = 0; h < height; ++h) { + file.read(surf.getBasePtr(0, h), width); + } + + if (height > maxHeight) { + maxHeight = height; + } + } + + if (_vertSpacing == -1) { + _vertSpacing = maxHeight; + } + + return true; +} + + +void Font::drawGlyph(uint8 glyph, uint8 baseColor, int16 &x, int16 &y, Graphics::ManagedSurface &surf) { + GlyphMap::iterator it = _glyphs.find(glyph); + if (it == _glyphs.end()) { + warning("Glyph %d not found", glyph); + return; + } + + Graphics::ManagedSurface &glyphSurface = it->_value; + + 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++; + } + } + surf.transBlitFrom(tmp.rawSurface(), Common::Point(x, y)); + + x += glyphSurface.w + _horizSpacing; +} + +void Font::drawString(const Common::String &str, uint8 baseColor, int16 x, int16 y, Graphics::ManagedSurface &surf) { + for (uint i = 0; i < str.size(); ++i) { + drawGlyph(str[i], baseColor, x, y, surf); // "x" is updated. + } +} + +uint8 Font::transformColor(uint8 baseColor, uint8 glyphColor) { + return baseColor + glyphColor - 0x10; +} + +SystemFont::SystemFont() : Font("sysfnt.aft", 1, 7) {} + +SpeechFont::SpeechFont() : Font("font1.aft", -1, -1) {} + +uint8 SpeechFont::transformColor(uint8 baseColor, uint8 glyphColor) { + // Hack in original game. + if (glyphColor == 0x11) { + return 0xC0; + } + + return Font::transformColor(baseColor, glyphColor); +} + +} diff --git a/engines/mutationofjb/font.h b/engines/mutationofjb/font.h new file mode 100644 index 000000000000..5aa6a4fb7835 --- /dev/null +++ b/engines/mutationofjb/font.h @@ -0,0 +1,70 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef MUTATIONOFJB_FONT_H +#define MUTATIONOFJB_FONT_H + +#include "common/scummsys.h" +#include "common/hashmap.h" +#include "graphics/managed_surface.h" + +namespace Common { +class String; +} + +namespace MutationOfJB { + +class Font { +public: + Font(const Common::String &fileName, int horizSpacing, int vertSpacing); + virtual ~Font() {} + void drawString(const Common::String &str, uint8 baseColor, int16 x, int16 y, Graphics::ManagedSurface &surf); + +protected: + virtual uint8 transformColor(uint8 baseColor, uint8 glyphColor); + +private: + void drawGlyph(uint8 glyph, uint8 baseColor, int16 &x, int16 &y, Graphics::ManagedSurface &surf); + bool load(const Common::String &fileName); + + int _horizSpacing; + int _vertSpacing; + typedef Common::HashMap GlyphMap; + GlyphMap _glyphs; +}; + +class SystemFont : public Font { +public: + SystemFont(); +}; + +class SpeechFont : public Font { +public: + SpeechFont(); + +protected: + virtual uint8 transformColor(uint8 baseColor, uint8 glyphColor) override; +}; + +} + +#endif diff --git a/engines/mutationofjb/game.cpp b/engines/mutationofjb/game.cpp index af0b76bb7e27..d6ab622e99fb 100644 --- a/engines/mutationofjb/game.cpp +++ b/engines/mutationofjb/game.cpp @@ -192,4 +192,12 @@ void Game::setCurrentAction(ActionInfo::Action action) { _currentAction = action; } +Font& Game::getSystemFont() { + return _systemFont; +} + +Font& Game::getSpeechFont() { + return _speechFont; +} + } diff --git a/engines/mutationofjb/game.h b/engines/mutationofjb/game.h index 19cf40616827..122c2a1f63c8 100644 --- a/engines/mutationofjb/game.h +++ b/engines/mutationofjb/game.h @@ -25,6 +25,7 @@ #include "common/scummsys.h" #include "mutationofjb/script.h" +#include "mutationofjb/font.h" #include "mutationofjb/gui.h" namespace Common { @@ -64,6 +65,9 @@ class Game { ActionInfo::Action getCurrentAction() const; void setCurrentAction(ActionInfo::Action); + Font& getSystemFont(); + Font& getSpeechFont(); + private: bool loadGameData(bool partB); void runActiveCommand(); @@ -81,6 +85,9 @@ class Game { ActionInfo::Action _currentAction; ScriptExecutionContext _scriptExecCtx; + + SystemFont _systemFont; + SpeechFont _speechFont; }; } diff --git a/engines/mutationofjb/gui.cpp b/engines/mutationofjb/gui.cpp index c7be3559d8b8..7102407c99ae 100644 --- a/engines/mutationofjb/gui.cpp +++ b/engines/mutationofjb/gui.cpp @@ -30,6 +30,7 @@ #include "mutationofjb/widgets/widget.h" #include "mutationofjb/widgets/inventorywidget.h" #include "mutationofjb/widgets/imagewidget.h" +#include "mutationofjb/widgets/conversationwidget.h" #include "common/rect.h" #include "graphics/screen.h" @@ -120,6 +121,12 @@ bool Gui::init() { _widgets.push_back(button); } + const Common::Rect conversationRect(CONVERSATION_X, CONVERSATION_Y, CONVERSATION_X + CONVERSATION_WIDTH, CONVERSATION_Y + CONVERSATION_HEIGHT); + const Graphics::Surface conversationSurface =_hudSurfaces[2].getSubArea(conversationRect); + _conversationWidget = new ConversationWidget(*this, conversationRect, conversationSurface); + _conversationWidget->setVisible(false); + _widgets.push_back(_conversationWidget); + return true; } @@ -141,6 +148,10 @@ void Gui::update() { } } +ConversationWidget& Gui::getConversationWidget() { + return *_conversationWidget; +} + class InventoryAnimationDecoderCallback : public AnimationDecoderCallback { public: InventoryAnimationDecoderCallback(Gui &gui) : _gui(gui) {} diff --git a/engines/mutationofjb/gui.h b/engines/mutationofjb/gui.h index 5d8358b47f59..d8e1286233bc 100644 --- a/engines/mutationofjb/gui.h +++ b/engines/mutationofjb/gui.h @@ -43,9 +43,21 @@ namespace MutationOfJB { class Game; class Widget; class InventoryWidget; +class ConversationWidget; class Gui : public InventoryObserver, public ButtonWidgetCallback { public: + enum Colors { + WHITE = 0xC6, + DARKGRAY = 0xC2, + LIGHTGRAY = 0xC4, + GREEN = 0xC8, + ORANGE = 0xCA, + DARKBLUE = 0xD6, + LIGHTBLUE = 0xDA, + BROWN = 0xDC + }; + typedef Common::HashMap InventoryMap; friend class InventoryAnimationDecoderCallback; @@ -64,6 +76,8 @@ class Gui : public InventoryObserver, public ButtonWidgetCallback { virtual void onInventoryChanged() override; virtual void onButtonClicked(ButtonWidget *) override; + ConversationWidget& getConversationWidget(); + private: bool loadInventoryGfx(); bool loadHudGfx(); @@ -78,6 +92,7 @@ class Gui : public InventoryObserver, public ButtonWidgetCallback { Common::Array _hudSurfaces; InventoryWidget *_inventoryWidget; + ConversationWidget *_conversationWidget; Common::Array _widgets; }; diff --git a/engines/mutationofjb/module.mk b/engines/mutationofjb/module.mk index 8604d403f069..2fd41230874d 100644 --- a/engines/mutationofjb/module.mk +++ b/engines/mutationofjb/module.mk @@ -20,6 +20,7 @@ MODULE_OBJS := \ commands/saycommand.o \ commands/seqcommand.o \ widgets/buttonwidget.o \ + widgets/conversationwidget.o \ widgets/imagewidget.o \ widgets/inventorywidget.o \ widgets/widget.o \ @@ -27,6 +28,7 @@ MODULE_OBJS := \ debug.o \ detection.o \ encryptedfile.o \ + font.o \ game.o \ gamedata.o \ gui.o \ diff --git a/engines/mutationofjb/widgets/conversationwidget.cpp b/engines/mutationofjb/widgets/conversationwidget.cpp new file mode 100644 index 000000000000..6196bc672a2b --- /dev/null +++ b/engines/mutationofjb/widgets/conversationwidget.cpp @@ -0,0 +1,65 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "mutationofjb/widgets/conversationwidget.h" +#include "mutationofjb/game.h" +#include "mutationofjb/gui.h" +#include "mutationofjb/font.h" + +namespace MutationOfJB { + +enum { + CONVERSATION_LINES_X = 5, + CONVERSATION_LINES_Y = 151, + CONVERSATION_LINE_HEIGHT = 12 +}; + +ConversationWidget::ConversationWidget(Gui &gui, const Common::Rect &area, const Graphics::Surface &surface) : + Widget(gui, area), + _surface(surface) {} + + +void ConversationWidget::setLine(int lineNo, const Common::String &str) { + if (lineNo >= CONVERSATION_LINES) { + return; + } + + _lines[lineNo] = str; + markDirty(); +} + +void ConversationWidget::_draw(Graphics::ManagedSurface &surface) { + surface.blitFrom(_surface, Common::Point(_area.left, _area.top)); + + for (int i = 0; i < CONVERSATION_LINES; ++i) { + Common::String &line = _lines[i]; + if (line.empty()) { + continue; + } + + // TODO: Active line should be Gui::WHITE. + _gui.getGame().getSystemFont().drawString(line, Gui::LIGHTGRAY, CONVERSATION_LINES_X, CONVERSATION_LINES_Y + i * CONVERSATION_LINE_HEIGHT, surface); + } +} + +} + diff --git a/engines/mutationofjb/widgets/conversationwidget.h b/engines/mutationofjb/widgets/conversationwidget.h new file mode 100644 index 000000000000..0f26a99d3f1f --- /dev/null +++ b/engines/mutationofjb/widgets/conversationwidget.h @@ -0,0 +1,50 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef MUTATIONOFJB_CONVERSATIONWIDGET_H +#define MUTATIONOFJB_CONVERSATIONWIDGET_H + +#include "mutationofjb/widgets/widget.h" +#include "graphics/surface.h" + +namespace MutationOfJB { + +class ConversationWidget : public Widget { +public: + enum { CONVERSATION_LINES = 4 }; + + ConversationWidget(Gui &gui, const Common::Rect &area, const Graphics::Surface &surface); + + void setLine(int lineNo, const Common::String &str); + +protected: + void _draw(Graphics::ManagedSurface &surface); + +private: + + Graphics::Surface _surface; + Common::String _lines[CONVERSATION_LINES]; +}; + +} + +#endif diff --git a/engines/mutationofjb/widgets/widget.cpp b/engines/mutationofjb/widgets/widget.cpp index fea7f6fbe027..5503f625cdd6 100644 --- a/engines/mutationofjb/widgets/widget.cpp +++ b/engines/mutationofjb/widgets/widget.cpp @@ -32,6 +32,17 @@ void Widget::setId(int id) { _id = id; } +bool Widget::isVisible() const { + return _visible; +} + +void Widget::setVisible(bool visible) { + if (!_visible && visible) { + markDirty(); + } + _visible = visible; +} + void Widget::markDirty() { _dirty = true; } @@ -42,7 +53,9 @@ bool Widget::isDirty() const { void Widget::update(Graphics::ManagedSurface &surface) { if (_dirty) { - _draw(surface); + if (_visible) { + _draw(surface); + } _dirty = false; } } diff --git a/engines/mutationofjb/widgets/widget.h b/engines/mutationofjb/widgets/widget.h index f81d466c1c25..ed3a3acd54b0 100644 --- a/engines/mutationofjb/widgets/widget.h +++ b/engines/mutationofjb/widgets/widget.h @@ -40,12 +40,15 @@ class Gui; class Widget { public: - Widget(Gui &gui, const Common::Rect &area) : _gui(gui), _area(area), _id(0), _dirty(true) {} + Widget(Gui &gui, const Common::Rect &area) : _gui(gui), _area(area), _id(0), _visible(true), _dirty(true) {} virtual ~Widget() {} int getId() const; void setId(int id); + bool isVisible() const; + void setVisible(bool visible); + bool isDirty() const; void markDirty(); void update(Graphics::ManagedSurface &); @@ -57,6 +60,7 @@ class Widget { Gui &_gui; Common::Rect _area; int _id; + bool _visible; bool _dirty; };