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