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/endian.h"
24 #include "common/str.h"
25 #include "graphics/cursorman.h"
26
27 #include "gob/gob.h"
28 #include "gob/draw.h"
29 #include "gob/global.h"
30 #include "gob/util.h"
31 #include "gob/game.h"
32 #include "gob/resources.h"
33 #include "gob/hotspots.h"
34 #include "gob/scenery.h"
35 #include "gob/inter.h"
36 #include "gob/sound/sound.h"
37
38 namespace Gob {
39
Draw_v1(GobEngine * vm)40 Draw_v1::Draw_v1(GobEngine *vm) : Draw(vm) {
41 }
42
initScreen()43 void Draw_v1::initScreen() {
44 _backSurface = _vm->_video->initSurfDesc(320, 200);
45 _frontSurface = _vm->_global->_primarySurfDesc;
46
47 _cursorSprites = _vm->_video->initSurfDesc(_cursorWidth * 2, _cursorHeight, 2);
48 _scummvmCursor = _vm->_video->initSurfDesc(_cursorWidth , _cursorHeight, SCUMMVM_CURSOR);
49 }
50
closeScreen()51 void Draw_v1::closeScreen() {
52 }
53
blitCursor()54 void Draw_v1::blitCursor() {
55 if (_cursorIndex == -1)
56 return;
57
58 if (_showCursor == 2)
59 _showCursor = 0;
60 }
61
animateCursor(int16 cursor)62 void Draw_v1::animateCursor(int16 cursor) {
63 int16 cursorIndex = cursor;
64 int16 newX = 0, newY = 0;
65 uint16 hotspotX = 0, hotspotY = 0;
66
67 _showCursor = 2;
68
69 if (cursorIndex == -1) {
70 cursorIndex =
71 _vm->_game->_hotspots->findCursor(_vm->_global->_inter_mouseX,
72 _vm->_global->_inter_mouseY);
73
74 if (_cursorAnimLow[cursorIndex] == -1)
75 cursorIndex = 1;
76 }
77
78 if (_cursorAnimLow[cursorIndex] != -1) {
79 if (cursorIndex == _cursorIndex) {
80 if (_cursorAnimDelays[_cursorIndex] != 0 &&
81 _cursorAnimDelays[_cursorIndex] * 10 +
82 _cursorTimeKey <= _vm->_util->getTimeKey()) {
83 _cursorAnim++;
84 _cursorTimeKey = _vm->_util->getTimeKey();
85 } else {
86 if (_noInvalidated && (_vm->_global->_inter_mouseX == _cursorX) &&
87 (_vm->_global->_inter_mouseY == _cursorY)) {
88 _vm->_video->waitRetrace();
89 return;
90 }
91 }
92 } else {
93 _cursorIndex = cursorIndex;
94 if (_cursorAnimDelays[_cursorIndex] != 0) {
95 _cursorAnim =
96 _cursorAnimLow[_cursorIndex];
97 _cursorTimeKey = _vm->_util->getTimeKey();
98 } else {
99 _cursorAnim = _cursorIndex;
100 }
101 }
102
103 if (_cursorAnimDelays[_cursorIndex] != 0 &&
104 (_cursorAnimHigh[_cursorIndex] < _cursorAnim ||
105 _cursorAnimLow[_cursorIndex] >
106 _cursorAnim)) {
107 _cursorAnim = _cursorAnimLow[_cursorIndex];
108 }
109
110 newX = _vm->_global->_inter_mouseX;
111 newY = _vm->_global->_inter_mouseY;
112 if (_cursorHotspotXVar != -1) {
113 newX -= hotspotX = (uint16) VAR(_cursorIndex + _cursorHotspotXVar);
114 newY -= hotspotY = (uint16) VAR(_cursorIndex + _cursorHotspotYVar);
115 } else if (_cursorHotspotX != -1) {
116 newX -= hotspotX = _cursorHotspotX;
117 newY -= hotspotY = _cursorHotspotY;
118 }
119
120 _scummvmCursor->clear();
121 _scummvmCursor->blit(*_cursorSprites,
122 cursorIndex * _cursorWidth, 0,
123 (cursorIndex + 1) * _cursorWidth - 1,
124 _cursorHeight - 1, 0, 0);
125 CursorMan.replaceCursor(_scummvmCursor->getData(),
126 _cursorWidth, _cursorHeight, hotspotX, hotspotY, 0, false, &_vm->getPixelFormat());
127
128 if (_frontSurface != _backSurface) {
129 _showCursor = 3;
130 if (!_noInvalidated) {
131 int16 tmp = _cursorIndex;
132 _cursorIndex = -1;
133 blitInvalidated();
134 _cursorIndex = tmp;
135 } else {
136 _vm->_video->waitRetrace();
137 if (MIN(newY, _cursorY) < 50)
138 _vm->_util->delay(5);
139 _showCursor = 0;
140 }
141 }
142 } else
143 blitCursor();
144
145 _cursorX = newX;
146 _cursorY = newY;
147 }
148
printTotText(int16 id)149 void Draw_v1::printTotText(int16 id) {
150 byte *dataPtr;
151 byte *ptr, *ptrEnd;
152 byte cmd;
153 int16 destX, destY;
154 int16 val;
155 int16 savedFlags;
156 int16 destSpriteX;
157 int16 spriteRight, spriteBottom;
158 char buf[20];
159
160 _vm->_sound->cdPlayMultMusic();
161
162 TextItem *textItem = _vm->_game->_resources->getTextItem(id);
163 if (!textItem)
164 return;
165
166 dataPtr = textItem->getData();
167 ptr = dataPtr;
168
169 destX = READ_LE_UINT16(ptr) & 0x7FFF;
170 destY = READ_LE_UINT16(ptr + 2);
171 spriteRight = READ_LE_UINT16(ptr + 4);
172 spriteBottom = READ_LE_UINT16(ptr + 6);
173 ptr += 8;
174
175 if (_renderFlags & RENDERFLAG_CAPTUREPUSH) {
176 _vm->_game->capturePush(destX, destY,
177 spriteRight - destX + 1, spriteBottom - destY + 1);
178 (*_vm->_scenery->_pCaptureCounter)++;
179 }
180
181 _destSpriteX = destX;
182 _destSpriteY = destY;
183 _spriteRight = spriteRight;
184 _spriteBottom = spriteBottom;
185 _destSurface = kBackSurface;
186
187 _backColor = *ptr++;
188 _transparency = 1;
189 spriteOperation(DRAW_CLEARRECT);
190
191 _backColor = 0;
192 savedFlags = _renderFlags;
193 _renderFlags &= ~RENDERFLAG_NOINVALIDATE;
194
195 while ((_destSpriteX = READ_LE_UINT16(ptr)) != -1) {
196 _destSpriteX += destX;
197 _destSpriteY = READ_LE_UINT16(ptr + 2) + destY;
198 _spriteRight = READ_LE_UINT16(ptr + 4) + destX;
199 _spriteBottom = READ_LE_UINT16(ptr + 6) + destY;
200 ptr += 8;
201
202 cmd = *ptr++;
203 switch ((cmd & 0xF0) >> 4) {
204 case 0:
205 _frontColor = cmd & 0xF;
206 spriteOperation(DRAW_DRAWLINE);
207 break;
208 case 1:
209 _frontColor = cmd & 0xF;
210 spriteOperation(DRAW_DRAWBAR);
211 break;
212 case 2:
213 _backColor = cmd & 0xF;
214 spriteOperation(DRAW_FILLRECTABS);
215 break;
216 default:
217 break;
218 }
219 }
220 ptr += 2;
221
222 for (ptrEnd = ptr; *ptrEnd != 1; ptrEnd++) {
223 if (*ptrEnd == 3)
224 ptrEnd++;
225
226 if (*ptrEnd == 2)
227 ptrEnd += 4;
228 }
229 ptrEnd++;
230
231 while (*ptr != 1) {
232 cmd = *ptr;
233 if (cmd == 3) {
234 ptr++;
235 _fontIndex = (*ptr & 0xF0) >> 4;
236 _frontColor = *ptr & 0xF;
237 ptr++;
238 continue;
239 } else if (cmd == 2) {
240 ptr++;
241 _destSpriteX = destX + READ_LE_UINT16(ptr);
242 _destSpriteY = destY + READ_LE_UINT16(ptr + 2);
243 ptr += 4;
244 continue;
245 }
246
247 if (*ptr != 0xBA) {
248 _letterToPrint = (char) *ptr;
249 spriteOperation(DRAW_DRAWLETTER);
250 _destSpriteX += _fonts[_fontIndex]->getCharWidth();
251 ptr++;
252 } else {
253 cmd = ptrEnd[17] & 0x7F;
254 if (cmd == 0) {
255 val = READ_LE_UINT16(ptrEnd + 18) * 4;
256 sprintf(buf, "%d", (int32)VAR_OFFSET(val));
257 } else if (cmd == 1) {
258 val = READ_LE_UINT16(ptrEnd + 18) * 4;
259
260 Common::strlcpy(buf, GET_VARO_STR(val), 20);
261 } else {
262 val = READ_LE_UINT16(ptrEnd + 18) * 4;
263
264 sprintf(buf, "%d", (int32)VAR_OFFSET(val));
265 if (buf[0] == '-') {
266 while (strlen(buf) - 1 < (uint32)ptrEnd[17]) {
267 _vm->_util->insertStr("0", buf, 1);
268 }
269 } else {
270 while (strlen(buf) - 1 < (uint32)ptrEnd[17]) {
271 _vm->_util->insertStr("0", buf, 0);
272 }
273 }
274
275 _vm->_util->insertStr(",", buf, strlen(buf) + 1 - ptrEnd[17]);
276 }
277
278 _textToPrint = buf;
279 destSpriteX = _destSpriteX;
280 spriteOperation(DRAW_PRINTTEXT);
281 if (ptrEnd[17] & 0x80) {
282 if (ptr[1] == ' ') {
283 _destSpriteX += _fonts[_fontIndex]->getCharWidth();
284 while (ptr[1] == ' ')
285 ptr++;
286 if (ptr[1] == 2) {
287 if (READ_LE_UINT16(ptr + 4) == _destSpriteY)
288 ptr += 5;
289 }
290 } else if (ptr[1] == 2 && READ_LE_UINT16(ptr + 4) == _destSpriteY) {
291 ptr += 5;
292 _destSpriteX += _fonts[_fontIndex]->getCharWidth();
293 }
294 } else {
295 _destSpriteX = destSpriteX + _fonts[_fontIndex]->getCharWidth();
296 }
297 ptrEnd += 23;
298 ptr++;
299 }
300 }
301
302 delete textItem;
303 _renderFlags = savedFlags;
304
305 if (_renderFlags & RENDERFLAG_COLLISIONS)
306 _vm->_game->_hotspots->check(0, 0);
307
308 if ((_renderFlags & RENDERFLAG_CAPTUREPOP) && *_vm->_scenery->_pCaptureCounter != 0) {
309 (*_vm->_scenery->_pCaptureCounter)--;
310 _vm->_game->capturePop(1);
311 }
312 }
313
spriteOperation(int16 operation)314 void Draw_v1::spriteOperation(int16 operation) {
315 int16 len;
316 int16 x, y;
317 int16 perLine;
318 Resource *resource;
319
320 operation &= 0x0F;
321
322 if (_sourceSurface >= 100)
323 _sourceSurface -= 80;
324 if (_destSurface >= 100)
325 _destSurface -= 80;
326
327 if (_renderFlags & RENDERFLAG_USEDELTAS) {
328 if (_sourceSurface == kBackSurface) {
329 _spriteLeft += _backDeltaX;
330 _spriteTop += _backDeltaY;
331 }
332
333 if (_destSurface == kBackSurface) {
334 _destSpriteX += _backDeltaX;
335 _destSpriteY += _backDeltaY;
336 if ((operation == DRAW_DRAWLINE) ||
337 ((operation >= DRAW_DRAWBAR) &&
338 (operation <= DRAW_FILLRECTABS))) {
339 _spriteRight += _backDeltaX;
340 _spriteBottom += _backDeltaY;
341 }
342 }
343 }
344
345 Font *font = 0;
346 switch (operation) {
347 case DRAW_BLITSURF:
348 _spritesArray[_destSurface]->blit(*_spritesArray[_sourceSurface],
349 _spriteLeft, _spriteTop,
350 _spriteLeft + _spriteRight - 1,
351 _spriteTop + _spriteBottom - 1,
352 _destSpriteX, _destSpriteY, (_transparency == 0) ? -1 : 0);
353
354 dirtiedRect(_destSurface, _destSpriteX, _destSpriteY,
355 _destSpriteX + _spriteRight - 1, _destSpriteY + _spriteBottom - 1);
356 break;
357
358 case DRAW_PUTPIXEL:
359 _spritesArray[_destSurface]->putPixel(_destSpriteX, _destSpriteY, _frontColor);
360
361 dirtiedRect(_destSurface, _destSpriteX, _destSpriteY, _destSpriteX, _destSpriteY);
362 break;
363
364 case DRAW_FILLRECT:
365 _spritesArray[_destSurface]->fillRect(_destSpriteX, _destSpriteY,
366 _destSpriteX + _spriteRight - 1,
367 _destSpriteY + _spriteBottom - 1, _backColor);
368
369 dirtiedRect(_destSurface, _destSpriteX, _destSpriteY,
370 _destSpriteX + _spriteRight - 1, _destSpriteY + _spriteBottom - 1);
371 break;
372
373 case DRAW_DRAWLINE:
374 _spritesArray[_destSurface]->drawLine(_destSpriteX, _destSpriteY,
375 _spriteRight, _spriteBottom, _frontColor);
376
377 dirtiedRect(_destSurface, _destSpriteX, _destSpriteY, _spriteRight, _spriteBottom);
378 break;
379
380 case DRAW_INVALIDATE:
381 dirtiedRect(_destSurface, _destSpriteX - _spriteRight, _destSpriteY - _spriteBottom,
382 _destSpriteX + _spriteRight, _destSpriteY + _spriteBottom);
383 break;
384
385 case DRAW_LOADSPRITE:
386 resource = _vm->_game->_resources->getResource((uint16) _spriteLeft,
387 &_spriteRight, &_spriteBottom);
388
389 if (!resource)
390 break;
391
392 _vm->_video->drawPackedSprite(resource->getData(),
393 _spriteRight, _spriteBottom, _destSpriteX, _destSpriteY,
394 _transparency, *_spritesArray[_destSurface]);
395
396 dirtiedRect(_destSurface, _destSpriteX, _destSpriteY,
397 _destSpriteX + _spriteRight - 1, _destSpriteY + _spriteBottom - 1);
398
399 delete resource;
400 break;
401
402 case DRAW_PRINTTEXT:
403 if ((_fontIndex >= kFontCount) || !_fonts[_fontIndex]) {
404 warning("Trying to print \"%s\" with undefined font %d", _textToPrint, _fontIndex);
405 break;
406 }
407
408 font = _fonts[_fontIndex];
409 len = strlen(_textToPrint);
410 dirtiedRect(_destSurface, _destSpriteX, _destSpriteY,
411 _destSpriteX + len * font->getCharWidth() - 1,
412 _destSpriteY + font->getCharHeight() - 1);
413
414 for (int i = 0; i < len; i++) {
415 font->drawLetter(*_spritesArray[_destSurface], _textToPrint[i],
416 _destSpriteX, _destSpriteY, _frontColor, _backColor, _transparency);
417
418 _destSpriteX += font->getCharWidth();
419 }
420 break;
421
422 case DRAW_DRAWBAR:
423 _spritesArray[_destSurface]->drawLine(_destSpriteX, _spriteBottom,
424 _spriteRight, _spriteBottom, _frontColor);
425
426 _spritesArray[_destSurface]->drawLine(_destSpriteX, _destSpriteY,
427 _destSpriteX, _spriteBottom, _frontColor);
428
429 _spritesArray[_destSurface]->drawLine(_spriteRight, _destSpriteY,
430 _spriteRight, _spriteBottom, _frontColor);
431
432 _spritesArray[_destSurface]->drawLine(_destSpriteX, _destSpriteY,
433 _spriteRight, _destSpriteY, _frontColor);
434
435 dirtiedRect(_destSurface, _destSpriteX, _destSpriteY, _spriteRight, _spriteBottom);
436 break;
437
438 case DRAW_CLEARRECT:
439 if (_backColor < 16) {
440 _spritesArray[_destSurface]->fillRect(_destSpriteX, _destSpriteY,
441 _spriteRight, _spriteBottom,
442 _backColor);
443 }
444 dirtiedRect(_destSurface, _destSpriteX, _destSpriteY, _spriteRight, _spriteBottom);
445 break;
446
447 case DRAW_FILLRECTABS:
448 _spritesArray[_destSurface]->fillRect(_destSpriteX, _destSpriteY,
449 _spriteRight, _spriteBottom, _backColor);
450
451 dirtiedRect(_destSurface, _destSpriteX, _destSpriteY, _spriteRight, _spriteBottom);
452 break;
453
454 case DRAW_DRAWLETTER:
455 if ((_fontIndex >= kFontCount) || !_fonts[_fontIndex]) {
456 warning("Trying to print \'%c\' with undefined font %d", _letterToPrint, _fontIndex);
457 break;
458 }
459
460 font = _fonts[_fontIndex];
461 if (_fontToSprite[_fontIndex].sprite == -1) {
462 dirtiedRect(_destSurface, _destSpriteX, _destSpriteY,
463 _destSpriteX + font->getCharWidth() - 1,
464 _destSpriteY + font->getCharHeight() - 1);
465 font->drawLetter(*_spritesArray[_destSurface], _letterToPrint,
466 _destSpriteX, _destSpriteY, _frontColor, _backColor, _transparency);
467 break;
468 }
469
470 perLine =
471 _spritesArray[(int16)_fontToSprite[_fontIndex].sprite]->getWidth() /
472 _fontToSprite[_fontIndex].width;
473
474 y = (_letterToPrint - _fontToSprite[_fontIndex].base) / perLine *
475 _fontToSprite[_fontIndex].height;
476
477 x = (_letterToPrint - _fontToSprite[_fontIndex].base) % perLine *
478 _fontToSprite[_fontIndex].width;
479
480 dirtiedRect(_destSurface, _destSpriteX, _destSpriteY,
481 _destSpriteX + _fontToSprite[_fontIndex].width,
482 _destSpriteY + _fontToSprite[_fontIndex].height);
483
484 _spritesArray[_destSurface]->blit(*_spritesArray[(int16)_fontToSprite[_fontIndex].sprite], x, y,
485 x + _fontToSprite[_fontIndex].width,
486 y + _fontToSprite[_fontIndex].height,
487 _destSpriteX, _destSpriteY, (_transparency == 0) ? -1 : 0);
488
489 break;
490
491 default:
492 break;
493 }
494
495 if (_renderFlags & RENDERFLAG_USEDELTAS) {
496 if (_sourceSurface == kBackSurface) {
497 _spriteLeft -= _backDeltaX;
498 _spriteTop -= _backDeltaY;
499 }
500
501 if (_destSurface == kBackSurface) {
502 _destSpriteX -= _backDeltaX;
503 _destSpriteY -= _backDeltaY;
504 }
505 }
506 }
507
508 } // End of namespace Gob
509