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