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 "common/cosinetables.h"
24 #include "common/sinetables.h"
25 #include "common/random.h"
26 #include "common/memstream.h"
27 #include "graphics/cursor.h"
28 #include "graphics/cursorman.h"
29 
30 #include "hdb/hdb.h"
31 #include "hdb/ai.h"
32 #include "hdb/file-manager.h"
33 #include "hdb/gfx.h"
34 #include "hdb/input.h"
35 #include "hdb/mpc.h"
36 #include "hdb/sound.h"
37 
38 namespace HDB {
39 
Gfx()40 Gfx::Gfx() {
41 	_tLookupArray = nullptr;
42 	_starsInfo.active = false;
43 	_gfxCache = new Common::Array<GfxCache *>;
44 	_globalSurface.create(g_hdb->_screenWidth, g_hdb->_screenHeight, g_hdb->_format);
45 	_pointerDisplayable = 1;
46 	_sines = new Common::SineTable(360);
47 	_cosines = new Common::CosineTable(360);
48 	_systemInit = false;
49 
50 	_numTiles = 0;
51 
52 	memset(&_fadeInfo, 0, sizeof(_fadeInfo));
53 	memset(&_snowInfo, 0, sizeof(_snowInfo));
54 	memset(&_skyTiles, 0, sizeof(_skyTiles));
55 
56 	_tileSkyStars = 0;
57 	_tileSkyStarsLeft = 0;
58 	_tileSkyClouds = 0;
59 	for (int i = 0; i < 4; ++i) {
60 		_starField[i] = nullptr;
61 		_mousePointer[2 * i] = nullptr;
62 		_mousePointer[(2 * i) + 1] = nullptr;
63 	}
64 
65 	_snowflake = nullptr;
66 	_skyClouds = nullptr;
67 	_starsInfo.gfx[0] = nullptr;
68 	_starsInfo.gfx[1] = nullptr;
69 	_starsInfo.timer = 0;
70 	_starsInfo.anim = 0;
71 	_starsInfo.radius = 0;
72 	_starsInfo.angleSpeed = 0;
73 	_starsInfo.totalTime = 0;
74 	_cursorX = 0;
75 	_cursorY = 0;
76 	_showCursor = false;
77 	_fontHeader.type = 0;
78 	_fontHeader.numChars = 0;
79 	_fontHeader.height = 0;
80 	_fontHeader.kerning = 0;
81 	_fontHeader.leading = 0;
82 	_fontGfx = 0;
83 	_eLeft = 0;
84 	_eRight = 0;
85 	_eTop = 0;
86 	_eBottom = 0;
87 	_currentSky = 0;
88 	for (int i = 0; i < kNum3DStars; ++i) {
89 		_stars3D[i].x = 0;
90 		_stars3D[i].y = 0;
91 		_stars3D[i].speed = 0;
92 		_stars3D[i].color = 0;
93 		_stars3DSlow[i].x = 0;
94 		_stars3DSlow[i].y = 0;
95 		_stars3DSlow[i].speed = 0;
96 		_stars3DSlow[i].color = 0;
97 	}
98 }
99 
~Gfx()100 Gfx::~Gfx() {
101 	for (uint i = 0; i < _gfxCache->size(); i++) {
102 		GfxCache *cache = _gfxCache->operator[](i);
103 		if (cache->status)
104 			delete cache->picGfx;
105 		else
106 			delete cache->tileGfx;
107 		delete cache;
108 	}
109 	delete _gfxCache;
110 	for (uint i = 0; i < _charInfoBlocks.size(); i++)
111 		delete _charInfoBlocks[i];
112 	delete _sines;
113 	delete _cosines;
114 	for (int i = 0; i < _fontHeader.numChars; i++)
115 		_fontSurfaces[i].free();
116 	_globalSurface.free();
117 	for (int i = 0; i < _numTiles; i++) {
118 		delete _tLookupArray[i].tData;
119 		_tLookupArray[i].tData = nullptr;
120 	}
121 	delete[] _tLookupArray;
122 	for (int i = 0; i < 8; i++)
123 		delete _mousePointer[i];
124 	for (int i = 0; i < 4; i++)
125 		delete _starField[i];
126 	delete _snowflake;
127 	delete _skyClouds;
128 }
129 
130 static const byte cursorPalette[16 * 3] = {
131 	0x00, 0x01, 0x00,
132 	0x09, 0x4E, 0xA2,
133 	0x42, 0x3D, 0xBE,
134 	0xFF, 0x00, 0xFD,
135 	0x00, 0x57, 0xB8,
136 	0x0C, 0x66, 0xCB,
137 	0x0D, 0x65, 0xED,
138 	0x01, 0x6A, 0xDE,
139 	0x34, 0x59, 0xF1,
140 	0x26, 0x5E, 0xEE,
141 	0x00, 0x77, 0xFA,
142 	0x23, 0x87, 0xFE,
143 	0x47, 0x94, 0xFA,
144 	0x69, 0xAF, 0xFC,
145 	0x9F, 0xCD, 0xFE,
146 	0xDE, 0xEE, 0xFD
147 };
148 
149 static const byte cursorData[] = {
150  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
151  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
152  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
153  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  0,  0,  0,  0,  0,  0,  0,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
154  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  0,  0, 11, 11, 11, 10, 10, 10, 10,  6,  0,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
155  3,  3,  3,  3,  3,  3,  3,  3,  3,  0, 13, 13, 12, 12, 11, 10, 10, 10, 10, 10, 10,  8,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,
156  3,  3,  3,  3,  3,  3,  3,  3,  0, 14, 13, 13, 13, 12, 11,  7,  7, 10, 10, 10, 10, 10,  6,  0,  3,  3,  3,  3,  3,  3,  3,  3,
157  3,  3,  3,  3,  3,  3,  3,  0, 14, 14, 14, 13, 12,  0,  0,  0,  0,  0,  0,  7, 10, 10, 10, 10,  0,  3,  3,  3,  3,  3,  3,  3,
158  3,  3,  3,  3,  3,  3,  0, 14, 15, 14, 13,  0,  0,  3,  3,  3,  3,  3,  3,  0,  0,  7, 10, 10,  6,  0,  3,  3,  3,  3,  3,  3,
159  3,  3,  3,  3,  3,  0, 13, 14, 14, 13,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  0,  7,  7,  7,  8,  0,  3,  3,  3,  3,  3,
160  3,  3,  3,  3,  3,  0, 13, 14, 13,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  0,  7,  7,  7,  0,  3,  3,  3,  3,  3,
161  3,  3,  3,  3,  0, 12, 13, 13,  5,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  0,  7,  7,  7,  8,  0,  3,  3,  3,  3,
162  3,  3,  3,  3,  0, 12, 13, 13,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  0,  7,  5,  6,  0,  3,  3,  3,  3,
163  3,  3,  3,  3,  0, 12, 12, 12,  0,  3,  3,  3,  3,  3,  3,  0,  0,  3,  3,  3,  3,  3,  3,  0,  5,  5,  5,  0,  3,  3,  3,  3,
164  3,  3,  3,  3,  0, 11, 11,  5,  0,  3,  3,  3,  3,  3,  0, 15, 15,  0,  3,  3,  3,  3,  3,  0,  5,  4,  4,  0,  3,  3,  3,  3,
165  3,  3,  3,  3,  0, 10, 11,  5,  0,  3,  3,  3,  3,  0, 15, 15, 13, 13,  0,  3,  3,  3,  3,  0,  7,  4,  4,  0,  3,  3,  3,  3,
166  3,  3,  3,  3,  0, 10, 11,  5,  0,  3,  3,  3,  3,  0, 15, 13, 13,  7,  0,  3,  3,  3,  3,  0,  7,  4,  4,  0,  3,  3,  3,  3,
167  3,  3,  3,  3,  0, 10, 10,  7,  0,  3,  3,  3,  3,  3,  0, 13,  7,  0,  3,  3,  3,  3,  3,  0,  5,  4,  4,  0,  3,  3,  3,  3,
168  3,  3,  3,  3,  0, 10, 10,  7,  0,  3,  3,  3,  3,  3,  3,  0,  0,  3,  3,  3,  3,  3,  3,  0,  4,  4,  4,  0,  3,  3,  3,  3,
169  3,  3,  3,  3,  0, 10, 10, 10,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  0,  4,  4,  4,  0,  3,  3,  3,  3,
170  3,  3,  3,  3,  0,  9, 10, 10,  7,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  0,  5,  1,  1,  2,  0,  3,  3,  3,  3,
171  3,  3,  3,  3,  3,  0, 10, 10, 10,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  0,  1,  1,  1,  0,  3,  3,  3,  3,  3,
172  3,  3,  3,  3,  3,  0,  8, 10, 10,  7,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  0,  1,  1,  1,  2,  0,  3,  3,  3,  3,  3,
173  3,  3,  3,  3,  3,  3,  0,  6, 10,  7,  7,  0,  0,  3,  3,  3,  3,  3,  3,  0,  0,  1,  1,  1,  4,  0,  3,  3,  3,  3,  3,  3,
174  3,  3,  3,  3,  3,  3,  3,  0, 10,  7,  7,  7,  7,  0,  0,  0,  0,  0,  0,  5,  1,  1,  1,  1,  0,  3,  3,  3,  3,  3,  3,  3,
175  3,  3,  3,  3,  3,  3,  3,  3,  0,  6,  7,  7,  7,  5,  5,  4,  4,  4,  4,  1,  1,  1,  4,  0,  3,  3,  3,  3,  3,  3,  3,  3,
176  3,  3,  3,  3,  3,  3,  3,  3,  3,  0,  9,  7,  5,  5,  4,  4,  4,  4,  4,  1,  1,  2,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,
177  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  0,  0,  9,  7,  4,  4,  4,  4,  4,  2,  0,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
178  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  0,  0,  0,  0,  0,  0,  0,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
179  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
180  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
181  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3
182 };
183 
184 
init()185 void Gfx::init() {
186 	// Set the default cursor pos & char clipping
187 	setCursor(0, 0);
188 
189 	if (g_hdb->isPPC()) {
190 		CursorMan.replaceCursorPalette(cursorPalette, 0, 16);
191 		CursorMan.replaceCursor(cursorData, 32, 32, 16, 16, 3);
192 	}
193 
194 	_eLeft = 0;
195 	_eRight = g_hdb->_screenWidth;
196 	_eTop = 0;
197 	_eBottom = g_hdb->_screenHeight;
198 
199 	// Need two main memory screen-sized surfaces for screen fading
200 	_fadeBuffer1.create(g_hdb->_screenWidth, g_hdb->_screenHeight, g_hdb->_format);
201 	_fadeBuffer2.create(g_hdb->_screenWidth, g_hdb->_screenHeight, g_hdb->_format);
202 
203 	// Load Game Font
204 	if (!loadFont(HDB_FONT))
205 		error("Gfx::init: Couldn't load fonts");
206 
207 	// Read total number of tiles in game
208 	_numTiles = g_hdb->_fileMan->getCount("t32_", TYPE_TILE32);
209 	if (!_numTiles)
210 		error("Gfx::init: No tiles in game");
211 
212 	// Setup Tile Lookup Array
213 	_tLookupArray = new TileLookup[_numTiles];
214 	Common::Array<const char *> *tileData = g_hdb->_fileMan->findFiles("t32_", TYPE_TILE32);
215 
216 	assert((uint)_numTiles == tileData->size());
217 
218 	int index = 0, skyIndex = 0;
219 	for (; index < _numTiles; index++) {
220 		_tLookupArray[index].filename = tileData->operator[](index);
221 		_tLookupArray[index].tData = nullptr;
222 		_tLookupArray[index].skyIndex = 0;
223 		_tLookupArray[index].animIndex = index;
224 		// Check if the loaded Tile is a Sky Tile
225 		if (strstr(tileData->operator[](index), "sky") && (skyIndex < kMaxSkies)) {
226 			_tLookupArray[index].skyIndex = skyIndex + 1;
227 			_skyTiles[skyIndex] = index;
228 			skyIndex++;
229 		}
230 	}
231 
232 	delete tileData;
233 
234 	// Add Animating Tile Info
235 	int found = -1;
236 	char search[32];
237 	Common::strlcpy(search, "anim_", 32);
238 	for (index = 0; index < _numTiles; index++) {
239 		// IF we have not found a start, look for it
240 		// ELSE IF we have found a start and are in the middle of an anim group
241 		// ELSE IF we're in an anim group and have just reached the end
242 		if (!strncmp(_tLookupArray[index].filename, search, strlen(search)) && found == -1) {
243 			found = index;
244 			memset(search, 0, sizeof(search));
245 			strncpy(search, _tLookupArray[index].filename, strlen(_tLookupArray[index].filename) - 2);
246 		} else if (!strncmp(_tLookupArray[index].filename, search, strlen(search)) && found >= 0)
247 			_tLookupArray[index - 1].animIndex = index;
248 		else if (strncmp(_tLookupArray[index].filename, search, strlen(search)) && found >= 0) {
249 			_tLookupArray[index - 1].animIndex = found;
250 			Common::strlcpy(search, "anim_", 32);
251 			found = -1;
252 			if (!strncmp(_tLookupArray[index].filename, search, strlen(search)))
253 				index--;
254 		}
255 	}
256 
257 	// Init Sky Data
258 	_currentSky = 0;
259 	_tileSkyStars = getTileIndex(TILE_SKY_STARS);
260 	_tileSkyStarsLeft = getTileIndex(TILE_SKY_STARS_LEFT_SLOW);
261 	_tileSkyClouds = getTileIndex(TILE_SKY_CLOUDS); // Not completely sure about this filename.
262 	_skyClouds = nullptr;
263 
264 	if (!g_hdb->isPPC()) {
265 		// Load Mouse Pointer and Display Cursor
266 		_mousePointer[0] = loadPic(PIC_MOUSE_CURSOR1);
267 		_mousePointer[1] = loadPic(PIC_MOUSE_CURSOR2);
268 		_mousePointer[2] = loadPic(PIC_MOUSE_CURSOR3);
269 		_mousePointer[3] = loadPic(PIC_MOUSE_CURSOR4);
270 		_mousePointer[4] = loadPic(PIC_MOUSE_CURSOR5);
271 		_mousePointer[5] = loadPic(PIC_MOUSE_CURSOR6);
272 		_mousePointer[6] = loadPic(PIC_MOUSE_CURSOR7);
273 		_mousePointer[7] = loadPic(PIC_MOUSE_CURSOR8);
274 		_showCursor = true;
275 
276 		// Load all 4 levels of star colors
277 		_starField[0] = getPicture(PIC_STAR64);
278 		_starField[1] = getPicture(PIC_STAR128);
279 		_starField[2] = getPicture(PIC_STAR192);
280 		_starField[3] = getPicture(PIC_STAR256);
281 		_snowflake = getPicture(PIC_SNOWFLAKE);
282 	} else {
283 		for (int i = 0; i < 8; i++)
284 			_mousePointer[i] = nullptr;
285 
286 		for (int i = 0; i < 4; i++)
287 			_starField[i] = nullptr;
288 
289 		_snowflake = nullptr;
290 
291 		_showCursor = false;
292 	}
293 
294 	_systemInit = true;
295 }
296 
save(Common::OutSaveFile * out)297 void Gfx::save(Common::OutSaveFile *out) {
298 	out->writeSint32LE(_currentSky);
299 
300 	out->writeByte(_fadeInfo.active);
301 	out->writeByte(_fadeInfo.stayFaded);
302 	out->writeByte(_fadeInfo.isBlack);
303 	out->writeSint32LE(_fadeInfo.speed);
304 	out->writeByte(_fadeInfo.isFadeIn);
305 	out->writeSint32LE(_fadeInfo.curStep);
306 
307 	out->writeByte(_snowInfo.active);
308 	for (int i = 0; i < MAX_SNOW; i++)
309 		out->writeDoubleLE(_snowInfo.x[i]);
310 	for (int i = 0; i < MAX_SNOW; i++)
311 		out->writeDoubleLE(_snowInfo.y[i]);
312 	for (int i = 0; i < MAX_SNOW; i++)
313 		out->writeDoubleLE(_snowInfo.yv[i]);
314 	for (int i = 0; i < MAX_SNOW; i++)
315 		out->writeSint32LE(_snowInfo.xvindex[i]);
316 }
317 
loadSaveFile(Common::InSaveFile * in)318 void Gfx::loadSaveFile(Common::InSaveFile *in) {
319 	_currentSky = in->readSint32LE();
320 
321 	_fadeInfo.active = in->readByte();
322 	_fadeInfo.stayFaded = in->readByte();
323 	_fadeInfo.isBlack = in->readByte();
324 	_fadeInfo.speed = in->readSint32LE();
325 	_fadeInfo.isFadeIn = in->readByte();
326 	_fadeInfo.curStep = in->readSint32LE();
327 
328 	_snowInfo.active = in->readByte();
329 
330 	for (int i = 0; i < MAX_SNOW; i++)
331 		_snowInfo.x[i] = in->readDoubleLE();
332 	for (int i = 0; i < MAX_SNOW; i++)
333 		_snowInfo.y[i] = in->readDoubleLE();
334 	for (int i = 0; i < MAX_SNOW; i++)
335 		_snowInfo.yv[i] = in->readDoubleLE();
336 	for (int i = 0; i < MAX_SNOW; i++)
337 		_snowInfo.xvindex[i] = in->readSint32LE();
338 
339 	setSky(_currentSky);
340 
341 	if (!g_hdb->isPPC()) {
342 		turnOffSnow();
343 		if (_snowInfo.active)
344 			turnOnSnow();
345 	}
346 }
347 
getSin(int index)348 double Gfx::getSin(int index) {
349 	return _sines->at(index);
350 }
getCos(int index)351 double Gfx::getCos(int index) {
352 	return _cosines->at(index);
353 }
354 
fillScreen(uint32 color)355 void Gfx::fillScreen(uint32 color) {
356 	_globalSurface.fillRect(Common::Rect(g_hdb->_screenWidth, g_hdb->_screenHeight), color);
357 	g_system->fillScreen(color);
358 }
359 
updateVideo()360 void Gfx::updateVideo() {
361 	updateFade();
362 
363 	if (!g_hdb->_progressGfx)
364 		return;
365 
366 	g_hdb->checkProgress();
367 
368 	int left = g_hdb->_screenWidth / 2 - g_hdb->_progressGfx->_width / 2;
369 
370 	Common::Rect clip(g_hdb->_progressGfx->getSurface()->getBounds());
371 	clip.moveTo(left, g_hdb->_progressY);
372 	clip.clip(_globalSurface.getBounds());
373 	if (!clip.isEmpty())
374 		g_system->copyRectToScreen(_globalSurface.getBasePtr(clip.left, clip.top), _globalSurface.pitch, clip.left, clip.top, clip.width(), clip.height());
375 
376 	g_system->updateScreen();
377 }
378 
drawPointer()379 void Gfx::drawPointer() {
380 	static int anim = 0;
381 	static uint32 animTime = 0;
382 
383 	if (animTime < g_system->getMillis()) {
384 		animTime = g_system->getMillis() + 50;
385 		anim = (anim + 1) & 7;
386 	}
387 
388 	// If pointer is not displayable and we are in game, exit
389 	if (!_pointerDisplayable && g_hdb->getGameState() == GAME_PLAY)
390 		return;
391 
392 	// If we are in game and the cursor should be displayed, draw it
393 	if (_showCursor || g_hdb->getGameState() != GAME_PLAY) {
394 		if (g_hdb->isPPC())
395 			CursorMan.showMouse(true);
396 		else
397 			_mousePointer[anim]->drawMasked(g_hdb->_input->getMouseX() - 16, g_hdb->_input->getMouseY() - 16);
398 	}
399 }
400 
setPointerState(int value)401 void Gfx::setPointerState(int value) {
402 	_pointerDisplayable = value;
403 }
404 
setFade(bool fadeIn,bool black,int steps)405 void Gfx::setFade(bool fadeIn, bool black, int steps) {
406 	_fadeInfo.isFadeIn = fadeIn;
407 	_fadeInfo.isBlack = black;
408 
409 	if (!steps)
410 		steps = 1;
411 
412 	_fadeInfo.speed = steps;
413 
414 	if (fadeIn)
415 		_fadeInfo.curStep = 0;
416 	else
417 		_fadeInfo.curStep = 255;
418 
419 	_fadeInfo.active = true;
420 }
421 
updateFade()422 void Gfx::updateFade() {
423 	if (!_fadeInfo.active && !_fadeInfo.stayFaded)
424 		return;
425 
426 	debug(7, "updateFade: active: %d stayFaded: %d isBlack: %d speed: %d isFadeIn: %d curStep: %d",
427 		_fadeInfo.active, _fadeInfo.stayFaded, _fadeInfo.isBlack, _fadeInfo.speed, _fadeInfo.isFadeIn, _fadeInfo.curStep);
428 
429 	if (g_hdb->isPPC()) {
430 		if (!_fadeInfo.isBlack) {
431 			// Black fade
432 			for (int y = 0; y < g_hdb->_screenHeight; y++) {
433 				uint16 *ptr = (uint16 *)_fadeBuffer1.getBasePtr(0, y);
434 				for (int x = 0; x < g_hdb->_screenWidth; x++) {
435 					uint16 value = *ptr;
436 					if (value) {
437 						uint8 r, g, b;
438 						g_hdb->_format.colorToRGB(value, r, g, b);
439 						r = (r * _fadeInfo.curStep) >> 8;
440 						g = (g * _fadeInfo.curStep) >> 8;
441 						b = (b * _fadeInfo.curStep) >> 8;
442 						*ptr = g_hdb->_format.RGBToColor(r, g, b);
443 					}
444 					ptr++;
445 				}
446 			}
447 
448 		} else {
449 			// White fade
450 			for (int y = 0; y < g_hdb->_screenHeight; y++) {
451 				uint16 *ptr = (uint16 *)_fadeBuffer1.getBasePtr(0, y);
452 				for (int x = 0; x < g_hdb->_screenWidth; x++) {
453 					uint16 value = *ptr;
454 
455 					uint8 r, g, b;
456 					g_hdb->_format.colorToRGB(value, r, g, b);
457 					r += (255 - r) * (256 - _fadeInfo.curStep) / 256;
458 					g += (255 - g) * (256 - _fadeInfo.curStep) / 256;
459 					b += (255 - b) * (256 - _fadeInfo.curStep) / 256;
460 					*ptr = g_hdb->_format.RGBToColor(r, g, b);
461 					ptr++;
462 				}
463 			}
464 		}
465 
466 		if (_fadeInfo.isFadeIn) {
467 			if (_fadeInfo.active)
468 				_fadeInfo.curStep += _fadeInfo.speed;
469 
470 			if (_fadeInfo.curStep > 255) {
471 				_fadeInfo.curStep = 255;
472 				_fadeInfo.active = false;
473 				_fadeInfo.stayFaded = false;
474 			}
475 		} else {
476 			if (_fadeInfo.active)
477 				_fadeInfo.curStep -= _fadeInfo.speed;
478 
479 			if (_fadeInfo.curStep < 1) {
480 				_fadeInfo.curStep = 0;
481 				_fadeInfo.active = false;
482 				_fadeInfo.stayFaded = true;
483 			}
484 		}
485 	} else {
486 		_fadeBuffer2.blitFrom(_globalSurface);
487 
488 		static int waitAFrame = 0;
489 
490 		do {
491 			// Copy pristine copy of background to modification buffer
492 			_fadeBuffer1.blitFrom(_fadeBuffer2);
493 
494 			// do the actual alphablending
495 
496 			if (!_fadeInfo.isBlack) {
497 				// Black Fade
498 
499 				for (int y = 0; y < g_hdb->_screenHeight; y++) {
500 					uint16 *ptr = (uint16 *)_fadeBuffer1.getBasePtr(0, y);
501 					for (int x = 0; x < g_hdb->_screenWidth; x++) {
502 						uint16 value = *ptr;
503 						if (value) {
504 							uint8 r, g, b;
505 							g_hdb->_format.colorToRGB(value, r, g, b);
506 							r = (r * _fadeInfo.curStep) >> 8;
507 							g = (g * _fadeInfo.curStep) >> 8;
508 							b = (b * _fadeInfo.curStep) >> 8;
509 							*ptr = g_hdb->_format.RGBToColor(r, g, b);
510 						}
511 						ptr++;
512 					}
513 				}
514 			} else {
515 				// White Fade
516 
517 				for (int y = 0; y < g_hdb->_screenHeight; y++) {
518 					uint16 *ptr = (uint16 *)_fadeBuffer1.getBasePtr(0, y);
519 					for (int x = 0; x < g_hdb->_screenWidth; x++) {
520 						uint16 value = *ptr;
521 						uint8 r, g, b;
522 						g_hdb->_format.colorToRGB(value, r, g, b);
523 						r += (255 - r) * (256 - _fadeInfo.curStep) / 256;
524 						g += (255 - g) * (256 - _fadeInfo.curStep) / 256;
525 						b += (255 - b) * (256 - _fadeInfo.curStep) / 256;
526 						*ptr = g_hdb->_format.RGBToColor(r, g, b);
527 						ptr++;
528 					}
529 				}
530 			}
531 
532 			_globalSurface.blitFrom(_fadeBuffer1);
533 			g_system->copyRectToScreen(_globalSurface.getBasePtr(0, 0), _globalSurface.pitch, 0, 0, _globalSurface.w, _globalSurface.h);
534 
535 			// step the fading values to the next one and
536 			// see if we're done yet
537 			if (_fadeInfo.isFadeIn) {
538 				if (_fadeInfo.active)
539 					_fadeInfo.curStep += _fadeInfo.speed;
540 
541 				if (_fadeInfo.curStep > 255) {
542 					_fadeInfo.curStep = 255;
543 					_fadeInfo.active = false;
544 					_fadeInfo.stayFaded = false;
545 				}
546 			} else {
547 				if (_fadeInfo.active == true)
548 					_fadeInfo.curStep -= _fadeInfo.speed;
549 
550 				if (_fadeInfo.curStep < 1) {
551 					_fadeInfo.curStep = 0;
552 					_fadeInfo.active = false;
553 					_fadeInfo.stayFaded = false;
554 				}
555 			}
556 
557 			// make sure we wait one frame at least - some logic in the game
558 			// doesn't draw the frame immediately
559 			if (!waitAFrame) {
560 				waitAFrame++;
561 				return;
562 			}
563 
564 			g_system->updateScreen();
565 			if (g_hdb->getDebug()) {
566 				g_hdb->_frames.push_back(g_system->getMillis());
567 				while (g_hdb->_frames[0] < g_system->getMillis() - 1000)
568 					g_hdb->_frames.remove_at(0);
569 			}
570 			g_system->delayMillis(1000 / kGameFPS);
571 
572 		} while (_fadeInfo.active);
573 
574 		waitAFrame = 0;			// reset counter
575 	}
576 }
577 
turnOnSnow()578 void Gfx::turnOnSnow() {
579 	_snowInfo.active = true;
580 	for (int i = 0; i < MAX_SNOW; i++) {
581 		_snowInfo.x[i] = g_hdb->_rnd->getRandomNumber(g_hdb->_screenWidth - 1);
582 		_snowInfo.y[i] = g_hdb->_rnd->getRandomNumber(g_hdb->_screenHeight - 1);
583 		_snowInfo.yv[i] = g_hdb->_rnd->getRandomNumber(2) + 1;
584 		_snowInfo.xvindex[i] = g_hdb->_rnd->getRandomNumber(MAX_SNOW_XV - 1);
585 	}
586 }
587 
loadPic(const char * picName)588 Picture *Gfx::loadPic(const char *picName) {
589 	Common::SeekableReadStream *stream = g_hdb->_fileMan->findFirstData(picName, TYPE_PIC);
590 	if (!stream)
591 		return nullptr;
592 
593 	Picture *pic = new Picture;
594 	pic->load(stream);
595 	delete stream;
596 	return pic;
597 }
598 
loadTile(const char * tileName)599 Tile *Gfx::loadTile(const char *tileName) {
600 	Common::SeekableReadStream *stream = g_hdb->_fileMan->findFirstData(tileName, TYPE_TILE32);
601 	if (!stream)
602 		return nullptr;
603 
604 	Tile *tile = new Tile;
605 	tile->load(stream);
606 	delete stream;
607 	return tile;
608 }
609 
loadIcon(const char * tileName)610 Tile *Gfx::loadIcon(const char *tileName) {
611 	Common::SeekableReadStream *stream = g_hdb->_fileMan->findFirstData(tileName, TYPE_ICON32);
612 	if (!stream)
613 		return nullptr;
614 
615 	Tile *tile = new Tile;
616 	tile->load(stream);
617 	delete stream;
618 	return tile;
619 }
620 
setPixel(int x,int y,uint16 color)621 void Gfx::setPixel(int x, int y, uint16 color) {
622 	if (x < 0 || y < 0 || x >= _globalSurface.w || y >= _globalSurface.h)
623 		return;
624 
625 	*(uint16 *)_globalSurface.getBasePtr(x, y) = color;
626 	g_system->copyRectToScreen(_globalSurface.getBasePtr(x, y), _globalSurface.pitch, x, y, 1, 1);
627 }
628 
getTile(int index)629 Tile *Gfx::getTile(int index) {
630 	if (index < 0 || index > _numTiles) {
631 		if (index != 0xFFFF)
632 			debug(6, "getTile(%d): wrong index > %d", index, _numTiles);
633 		return nullptr;
634 	}
635 	if (_tLookupArray[index].skyIndex) {
636 		debug(6, "getTile(%d): sky tile (%d)", index, _tLookupArray[index].skyIndex);
637 		// We don't draw Sky Tiles, so return nullptr
638 		return nullptr;
639 	}
640 
641 	if (_tLookupArray[index].tData == nullptr) {
642 		Common::SeekableReadStream *stream = g_hdb->_fileMan->findFirstData(_tLookupArray[index].filename, TYPE_TILE32);
643 		Tile *tile = new Tile;
644 		tile->load(stream);
645 		delete stream;
646 		_tLookupArray[index].tData = tile;
647 	}
648 
649 	return _tLookupArray[index].tData;
650 }
651 
emptyGfxCaches()652 void Gfx::emptyGfxCaches() {
653 	// We have plenty of memory, so do not do it
654 }
655 
cacheTileSequence(int tileIndex,int count)656 void Gfx::cacheTileSequence(int tileIndex, int count) {
657 	for (int i = tileIndex; i < tileIndex + count; i++)
658 		getTile(i);
659 }
660 
getTileIndex(const char * name)661 int Gfx::getTileIndex(const char *name) {
662 	if (!name)
663 		return -1;
664 
665 	for (int i = 0; i < _numTiles; i++) {
666 		if (Common::matchString(_tLookupArray[i].filename, name))
667 			return i;
668 	}
669 	return -1;
670 }
671 
getPicture(const char * name)672 Picture *Gfx::getPicture(const char *name) {
673 	Common::SeekableReadStream *stream = g_hdb->_fileMan->findFirstData(name, TYPE_PIC);
674 	if (stream == nullptr)
675 		return nullptr;
676 
677 	Picture *picture = new Picture;
678 	picture->load(stream);
679 	delete stream;
680 	return picture;
681 }
682 
683 // Returns: true->Tile, false->Pic
selectGfxType(const char * name)684 bool Gfx::selectGfxType(const char *name) {
685 	// Check for Pic types
686 	if (Common::matchString(name, "clubup1"))
687 		return false;
688 	if (Common::matchString(name, "clubup2"))
689 		return false;
690 	if (Common::matchString(name, "clubup3"))
691 		return false;
692 	if (Common::matchString(name, "clubup4"))
693 		return false;
694 	if (Common::matchString(name, "clubdown1"))
695 		return false;
696 	if (Common::matchString(name, "clubdown2"))
697 		return false;
698 	if (Common::matchString(name, "clubdown3"))
699 		return false;
700 	if (Common::matchString(name, "clubdown4"))
701 		return false;
702 	if (Common::matchString(name, "clubleft1"))
703 		return false;
704 	if (Common::matchString(name, "clubleft2"))
705 		return false;
706 	if (Common::matchString(name, "clubleft3"))
707 		return false;
708 	if (Common::matchString(name, "clubleft4"))
709 		return false;
710 	if (Common::matchString(name, "clubright1"))
711 		return false;
712 	if (Common::matchString(name, "clubright2"))
713 		return false;
714 	if (Common::matchString(name, "clubright3"))
715 		return false;
716 	if (Common::matchString(name, "clubright4"))
717 		return false;
718 	if (Common::matchString(name, "slug_shot1"))
719 		return false;
720 	if (Common::matchString(name, "slug_shot2"))
721 		return false;
722 	if (Common::matchString(name, "slug_shot3"))
723 		return false;
724 	if (Common::matchString(name, "slug_shot4"))
725 		return false;
726 
727 	return true;
728 }
729 
getTileGfx(const char * name,int32 size)730 Tile *Gfx::getTileGfx(const char *name, int32 size) {
731 	// Try to find graphic
732 	for (Common::Array<GfxCache *>::iterator it = _gfxCache->begin(); it != _gfxCache->end(); ++it) {
733 		if (Common::matchString((*it)->name, name)) {
734 			if ((*it)->loaded == -1) {	// Marked for Deletetion?
735 				(*it)->loaded = 1;		// Reactivate it
736 				return (*it)->tileGfx;
737 			}
738 		}
739 	}
740 
741 	GfxCache *gc = new GfxCache;
742 	Common::strlcpy(gc->name, name, 32);
743 	gc->tileGfx = loadTile(name);
744 	gc->status = false;
745 	if (size == -1)
746 		size = g_hdb->_fileMan->getLength(name, TYPE_TILE32);
747 	gc->size = size;
748 	gc->loaded = 1;
749 
750 	_gfxCache->push_back(gc);
751 
752 	return gc->tileGfx;
753 }
754 
markGfxCacheFreeable()755 void Gfx::markGfxCacheFreeable() {
756 	for (Common::Array<GfxCache *>::iterator it = _gfxCache->begin(); it != _gfxCache->end(); ++it)
757 		(*it)->loaded = -1;
758 }
759 
markTileCacheFreeable()760 void Gfx::markTileCacheFreeable() {
761 	// we have plenty of memory, so do not do it
762 }
763 
getPicGfx(const char * name,int32 size)764 Picture *Gfx::getPicGfx(const char *name, int32 size) {
765 	// Try to find graphic
766 	for (Common::Array<GfxCache *>::iterator it = _gfxCache->begin(); it != _gfxCache->end(); ++it) {
767 		if (Common::matchString((*it)->name, name)) {
768 			if ((*it)->loaded == -1) {	// Marked for Deletetion?
769 				(*it)->loaded = 1;		// Reactivate it
770 				return (*it)->picGfx;
771 			}
772 		}
773 	}
774 
775 	GfxCache *gc = new GfxCache;
776 	Common::strlcpy(gc->name, name, 32);
777 	gc->picGfx = loadPic(name);
778 	gc->status = true;
779 	if (size == -1)
780 		size = g_hdb->_fileMan->getLength(name, TYPE_PIC);
781 	gc->size = size;
782 	gc->loaded = 1;
783 
784 	_gfxCache->push_back(gc);
785 
786 	return gc->picGfx;
787 }
788 
isSky(int index)789 int Gfx::isSky(int index) {
790 	if (!index)
791 		return 0;
792 
793 	for (int i = 0; i < kMaxSkies; i++) {
794 		if (_skyTiles[i] == index)
795 			return i + 1; // The skyTiles are indexed from 1. 0 => No Sky tile
796 	}
797 
798 	return 0;
799 }
800 
setSky(int skyIndex)801 void Gfx::setSky(int skyIndex) {
802 	int tileIndex = _skyTiles[skyIndex - 1];
803 	_currentSky = skyIndex;
804 
805 	// Clear memory used by last sky
806 	if (tileIndex != _tileSkyClouds && _skyClouds) {
807 		delete _skyClouds;
808 		_skyClouds = nullptr;
809 	}
810 
811 	// Setup current sky
812 	if (tileIndex == _tileSkyStars)
813 		setup3DStars();
814 	else if (tileIndex == _tileSkyStarsLeft)
815 		setup3DStarsLeft();
816 	else if (tileIndex == _tileSkyClouds)
817 		_skyClouds = getPicture(CLOUDY_SKIES);
818 }
819 
setup3DStars()820 void Gfx::setup3DStars() {
821 	for (int i = 0; i < kNum3DStars; i++) {
822 		_stars3D[i].x = g_hdb->_rnd->getRandomNumber(g_hdb->_screenWidth - 1);
823 		_stars3D[i].y = g_hdb->_rnd->getRandomNumber(g_hdb->_screenHeight - 1);
824 		_stars3D[i].speed = g_hdb->_rnd->getRandomNumber(255);
825 		if (g_hdb->isPPC())
826 			_stars3D[i].color = g_hdb->_format.RGBToColor(_stars3D[i].speed, _stars3D[i].speed, _stars3D[i].speed);
827 		else {
828 			_stars3D[i].speed >>= 1;
829 			_stars3D[i].color = _stars3D[i].speed / 64;
830 		}
831 	}
832 }
833 
setup3DStarsLeft()834 void Gfx::setup3DStarsLeft() {
835 	for (int i = 0; i < kNum3DStars; i++) {
836 		_stars3DSlow[i].x = g_hdb->_rnd->getRandomNumber(g_hdb->_screenWidth - 1);
837 		_stars3DSlow[i].y = g_hdb->_rnd->getRandomNumber(g_hdb->_screenHeight - 1);
838 		_stars3DSlow[i].speed = ((double) (1 + g_hdb->_rnd->getRandomNumber(4))) / 6.0;
839 		if (g_hdb->isPPC())
840 			_stars3DSlow[i].color = g_hdb->_format.RGBToColor((int)(_stars3DSlow[i].speed * 250), (int)(_stars3DSlow[i].speed * 250), (int)(_stars3DSlow[i].speed * 250));
841 		else
842 			_stars3DSlow[i].color = (int) (_stars3DSlow[i].speed * 4.00);
843 	}
844 }
845 
draw3DStars()846 void Gfx::draw3DStars() {
847 	fillScreen(0);
848 	for (int i = 0; i < kNum3DStars; i++) {
849 		if (g_hdb->isPPC()) {
850 			setPixel((int)_stars3D[i].x, (int)_stars3D[i].y, _stars3D[i].color);
851 			_stars3D[i].y += (_stars3D[i].speed >> 5);
852 		} else {
853 			_starField[_stars3D[i].color]->drawMasked((int)_stars3D[i].x, (int)_stars3D[i].y);
854 			_stars3D[i].y += (_stars3D[i].speed >> 5) + 1;
855 		}
856 
857 		if (_stars3D[i].y > g_hdb->_screenHeight)
858 			_stars3D[i].y = 0;
859 	}
860 }
861 
draw3DStarsLeft()862 void Gfx::draw3DStarsLeft() {
863 	fillScreen(0);
864 	for (int i = 0; i < kNum3DStars; i++) {
865 		if (g_hdb->isPPC())
866 			setPixel((int)_stars3DSlow[i].x, (int)_stars3DSlow[i].y, _stars3DSlow[i].color);
867 		else
868 			_starField[_stars3DSlow[i].color]->drawMasked((int)_stars3DSlow[i].x, (int)_stars3DSlow[i].y);
869 		_stars3DSlow[i].x -= _stars3DSlow[i].speed;
870 		if (_stars3DSlow[i].x < 0)
871 			_stars3DSlow[i].x = g_hdb->_screenWidth - 1;
872 	}
873 }
874 
drawSky()875 void Gfx::drawSky() {
876 	int tile = _skyTiles[_currentSky - 1];
877 
878 	if (tile == _tileSkyStars)
879 		draw3DStars();
880 	else if (tile == _tileSkyStarsLeft)
881 		draw3DStarsLeft();
882 	else if (tile == _tileSkyClouds) {
883 		static int offset = 0, wait = 0;
884 		for (int j = -64; j < g_hdb->_screenHeight; j += 64) {
885 			for (int i = -64; i < g_hdb->_screenWidth; i += 64) {
886 				if (_skyClouds)
887 					_skyClouds->draw(i + offset, j + offset);
888 			}
889 		}
890 		wait--;
891 		if (wait < 1) {
892 			offset = (offset + 1) & 63;
893 			wait = 5;
894 		}
895 	}
896 }
897 
898 static const int snowXVList[13] = {0, -1, -1, -2, -2, -1, 0, 0, 0, -1, -2, -1, 0};
899 
drawSnow()900 void Gfx::drawSnow() {
901 	if (_snowInfo.active == false)
902 		return;
903 
904 	for (int i = 0; i < MAX_SNOW; i++) {
905 		if (g_hdb->isPPC()) {
906 			uint16 color = g_hdb->_format.RGBToColor(160, 160, 160);
907 			setPixel((int)_snowInfo.x[i] + 1, (int)_snowInfo.y[i], color);
908 			setPixel((int)_snowInfo.x[i] - 1, (int)_snowInfo.y[i], color);
909 			setPixel((int)_snowInfo.x[i], (int)_snowInfo.y[i] + 1, color);
910 			setPixel((int)_snowInfo.x[i], (int)_snowInfo.y[i] - 1, color);
911 		} else
912 			_snowflake->drawMasked((int)_snowInfo.x[i], (int)_snowInfo.y[i]);
913 		_snowInfo.x[i] += snowXVList[_snowInfo.xvindex[i]++];
914 		_snowInfo.y[i] += _snowInfo.yv[i];
915 		if (_snowInfo.xvindex[i] == MAX_SNOW_XV)
916 			_snowInfo.xvindex[i] = 0;
917 		if (_snowInfo.x[i] < 0)
918 			_snowInfo.x[i] = g_hdb->_screenWidth - 1;
919 		if (_snowInfo.y[i] > g_hdb->_screenHeight - 1)
920 			_snowInfo.y[i] = 0;
921 	}
922 }
923 
animateTile(int tileIndex)924 int Gfx::animateTile(int tileIndex) {
925 	return _tLookupArray[tileIndex].animIndex;
926 }
927 
loadFont(const char * string)928 bool Gfx::loadFont(const char *string) {
929 	Common::SeekableReadStream *stream = g_hdb->_fileMan->findFirstData(string, TYPE_FONT);
930 	if (!stream)
931 		return false;
932 
933 	if (g_hdb->isPPC()) {
934 		const int32 ulength = g_hdb->_fileMan->getLength(string, TYPE_FONT);
935 		byte *buffer = (byte *)malloc(ulength);
936 		stream->read(buffer, ulength);
937 		Common::MemoryReadStream memoryStream(buffer, ulength, DisposeAfterUse::YES);
938 		delete stream;
939 
940 		// Loading _fontHeader
941 		_fontHeader.type = (int)memoryStream.readUint32LE();
942 		_fontHeader.numChars = (int)memoryStream.readUint32LE();
943 		_fontHeader.height = (int)memoryStream.readUint32LE();
944 		_fontHeader.kerning = (int)memoryStream.readUint32LE();
945 		_fontHeader.leading = (int)memoryStream.readUint32LE();
946 
947 		debug(3, "Loaded _fontHeader with following data");
948 		debug(3, "type: %d", _fontHeader.type);
949 		debug(3, "numChars: %d", _fontHeader.numChars);
950 		debug(3, "height: %d", _fontHeader.height);
951 		debug(3, "kerning: %d", _fontHeader.kerning);
952 		debug(3, "leading: %d", _fontHeader.leading);
953 
954 		// Loading _charInfoBlocks & creating character surfaces
955 
956 		// Position after _fontHeader
957 		int startPos = memoryStream.pos();
958 		for (int i = 0; i < _fontHeader.numChars; i++) {
959 			CharInfo *cInfo = new CharInfo;
960 			cInfo->width = (int16)memoryStream.readUint32LE();
961 			cInfo->offset = (int32)memoryStream.readUint32LE();
962 
963 			debug(3, "Loaded _charInfoBlocks[%d]: width: %d, offset: %d", i, cInfo->width, cInfo->offset);
964 
965 			// Position after reading cInfo
966 			int curPos = memoryStream.pos();
967 
968 			_fontSurfaces[i].create(cInfo->width, _fontHeader.height, g_hdb->_format);
969 
970 			// Go to character location
971 			memoryStream.seek(startPos + cInfo->offset);
972 
973 			for (int x = 0; x < cInfo->width; x++) {
974 				for (int y = 0; y < _fontHeader.height; y++) {
975 					int u = x;
976 					int v = _fontHeader.height - y - 1;
977 					uint16 *ptr = (uint16 *)_fontSurfaces[i].getBasePtr(u, v);
978 					*ptr = memoryStream.readUint16LE();
979 				}
980 			}
981 
982 			memoryStream.seek(curPos);
983 
984 			_charInfoBlocks.push_back(cInfo);
985 		}
986 
987 		// Loading _fontGfx
988 		_fontGfx = memoryStream.readUint16LE();
989 	} else {
990 		// Loading _fontHeader
991 		_fontHeader.type = (int)stream->readUint32LE();
992 		_fontHeader.numChars = (int)stream->readUint32LE();
993 		_fontHeader.height = (int)stream->readUint32LE();
994 		_fontHeader.kerning = (int)stream->readUint32LE();
995 		_fontHeader.leading = (int)stream->readUint32LE();
996 
997 		debug(3, "Loaded _fontHeader with following data");
998 		debug(3, "type: %d", _fontHeader.type);
999 		debug(3, "numChars: %d", _fontHeader.numChars);
1000 		debug(3, "height: %d", _fontHeader.height);
1001 		debug(3, "kerning: %d", _fontHeader.kerning);
1002 		debug(3, "leading: %d", _fontHeader.leading);
1003 
1004 		// Loading _charInfoBlocks & creating character surfaces
1005 
1006 		// Position after _fontHeader
1007 		int startPos = stream->pos();
1008 		for (int i = 0; i < _fontHeader.numChars; i++) {
1009 			CharInfo *cInfo = new CharInfo;
1010 			cInfo->width = (int16)stream->readUint32LE();
1011 			cInfo->offset = (int32)stream->readUint32LE();
1012 
1013 			debug(3, "Loaded _charInfoBlocks[%d]: width: %d, offset: %d", i, cInfo->width, cInfo->offset);
1014 
1015 			// Position after reading cInfo
1016 			int curPos = stream->pos();
1017 
1018 			_fontSurfaces[i].create(cInfo->width, _fontHeader.height, g_hdb->_format);
1019 
1020 			// Go to character location
1021 			stream->seek(startPos + cInfo->offset);
1022 
1023 			for (int y = 0; y < _fontHeader.height; y++) {
1024 				uint16 *ptr = (uint16 *)_fontSurfaces[i].getBasePtr(0, y);
1025 				for (int x = 0; x < cInfo->width; x++) {
1026 					*ptr = stream->readUint16LE();
1027 					ptr++;
1028 				}
1029 			}
1030 
1031 			stream->seek(curPos);
1032 
1033 			_charInfoBlocks.push_back(cInfo);
1034 		}
1035 
1036 		// Loading _fontGfx
1037 		_fontGfx = stream->readUint16LE();
1038 		delete stream;
1039 	}
1040 
1041 	return true;
1042 }
1043 
drawText(const char * string)1044 void Gfx::drawText(const char *string) {
1045 	if (!_systemInit)
1046 		return;
1047 
1048 	if (_cursorX < _eLeft)
1049 		_cursorX = _eLeft;
1050 	if (_cursorY < _eTop)
1051 		_cursorY = _eTop;
1052 
1053 	// Word Wrapping
1054 	int width = _eLeft;
1055 	char cr[256];	// Carriage Return Array
1056 
1057 	for (int i = 0; i < (int)strlen(string); i++) {
1058 		unsigned char c = string[i];
1059 		width += _charInfoBlocks[c]->width + _fontHeader.kerning + kFontIncrement;
1060 		if (c == ' ')
1061 			width += kFontSpace;
1062 
1063 		cr[i] = 0;
1064 		if (c == '\n') {
1065 			cr[i] = 1;
1066 			width = _eLeft;
1067 		} else if (width > _eRight) {
1068 			i--;
1069 			while (string[i] != ' ' && i > 0)
1070 				i--;
1071 			cr[i] = 1;
1072 			width = _eLeft;
1073 		}
1074 	}
1075 
1076 	// Draw the characters
1077 	for (int j = 0; j < (int)strlen(string); j++) {
1078 		unsigned char c = string[j];
1079 		if (c == '\n' || cr[j]) {
1080 			_cursorX = _eLeft;
1081 			_cursorY += _fontHeader.height + _fontHeader.leading;
1082 			if (_cursorY + _fontHeader.height > _eBottom)
1083 				_cursorY = _eTop;
1084 			continue;
1085 		}
1086 
1087 		width = _charInfoBlocks[c]->width;
1088 		if (c == ' ')
1089 			width = kFontSpace;
1090 
1091 		// Blit the character
1092 		_globalSurface.transBlitFrom(_fontSurfaces[c], Common::Point(_cursorX, _cursorY), 0xf81f);
1093 
1094 		Common::Rect clip(0, 0, width, _fontHeader.height);
1095 		clip.moveTo(_cursorX, _cursorY);
1096 		clip.clip(_globalSurface.getBounds());
1097 		if (!clip.isEmpty()) {
1098 			g_system->copyRectToScreen(_globalSurface.getBasePtr(clip.left, clip.top), _globalSurface.pitch, clip.left, clip.top, clip.width(), clip.height());
1099 		}
1100 
1101 		// Advance the cursor
1102 		_cursorX += width + _fontHeader.kerning + kFontIncrement;
1103 		if (_cursorX > g_hdb->_screenWidth) {
1104 			_cursorX = 0;
1105 			_cursorY += _fontHeader.height + _fontHeader.leading;
1106 			if (_cursorY + _fontHeader.height > g_hdb->_screenHeight)
1107 				_cursorY = 0;
1108 		}
1109 	}
1110 }
1111 
1112 // Calculates pixel width of a string
getDimensions(const char * string,int * pixelsWide,int * lines)1113 void Gfx::getDimensions(const char *string, int *pixelsWide, int *lines) {
1114 	if (!string) {
1115 		*pixelsWide = kFontSpace;
1116 		*lines = 1;
1117 		return;
1118 	}
1119 
1120 	int maxWidth = 0;
1121 	int width = _eLeft;
1122 	int height = 1;
1123 
1124 	for (int i = 0; i < (int)strlen(string); i++) {
1125 		unsigned char c = string[i];
1126 		width += _charInfoBlocks[c]->width + _fontHeader.kerning + kFontIncrement;
1127 		if (c == ' ')
1128 			width += kFontSpace;
1129 
1130 		if (c == '\n') {
1131 			height++;
1132 			if (width > maxWidth)
1133 				maxWidth = width;
1134 			width = _eLeft;
1135 		} else if (width > _eRight) {
1136 			int oldWidth = width;
1137 			i--;
1138 			while (string[i] != ' ' && i > 0) {
1139 				c = string[i];
1140 				width -= _charInfoBlocks[c]->width + _fontHeader.kerning + kFontIncrement;
1141 				i--;
1142 			}
1143 			if (!i && !g_hdb->isPPC()) {
1144 				maxWidth = oldWidth;
1145 				break;
1146 			}
1147 			height++;
1148 			if (width > maxWidth)
1149 				maxWidth = width;
1150 			width = _eLeft;
1151 		}
1152 	}
1153 
1154 	if (width > maxWidth)
1155 		maxWidth = width;
1156 
1157 	// If its one line, add 8 pixels
1158 	if (height == 1)
1159 		maxWidth += 8;
1160 
1161 	*pixelsWide = maxWidth - _eLeft;
1162 	*lines = height;
1163 }
1164 
stringLength(const char * string)1165 int Gfx::stringLength(const char *string) {
1166 	int w, h;
1167 	getDimensions(string, &w, &h);
1168 	return w;
1169 }
1170 
centerPrint(const char * string)1171 void Gfx::centerPrint(const char *string) {
1172 	int totalWidth = 0;
1173 
1174 	for (int i = 0; i < (int)strlen(string); i++) {
1175 		if (string[i] == ' ')
1176 			totalWidth += kFontSpace;
1177 		else if (string[i] != '\n')
1178 			totalWidth += _charInfoBlocks[string[i]]->width;
1179 	}
1180 
1181 	setCursor(g_hdb->_screenWidth / 2 - totalWidth / 2, _cursorY);
1182 	drawText(string);
1183 }
1184 
setTextEdges(int left,int right,int top,int bottom)1185 void Gfx::setTextEdges(int left, int right, int top, int bottom) {
1186 	_eLeft = left;
1187 	_eRight = right;
1188 	_eTop = top;
1189 	_eBottom = bottom;
1190 }
1191 
getTextEdges(int * left,int * right,int * top,int * bottom)1192 void Gfx::getTextEdges(int *left, int *right, int *top, int *bottom) {
1193 	*left = _eLeft;
1194 	*right = _eRight;
1195 	*top = _eTop;
1196 	*bottom = _eBottom;
1197 }
1198 
setKernLead(int kern,int lead)1199 void Gfx::setKernLead(int kern, int lead) {
1200 	_fontHeader.kerning = kern;
1201 	_fontHeader.leading = lead;
1202 }
1203 
getKernLead(int * kern,int * lead)1204 void Gfx::getKernLead(int *kern, int *lead) {
1205 	*kern = _fontHeader.kerning;
1206 	*lead = _fontHeader.leading;
1207 }
1208 
setCursor(int x,int y)1209 void Gfx::setCursor(int x, int y) {
1210 	_cursorX = x;
1211 	_cursorY = y;
1212 }
1213 
getCursor(int * x,int * y)1214 void Gfx::getCursor(int *x, int *y) {
1215 	*x = _cursorX;
1216 	*y = _cursorY;
1217 }
1218 
turnOnBonusStars(int which)1219 void Gfx::turnOnBonusStars(int which) {
1220 	if (!g_hdb->isDemo())
1221 		return;
1222 
1223 	_starsInfo.active = true;
1224 	for (int i = 0; i < 10; i++)
1225 		_starsInfo.starAngle[i] = (36 * (i + 1)) - 10;
1226 	if (!_starsInfo.gfx[0]) {
1227 		switch (which) {
1228 		case 0:		// Red Star
1229 			_starsInfo.gfx[0] = loadPic(SECRETSTAR_RED1);
1230 			_starsInfo.gfx[1] = loadPic(SECRETSTAR_RED2);
1231 			break;
1232 		case 1:		// Green Star
1233 			_starsInfo.gfx[0] = loadPic(SECRETSTAR_GREEN1);
1234 			_starsInfo.gfx[1] = loadPic(SECRETSTAR_GREEN2);
1235 			break;
1236 		case 2:		// Blue Star
1237 			_starsInfo.gfx[0] = loadPic(SECRETSTAR_BLUE1);
1238 			_starsInfo.gfx[1] = loadPic(SECRETSTAR_BLUE2);
1239 			break;
1240 		default:
1241 			break;
1242 		}
1243 	}
1244 
1245 	_starsInfo.radius = 0;
1246 	_starsInfo.angleSpeed = 25;
1247 	_starsInfo.timer = g_hdb->getTimeSlice() + 500;
1248 	_starsInfo.anim = 0;
1249 	_starsInfo.totalTime = g_hdb->getTimeSlice() + 5000;		// 5 seconds long
1250 	g_hdb->_sound->playSound(SND_MONKEYSTONE_SECRET_STAR);
1251 }
1252 
drawBonusStars()1253 void Gfx::drawBonusStars() {
1254 	if (!_starsInfo.active)
1255 		return;
1256 
1257 	if (_starsInfo.timer < g_hdb->getTimeSlice()) {
1258 		_starsInfo.timer = g_hdb->getTimeSlice() + 500;
1259 		_starsInfo.anim = 1 - _starsInfo.anim;
1260 	}
1261 
1262 	int w = _starsInfo.gfx[0]->_width / 2;
1263 	int h = _starsInfo.gfx[0]->_height / 2;
1264 
1265 	for (int i = 0; i < 10; i++) {
1266 		if (g_hdb->isPPC()) {
1267 			_starsInfo.gfx[_starsInfo.anim]->drawMasked(
1268 				(g_hdb->_screenWidth / 2) + (int)((double)_starsInfo.radius * _cosines->at(_starsInfo.starAngle[i]) - w),
1269 				(g_hdb->_screenHeight / 2) + (int)((double)_starsInfo.radius * _sines->at(_starsInfo.starAngle[i]) - h)
1270 				);
1271 		} else {
1272 			_starsInfo.gfx[_starsInfo.anim]->drawMasked(
1273 				(int)(g_hdb->_screenDrawWidth / 2 + ((float)_starsInfo.radius / 2)) + (int)((double)_starsInfo.radius * _cosines->at(_starsInfo.starAngle[i]) - w),
1274 				(g_hdb->_screenDrawHeight / 2) + (int)((double)_starsInfo.radius * _sines->at(_starsInfo.starAngle[i]) - h)
1275 			);
1276 		}
1277 
1278 		int angle = (int)(_starsInfo.starAngle[i] + _starsInfo.angleSpeed);
1279 		if (angle >= 360)
1280 			angle = 0;
1281 		_starsInfo.starAngle[i] = angle;
1282 	}
1283 
1284 	_starsInfo.radius++;
1285 	_starsInfo.angleSpeed -= 0.25;
1286 	if (_starsInfo.angleSpeed < 15)
1287 		_starsInfo.angleSpeed = 15;
1288 
1289 	// timed out?
1290 	if (_starsInfo.totalTime < g_hdb->getTimeSlice()) {
1291 		_starsInfo.active = false;
1292 		delete _starsInfo.gfx[0];
1293 		delete _starsInfo.gfx[1];
1294 		_starsInfo.gfx[0] = _starsInfo.gfx[1] = 0;
1295 	}
1296 }
1297 
drawDebugInfo(Tile * _debugLogo,int fps)1298 void Gfx::drawDebugInfo(Tile *_debugLogo, int fps) {
1299 	_debugLogo->drawMasked(g_hdb->_screenWidth - 32, 0);
1300 
1301 	// Draw  FPS
1302 	setCursor(0, 0);
1303 	char buff[64];
1304 	sprintf(buff, "FPS: %d", fps);
1305 	drawText(buff);
1306 
1307 	// Draw Player Info
1308 	setCursor(0, 16);
1309 
1310 	int x, y;
1311 	g_hdb->_ai->getPlayerXY(&x, &y);
1312 	sprintf(buff, "Player X: %d, Y: %d", x / kTileWidth, y / kTileHeight);
1313 	drawText(buff);
1314 
1315 	setCursor(0, 32);
1316 	AIEntity *p = g_hdb->_ai->getPlayer();
1317 	if (p) {
1318 		sprintf(buff, "Player height level: %d", p->level);
1319 		drawText(buff);
1320 	}
1321 
1322 	setCursor(0, 48);
1323 	sprintf(buff, "Map Name: %s", g_hdb->getInMapName());
1324 	drawText(buff);
1325 
1326 	setCursor(0, 64);
1327 	g_hdb->getActionMode() ? sprintf(buff, "Action Mode") : sprintf(buff, "Puzzle Mode");
1328 	drawText(buff);
1329 }
1330 
Picture()1331 Picture::Picture() : _width(0), _height(0) {
1332 	_name[0] = 0;
1333 	_surface.create(_width, _height, g_hdb->_format);
1334 }
1335 
~Picture()1336 Picture::~Picture() {
1337 }
1338 
load(Common::SeekableReadStream * stream)1339 Graphics::Surface Picture::load(Common::SeekableReadStream *stream) {
1340 	_width = stream->readUint32LE();
1341 	_height = stream->readUint32LE();
1342 	stream->read(_name, 64);
1343 
1344 	debug(8, "Picture: _width: %d, _height: %d", _width, _height);
1345 	debug(8, "Picture: _name: %s", _name);
1346 
1347 	if (g_hdb->isPPC()) {
1348 		_surface.create(_width, _height, g_hdb->_format);
1349 
1350 		for (int x = 0; x < _width; x++) {
1351 			for (int y = 0; y < _height; y++) {
1352 				int u = x;
1353 				int v = _height - y - 1;
1354 				uint16 *ptr = (uint16 *)_surface.getBasePtr(u, v);
1355 				*ptr = stream->readUint16LE();
1356 			}
1357 		}
1358 
1359 	} else {
1360 		_surface.create(_width, _height, g_hdb->_format);
1361 		stream->readUint32LE(); // Skip Win32 Surface
1362 
1363 		for (int y = 0; y < _height; y++) {
1364 			uint16 *ptr = (uint16 *)_surface.getBasePtr(0, y);
1365 			for (int x = 0; x < _width; x++) {
1366 				*ptr = stream->readUint16LE();
1367 				ptr++;
1368 			}
1369 		}
1370 	}
1371 
1372 	return _surface;
1373 }
1374 
draw(int x,int y)1375 int Picture::draw(int x, int y) {
1376 	g_hdb->_gfx->_globalSurface.blitFrom(_surface, Common::Point(x, y));
1377 
1378 	Common::Rect clip(_surface.getBounds());
1379 	clip.moveTo(x, y);
1380 	clip.clip(g_hdb->_gfx->_globalSurface.getBounds());
1381 	if (!clip.isEmpty()) {
1382 		g_system->copyRectToScreen(g_hdb->_gfx->_globalSurface.getBasePtr(clip.left, clip.top), g_hdb->_gfx->_globalSurface.pitch, clip.left, clip.top, clip.width(), clip.height());
1383 		return 1;
1384 	}
1385 	return 0;
1386 }
1387 
drawMasked(int x,int y,int alpha)1388 int Picture::drawMasked(int x, int y, int alpha) {
1389 	g_hdb->_gfx->_globalSurface.transBlitFrom(_surface, Common::Point(x, y), 0xf81f, false, 0, alpha & 0xff);
1390 
1391 	Common::Rect clip(_surface.getBounds());
1392 	clip.moveTo(x, y);
1393 	clip.clip(g_hdb->_gfx->_globalSurface.getBounds());
1394 	if (!clip.isEmpty()) {
1395 		g_system->copyRectToScreen(g_hdb->_gfx->_globalSurface.getBasePtr(clip.left, clip.top), g_hdb->_gfx->_globalSurface.pitch, clip.left, clip.top, clip.width(), clip.height());
1396 		return 1;
1397 	}
1398 	return 0;
1399 }
1400 
Tile()1401 Tile::Tile() : _flags(0) {
1402 	_name[0] = 0;
1403 	_surface.create(32, 32, g_hdb->_format);
1404 }
1405 
~Tile()1406 Tile::~Tile() {
1407 }
1408 
load(Common::SeekableReadStream * stream)1409 Graphics::Surface Tile::load(Common::SeekableReadStream *stream) {
1410 	_flags = stream->readUint32LE();
1411 	stream->read(_name, 64);
1412 
1413 	_surface.create(32, 32, g_hdb->_format);
1414 	if (g_hdb->isPPC()) {
1415 		for (int y = 0; y < 32; y++) {
1416 			for (int x = 0; x < 32; x++) {
1417 				int u = y;
1418 				int v = 32 - x - 1;
1419 				uint16 *ptr = (uint16 *)_surface.getBasePtr(u, v);
1420 				*ptr = stream->readUint16LE();
1421 			}
1422 		}
1423 	} else {
1424 		stream->readUint32LE(); // Skip Win32 Surface
1425 		for (uint y = 0; y < 32; y++) {
1426 			uint16 *ptr = (uint16 *)_surface.getBasePtr(0, y);
1427 			for (uint x = 0; x < 32; x++) {
1428 				*ptr = stream->readUint16LE();
1429 				ptr++;
1430 			}
1431 		}
1432 	}
1433 
1434 	return _surface;
1435 }
1436 
draw(int x,int y)1437 int Tile::draw(int x, int y) {
1438 	g_hdb->_gfx->_globalSurface.blitFrom(_surface, Common::Point(x, y));
1439 
1440 	Common::Rect clip(_surface.getBounds());
1441 	clip.moveTo(x, y);
1442 	clip.clip(g_hdb->_gfx->_globalSurface.getBounds());
1443 	if (!clip.isEmpty()) {
1444 		g_system->copyRectToScreen(g_hdb->_gfx->_globalSurface.getBasePtr(clip.left, clip.top), g_hdb->_gfx->_globalSurface.pitch, clip.left, clip.top, clip.width(), clip.height());
1445 		return 1;
1446 	}
1447 	return 0;
1448 }
1449 
drawMasked(int x,int y,int alpha)1450 int Tile::drawMasked(int x, int y, int alpha) {
1451 	g_hdb->_gfx->_globalSurface.transBlitFrom(_surface, Common::Point(x, y), 0xf81f, false, 0, alpha & 0xff);
1452 
1453 	Common::Rect clip(_surface.getBounds());
1454 	clip.moveTo(x, y);
1455 	clip.clip(g_hdb->_gfx->_globalSurface.getBounds());
1456 	if (!clip.isEmpty()) {
1457 		g_system->copyRectToScreen(g_hdb->_gfx->_globalSurface.getBasePtr(clip.left, clip.top), g_hdb->_gfx->_globalSurface.pitch, clip.left, clip.top, clip.width(), clip.height());
1458 		return 1;
1459 	}
1460 	return 0;
1461 }
1462 
1463 }
1464