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