1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "graphics/fonts/ttf.h"
24 #include "graphics/fontman.h"
25
26 #include "petka/q_manager.h"
27 #include "petka/petka.h"
28 #include "petka/video.h"
29 #include "petka/objects/text.h"
30 #include "petka/q_system.h"
31 #include "petka/interfaces/panel.h"
32 #include "petka/sound.h"
33 #include "petka/interfaces/main.h"
34 #include "petka/flc.h"
35
36 namespace Petka {
37
QText(const Common::U32String & text,uint16 textColor,uint16 outlineColor)38 QText::QText(const Common::U32String &text, uint16 textColor, uint16 outlineColor) {
39 _resourceId = -2;
40 _z = 3000;
41
42 Common::ScopedPtr<Graphics::Font> font(Graphics::loadTTFFontFromArchive("FreeSans.ttf", 20));
43
44 Common::Rect rect = calculateBoundingBoxForText(text, *font);
45 rect.right += 10;
46 rect.bottom += 10;
47
48 _rect = Common::Rect((640 - rect.width()) / 2, 479 - rect.height(), 639 - (640 - rect.width()) / 2, 479);
49 Graphics::Surface *s = g_vm->resMgr()->getSurface(-2, _rect.width(), _rect.height());
50
51 drawText(*s, 0, 630, text, textColor, *font);
52 drawOutline(s, outlineColor);
53 }
54
draw()55 void QText::draw() {
56 const Graphics::Surface *s = g_vm->resMgr()->getSurface(-2);
57 if (s) {
58 g_vm->videoSystem()->transBlitFrom(*s, Common::Point((640 - s->w) / 2, 479 - s->h));
59 }
60 }
61
getRect()62 const Common::Rect &QText::getRect() {
63 return _rect;
64 }
65
drawOutline(Graphics::Surface * s,uint16 color)66 void QText::drawOutline(Graphics::Surface *s, uint16 color) {
67 for (int y = 0; y < s->h; ++y) {
68 for (int x = 1; x < s->w - 1; ++x) {
69 uint16 *pixel = (uint16 *)s->getBasePtr(x, y);
70 if (*pixel && *pixel != color) {
71 if (!pixel[-1])
72 pixel[-1] = (uint16)color;
73 if (!pixel[1])
74 pixel[1] = (uint16)color;
75 }
76 }
77 }
78
79 for (int x = 0; x < s->w; ++x) {
80 for (int y = 0; y < s->h - 1; ++y) {
81 uint16 *pixel = (uint16 *)s->getBasePtr(x, y);
82 if (*pixel && *pixel != color) {
83 pixel = (uint16 *)s->getBasePtr(x, y - 1);
84 if (*pixel == 0)
85 *pixel = color;
86 pixel = (uint16 *)s->getBasePtr(x, y + 1);
87 if (*pixel == 0)
88 *pixel = color;
89 }
90 }
91 }
92 }
93
QText()94 QText::QText() {
95 _resourceId = -2;
96 _z = 3000;
97 }
98
update(int)99 void QText::update(int) {
100 g_vm->videoSystem()->addDirtyRect(_rect);
101 }
102
QTextPhrase(const Common::U32String & text,uint16 textColor,uint16 outlineColor)103 QTextPhrase::QTextPhrase(const Common::U32String &text, uint16 textColor, uint16 outlineColor)
104 : QText(text, textColor, outlineColor), _phrase(text), _time(0) {}
105
draw()106 void QTextPhrase::draw() {
107 if (g_vm->getQSystem()->_panelInterface->showSubtitles()) {
108 QText::draw();
109 }
110 }
111
update(int time)112 void QTextPhrase::update(int time) {
113 DialogInterface &dialog = g_vm->getQSystem()->_mainInterface->_dialog;
114 _time += time;
115 QText::update(time);
116 Sound *sound = dialog.findSound();
117 if (sound) {
118 if (!sound->isPlaying()) {
119 _time = 0;
120 dialog.next(-1);
121 }
122 } else if (_time > _phrase.size() * 30 + 1000 || !g_vm->getQSystem()->_panelInterface->showSubtitles()) {
123 _time = 0;
124 dialog.next(-1);
125 }
126 }
127
onClick(Common::Point p)128 void QTextPhrase::onClick(Common::Point p) {
129 DialogInterface &dialog = g_vm->getQSystem()->_mainInterface->_dialog;
130 dialog.next(-1);
131 }
132
QTextDescription(const Common::U32String & desc,uint32 frame)133 QTextDescription::QTextDescription(const Common::U32String &desc, uint32 frame) {
134 _z = 999;
135 _resourceId = -2;
136 _rect = Common::Rect(0, 0, 640, 480);
137
138 FlicDecoder *flc = g_vm->resMgr()->getFlic(6008);
139 flc->setFrame(frame);
140
141 const Graphics::Surface *frameS = flc->getCurrentFrame();
142 Graphics::Surface *s = g_vm->resMgr()->getSurface(-2, 640, 480);
143
144 Graphics::Surface *convS = frameS->convertTo(s->format, flc->getPalette());
145 s->copyRectToSurface(*convS, 0, 0, _rect);
146 convS->free();
147 delete convS;
148
149 Common::Rect textArea(160, 275, 598, 376);
150 Common::ScopedPtr<Graphics::Font> font(Graphics::loadTTFFontFromArchive("FreeSans.ttf", 16));
151
152 auto textSurface = s->getSubArea(textArea);
153
154 drawText(textSurface, 0, textArea.width(), desc, 0, *font);
155
156 g_vm->videoSystem()->addDirtyRect(_rect);
157 }
158
onClick(Common::Point p)159 void QTextDescription::onClick(Common::Point p) {
160 g_vm->getQSystem()->_mainInterface->removeTextDescription();
161 }
162
draw()163 void QTextDescription::draw() {
164 QManager *resMgr = g_vm->resMgr();
165 VideoSystem *videoSys = g_vm->videoSystem();
166 Graphics::Surface *s = resMgr->getSurface(-2);
167 FlicDecoder *flc = resMgr->getFlic(6008);
168
169 for (auto dirty : videoSys->rects()) {
170 videoSys->transBlitFrom(*s, dirty, dirty, flc->getTransColor(s->format));
171 }
172 }
173
QTextChoice(const Common::Array<Common::U32String> & choices,uint16 color,uint16 selectedColor)174 QTextChoice::QTextChoice(const Common::Array<Common::U32String> &choices, uint16 color, uint16 selectedColor) {
175 _activeChoice = 0;
176 _choiceColor = color;
177 _selectedColor = selectedColor;
178 _choices = choices;
179
180 int w = 0;
181 int h = 0;
182
183 Common::ScopedPtr<Graphics::Font> font(Graphics::loadTTFFontFromArchive("FreeSans.ttf", 20));
184 _rects.resize(choices.size());
185 for (uint i = 0; i < _choices.size(); ++i) {
186 _rects[i] = calculateBoundingBoxForText(_choices[i], *font);
187 w = MAX<int>(w, _rects[i].width());
188 h += _rects[i].height();
189 }
190
191 w += 10;
192 h += 5;
193
194 _rect = Common::Rect((640 - w) / 2, 479 - h, 639 - (640 - w) / 2, 479);
195
196 Graphics::Surface *s = g_vm->resMgr()->getSurface(-2, w, h);
197
198 int y = 0;
199 for (uint i = 0; i < _choices.size(); ++i) {
200 drawText(*s, y, 630, _choices[i], _choiceColor, *font);
201
202 _rects[i].moveTo(0, y);
203 y += _rects[i].height();
204 }
205 }
206
onMouseMove(Common::Point p)207 void QTextChoice::onMouseMove(Common::Point p) {
208 p.x = p.x - _rect.left - g_vm->getQSystem()->_xOffset;
209 p.y = p.y - _rect.top;
210 uint newChoice;
211 for (newChoice = 0; newChoice < _rects.size(); ++newChoice) {
212 if (_rects[newChoice].contains(p)) {
213 break;
214 }
215 }
216
217 if (newChoice != _activeChoice) {
218 Graphics::Surface *s = g_vm->resMgr()->getSurface(-2);
219 Common::ScopedPtr<Graphics::Font> font(Graphics::loadTTFFontFromArchive("FreeSans.ttf", 20));
220
221 s->fillRect(Common::Rect(s->w, s->h), 0);
222 for (uint i = 0; i < _choices.size(); ++i) {
223 uint color = (i == newChoice) ? _selectedColor : _choiceColor;
224 drawText(*s, _rects[i].top, 630, _choices[i], color, *font);
225 }
226
227 _activeChoice = newChoice;
228 }
229 }
230
onClick(Common::Point p)231 void QTextChoice::onClick(Common::Point p) {
232 if (_activeChoice < _choices.size()) {
233 g_vm->getQSystem()->_mainInterface->_dialog.next(_activeChoice);
234 }
235 }
236
calculateBoundingBoxForText(const Common::U32String & text,Graphics::Font & font)237 Common::Rect QText::calculateBoundingBoxForText(const Common::U32String &text, Graphics::Font &font) {
238 if (text.empty())
239 return {};
240
241 Common::Array<Common::U32String> lines;
242 font.wordWrapText(text, 630, lines);
243
244 Common::Rect rect = font.getBoundingBox(lines[0]);
245 for (uint j = 1; j < lines.size(); ++j) {
246 auto box = font.getBoundingBox(lines[j]);
247 rect.setHeight(rect.height() + box.height());
248 if (box.width() > rect.width())
249 rect.setWidth(box.width());
250 }
251
252 return rect;
253 }
254
drawText(Graphics::Surface & s,int y,int maxWidth,const Common::U32String & text,uint color,Graphics::Font & font)255 void QText::drawText(Graphics::Surface &s, int y, int maxWidth, const Common::U32String &text, uint color, Graphics::Font &font) {
256 Common::Array<Common::U32String> lines;
257 font.wordWrapText(text, maxWidth, lines);
258
259 int h = 0;
260 for (uint i = 0; i < lines.size(); ++i) {
261 font.drawString(&s, lines[i], 0, y + h, s.w, color);
262 h += font.getBoundingBox(lines[i]).height();
263 }
264 }
265
266 } // End of namespace Petka
267