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