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 "gnap/gamesys.h"
24 #include "gnap/fontdata.h"
25 #include "graphics/fontman.h"
26 #include "graphics/font.h"
27 #include "image/bmp.h"
28
29 namespace Gnap {
30
testUpdRect(const Common::Rect & updRect)31 void GfxItem::testUpdRect(const Common::Rect &updRect) {
32 Common::Rect intersectingRect;
33 if (!_updFlag && _prevFrame._spriteId != -1 &&
34 _updRectsCount < 20 && intersectRect(intersectingRect, _prevFrame._rect, updRect))
35 _updRects[_updRectsCount++] = intersectingRect;
36 }
37
38 // GameSys
39
GameSys(GnapEngine * vm)40 GameSys::GameSys(GnapEngine *vm) : _vm(vm) {
41 _newSpriteDrawItemsCount = 0;
42 _removeSequenceItemsCount = 0;
43 _removeSpriteDrawItemsCount = 0;
44 _grabSpriteId = -1;
45 _grabSpriteChanged = false;
46 _reqRemoveSequenceItem = false;
47 _removeSequenceItemSequenceId = -1;
48 _removeSequenceItemValue = 0;
49 _gfxItemsCount = 0;
50 _animationsCount = 0;
51 _animationsDone = false;
52 _backgroundImageValue3 = 0;
53 _backgroundImageValue1 = 0;
54 _backgroundImageValue4 = 1000;
55 _backgroundImageValue2 = 1000;
56 _gameSysClock = 0;
57 _lastUpdateClock = 0;
58 _backgroundSurface = nullptr;
59 _frontSurface = nullptr;
60 for (int i = 0; i < kMaxAnimations; ++i) {
61 _animations[i]._sequenceId = -1;
62 _animations[i]._id = -1;
63 _animations[i]._status = 0;
64 }
65 _removeSequenceItems->_sequenceId = -1;
66 _removeSequenceItems->_id = -1;
67 _removeSequenceItems->_forceFrameReset = false;
68 _removeSpriteDrawItems->_id = -1;
69 _removeSpriteDrawItems->_surface = nullptr;
70
71 _grabSpriteSurface1 = _grabSpriteSurface2 = nullptr;
72
73 _screenRect = Common::Rect(0, 0, 800, 600);
74 }
75
~GameSys()76 GameSys::~GameSys() {
77 if (_frontSurface)
78 _frontSurface->free();
79 delete _frontSurface;
80 }
81
insertSequence(int sequenceId,int id,int sequenceId2,int id2,int flags,int totalDuration,int16 x,int16 y)82 void GameSys::insertSequence(int sequenceId, int id, int sequenceId2, int id2, int flags, int totalDuration, int16 x, int16 y) {
83 debugC(kDebugBasic, "GameSys::insertSequence() [%08X, %d] -> [%08X, %d] (%d, %d)", sequenceId, id, sequenceId2, id2, x, y);
84 Sequence sequence;
85 SequenceResource *sequenceResource = _vm->_sequenceCache->get(sequenceId);
86 sequenceResource->_sequenceId = sequenceId;
87 sequence._sequenceId = sequenceId;
88 sequence._id = id != -1 ? id : sequenceResource->_defaultId;
89 sequence._sequenceId2 = sequenceId2 != (int32)0x80000000 ? sequenceId2 : sequenceResource->_sequenceId2;
90 sequence._id2 = id2 != -1 ? id2 : sequenceResource->_defaultId2;
91 sequence._flags = flags != -1 ? flags : sequenceResource->_flags;
92 sequence._totalDuration = totalDuration != -1 ? totalDuration : sequenceResource->_totalDuration;
93 sequence._x = (x < 10000 && x > -10000) ? x : sequenceResource->_xOffs;
94 sequence._y = (y < 10000 && y > -10000) ? y : sequenceResource->_yOffs;
95 _fatSequenceItems.push_back(sequence);
96 }
97
insertDirtyRect(const Common::Rect & rect)98 void GameSys::insertDirtyRect(const Common::Rect &rect) {
99 _dirtyRects.push_back(rect);
100 }
101
removeSequence(int sequenceId,int id,bool resetFl)102 void GameSys::removeSequence(int sequenceId, int id, bool resetFl) {
103 //WaitForSingleObject(removeSequence2Mutex, INFINITE);
104 if (_removeSequenceItemsCount < kMaxSequenceItems) {
105 _removeSequenceItems[_removeSequenceItemsCount]._sequenceId = sequenceId;
106 _removeSequenceItems[_removeSequenceItemsCount]._id = id;
107 _removeSequenceItems[_removeSequenceItemsCount]._forceFrameReset = resetFl;
108 ++_removeSequenceItemsCount;
109 //ResetEvent(removeSequenceItemsEvent);
110 //ReleaseMutex(removeSequence2Mutex);
111 //WaitForSingleObject(removeSequenceItemsEvent, INFINITE);
112 }
113 }
114
invalidateGrabCursorSprite(int id,Common::Rect & rect,Graphics::Surface * surface1,Graphics::Surface * surface2)115 void GameSys::invalidateGrabCursorSprite(int id, Common::Rect &rect, Graphics::Surface *surface1, Graphics::Surface *surface2) {
116 //WaitForSingleObject(grabSpriteMutex, INFINITE);
117 _grabSpriteId = id;
118 _grabSpriteRect = rect;
119 _grabSpriteSurface2 = surface2;
120 _grabSpriteSurface1 = surface1;
121 //ResetEvent(grabSpriteEvent);
122 _grabSpriteChanged = true;
123 //ReleaseMutex(grabSpriteMutex);
124 //WaitForSingleObject(grabSpriteEvent, INFINITE);
125 }
126
requestClear2(bool resetFl)127 void GameSys::requestClear2(bool resetFl) {
128 _fatSequenceItems.clear();
129 _seqItems.clear();
130 for (int i = 0; i < _gfxItemsCount; ++i) {
131 GfxItem *gfxItem = &_gfxItems[i];
132 gfxItem->_sequenceId = -1;
133 gfxItem->_animation = nullptr;
134 if (resetFl) {
135 gfxItem->_currFrame._duration = 0;
136 gfxItem->_currFrame._spriteId = -1;
137 gfxItem->_currFrame._soundId = -1;
138 gfxItem->_updFlag = true;
139 } else {
140 gfxItem->_updFlag = false;
141 }
142 }
143 _lastUpdateClock = 0;
144 _gameSysClock = 0;
145 }
146
requestClear1()147 void GameSys::requestClear1() {
148 _gfxItemsCount = 0;
149 _fatSequenceItems.clear();
150 _seqItems.clear();
151 _lastUpdateClock = 0;
152 _gameSysClock = 0;
153 }
154
requestRemoveSequence(int sequenceId,int id)155 void GameSys::requestRemoveSequence(int sequenceId, int id) {
156 //WaitForSingleObject(removeSequence2Mutex, INFINITE);
157 _reqRemoveSequenceItem = true;
158 _removeSequenceItemSequenceId = sequenceId;
159 _removeSequenceItemValue = id;
160
161 handleReqRemoveSequenceItem(); //CHECKME?
162
163 //ResetEvent(reqClearEvent);
164 //ReleaseMutex(removeSequence2Mutex);
165 //WaitForSingleObject(reqClearEvent, INFINITE);
166 }
167
waitForUpdate()168 void GameSys::waitForUpdate() {
169 //ResetEvent(updateEvent);
170 //WaitForSingleObject(updateEvent, INFINITE);
171 while ( !_animationsDone) {
172 _vm->gameUpdateTick();
173 }
174 }
175
isSequenceActive(int sequenceId,int id)176 int GameSys::isSequenceActive(int sequenceId, int id) {
177 for (uint i = 0; i < _seqItems.size(); ++i)
178 if (_seqItems[i]._sequenceId == sequenceId && _seqItems[i]._id == id)
179 return true;
180 return false;
181 }
182
setBackgroundSurface(Graphics::Surface * surface,int a4,int a5,int a6,int a7)183 void GameSys::setBackgroundSurface(Graphics::Surface *surface, int a4, int a5, int a6, int a7) {
184 debugC(kDebugBasic, "GameSys::setBackgroundSurface() Setting background image");
185
186 _backgroundSurface = surface;
187 if (!_backgroundSurface) {
188 return;
189 }
190
191 if (!_frontSurface || _frontSurface->w != surface->w || _frontSurface->h != surface->h) {
192 debugC(kDebugBasic, "GameSys::setBackgroundSurface() Creating background working surface");
193 if (_frontSurface)
194 _frontSurface->free();
195 delete _frontSurface;
196 _frontSurface = new Graphics::Surface();
197 _frontSurface->create(surface->w, surface->h, surface->format);
198 }
199
200 memcpy(_frontSurface->getPixels(), surface->getPixels(), surface->pitch * surface->h);
201 _vm->_system->copyRectToScreen(_frontSurface->getPixels(), _frontSurface->pitch, 0, 0, _frontSurface->w, _frontSurface->h);
202
203 _backgroundImageValue1 = a4;
204 _backgroundImageValue3 = a6;
205 _backgroundImageValue2 = a5;
206 _backgroundImageValue4 = a7;
207 _lastUpdateClock = 0;
208 _gameSysClock = 0;
209 }
210
setScaleValues(int a1,int a2,int a3,int a4)211 void GameSys::setScaleValues(int a1, int a2, int a3, int a4) {
212 _backgroundImageValue1 = a1;
213 _backgroundImageValue3 = a3;
214 _backgroundImageValue2 = a2;
215 _backgroundImageValue4 = a4;
216 }
217
insertSpriteDrawItem(Graphics::Surface * surface,int x,int y,int id)218 void GameSys::insertSpriteDrawItem(Graphics::Surface *surface, int x, int y, int id) {
219 if (surface && _newSpriteDrawItemsCount < kMaxSpriteDrawItems) {
220 _newSpriteDrawItems[_newSpriteDrawItemsCount]._id = id;
221 _newSpriteDrawItems[_newSpriteDrawItemsCount]._rect = Common::Rect(x, y, x + surface->w, y + surface->h);
222 _newSpriteDrawItems[_newSpriteDrawItemsCount]._surface = surface;
223 ++_newSpriteDrawItemsCount;
224 }
225 }
226
removeSpriteDrawItem(Graphics::Surface * surface,int id)227 void GameSys::removeSpriteDrawItem(Graphics::Surface *surface, int id) {
228 if (surface && _removeSpriteDrawItemsCount < kMaxSpriteDrawItems) {
229 _removeSpriteDrawItems[_removeSpriteDrawItemsCount]._id = id;
230 _removeSpriteDrawItems[_removeSpriteDrawItemsCount]._surface = surface;
231 ++_removeSpriteDrawItemsCount;
232 }
233 }
234
drawSpriteToBackground(int x,int y,int resourceId)235 void GameSys::drawSpriteToBackground(int x, int y, int resourceId) {
236 SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
237 uint32 *sourcePalette = spriteResource->_palette;
238 byte *sourcePixels = spriteResource->_pixels;
239 int spriteWidth = spriteResource->_width;
240 int spriteHeight = spriteResource->_height;
241 Common::Rect dstRect(0, 0, spriteWidth, spriteHeight);
242 blitSprite32(_backgroundSurface, x, y, sourcePixels, spriteResource->_width, dstRect, sourcePalette, spriteResource->_transparent);
243 _vm->_spriteCache->release(resourceId);
244
245 // Add dirty rect so the modified background is redrawn
246 insertDirtyRect(Common::Rect(x, y, x + spriteWidth, y + spriteHeight));
247 }
248
allocSurface(int width,int height)249 Graphics::Surface *GameSys::allocSurface(int width, int height) {
250 Graphics::Surface *surface = new Graphics::Surface();
251 surface->create(width, height, _backgroundSurface->format);
252 surface->fillRect(Common::Rect(0, 0, surface->w, surface->h), 0xFFFFFF00);
253 return surface;
254 }
255
createSurface(int resourceId)256 Graphics::Surface *GameSys::createSurface(int resourceId) {
257 debugC(kDebugBasic, "GameSys::createSurface() resourceId: %08X", resourceId);
258
259 SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
260 Graphics::Surface *surface = allocSurface(spriteResource->_width, spriteResource->_height);
261 _vm->_spriteCache->release(resourceId);
262
263 drawSpriteToSurface(surface, 0, 0, resourceId);
264
265 return surface;
266 }
267
drawSpriteToSurface(Graphics::Surface * surface,int x,int y,int resourceId)268 void GameSys::drawSpriteToSurface(Graphics::Surface *surface, int x, int y, int resourceId) {
269 SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
270 uint32 *sourcePalette = spriteResource->_palette;
271 byte *sourcePixels = spriteResource->_pixels;
272 Common::Rect dstRect(0, 0, spriteResource->_width, spriteResource->_height);
273 blitSprite32(surface, x, y, sourcePixels, spriteResource->_width, dstRect, sourcePalette, true);
274 _vm->_spriteCache->release(resourceId);
275 }
276
drawTextToSurface(Graphics::Surface * surface,int x,int y,byte r,byte g,byte b,const char * text)277 void GameSys::drawTextToSurface(Graphics::Surface *surface, int x, int y, byte r, byte g, byte b, const char *text) {
278 bool doDirty = false;
279
280 if (!surface) {
281 surface = _backgroundSurface;
282 doDirty = true;
283 }
284
285 uint32 color = surface->format.RGBToColor(r, g, b);
286 if (_vm->_font) {
287 _vm->_font->drawString(surface, text, x, y, _vm->_font->getStringWidth(text), color);
288
289 if (doDirty)
290 insertDirtyRect(Common::Rect(x, y, x + _vm->_font->getStringWidth(text), y + _vm->_font->getFontHeight()));
291 } else {
292 for (const char *cp = text; *cp != 0; ++cp) {
293 byte c = *cp;
294 if (c < 32 || c >= 127)
295 c = (byte)'_';
296 c -= 32;
297 int w = _dejaVuSans9ptWidth[c];
298 const byte *data = _dejaVuSans9ptCharBitmaps + _dejaVuSans9ptOffsets[c];
299 for (int xc = 0; xc < w; ++xc) {
300 for (int yc = 15; yc >= 0; --yc) {
301 byte *dst = (byte *)surface->getBasePtr(x + xc, y + yc);
302 if (data[1 - (yc >> 3)] & (1 << (yc & 7)))
303 WRITE_LE_UINT32(dst, color);
304 }
305 data += 2;
306 }
307 x += w + 1;
308 }
309
310 if (doDirty)
311 insertDirtyRect(Common::Rect(x, y, x + getTextWidth(text), y + 16));
312 }
313 }
314
getTextHeight(const char * text)315 int GameSys::getTextHeight(const char *text) {
316 byte height = 0;
317 for (const char *cp = text; *cp != 0; ++cp) {
318 byte c = *cp;
319 if (c < 32 || c >= 127)
320 c = (byte)'_';
321 c -= 32;
322 height = MAX(height, _dejaVuSans9ptWidth[c]);
323 }
324 return height;
325 }
326
getTextWidth(const char * text)327 int GameSys::getTextWidth(const char *text) {
328 int width = 0;
329 for (const char *cp = text; *cp != 0; ++cp) {
330 byte c = *cp;
331 if (c < 32 || c >= 127)
332 c = (byte)'_';
333 c -= 32;
334 width += _dejaVuSans9ptWidth[c] + 1;
335 }
336 return width;
337 }
338
fillSurface(Graphics::Surface * surface,int x,int y,int width,int height,byte r,byte g,byte b)339 void GameSys::fillSurface(Graphics::Surface *surface, int x, int y, int width, int height, byte r, byte g, byte b) {
340 Common::Rect rect(x, y, x + width, y + height);
341 if (!surface) {
342 _backgroundSurface->fillRect(rect, _backgroundSurface->format.RGBToColor(r, g, b));
343 insertDirtyRect(rect);
344 } else {
345 surface->fillRect(rect, surface->format.RGBToColor(r, g, b));
346 }
347 }
348
setAnimation(int sequenceId,int id,int animationIndex)349 void GameSys::setAnimation(int sequenceId, int id, int animationIndex) {
350 if (animationIndex < kMaxAnimations) {
351 _animations[animationIndex]._sequenceId = sequenceId;
352 _animations[animationIndex]._id = id;
353 _animations[animationIndex]._status = 0;
354 }
355 }
356
getAnimationStatus(int animationIndex)357 int GameSys::getAnimationStatus(int animationIndex) {
358 int result = -1;
359 if (animationIndex < kMaxAnimations)
360 result = _animations[animationIndex]._status;
361 return result;
362 }
363
getSpriteWidthById(int resourceId)364 int GameSys::getSpriteWidthById(int resourceId) {
365 SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
366 const int width = spriteResource->_width;
367 _vm->_spriteCache->release(resourceId);
368 return width;
369 }
370
getSpriteHeightById(int resourceId)371 int GameSys::getSpriteHeightById(int resourceId) {
372 SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
373 const int height = spriteResource->_height;
374 _vm->_spriteCache->release(resourceId);
375 return height;
376 }
377
loadBitmap(int resourceId)378 Graphics::Surface *GameSys::loadBitmap(int resourceId) {
379 debugC(kDebugBasic, "GameSys::loadBitmap() resourceId: %08X", resourceId);
380 if (_vm->_dat->getResourceType(resourceId) != 1)
381 return nullptr;
382 byte *resourceData = _vm->_dat->loadResource(resourceId);
383 uint32 resourceSize = _vm->_dat->getResourceSize(resourceId);
384 Common::MemoryReadStream stream(resourceData, resourceSize, DisposeAfterUse::NO);
385 Graphics::Surface *bmpSurface;
386 Image::BitmapDecoder bmp;
387 if (!bmp.loadStream(stream))
388 error("GameSys::loadBitmap() Could not load bitmap resource %08X", resourceId);
389 bmpSurface = bmp.getSurface()->convertTo(_vm->_system->getScreenFormat());
390 delete[] resourceData;
391 return bmpSurface;
392 }
393
drawBitmap(int resourceId)394 void GameSys::drawBitmap(int resourceId) {
395 assert(_backgroundSurface);
396
397 Graphics::Surface *bmpSurface = loadBitmap(resourceId);
398 if (!bmpSurface)
399 error("GameSys::drawBitmap() Error loading the bitmap");
400
401 if (bmpSurface->format != _backgroundSurface->format
402 || bmpSurface->w != _backgroundSurface->w || bmpSurface->h != _backgroundSurface->h)
403 error("GameSys::drawBitmap() Different bitmap properties than current background");
404
405 byte *src = (byte *)bmpSurface->getPixels();
406 byte *dst = (byte *)_backgroundSurface->getPixels();
407 const int pitch = bmpSurface->pitch;
408 int height = bmpSurface->h;
409 while (height--) {
410 memcpy(dst, src, pitch);
411 src += pitch;
412 dst += pitch;
413 }
414
415 bmpSurface->free();
416 delete bmpSurface;
417
418 insertDirtyRect(Common::Rect(0, 0, 800, 600));
419 }
420
seqFind(int sequenceId,int id,int * outIndex)421 Sequence *GameSys::seqFind(int sequenceId, int id, int *outIndex) {
422 for (uint i = 0; i < _seqItems.size(); ++i)
423 if (_seqItems[i]._sequenceId == sequenceId && _seqItems[i]._id == id) {
424 if (outIndex)
425 *outIndex = i;
426 return &_seqItems[i];
427 }
428 return nullptr;
429 }
430
seqLocateGfx(int sequenceId,int id,int * outGfxIndex)431 int GameSys::seqLocateGfx(int sequenceId, int id, int *outGfxIndex) {
432 for (int i = 0; i < _gfxItemsCount; ++i) {
433 GfxItem *gfxItem = &_gfxItems[i];
434 if (gfxItem->_sequenceId == sequenceId && gfxItem->_id == id) {
435 if (outGfxIndex)
436 *outGfxIndex = i;
437 return gfxItem->_sequenceId;
438 }
439 if (gfxItem->_id > id) {
440 if (outGfxIndex)
441 *outGfxIndex = i;
442 return 0;
443 }
444 }
445 if (outGfxIndex)
446 *outGfxIndex = _gfxItemsCount;
447 return 0;
448 }
449
seqInsertGfx(int index,int duration)450 void GameSys::seqInsertGfx(int index, int duration) {
451 Sequence *seqItem = &_seqItems[index];
452 SequenceResource *sequenceResource = _vm->_sequenceCache->get(seqItem->_sequenceId);
453
454 if (sequenceResource->_animationsCount > 50 - _gfxItemsCount)
455 return;
456
457 int gfxIndex;
458 seqLocateGfx(seqItem->_sequenceId, seqItem->_id, &gfxIndex);
459
460 if (gfxIndex != _gfxItemsCount)
461 memmove(&_gfxItems[gfxIndex + sequenceResource->_animationsCount], &_gfxItems[gfxIndex], sizeof(GfxItem) * (_gfxItemsCount - gfxIndex));
462 _gfxItemsCount += sequenceResource->_animationsCount;
463
464 for (int i = 0; i < sequenceResource->_animationsCount; ++i) {
465 GfxItem *gfxItem = &_gfxItems[i + gfxIndex];
466 SequenceAnimation *animation = &sequenceResource->_animations[i];
467
468 debugC(kDebugBasic, "GameSys::seqInsertGfx() seqItem->sequenceId: %08X", seqItem->_sequenceId);
469
470 gfxItem->_sequenceId = seqItem->_sequenceId;
471 gfxItem->_id = seqItem->_id;
472 gfxItem->_animation = animation;
473 gfxItem->_currFrameNum = 0;
474 gfxItem->_flags = 0;
475 gfxItem->_delayTicks = seqItem->_totalDuration + animation->_additionalDelay;
476 gfxItem->_updFlag = false;
477 gfxItem->_updRectsCount = 0;
478 gfxItem->_prevFrame._duration = 0;
479 gfxItem->_prevFrame._spriteId = -1;
480 gfxItem->_prevFrame._soundId = -1;
481 int totalDuration = duration;
482 if ((seqItem->_flags & kSeqUnk) && totalDuration > 0) {
483 gfxItem->_prevFrame._duration = 1;
484 if (gfxItem->_delayTicks <= totalDuration)
485 gfxItem->_delayTicks = 0;
486 else
487 gfxItem->_delayTicks -= totalDuration + 1;
488 gfxItem->_updFlag = false;
489 } else if (gfxItem->_delayTicks <= totalDuration) {
490 int j;
491 totalDuration -= gfxItem->_delayTicks;
492 gfxItem->_delayTicks = 0;
493 for (j = gfxItem->_currFrameNum; j < animation->_framesCount && animation->frames[j]._duration <= totalDuration; ++j) {
494 if (animation->frames[j]._soundId != -1)
495 _soundIds.push_back((gfxItem->_sequenceId & 0xFFFF0000) | animation->frames[j]._soundId);
496 totalDuration -= animation->frames[j]._duration;
497 }
498 if (animation->_framesCount > j)
499 gfxItem->_currFrame = animation->frames[j++];
500 else
501 gfxItem->_currFrame = animation->frames[j - 1];
502 if (gfxItem->_currFrame._spriteId != -1 && (seqItem->_x != 0 || seqItem->_y != 0))
503 gfxItem->_currFrame._rect.translate(seqItem->_x, seqItem->_y);
504 // Update sprite scaling
505 if ((seqItem->_flags & kSeqScale) && gfxItem->_currFrame._rect.bottom >= _backgroundImageValue1 && gfxItem->_currFrame._rect.bottom <= _backgroundImageValue3) {
506 int scaleValue = _backgroundImageValue2 + (gfxItem->_currFrame._rect.bottom - _backgroundImageValue1) *
507 (_backgroundImageValue4 - _backgroundImageValue2) /
508 (_backgroundImageValue3 - _backgroundImageValue1);
509 gfxItem->_currFrame._rect.top = gfxItem->_currFrame._rect.bottom - scaleValue * (gfxItem->_currFrame._rect.bottom - gfxItem->_currFrame._rect.top) / 1000;
510 gfxItem->_currFrame._rect.right = scaleValue * (gfxItem->_currFrame._rect.right - gfxItem->_currFrame._rect.left) / 1000 + gfxItem->_currFrame._rect.left;
511 gfxItem->_currFrame._isScaled = true;
512 }
513 gfxItem->_currFrame._duration -= totalDuration;
514 if (gfxItem->_currFrame._soundId != -1)
515 _soundIds.push_back((gfxItem->_sequenceId & 0xFFFF0000) | gfxItem->_currFrame._soundId);
516 gfxItem->_currFrameNum = j;
517 gfxItem->_updFlag = true;
518 } else {
519 gfxItem->_delayTicks -= totalDuration + 1;
520 gfxItem->_updFlag = false;
521 }
522 }
523
524 for (int k = 0; k < kMaxAnimations; ++k) {
525 if (_animations[k]._sequenceId != -1 && _animations[k]._sequenceId == seqItem->_sequenceId && _animations[k]._id == seqItem->_id) {
526 _animations[k]._status = 1;
527 break;
528 }
529 }
530 }
531
seqRemoveGfx(int sequenceId,int id)532 void GameSys::seqRemoveGfx(int sequenceId, int id) {
533 int gfxIndex;
534 if (seqLocateGfx(sequenceId, id, &gfxIndex)) {
535 GfxItem *gfxItem = &_gfxItems[gfxIndex];
536 while (gfxIndex < _gfxItemsCount && gfxItem->_sequenceId == sequenceId && gfxItem->_id == id) {
537 if (gfxItem->_prevFrame._spriteId == -1) {
538 --_gfxItemsCount;
539 if (gfxIndex != _gfxItemsCount)
540 memmove(&_gfxItems[gfxIndex], &_gfxItems[gfxIndex + 1], sizeof(GfxItem) * (_gfxItemsCount - gfxIndex));
541 } else {
542 gfxItem->_sequenceId = -1;
543 gfxItem->_animation = nullptr;
544 gfxItem->_currFrame._duration = 0;
545 gfxItem->_currFrame._spriteId = -1;
546 gfxItem->_currFrame._soundId = -1;
547 gfxItem->_updFlag = true;
548 ++gfxIndex;
549 gfxItem = &_gfxItems[gfxIndex];
550 }
551 }
552 }
553 }
554
updateSequenceDuration(int sequenceId,int id,int * outDuration)555 bool GameSys::updateSequenceDuration(int sequenceId, int id, int *outDuration) {
556 bool found = false;
557 int duration = 0x7FFFFFFF;
558 *outDuration = 0;
559 for (int i = 0; i < _gfxItemsCount; ++i) {
560 GfxItem *gfxItem = &_gfxItems[i];
561 if (gfxItem->_sequenceId == sequenceId && gfxItem->_id == id) {
562 found = true;
563 SequenceAnimation *animation = gfxItem->_animation;
564 if (animation) {
565 if (gfxItem->_currFrameNum < animation->_framesCount)
566 return false;
567 if (gfxItem->_updFlag) {
568 if (gfxItem->_currFrame._duration > 0)
569 return false;
570 if (-gfxItem->_currFrame._duration < duration)
571 duration = -gfxItem->_currFrame._duration;
572 } else {
573 if (gfxItem->_prevFrame._duration > 0)
574 return false;
575 if (-gfxItem->_prevFrame._duration < duration)
576 duration = -gfxItem->_prevFrame._duration;
577 }
578 }
579 }
580 }
581
582 if (found)
583 *outDuration = duration;
584
585 return found;
586 }
587
updateAnimationsStatus(int sequenceId,int id)588 void GameSys::updateAnimationsStatus(int sequenceId, int id) {
589 Animation *foundAnimation = nullptr;
590 for (int animationIndex = 0; animationIndex < kMaxAnimations; ++animationIndex) {
591 Animation *animation = &_animations[animationIndex];
592 if (animation->_sequenceId != -1 && animation->_sequenceId == sequenceId && animation->_id == id) {
593 foundAnimation = animation;
594 break;
595 }
596 }
597
598 if (!foundAnimation)
599 return;
600
601 bool foundSequence = false;
602 for (int i = 0; i < _gfxItemsCount; ++i) {
603 GfxItem *gfxItem = &_gfxItems[i];
604 SequenceAnimation *animation = gfxItem->_animation;
605 if (gfxItem->_sequenceId == sequenceId && gfxItem->_id == id && animation) {
606 foundSequence = true;
607 if (animation->_framesCount > gfxItem->_currFrameNum ||
608 (gfxItem->_updFlag && gfxItem->_currFrame._duration > 1) ||
609 gfxItem->_prevFrame._duration > 1)
610 foundSequence = false;
611 break;
612 }
613 }
614
615 if (foundSequence) {
616 foundAnimation->_sequenceId = -1;
617 foundAnimation->_status = 2;
618 }
619 }
620
restoreBackgroundRect(const Common::Rect & rect)621 void GameSys::restoreBackgroundRect(const Common::Rect &rect) {
622 Common::Rect clipRect;
623 if (!intersectRect(clipRect, rect, _screenRect))
624 return;
625 byte *src = (byte *)_backgroundSurface->getBasePtr(clipRect.left, clipRect.top);
626 byte *dst = (byte *)_frontSurface->getBasePtr(clipRect.left, clipRect.top);
627 const int bytes = _backgroundSurface->format.bytesPerPixel * clipRect.width();
628 int height = clipRect.height();
629 while (height--) {
630 memcpy(dst, src, bytes);
631 src += _backgroundSurface->pitch;
632 dst += _frontSurface->pitch;
633 }
634 }
635
blitSurface32(Graphics::Surface * destSurface,int x,int y,Graphics::Surface * sourceSurface,Common::Rect & sourceRect,bool transparent)636 void GameSys::blitSurface32(Graphics::Surface *destSurface, int x, int y, Graphics::Surface *sourceSurface,
637 Common::Rect &sourceRect, bool transparent) {
638
639 const int sourcePitch = sourceSurface->pitch;
640 byte *dst = (byte *)destSurface->getBasePtr(x, y);
641 byte *src = (byte *)sourceSurface->getBasePtr(sourceRect.left, sourceRect.top);
642 int width = sourceRect.width();
643 int height = sourceRect.height();
644 while (height--) {
645 byte *rsrc = src;
646 byte *rdst = dst;
647 for (int xc = 0; xc < width; ++xc) {
648 uint32 pixel = READ_UINT32(rsrc);
649 if (!transparent || pixel != 0xFFFFFF00)
650 WRITE_UINT32(rdst, pixel);
651 rsrc += 4;
652 rdst += 4;
653 }
654 dst += destSurface->pitch;
655 src += sourcePitch;
656 }
657 }
658
blitSprite32(Graphics::Surface * destSurface,int x,int y,byte * sourcePixels,int sourceWidth,Common::Rect & sourceRect,uint32 * sourcePalette,bool transparent)659 void GameSys::blitSprite32(Graphics::Surface *destSurface, int x, int y, byte *sourcePixels,
660 int sourceWidth, Common::Rect &sourceRect, uint32 *sourcePalette, bool transparent) {
661
662 const int sourcePitch = (sourceWidth + 3) & 0xFFFFFFFC;
663 byte *dst = (byte *)destSurface->getBasePtr(x, y);
664 byte *src = sourcePixels + sourceRect.left + sourcePitch * sourceRect.top;
665 int width = sourceRect.width();
666 int height = sourceRect.height();
667 while (height--) {
668 byte *rdst = dst;
669 for (int xc = 0; xc < width; ++xc) {
670 byte srcPixel = src[xc];
671 if (!transparent || srcPixel) {
672 uint32 rgb = sourcePalette[srcPixel];
673 rdst[0] = 0xFF;
674 rdst[1] = rgb & 0x000000FF;
675 rdst[2] = (rgb & 0x0000FF00) >> 8;
676 rdst[3] = (rgb & 0x00FF0000) >> 16;
677 }
678 rdst += 4;
679 }
680 dst += destSurface->pitch;
681 src += sourcePitch;
682 }
683 }
684
blitSpriteScaled32(Graphics::Surface * destSurface,Common::Rect & frameRect,Common::Rect & destRect,byte * sourcePixels,int sourceWidth,Common::Rect & sourceRect,uint32 * sourcePalette)685 void GameSys::blitSpriteScaled32(Graphics::Surface *destSurface, Common::Rect &frameRect,
686 Common::Rect &destRect, byte *sourcePixels, int sourceWidth, Common::Rect &sourceRect, uint32 *sourcePalette) {
687
688 if (frameRect.height() <= 0 || frameRect.width() <= 0)
689 return;
690
691 const int ys = ((sourceRect.bottom - sourceRect.top - 1) << 16) / (frameRect.bottom - frameRect.top - 1);
692 const int xs = ((sourceRect.right - sourceRect.left - 1) << 16) / (frameRect.right - frameRect.left - 1);
693 const int destPitch = destSurface->pitch;
694 const int sourcePitch = (sourceWidth + 3) & 0xFFFFFFFC;
695
696 if (!frameRect.equals(destRect)) {
697 byte *dst = (byte *)destSurface->getBasePtr(destRect.left, destRect.top);
698 byte *src = sourcePixels + sourcePitch * sourceRect.top + sourceRect.left;
699 const int height = destRect.bottom - destRect.top;
700 const int width = destRect.right - destRect.left;
701 int yi = ys * (destRect.top - frameRect.top);
702 byte *hsrc = src + sourcePitch * ((yi + 0x8000) >> 16);
703 for (int i = 0; i < height; ++i) {
704 byte *wdst = dst;
705 int xi = xs * (destRect.left - frameRect.left);
706 byte *wsrc = hsrc + ((xi + 0x8000) >> 16);
707 for (int j = 0; j < width; ++j) {
708 byte srcPixel = *wsrc;
709 if (srcPixel) {
710 uint32 rgb = sourcePalette[srcPixel];
711 wdst[0] = 0xFF;
712 wdst[1] = rgb & 0x000000FF;
713 wdst[2] = (rgb & 0x0000FF00) >> 8;
714 wdst[3] = (rgb & 0x00FF0000) >> 16;
715 }
716 wdst += 4;
717 xi += xs;
718 wsrc = hsrc + ((xi + 0x8000) >> 16);
719 }
720 dst += destPitch;
721 yi += ys;
722 hsrc = src + sourcePitch * ((yi + 0x8000) >> 16);
723 }
724 } else {
725 byte *dst = (byte *)destSurface->getBasePtr(frameRect.left, frameRect.top);
726 byte *src = sourcePixels + sourcePitch * sourceRect.top + sourceRect.left;
727 const int height = frameRect.bottom - frameRect.top;
728 const int width = frameRect.right - frameRect.left;
729 byte *hsrc = sourcePixels + sourcePitch * sourceRect.top + sourceRect.left;
730 int yi = 0;
731 for (int i = 0; i < height; ++i) {
732 byte *wdst = dst;
733 byte *wsrc = hsrc;
734 int xi = 0;
735 for (int j = 0; j < width; ++j) {
736 byte srcPixel = *wsrc;
737 if (srcPixel) {
738 uint32 rgb = sourcePalette[srcPixel];
739 wdst[0] = 0xFF;
740 wdst[1] = rgb & 0x000000FF;
741 wdst[2] = (rgb & 0x0000FF00) >> 8;
742 wdst[3] = (rgb & 0x00FF0000) >> 16;
743 }
744 wdst += 4;
745 xi += xs;
746 wsrc = hsrc + ((xi + 0x8000) >> 16);
747 }
748 dst += destPitch;
749 yi += ys;
750 hsrc = src + sourcePitch * ((yi + 0x8000) >> 16);
751 }
752 }
753
754 }
755
seqDrawStaticFrame(Graphics::Surface * surface,SequenceFrame & frame,Common::Rect * subRect)756 void GameSys::seqDrawStaticFrame(Graphics::Surface *surface, SequenceFrame &frame, Common::Rect *subRect) {
757 debugC(kDebugBasic, "GameSys::seqDrawStaticFrame() rect: (%d, %d, %d, %d)",
758 frame._rect.left, frame._rect.top, frame._rect.right, frame._rect.bottom);
759
760 Common::Rect srcRect = subRect ? *subRect : frame._rect;
761 Common::Rect clipRect;
762
763 if (!intersectRect(clipRect, srcRect, _screenRect)) {
764 debugC(kDebugBasic, "GameSys::seqDrawStaticFrame() Surface not inside screen");
765 return;
766 }
767
768 const int x = clipRect.left, y = clipRect.top;
769
770 clipRect.translate(-frame._rect.left, -frame._rect.top);
771
772 // TODO Save transparent flag somewhere
773 blitSurface32(_frontSurface, x, y, surface, clipRect, true);
774 }
775
seqDrawSpriteFrame(SpriteResource * spriteResource,SequenceFrame & frame,Common::Rect * subRect)776 void GameSys::seqDrawSpriteFrame(SpriteResource *spriteResource, SequenceFrame &frame, Common::Rect *subRect) {
777 debugC(kDebugBasic, "GameSys::seqDrawSpriteFrame() spriteId: %04X; rect: (%d, %d, %d, %d)",
778 frame._spriteId, frame._rect.left, frame._rect.top, frame._rect.right, frame._rect.bottom);
779
780 Common::Rect srcRect = subRect ? *subRect : frame._rect;
781 Common::Rect clipRect;
782
783 if (!intersectRect(clipRect, srcRect, _screenRect)) {
784 debugC(kDebugBasic, "GameSys::seqDrawSpriteFrame() Sprite not inside screen");
785 return;
786 }
787
788 uint32 *sourcePalette = spriteResource->_palette;
789 byte *sourcePixels = spriteResource->_pixels;
790
791 const int x = clipRect.left, y = clipRect.top;
792
793 debugC(kDebugBasic, "GameSys::seqDrawSpriteFrame() destX: %d; destY: %d; frame.isScaled: %d", x, y, frame._isScaled ? 1 : 0);
794
795 // 32bit sprite drawing
796 if (frame._isScaled) {
797 Common::Rect sourceRect(0, 0, spriteResource->_width, spriteResource->_height);
798 blitSpriteScaled32(_frontSurface, frame._rect, clipRect, sourcePixels, spriteResource->_width, sourceRect, sourcePalette);
799 } else {
800 clipRect.translate(-frame._rect.left, -frame._rect.top);
801 blitSprite32(_frontSurface, x, y, sourcePixels, spriteResource->_width, clipRect, sourcePalette, true);
802 }
803 }
804
drawSprites()805 void GameSys::drawSprites() {
806 debugC(kDebugBasic, "GameSys::drawSprites() _gfxItemsCount: %d", _gfxItemsCount);
807
808 // Restore dirty background and collect rects to be redrawn for all sprites
809 // which aren't marked to be redrawn yet
810 Common::Rect intersectingRect;
811 for (uint i = 0; i < _dirtyRects.size(); ++i) {
812 restoreBackgroundRect(_dirtyRects[i]);
813 for (int j = 0; j < _gfxItemsCount; ++j)
814 _gfxItems[j].testUpdRect(_dirtyRects[i]);
815 }
816
817 for (int k = 0; k < _gfxItemsCount; ++k) {
818 GfxItem *gfxItem2 = &_gfxItems[k];
819
820 if (!gfxItem2->_updFlag)
821 continue;
822
823 if (gfxItem2->_prevFrame._spriteId != -1) {
824 bool transparent = false;
825 if (gfxItem2->_currFrame._spriteId != -1) {
826 if (gfxItem2->_flags) {
827 transparent = true;
828 } else {
829 int resourceId = (gfxItem2->_sequenceId & 0xFFFF0000) | gfxItem2->_currFrame._spriteId;
830 SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
831 transparent = spriteResource->_transparent;
832 _vm->_spriteCache->release(resourceId);
833 }
834 }
835 if (gfxItem2->_currFrame._spriteId == -1 || !gfxItem2->_prevFrame._rect.equals(gfxItem2->_currFrame._rect) || !transparent) {
836 restoreBackgroundRect(gfxItem2->_prevFrame._rect);
837 for (int l = 0; l < _gfxItemsCount; ++l)
838 _gfxItems[l].testUpdRect(gfxItem2->_prevFrame._rect);
839 }
840 }
841
842 if (gfxItem2->_currFrame._spriteId != -1) {
843 bool transparent = false;
844 if (gfxItem2->_flags) {
845 transparent = true;
846 } else {
847 int resourceId = (gfxItem2->_sequenceId & 0xFFFF0000) | gfxItem2->_currFrame._spriteId;
848 SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
849 transparent = spriteResource->_transparent;
850 _vm->_spriteCache->release(resourceId);
851 }
852 if (gfxItem2->_prevFrame._spriteId == -1 || !gfxItem2->_prevFrame._rect.equals(gfxItem2->_currFrame._rect) || transparent) {
853 for (int l = k; l < _gfxItemsCount; ++l)
854 _gfxItems[l].testUpdRect(gfxItem2->_currFrame._rect);
855 }
856 }
857 }
858
859 for (int m = 0; m < _gfxItemsCount; ++m) {
860 GfxItem *gfxItem5 = &_gfxItems[m];
861
862 debugC(kDebugBasic, "DrawGfxItem(%d) updFlag: %d; currFrame.spriteId: %04X; updRectsCount: %d; flags: %04X; sequenceId: %08X",
863 m, gfxItem5->_updFlag, gfxItem5->_currFrame._spriteId, gfxItem5->_updRectsCount, gfxItem5->_flags, gfxItem5->_sequenceId);
864
865 if (gfxItem5->_updFlag) {
866 if (gfxItem5->_currFrame._spriteId != -1) {
867 if (gfxItem5->_flags) {
868 seqDrawStaticFrame(gfxItem5->_surface, gfxItem5->_currFrame, nullptr);
869 } else {
870 int resourceId = (gfxItem5->_sequenceId & 0xFFFF0000) | gfxItem5->_currFrame._spriteId;
871 SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
872 seqDrawSpriteFrame(spriteResource, gfxItem5->_currFrame, nullptr);
873 _vm->_spriteCache->release(resourceId);
874 }
875 }
876 } else if (gfxItem5->_updRectsCount > 0) {
877 if (gfxItem5->_flags) {
878 for (int n = 0; n < gfxItem5->_updRectsCount; ++n)
879 seqDrawStaticFrame(gfxItem5->_surface, gfxItem5->_prevFrame, &gfxItem5->_updRects[n]);
880 } else {
881 int resourceId = (gfxItem5->_sequenceId & 0xFFFF0000) | gfxItem5->_prevFrame._spriteId;
882 SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
883 for (int n = 0; n < gfxItem5->_updRectsCount; ++n)
884 seqDrawSpriteFrame(spriteResource, gfxItem5->_prevFrame, &gfxItem5->_updRects[n]);
885 _vm->_spriteCache->release(resourceId);
886 }
887 }
888 }
889
890 debugC(kDebugBasic, "GameSys::drawSprites() OK");
891 }
892
updateRect(const Common::Rect & r)893 void GameSys::updateRect(const Common::Rect &r) {
894 debugC(kDebugBasic, "GameSys::updateRect() %d, %d, %d, %d [%d, %d]", r.left, r.top, r.right, r.bottom, r.width(), r.height());
895 if (r.width() > 0 && r.height() > 0) {
896 byte *pixels = (byte *)_frontSurface->getBasePtr(r.left, r.top);
897 _vm->_system->copyRectToScreen(pixels, _frontSurface->pitch, r.left, r.top,
898 r.width(), r.height());
899 }
900 }
901
updateScreen()902 void GameSys::updateScreen() {
903 debugC(kDebugBasic, "GameSys::updateScreen()");
904
905 for (uint i = 0; i < _dirtyRects.size(); ++i)
906 updateRect(_dirtyRects[i]);
907
908 if (_dirtyRects.size() > 0) {
909 _dirtyRects.clear();
910 _lastUpdateClock = 0;
911 _gameSysClock = 0;
912 }
913
914 Common::Rect dstRect, srcRect, rcSrc2;
915
916 for (int j = 0; j < _gfxItemsCount; ++j) {
917
918 GfxItem *gfxItem = &_gfxItems[j];
919
920 if (!gfxItem->_updFlag)
921 continue;
922
923 if (gfxItem->_prevFrame._spriteId == -1 ||
924 !intersectRect(srcRect, _screenRect, gfxItem->_prevFrame._rect)) {
925 if (gfxItem->_currFrame._spriteId != -1 && intersectRect(rcSrc2, _screenRect, gfxItem->_currFrame._rect))
926 updateRect(rcSrc2);
927 } else if (gfxItem->_currFrame._spriteId != -1 &&
928 intersectRect(rcSrc2, _screenRect, gfxItem->_currFrame._rect)) {
929 updateRect(srcRect);
930 updateRect(rcSrc2);
931 }
932 gfxItem->_prevFrame = gfxItem->_currFrame;
933 }
934
935 updateRect(Common::Rect(0, 0, 800, 600));
936
937 debugC(kDebugBasic, "GameSys::updateScreen() OK");
938 }
939
handleReqRemoveSequenceItem()940 void GameSys::handleReqRemoveSequenceItem() {
941 if (_reqRemoveSequenceItem) {
942 int gfxIndex2;
943 _reqRemoveSequenceItem = false;
944 if (seqFind(_removeSequenceItemSequenceId, _removeSequenceItemValue, &gfxIndex2))
945 _seqItems.remove_at(gfxIndex2);
946 if (seqLocateGfx(_removeSequenceItemSequenceId, _removeSequenceItemValue, &gfxIndex2)) {
947 int gfxIndex2a = gfxIndex2;
948 for (GfxItem *gfxItem = &_gfxItems[gfxIndex2a];
949 gfxIndex2a < _gfxItemsCount && gfxItem->_sequenceId == _removeSequenceItemSequenceId && gfxItem->_id == _removeSequenceItemValue;
950 gfxItem = &_gfxItems[gfxIndex2a])
951 ++gfxIndex2a;
952 _gfxItemsCount -= gfxIndex2a - gfxIndex2;
953 if (_gfxItemsCount != gfxIndex2)
954 memmove(&_gfxItems[gfxIndex2], &_gfxItems[gfxIndex2a], sizeof(GfxItem) * (_gfxItemsCount - gfxIndex2));
955 }
956 }
957 }
958
handleReqRemoveSequenceItems()959 void GameSys::handleReqRemoveSequenceItems() {
960 if (_removeSequenceItemsCount > 0) {
961 for (int i = 0; i < _removeSequenceItemsCount; ++i) {
962 int gfxIndex;
963 if (seqFind(_removeSequenceItems[i]._sequenceId, _removeSequenceItems[i]._id, &gfxIndex))
964 _seqItems.remove_at(gfxIndex);
965 seqLocateGfx(_removeSequenceItems[i]._sequenceId, _removeSequenceItems[i]._id, &gfxIndex);
966 for (GfxItem *gfxItem = &_gfxItems[gfxIndex];
967 gfxIndex < _gfxItemsCount && gfxItem->_sequenceId == _removeSequenceItems[i]._sequenceId && gfxItem->_id == _removeSequenceItems[i]._id;
968 gfxItem = &_gfxItems[gfxIndex]) {
969 gfxItem->_sequenceId = -1;
970 gfxItem->_animation = nullptr;
971 if (_removeSequenceItems[i]._forceFrameReset) {
972 gfxItem->_currFrame._duration = 0;
973 gfxItem->_currFrame._spriteId = -1;
974 gfxItem->_currFrame._soundId = -1;
975 gfxItem->_updFlag = true;
976 } else {
977 gfxItem->_updFlag = false;
978 }
979 ++gfxIndex;
980 }
981 }
982 _removeSequenceItemsCount = 0;
983 }
984 }
985
handleReqRemoveSpriteDrawItems()986 void GameSys::handleReqRemoveSpriteDrawItems() {
987 if (_removeSpriteDrawItemsCount > 0) {
988 for (int j = 0; j < _removeSpriteDrawItemsCount; ++j) {
989 for (int i = 0; i < _gfxItemsCount; ++i) {
990 GfxItem *gfxItem = &_gfxItems[i];
991 if (gfxItem->_sequenceId == -1 && !gfxItem->_animation && gfxItem->_flags
992 && gfxItem->_id == _removeSpriteDrawItems[j]._id && _removeSpriteDrawItems[j]._surface == gfxItem->_surface) {
993 gfxItem->_flags = 0;
994 gfxItem->_currFrame._duration = 0;
995 gfxItem->_currFrame._spriteId = -1;
996 gfxItem->_currFrame._soundId = -1;
997 gfxItem->_updFlag = true;
998 }
999 }
1000 }
1001 _removeSpriteDrawItemsCount = 0;
1002 }
1003 }
1004
fatUpdateFrame()1005 void GameSys::fatUpdateFrame() {
1006 debugC(kDebugBasic, "GameSys::fatUpdateFrame()");
1007
1008 int32 clockDelta = _gameSysClock - _lastUpdateClock;
1009 _lastUpdateClock = _gameSysClock;
1010
1011 debugC(kDebugBasic, "GameSys::fatUpdateFrame() clockDelta: %d", clockDelta);
1012
1013 if (clockDelta <= 0)
1014 return;
1015
1016 _animationsDone = true;
1017
1018 int duration, currFrameNum;
1019
1020 for (int i = 0; i < _gfxItemsCount; ++i) {
1021 GfxItem *gfxItem = &_gfxItems[i];
1022 SequenceAnimation *animation = gfxItem->_animation;
1023 if ((gfxItem->_sequenceId != -1 && animation) || gfxItem->_prevFrame._spriteId != -1 || gfxItem->_prevFrame._duration > 0) {
1024 if (gfxItem->_sequenceId != -1 && !gfxItem->_updFlag) {
1025 Sequence *seqItem = seqFind(gfxItem->_sequenceId, gfxItem->_id, nullptr);
1026 if (!animation) {
1027 gfxItem->_sequenceId = -1;
1028 gfxItem->_animation = nullptr;
1029 gfxItem->_currFrame._duration = 0;
1030 gfxItem->_currFrame._spriteId = -1;
1031 gfxItem->_currFrame._soundId = -1;
1032 gfxItem->_updFlag = true;
1033 } else if (!seqItem) {
1034 gfxItem->_animation = nullptr;
1035 gfxItem->_currFrame._duration = 0;
1036 gfxItem->_currFrame._spriteId = -1;
1037 gfxItem->_currFrame._soundId = -1;
1038 gfxItem->_updFlag = true;
1039 } else if ((seqItem->_flags & kSeqUnk) && clockDelta > 1) {
1040 if (gfxItem->_delayTicks < clockDelta) {
1041 duration = clockDelta - gfxItem->_delayTicks;
1042 gfxItem->_delayTicks = 0;
1043 if (gfxItem->_prevFrame._duration <= duration)
1044 gfxItem->_prevFrame._duration = 1;
1045 else
1046 gfxItem->_prevFrame._duration -= duration;
1047 } else {
1048 gfxItem->_delayTicks -= clockDelta;
1049 }
1050 gfxItem->_updFlag = false;
1051 } else if (gfxItem->_delayTicks < clockDelta) {
1052 duration = clockDelta - gfxItem->_delayTicks;
1053 gfxItem->_delayTicks = 0;
1054 if (gfxItem->_prevFrame._duration <= duration) {
1055 bool v20 = false;
1056 if (gfxItem->_prevFrame._duration > 0) {
1057 duration -= gfxItem->_prevFrame._duration;
1058 gfxItem->_prevFrame._duration = -duration;
1059 } else {
1060 gfxItem->_prevFrame._duration = 0;
1061 v20 = true;
1062 }
1063 currFrameNum = gfxItem->_currFrameNum;
1064 if (animation->_framesCount > currFrameNum) {
1065 while (animation->_framesCount > currFrameNum
1066 && animation->frames[currFrameNum]._duration <= duration) {
1067 if (animation->frames[currFrameNum]._soundId != -1)
1068 _soundIds.push_back((gfxItem->_sequenceId & 0xFFFF0000) | animation->frames[currFrameNum]._soundId);
1069 duration -= animation->frames[currFrameNum]._duration;
1070 ++currFrameNum;
1071 }
1072 if (animation->_framesCount > currFrameNum)
1073 gfxItem->_currFrame = animation->frames[currFrameNum++];
1074 else
1075 gfxItem->_currFrame = animation->frames[currFrameNum - 1];
1076 if (gfxItem->_currFrame._spriteId != -1 && (seqItem->_x != 0 || seqItem->_y != 0))
1077 gfxItem->_currFrame._rect.translate(seqItem->_x, seqItem->_y);
1078 // Update sprite scaling
1079 if ((seqItem->_flags & kSeqScale) && gfxItem->_currFrame._rect.bottom >= _backgroundImageValue1 && gfxItem->_currFrame._rect.bottom <= _backgroundImageValue3) {
1080 int v17 = _backgroundImageValue2 + (gfxItem->_currFrame._rect.bottom - _backgroundImageValue1) *
1081 (_backgroundImageValue4 - _backgroundImageValue2) /
1082 (_backgroundImageValue3 - _backgroundImageValue1);
1083 gfxItem->_currFrame._rect.top = gfxItem->_currFrame._rect.bottom - v17 * (gfxItem->_currFrame._rect.bottom - gfxItem->_currFrame._rect.top) / 1000;
1084 gfxItem->_currFrame._rect.right = v17 * (gfxItem->_currFrame._rect.right - gfxItem->_currFrame._rect.left) / 1000 + gfxItem->_currFrame._rect.left;
1085 gfxItem->_currFrame._isScaled = true;
1086 }
1087 gfxItem->_currFrame._duration -= duration;
1088 if (gfxItem->_currFrame._soundId != -1)
1089 _soundIds.push_back((gfxItem->_sequenceId & 0xFFFF0000) | gfxItem->_currFrame._soundId);
1090 gfxItem->_currFrameNum = currFrameNum;
1091 gfxItem->_updFlag = true;
1092 } else if (v20 && gfxItem->_prevFrame._spriteId == -1) {
1093 --_gfxItemsCount;
1094 if (_gfxItemsCount != i)
1095 memmove(&_gfxItems[i], &_gfxItems[i + 1], sizeof(GfxItem) * (_gfxItemsCount - i));
1096 --i;
1097 } else {
1098 gfxItem->_updFlag = false;
1099 }
1100 } else {
1101 gfxItem->_prevFrame._duration -= duration;
1102 gfxItem->_updFlag = false;
1103 _animationsDone = false;
1104 }
1105 } else {
1106 gfxItem->_delayTicks -= clockDelta;
1107 gfxItem->_updFlag = false;
1108 _animationsDone = false;
1109 }
1110 }
1111 } else {
1112 --_gfxItemsCount;
1113 if (_gfxItemsCount != i)
1114 memmove(&_gfxItems[i], &_gfxItems[i + 1], sizeof(GfxItem) * (_gfxItemsCount - i));
1115 --i;
1116 }
1117 }
1118
1119 if (_newSpriteDrawItemsCount > 0) {
1120 debugC(kDebugBasic, "_newSpriteDrawItemsCount: %d", _newSpriteDrawItemsCount);
1121 for (int k = 0; k < _newSpriteDrawItemsCount; ++k) {
1122 // The original was allowing a buffer overflow.
1123 // In order to fit in memory, insertIndex + 1 + (_gfxItemsCount - InsertIndex) must be
1124 // smaller than the size _gfxItems array (50).
1125 if (_gfxItemsCount + 1 < 50) {
1126 int insertIndex;
1127 seqLocateGfx(-1, _newSpriteDrawItems[k]._id, &insertIndex);
1128 if (_gfxItemsCount != insertIndex)
1129 memmove(&_gfxItems[insertIndex + 1], &_gfxItems[insertIndex], sizeof(GfxItem) * (_gfxItemsCount - insertIndex));
1130 ++_gfxItemsCount;
1131 GfxItem *gfxItem = &_gfxItems[insertIndex];
1132 gfxItem->_sequenceId = -1;
1133 gfxItem->_id = _newSpriteDrawItems[k]._id;
1134 gfxItem->_animation = nullptr;
1135 gfxItem->_currFrameNum = 0;
1136 gfxItem->_flags = 1;
1137 gfxItem->_delayTicks = 0;
1138 gfxItem->_updFlag = true;
1139 gfxItem->_updRectsCount = 0;
1140 gfxItem->_surface = _newSpriteDrawItems[k]._surface;
1141 gfxItem->_prevFrame._duration = 0;
1142 gfxItem->_prevFrame._spriteId = -1;
1143 gfxItem->_prevFrame._soundId = -1;
1144 gfxItem->_currFrame._duration = 0;
1145 gfxItem->_currFrame._isScaled = false;
1146 gfxItem->_currFrame._rect = _newSpriteDrawItems[k]._rect;
1147 gfxItem->_currFrame._spriteId = _newSpriteDrawItems[k]._surface ? (int32)0xCAFEBABE : -1;// TODO
1148 gfxItem->_currFrame._soundId = -1;
1149 _animationsDone = false;
1150 }
1151 }
1152 _newSpriteDrawItemsCount = 0;
1153 }
1154
1155 if (_grabSpriteChanged) {
1156 for (int i = 0; i < _gfxItemsCount; ++i) {
1157 GfxItem *gfxItem = &_gfxItems[i];
1158 if (gfxItem->_sequenceId == -1 && !gfxItem->_animation && gfxItem->_flags
1159 && gfxItem->_id == _grabSpriteId && gfxItem->_surface == _grabSpriteSurface1) {
1160 gfxItem->_currFrame._duration = 0;
1161 gfxItem->_currFrame._isScaled = false;
1162 gfxItem->_currFrame._rect = _grabSpriteRect;
1163 gfxItem->_currFrame._spriteId = _grabSpriteSurface2 ? 1 : -1;// TODO
1164 gfxItem->_currFrame._soundId = -1;
1165 gfxItem->_updFlag = true;
1166 gfxItem->_surface = _grabSpriteSurface2;
1167 _animationsDone = false;
1168 break;
1169 }
1170 }
1171 _grabSpriteChanged = false;
1172 }
1173
1174 debugC(kDebugBasic, "GameSys::fatUpdateFrame() _fatSequenceItems.size(): %d", _fatSequenceItems.size());
1175
1176 for (uint i = 0; i < _fatSequenceItems.size(); ++i) {
1177 Sequence *seqItem = &_fatSequenceItems[i];
1178 if (((seqItem->_flags & kSeqSyncWait) || (seqItem->_flags & kSeqSyncExists)) && seqItem->_sequenceId2 != -1) {
1179 duration = 0;
1180 if (((seqItem->_flags & kSeqSyncExists) && seqLocateGfx(seqItem->_sequenceId2, seqItem->_id2, nullptr)) ||
1181 updateSequenceDuration(seqItem->_sequenceId2, seqItem->_id2, &duration)) {
1182 int index = -1;
1183 bool found = false;
1184 if (seqItem->_sequenceId2 == seqItem->_sequenceId && seqItem->_id == seqItem->_id2 &&
1185 seqFind(seqItem->_sequenceId, seqItem->_id, &index)) {
1186 _seqItems[index] = *seqItem;
1187 found = true;
1188 } else if (_seqItems.size() < 50) {
1189 index = _seqItems.size();
1190 _seqItems.push_back(*seqItem);
1191 found = true;
1192 }
1193 if (found) {
1194 _animationsDone = false;
1195 seqRemoveGfx(seqItem->_sequenceId2, seqItem->_id2);
1196 seqRemoveGfx(seqItem->_sequenceId, seqItem->_id);
1197 _fatSequenceItems.remove_at(i);
1198 --i;
1199 seqInsertGfx(index, duration);
1200 }
1201 }
1202 } else {
1203 if (seqItem->_totalDuration < clockDelta) {
1204 int index;
1205 bool found = false;
1206 duration = clockDelta - seqItem->_totalDuration;
1207 seqItem->_totalDuration = 0;
1208 if (seqFind(seqItem->_sequenceId, seqItem->_id, &index)) {
1209 _seqItems[index] = *seqItem;
1210 found = true;
1211 } else if (_seqItems.size() < 50) {
1212 index = _seqItems.size();
1213 _seqItems.push_back(*seqItem);
1214 found = true;
1215 }
1216 if (found) {
1217 _animationsDone = false;
1218 seqRemoveGfx(seqItem->_sequenceId, seqItem->_id);
1219 _fatSequenceItems.remove_at(i);
1220 --i;
1221 seqInsertGfx(index, duration - 1);
1222 }
1223 } else {
1224 seqItem->_totalDuration -= clockDelta;
1225 }
1226 }
1227 }
1228
1229 debugC(kDebugBasic, "GameSys::fatUpdateFrame() _seqItems.size(): %d", _seqItems.size());
1230
1231 for (uint i = 0; i < _seqItems.size(); ++i) {
1232 Sequence *seqItem = &_seqItems[i];
1233 if (seqLocateGfx(seqItem->_sequenceId, seqItem->_id, nullptr)) {
1234 updateAnimationsStatus(seqItem->_sequenceId, seqItem->_id);
1235 if (seqItem->_flags & kSeqLoop) {
1236 int gfxDuration;
1237 if (updateSequenceDuration(seqItem->_sequenceId, seqItem->_id, &gfxDuration)) {
1238 seqRemoveGfx(seqItem->_sequenceId, seqItem->_id);
1239 seqInsertGfx(i, gfxDuration);
1240 }
1241 _animationsDone = false;
1242 }
1243 } else {
1244 _seqItems.remove_at(i);
1245 --i;
1246 }
1247 }
1248 }
1249
fatUpdate()1250 void GameSys::fatUpdate() {
1251 debugC(kDebugBasic, "GameSys::fatUpdate() _gfxItemsCount: %d", _gfxItemsCount);
1252
1253 for (int i = 0; i < _gfxItemsCount; ++i) {
1254 _gfxItems[i]._updFlag = false;
1255 _gfxItems[i]._updRectsCount = 0;
1256 }
1257
1258 handleReqRemoveSequenceItem();
1259 handleReqRemoveSequenceItems();
1260 handleReqRemoveSpriteDrawItems();
1261
1262 fatUpdateFrame();
1263 }
1264
updatePlaySounds()1265 void GameSys::updatePlaySounds() {
1266 for (uint i = 0; i < _soundIds.size(); ++i)
1267 _vm->playSound(_soundIds[i], false);
1268 _soundIds.clear();
1269 }
1270
intersectRect(Common::Rect & intersectingRect,const Common::Rect & r1,const Common::Rect & r2)1271 bool intersectRect(Common::Rect &intersectingRect, const Common::Rect &r1, const Common::Rect &r2) {
1272 if (r1.intersects(r2)) {
1273 intersectingRect = r1.findIntersectingRect(r2);
1274 return true;
1275 } else
1276 return false;
1277 }
1278
1279 } // End of namespace Gnap
1280