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/scummsys.h"
24 #include "common/timer.h"
25
26 #include "asylum/system/screen.h"
27
28 #include "asylum/resources/actor.h"
29 #include "asylum/resources/script.h"
30 #include "asylum/resources/worldstats.h"
31
32 #include "asylum/system/graphics.h"
33
34 #include "asylum/views/scene.h"
35
36 #include "asylum/asylum.h"
37 #include "asylum/respack.h"
38
39 namespace Asylum {
40
41 int g_debugDrawRects;
42
43 #define TRANSPARENCY_TABLE_SIZE (256 * 256)
44
Screen(AsylumEngine * vm)45 Screen::Screen(AsylumEngine *vm) : _vm(vm) ,
46 _useColorKey(false), _transTableCount(0), _transTable(NULL), _transTableBuffer(NULL) {
47 _backBuffer.create(640, 480, Graphics::PixelFormat::createFormatCLUT8());
48
49 _flag = -1;
50 _clipRect = Common::Rect(0, 0, 640, 480);
51
52 memset(&_currentPalette, 0, sizeof(_currentPalette));
53 memset(&_mainPalette, 0, sizeof(_mainPalette));
54 _isFading = false;
55 _fadeStop = false;
56 _fadeResourceId = kResourceNone;
57 _fadeTicksWait = 0;
58 _fadeDelta = 0;
59
60 g_debugDrawRects = 0;
61 }
62
~Screen()63 Screen::~Screen() {
64 _vm->getTimerManager()->removeTimerProc(&paletteFadeTimer);
65
66 _backBuffer.free();
67
68 clearTransTables();
69 }
70
71 //////////////////////////////////////////////////////////////////////////
72 // Drawing
73 //////////////////////////////////////////////////////////////////////////
draw(ResourceId resourceId)74 void Screen::draw(ResourceId resourceId) {
75 draw(resourceId, 0, Common::Point(0, 0), kDrawFlagNone, kResourceNone, Common::Point(0, 0), false);
76 }
77
draw(ResourceId resourceId,uint32 frameIndex,const Common::Point & source,DrawFlags flags,bool colorKey)78 void Screen::draw(ResourceId resourceId, uint32 frameIndex, const Common::Point &source, DrawFlags flags, bool colorKey) {
79 draw(resourceId, frameIndex, source, flags, kResourceNone, Common::Point(0, 0), colorKey);
80 }
81
draw(ResourceId resourceId,uint32 frameIndex,const int16 (* srcPtr)[2],DrawFlags flags,bool colorKey)82 void Screen::draw(ResourceId resourceId, uint32 frameIndex, const int16 (*srcPtr)[2], DrawFlags flags, bool colorKey) {
83 draw(resourceId, frameIndex, Common::Point((*srcPtr)[0], (*srcPtr)[1]), flags, kResourceNone, Common::Point(0, 0), colorKey);
84 }
85
drawTransparent(ResourceId resourceId,uint32 frameIndex,const Common::Point & source,DrawFlags flags,uint32 transTableNum)86 void Screen::drawTransparent(ResourceId resourceId, uint32 frameIndex, const Common::Point &source, DrawFlags flags, uint32 transTableNum) {
87 byte *index = _transTable;
88 selectTransTable(transTableNum);
89
90 draw(resourceId, frameIndex, source, (DrawFlags)(flags | 0x90000000));
91
92 _transTable = index;
93 }
94
draw(ResourceId resourceId,uint32 frameIndex,const Common::Point & source,DrawFlags flags,ResourceId resourceIdDestination,const Common::Point & destination,bool colorKey)95 void Screen::draw(ResourceId resourceId, uint32 frameIndex, const Common::Point &source, DrawFlags flags, ResourceId resourceIdDestination, const Common::Point &destination, bool colorKey) {
96 // Get the frame to draw
97 GraphicResource *resource = new GraphicResource(_vm, resourceId);
98
99 draw(resource, frameIndex, source, flags, resourceIdDestination, destination, colorKey);
100
101 delete resource;
102 }
103
draw(GraphicResource * resource,uint32 frameIndex,const Common::Point & source,DrawFlags flags,bool colorKey)104 void Screen::draw(GraphicResource *resource, uint32 frameIndex, const Common::Point &source, DrawFlags flags, bool colorKey) {
105 draw(resource, frameIndex, source, flags, kResourceNone, Common::Point(0, 0), colorKey);
106 }
107
drawTransparent(GraphicResource * resource,uint32 frameIndex,const Common::Point & source,DrawFlags flags,uint32 transTableNum)108 void Screen::drawTransparent(GraphicResource *resource, uint32 frameIndex, const Common::Point &source, DrawFlags flags, uint32 transTableNum) {
109 byte *index = _transTable;
110 selectTransTable(transTableNum);
111
112 draw(resource, frameIndex, source, (DrawFlags)(flags | 0x90000000));
113
114 _transTable = index;
115 }
116
draw(GraphicResource * resource,uint32 frameIndex,const Common::Point & source,DrawFlags flags,ResourceId resourceIdDestination,const Common::Point & destination,bool colorKey)117 void Screen::draw(GraphicResource *resource, uint32 frameIndex, const Common::Point &source, DrawFlags flags, ResourceId resourceIdDestination, const Common::Point &destination, bool colorKey) {
118 GraphicFrame *frame = resource->getFrame(frameIndex);
119 ResourceEntry *resourceMask = NULL;
120
121 // Compute coordinates
122 Common::Rect src;
123 Common::Rect dest;
124 Common::Rect srcMask;
125 Common::Rect destMask;
126
127 dest.left = source.x + frame->x;
128 if (flags & kDrawFlagMirrorLeftRight) {
129 if (_flag == -1) {
130 if ((resource->getData().flags & 15) >= 2) {
131 dest.left = source.x + (int16)resource->getData().maxWidth - ((int16)frame->getWidth() + frame->x);
132 }
133 } else {
134 dest.left += (int16)(2 * (_flag - (frame->getHeight() * 2 - frame->x)));
135 }
136 }
137
138 dest.top = source.y + frame->y;
139 dest.right = dest.left + (int16)frame->getWidth();
140 dest.bottom = dest.top + (int16)frame->getHeight();
141
142 src.left = 0;
143 src.top = 0;
144 src.right = frame->getWidth();
145 src.bottom = frame->getHeight();
146
147 clip(&src, &dest, flags);
148
149 bool masked = false;
150 if (resourceIdDestination) {
151 masked = true;
152
153 // Get the resource to use as a mask
154 resourceMask = getResource()->get(resourceIdDestination);
155
156 // Adjust masked rectangles
157 srcMask = Common::Rect(0, 0, (int16)resourceMask->getData(4), (int16)resourceMask->getData(0));
158
159 destMask = Common::Rect(destination.x,
160 destination.y,
161 destination.x + (int16)resourceMask->getData(4),
162 destination.y + (int16)resourceMask->getData(0));
163
164 clip(&srcMask, &destMask, 0);
165
166 if (!dest.intersects(destMask))
167 masked = false;
168
169 if (g_debugDrawRects)
170 _backBuffer.frameRect(destMask, 0x125);
171 }
172
173 // Check src rectangle
174 if (!src.isValidRect())
175 return;
176
177 // Set the color key (always 0 if set)
178 _useColorKey = colorKey;
179
180 if (masked) {
181 if (!resourceMask)
182 error("[Screen::draw] Trying to draw masked with an invalid resource mask");
183
184 blitMasked(frame, &src, resourceMask->data + 8, &srcMask, &destMask, (uint16)resourceMask->getData(4), &dest, flags);
185 } else {
186 blit(frame, &src, &dest, flags);
187 }
188 }
189
190 //////////////////////////////////////////////////////////////////////////
191 // Misc
192 //////////////////////////////////////////////////////////////////////////
clear()193 void Screen::clear() {
194 _backBuffer.fillRect(Common::Rect(0, 0, 640, 480), 0);
195 copyBackBufferToScreen();
196 }
197
drawWideScreenBars(int16 barSize) const198 void Screen::drawWideScreenBars(int16 barSize) const {
199 if (barSize > 0) {
200 _vm->_system->lockScreen()->fillRect(Common::Rect(0, 0, 640, barSize), 0);
201 _vm->_system->unlockScreen();
202 _vm->_system->lockScreen()->fillRect(Common::Rect(0, 480 - barSize, 640, 480), 0);
203 _vm->_system->unlockScreen();
204 }
205 }
206
fillRect(int16 x,int16 y,int16 width,int16 height,uint32 color)207 void Screen::fillRect(int16 x, int16 y, int16 width, int16 height, uint32 color) {
208 _backBuffer.fillRect(Common::Rect(x, y, x + width, y + height), color);
209 }
210
copyBackBufferToScreen()211 void Screen::copyBackBufferToScreen() {
212 _vm->_system->copyRectToScreen((byte *)_backBuffer.getPixels(), _backBuffer.w, 0, 0, _backBuffer.w, _backBuffer.h);
213 }
214
clip(Common::Rect * source,Common::Rect * destination,int32 flags) const215 void Screen::clip(Common::Rect *source, Common::Rect *destination, int32 flags) const {
216 int16 diffLeft = _clipRect.left - destination->left;
217 if (diffLeft > 0) {
218 destination->left = _clipRect.left;
219
220 if (flags & 2)
221 source->right -= diffLeft;
222 else
223 source->left += diffLeft;
224 }
225
226 int16 diffRight = destination->right - _clipRect.right;
227 if (diffRight > 0) {
228 destination->right -= diffRight;
229
230 if (flags & 2)
231 source->left += diffRight;
232 else
233 source->right -= diffRight;
234 }
235
236 int16 diffTop = _clipRect.top - destination->top;
237 if (diffTop > 0) {
238 destination->top = _clipRect.top;
239 source->top += diffTop;
240 }
241
242 int16 diffBottom = destination->bottom - _clipRect.bottom;
243 if (diffBottom > 0) {
244 source->bottom -= diffBottom;
245 destination->bottom -= diffBottom;
246 }
247 }
248
249 //////////////////////////////////////////////////////////////////////////
250 // Palette
251 //////////////////////////////////////////////////////////////////////////
getPaletteData(ResourceId id)252 byte *Screen::getPaletteData(ResourceId id) {
253 ResourceEntry *resource = getResource()->get(id);
254
255 // Check that resource is a valid palette
256 byte flag = *(resource->data + 5);
257 if (!(flag & 32))
258 error("[Screen::getPaletteData] Invalid palette resource id %d (0x%X) with flag %d", id, id, flag);
259
260 return (resource->data + resource->getData(12));
261 }
262
loadGrayPalette()263 void Screen::loadGrayPalette() {
264 // Get the current action palette
265 ResourceId paletteId = getWorld()->actions[getScene()->getActor()->getActionIndex3()]->paletteResourceId;
266 if (!paletteId)
267 paletteId = getWorld()->currentPaletteId;
268
269 // Get the data
270 byte *paletteData = getPaletteData(paletteId);
271 paletteData += 4;
272
273 // Store grayscale data into our global palette
274 for (uint32 j = 3; j < ARRAYSIZE(_currentPalette) - 3; j += 3) {
275 uint32 gray = 4 * (paletteData[j] + paletteData[j + 1] + paletteData[j + 2]) / 3;
276 _currentPalette[j] = _currentPalette[j + 1] = _currentPalette[j + 2] = (byte)gray;
277 }
278 }
279
setPalette(ResourceId id)280 void Screen::setPalette(ResourceId id) {
281 byte *data = getPaletteData(id);
282
283 setupPalette(data + 4, data[2], READ_LE_UINT16(data));
284 }
285
setMainPalette(const byte * data)286 void Screen::setMainPalette(const byte *data) {
287 memcpy(&_mainPalette, data, sizeof(_mainPalette));
288 }
289
setupPalette(byte * buffer,int start,int count)290 void Screen::setupPalette(byte *buffer, int start, int count) {
291 // Check parameters
292 if (start < 0 || start > 256)
293 error("[Screen::setupPalette] Invalid start parameter (was: %d, valid: [0 ; 255])", start);
294
295 if ((count + start) > 256)
296 error("[Screen::setupPalette] Parameters go past the palette buffer (start: %d, count: %d with sum > 256)", start, count);
297
298 // TODO: Update transparent palette if needed
299
300 // Setup our main palette
301 if (count > 0) {
302 byte *palette = (byte *)_mainPalette;
303 palette += start;
304
305 for (int32 i = 0; i < count; i++) {
306 palette[0] = (byte)(buffer[0] * 4);
307 palette[1] = (byte)(buffer[1] * 4);
308 palette[2] = (byte)(buffer[2] * 4);
309
310 buffer += 3;
311 palette += 3;
312 }
313 }
314
315 // Change the system palette
316 _vm->_system->getPaletteManager()->setPalette(_mainPalette, 0, 256);
317 }
318
updatePalette()319 void Screen::updatePalette() {
320 // FIXME: This is used to replace all the inline code to setup the palette before calls to setupPalette/paletteFade
321 // See if all that code can really be factorized into a single function or not
322 debugC(kDebugLevelScene, "[Screen::updatePalette] Not implemented!");
323 }
324
updatePalette(int32 param)325 void Screen::updatePalette(int32 param) {
326 if (param >= 21) {
327 for (uint32 j = 3; j < ARRAYSIZE(_mainPalette) - 3; j += 3) {
328 _mainPalette[j] = _currentPalette[j];
329 _mainPalette[j + 1] = _currentPalette[j + 1];
330 _mainPalette[j + 2] = _currentPalette[j + 2];
331 }
332
333 setupPalette(NULL, 0, 0);
334 paletteFade(0, 25, 10);
335 } else {
336 // Get the current action palette
337 ResourceId paletteId = getWorld()->actions[getScene()->getActor()->getActionIndex3()]->paletteResourceId;
338 if (!paletteId)
339 paletteId = getWorld()->currentPaletteId;
340
341 // Get the data
342 byte *paletteData = getPaletteData(paletteId);
343 paletteData += 4;
344
345 float fParam = param / 20.0;
346 for (uint32 j = 3; j < ARRAYSIZE(_mainPalette) - 3; j += 3) {
347 _mainPalette[j] = (byte)((1.0 - fParam) * 4 * paletteData[j] + fParam * _currentPalette[j]);
348 _mainPalette[j + 1] = (byte)((1.0 - fParam) * 4 * paletteData[j + 1] + fParam * _currentPalette[j + 1]);
349 _mainPalette[j + 2] = (byte)((1.0 - fParam) * 4 * paletteData[j + 2] + fParam * _currentPalette[j + 2]);
350 }
351
352 setupPalette(NULL, 0, 0);
353 }
354 }
355
356 //////////////////////////////////////////////////////////////////////////
357 // Palette fading
358 //////////////////////////////////////////////////////////////////////////
paletteFadeTimer(void * refCon)359 void Screen::paletteFadeTimer(void *refCon) {
360 ((Screen *)refCon)->handlePaletteFadeTimer();
361 }
362
handlePaletteFadeTimer()363 void Screen::handlePaletteFadeTimer() {
364 // Reset flag
365 _fadeStop = false;
366
367 // Start fading
368 _isFading = true;
369
370 paletteFadeWorker(_fadeResourceId, _fadeTicksWait, _fadeDelta);
371
372 // Remove ourselves as a timer (we finished fading or were interrupted)
373 _vm->getTimerManager()->removeTimerProc(&paletteFadeTimer);
374
375 _isFading = false;
376 }
377
startPaletteFade(ResourceId resourceId,int32 ticksWait,int32 delta)378 void Screen::startPaletteFade(ResourceId resourceId, int32 ticksWait, int32 delta) {
379 if (_isFading && resourceId == _fadeResourceId)
380 return;
381
382 stopPaletteFadeTimer();
383 _fadeResourceId = resourceId;
384 _fadeTicksWait = ticksWait;
385 _fadeDelta = delta;
386
387 // Inverval == 1: we want to execute directly, since we are only going to be called back once
388 _vm->getTimerManager()->installTimerProc(&paletteFadeTimer, 1, this, "Palette fade timer");
389 }
390
stopPaletteFade(char red,char green,char blue)391 void Screen::stopPaletteFade(char red, char green, char blue) {
392 // Setup main palette
393 byte *palette = (byte *)&_mainPalette;
394 palette += 4;
395
396 for (uint32 i = 0; i < ARRAYSIZE(_mainPalette) - 3; i += 3) {
397 palette[0] = (byte)red;
398 palette[1] = (byte)green;
399 palette[2] = (byte)blue;
400
401 palette += 3;
402 }
403
404 stopPaletteFadeTimer();
405 setupPalette(NULL, 0, 0);
406 }
407
stopPaletteFadeAndSet(ResourceId id,int32 ticksWait,int32 delta)408 void Screen::stopPaletteFadeAndSet(ResourceId id, int32 ticksWait, int32 delta) {
409 stopPaletteFadeTimer();
410 paletteFadeWorker(id, ticksWait, delta);
411 }
412
paletteFade(uint32 start,int32 ticksWait,int32 delta)413 void Screen::paletteFade(uint32 start, int32 ticksWait, int32 delta) {
414 if (start > 255 || ticksWait < 0 || delta <= 0)
415 return;
416
417 byte palette[PALETTE_SIZE];
418 memcpy(&palette, &_mainPalette, sizeof(palette));
419
420 // Prepare for palette fading loop
421 int32 colorDelta = delta + 1;
422 byte red = palette[3 * start];
423 byte green = palette[3 * start + 1];
424 byte blue = palette[3 * start + 2];
425
426 for (int32 i = 1; i < colorDelta; i++) {
427 for (uint32 j = 3; j < ARRAYSIZE(_mainPalette) - 3; j += 3) {
428 _mainPalette[j] = (byte)(palette[j] + i * (red - palette[j]) / colorDelta);
429 _mainPalette[j + 1] = (byte)(palette[j + 1] + i * (green - palette[j + 1]) / colorDelta);
430 _mainPalette[j + 2] = (byte)(palette[j + 2] + i * (blue - palette[j + 2]) / colorDelta);
431 }
432
433 setupPalette(NULL, 0, 0);
434
435 g_system->delayMillis((uint32)ticksWait);
436
437 // Poll events (this ensure we don't freeze the screen)
438 Common::Event ev;
439 do {
440 } while (_vm->getEventManager()->pollEvent(ev));
441
442 // Refresh the screen
443 g_system->updateScreen();
444 }
445 }
446
paletteFadeWorker(ResourceId id,int32 ticksWait,int32 delta)447 void Screen::paletteFadeWorker(ResourceId id, int32 ticksWait, int32 delta) {
448 byte *data = getPaletteData(id);
449
450 if (ticksWait < 0 || delta <= 0)
451 return;
452
453 // Setup our palette
454 byte original[PALETTE_SIZE];
455 byte palette[PALETTE_SIZE];
456 memcpy(&original, &_mainPalette, sizeof(original));
457 memcpy(&palette, &_mainPalette, sizeof(palette));
458
459 // Adjust palette using the target palette data
460 int16 count = READ_LE_UINT16(data);
461 byte start = data[2];
462 if (count > 0) {
463 byte *pData = data + 4;
464
465 for (int16 i = 0; i < count; i++) {
466 palette[i + start] = (byte)(4 * pData[0]);
467 palette[i + start + 1] = (byte)(4 * pData[1]);
468 palette[i + start + 2] = (byte)(4 * pData[2]);
469
470 pData += 3;
471 }
472 }
473
474 // Adjust gamma
475 setPaletteGamma(data, (byte *)&palette);
476
477 // Prepare for palette fading loop
478 int32 colorDelta = delta + 1;
479 for (int32 i = 1; i < colorDelta; i++) {
480 for (uint32 j = 3; j < ARRAYSIZE(_mainPalette) - 3; j += 3) {
481 _mainPalette[j] = (byte)(original[j] + i * (palette[j] - original[j]) / colorDelta);
482 _mainPalette[j + 1] = (byte)(original[j + 1] + i * (palette[j + 1] - original[j + 1]) / colorDelta);
483 _mainPalette[j + 2] = (byte)(original[j + 2] + i * (palette[j + 2] - original[j + 2]) / colorDelta);
484 }
485
486 setupPalette(NULL, 0, 0);
487
488 // Original waits for event and so can be interrupted in the middle of the wait
489 g_system->delayMillis((uint32)ticksWait);
490 if (_fadeStop)
491 break;
492
493 // Refresh the screen
494 g_system->updateScreen();
495 }
496 }
497
stopPaletteFadeTimer()498 void Screen::stopPaletteFadeTimer() {
499 if (!_isFading)
500 return;
501
502 // Signal timer to exit its main loop
503 _fadeStop = true;
504 }
505
506 //////////////////////////////////////////////////////////////////////////
507 // Gamma
508 //////////////////////////////////////////////////////////////////////////
setPaletteGamma(ResourceId id)509 void Screen::setPaletteGamma(ResourceId id) {
510 setPaletteGamma(getPaletteData(id));
511 }
512
setPaletteGamma(byte * data,byte * target)513 void Screen::setPaletteGamma(byte *data, byte *target) {
514 if (target == NULL)
515 target = (byte *)&_mainPalette;
516
517 // Skip first entry
518 data += 4;
519
520 for (int32 i = 1; i < 256; i++) {
521 byte color = 0;
522 if (data[0] > 0)
523 color = data[0];
524 if (data[1] > color)
525 color = data[1];
526 if (data[2] > color)
527 color = data[2];
528
529 int gamma = color + (Config.gammaLevel * (63 - color) + 31) / 63;
530
531 if (gamma && color != 0) {
532 if (data[0])
533 target[0] = (byte)(4 * ((color >> 1) + data[0] * gamma) / color);
534 if (data[1])
535 target[1] = (byte)(4 * ((color >> 1) + data[1] * gamma) / color);
536 if (data[2])
537 target[2] = (byte)(4 * ((color >> 1) + data[2] * gamma) / color);
538 }
539
540 // Advance palette data
541 target += 3;
542 data += 3;
543 }
544 }
545
setGammaLevel(ResourceId id)546 void Screen::setGammaLevel(ResourceId id) {
547 if (!Config.gammaLevel)
548 return;
549
550 if (!id)
551 error("[Screen::setGammaLevel] Resource Id is invalid");
552
553 setPaletteGamma(getPaletteData(id));
554 setupPalette(NULL, 0, 0);
555 }
556
557 //////////////////////////////////////////////////////////////////////////
558 // Transparency tables
559 //////////////////////////////////////////////////////////////////////////
setupTransTable(ResourceId resourceId)560 void Screen::setupTransTable(ResourceId resourceId) {
561 if (resourceId)
562 setupTransTables(1, resourceId);
563 else
564 setupTransTables(0);
565 }
566
setupTransTables(uint32 count,...)567 void Screen::setupTransTables(uint32 count, ...) {
568 if (!count) {
569 clearTransTables();
570 return;
571 }
572
573 // Load tables
574 va_list va;
575 va_start(va, count);
576
577 if (_transTableCount != count)
578 clearTransTables();
579
580 _transTableCount = count;
581
582 if (!_transTableBuffer) {
583 _transTableBuffer = (byte *)malloc(count * TRANSPARENCY_TABLE_SIZE);
584 if (!_transTableBuffer)
585 error("[Screen::setupTransTables] Cannot allocate memory for transparency table buffer");
586
587 _transTable = _transTableBuffer;
588 }
589
590 uint32 index = 0;
591 for (uint32 i = 0; i < _transTableCount; i++) {
592 ResourceId id = va_arg(va, ResourceId);
593
594 memcpy(&_transTableBuffer[index], getResource()->get(id)->data, TRANSPARENCY_TABLE_SIZE);
595 index += TRANSPARENCY_TABLE_SIZE;
596 }
597 }
598
clearTransTables()599 void Screen::clearTransTables() {
600 free(_transTableBuffer);
601 _transTableBuffer = NULL;
602 _transTable = NULL;
603 _transTableCount = 0;
604 }
605
selectTransTable(uint32 index)606 void Screen::selectTransTable(uint32 index) {
607 if (!_transTableBuffer)
608 error("[Screen::selectTransTable] Transparency table buffer not initialized");
609
610 if (index >= _transTableCount)
611 return;
612
613 _transTable = &_transTableBuffer[TRANSPARENCY_TABLE_SIZE * index];
614 }
615
616 //////////////////////////////////////////////////////////////////////////
617 // Graphic queue
618 //////////////////////////////////////////////////////////////////////////
addGraphicToQueue(ResourceId resourceId,uint32 frameIndex,const Common::Point & point,DrawFlags flags,int32 transTableNum,int32 priority)619 void Screen::addGraphicToQueue(ResourceId resourceId, uint32 frameIndex, const Common::Point &point, DrawFlags flags, int32 transTableNum, int32 priority) {
620 GraphicQueueItem item;
621 item.priority = priority;
622
623 item.type = kGraphicItemNormal;
624 item.source = point;
625 item.resourceId = resourceId;
626 item.frameIndex = frameIndex;
627 item.flags = flags;
628 item.transTableNum = transTableNum;
629
630 _queueItems.push_back(item);
631 }
632
addGraphicToQueue(ResourceId resourceId,uint32 frameIndex,const int16 (* pointPtr)[2],DrawFlags flags,int32 transTableNum,int32 priority)633 void Screen::addGraphicToQueue(ResourceId resourceId, uint32 frameIndex, const int16 (*pointPtr)[2], DrawFlags flags, int32 transTableNum, int32 priority) {
634 addGraphicToQueue(resourceId, frameIndex, Common::Point((*pointPtr)[0], (*pointPtr)[1]), flags, transTableNum, priority);
635 }
636
addGraphicToQueueMasked(ResourceId resourceId,uint32 frameIndex,const Common::Point & source,int32 resourceIdDestination,const Common::Point & destination,DrawFlags flags,int32 priority)637 void Screen::addGraphicToQueueMasked(ResourceId resourceId, uint32 frameIndex, const Common::Point &source, int32 resourceIdDestination, const Common::Point &destination, DrawFlags flags, int32 priority) {
638 GraphicQueueItem item;
639 item.priority = priority;
640
641 item.type = kGraphicItemMasked;
642 item.source = source;
643 item.resourceId = resourceId;
644 item.frameIndex = frameIndex;
645 item.flags = flags;
646 item.resourceIdDestination = resourceIdDestination;
647 item.destination = destination;
648
649 _queueItems.push_back(item);
650 }
651
addGraphicToQueueCrossfade(ResourceId resourceId,uint32 frameIndex,const Common::Point & point,int32 objectResourceId,const Common::Point & destination,uint32 transTableNum)652 void Screen::addGraphicToQueueCrossfade(ResourceId resourceId, uint32 frameIndex, const Common::Point &point, int32 objectResourceId, const Common::Point &destination, uint32 transTableNum) {
653 // Save current transparency index
654 byte *transparencyIndex= _transTable;
655 selectTransTable(transTableNum);
656
657 // Get graphic frames
658 GraphicResource *resource = new GraphicResource(_vm, resourceId);
659 GraphicFrame *frame = resource->getFrame(frameIndex);
660
661 GraphicResource *resourceObject = new GraphicResource(_vm, objectResourceId);
662 GraphicFrame *frameObject = resourceObject->getFrame(0);
663
664 // Compute rectangles
665 Common::Rect src(0, 0, frame->getWidth(), frame->getHeight());
666 Common::Rect dst = src;
667 dst.translate(point.x + frame->x, point.y + frame->y);
668
669 clip(&src, &dst, 0);
670 if (src.isValidRect()) {
671 // Set the color key (always 0)
672 _useColorKey = true;
673
674 blitCrossfade((byte *)_backBuffer.getPixels() + dst.top * _backBuffer.pitch + dst.left,
675 (byte *)frame->surface.getPixels() + src.top * frame->surface.pitch + src.left,
676 (byte *)frameObject->surface.getPixels() + (destination.y + dst.top) * frameObject->surface.pitch + (dst.left + destination.x),
677 dst.height(),
678 dst.width(),
679 (uint16)(frame->surface.pitch - dst.width()),
680 (uint16)(_backBuffer.pitch - dst.width()),
681 (uint16)(frameObject->surface.pitch - dst.width()));
682 }
683
684 // Restore transparency table
685 _transTable = transparencyIndex;
686
687 delete resource;
688 delete resourceObject;
689 }
690
addGraphicToQueue(GraphicQueueItem const & item)691 void Screen::addGraphicToQueue(GraphicQueueItem const &item) {
692 _queueItems.push_back(item);
693 }
694
graphicQueueItemComparator(const GraphicQueueItem & item1,const GraphicQueueItem & item2)695 bool Screen::graphicQueueItemComparator(const GraphicQueueItem &item1, const GraphicQueueItem &item2) {
696 return item1.priority > item2.priority;
697 }
698
drawGraphicsInQueue()699 void Screen::drawGraphicsInQueue() {
700 // Sort by priority first
701 Common::sort(_queueItems.begin(), _queueItems.end(), &Screen::graphicQueueItemComparator);
702
703 for (Common::Array<GraphicQueueItem>::const_iterator i = _queueItems.begin(); i != _queueItems.end(); i++) {
704 const GraphicQueueItem *item = i;
705
706 if (item->type == kGraphicItemNormal) {
707 if (item->transTableNum <= 0 || Config.performance <= 1)
708 draw(item->resourceId, item->frameIndex, item->source, item->flags);
709 else
710 drawTransparent(item->resourceId, item->frameIndex, item->source, item->flags, (uint32)(item->transTableNum - 1));
711 } else if (item->type == kGraphicItemMasked) {
712 draw(item->resourceId, item->frameIndex, item->source, item->flags, item->resourceIdDestination, item->destination);
713 }
714 }
715 }
716
clearGraphicsInQueue()717 void Screen::clearGraphicsInQueue() {
718 _queueItems.clear();
719 }
720
deleteGraphicFromQueue(ResourceId resourceId)721 void Screen::deleteGraphicFromQueue(ResourceId resourceId) {
722 for (uint32 i = 0; i < _queueItems.size(); i++) {
723 if (_queueItems[i].resourceId == resourceId) {
724 _queueItems.remove_at(i);
725 break;
726 }
727 }
728 }
729
730 //////////////////////////////////////////////////////////////////////////
731 // Graphic Data
732 //////////////////////////////////////////////////////////////////////////
blit(GraphicFrame * frame,Common::Rect * source,Common::Rect * destination,int32 flags)733 void Screen::blit(GraphicFrame *frame, Common::Rect *source, Common::Rect *destination, int32 flags) {
734 if (!_transTable)
735 error("[Screen::blit] Transparency table buffer not initialized");
736
737 if ((uint32)flags & 0x80000000) {
738 // Used in the menu (and more?)
739
740 int32 flagSet = flags & 0x7FFFFFFF;
741 bool hasTransTableIndex = false;
742
743 if (flags & 0x10000000) {
744 flagSet = flags & 0x6FFFFFFF;
745 hasTransTableIndex = (_transTable ? true : false);
746 }
747
748 bool isMirrored = (flagSet == kDrawFlagMirrorLeftRight);
749
750 if (hasTransTableIndex) {
751 if (isMirrored) {
752 blitTranstableMirrored((byte *)_backBuffer.getPixels() + destination->top * _backBuffer.pitch + destination->left,
753 (byte *)frame->surface.getPixels() + source->top * frame->surface.pitch + source->right - 1,
754 destination->height(),
755 destination->width(),
756 (uint16)destination->width() + frame->surface.pitch,
757 _backBuffer.pitch - (uint16)destination->width());
758 } else {
759 blitTranstable((byte *)_backBuffer.getPixels() + destination->top * _backBuffer.pitch + destination->left,
760 (byte *)frame->surface.getPixels() + source->top * frame->surface.pitch + source->left,
761 destination->height(),
762 destination->width(),
763 frame->surface.pitch - (uint16)destination->width(),
764 _backBuffer.pitch - (uint16)destination->width());
765 }
766 } else if (flagSet) {
767 if (isMirrored) {
768 if (_useColorKey) {
769 blitMirroredColorKey((byte *)_backBuffer.getPixels() + destination->top * _backBuffer.pitch + destination->left,
770 (byte *)frame->surface.getPixels() + source->top * frame->surface.pitch + source->right,
771 destination->height(),
772 destination->width(),
773 frame->surface.pitch + (uint16)destination->width(),
774 _backBuffer.pitch - (uint16)destination->width());
775 } else {
776 blitMirrored((byte *)_backBuffer.getPixels() + destination->top * _backBuffer.pitch + destination->left,
777 (byte *)frame->surface.getPixels() + source->top * frame->surface.pitch + source->right,
778 destination->height(),
779 destination->width(),
780 frame->surface.pitch + (uint16)destination->width(),
781 _backBuffer.pitch - (uint16)destination->width());
782 }
783 }
784 } else {
785 if (_useColorKey) {
786 blitRawColorKey((byte *)_backBuffer.getPixels() + destination->top * _backBuffer.pitch + destination->left,
787 (byte *)frame->surface.getPixels() + source->top * frame->surface.pitch + source->left,
788 destination->height(),
789 destination->width(),
790 frame->surface.pitch - (uint16)destination->width(),
791 _backBuffer.pitch - (uint16)destination->width());
792 } else {
793 blitRaw((byte *)_backBuffer.getPixels() + destination->top * _backBuffer.pitch + destination->left,
794 (byte *)frame->surface.getPixels() + source->top * frame->surface.pitch + source->left,
795 destination->height(),
796 destination->width(),
797 frame->surface.pitch - (uint16)destination->width(),
798 _backBuffer.pitch - (uint16)destination->width());
799 }
800 }
801 } else if (flags) {
802 blt(destination, frame, source, flags);
803 } else {
804 bltFast(destination->left, destination->top, frame, source);
805 }
806
807 if (g_debugDrawRects)
808 _backBuffer.frameRect(*destination, 0x220);
809 }
810
blitTranstable(byte * dstBuffer,byte * srcBuffer,int16 height,int16 width,uint16 srcPitch,uint16 dstPitch) const811 void Screen::blitTranstable(byte *dstBuffer, byte *srcBuffer, int16 height, int16 width, uint16 srcPitch, uint16 dstPitch) const {
812 if (!_transTable)
813 error("[Screen::blitTranstable] Transparency table buffer not initialized");
814
815 while (height--) {
816 for (int16 i = width; i; --i) {
817 if (*srcBuffer)
818 *dstBuffer = _transTable[(*srcBuffer << 8) + *dstBuffer];
819
820 dstBuffer++;
821 srcBuffer++;
822 }
823
824 dstBuffer += dstPitch;
825 srcBuffer += srcPitch;
826 }
827 }
828
blitTranstableMirrored(byte * dstBuffer,byte * srcBuffer,int16 height,int16 width,uint16 srcPitch,uint16 dstPitch) const829 void Screen::blitTranstableMirrored(byte *dstBuffer, byte *srcBuffer, int16 height, int16 width, uint16 srcPitch, uint16 dstPitch) const {
830 if (!_transTable)
831 error("[Screen::blitTranstableMirrored] Transparency table buffer not initialized");
832
833 while (height--) {
834 for (int16 i = width; i; --i) {
835 if (*srcBuffer)
836 *dstBuffer = _transTable[(*srcBuffer << 8) + *dstBuffer];
837
838 dstBuffer++;
839 srcBuffer--;
840 }
841
842 dstBuffer += dstPitch;
843 srcBuffer += srcPitch;
844 }
845 }
846
blitCrossfade(byte * dstBuffer,byte * srcBuffer,byte * objectBuffer,int16 height,int16 width,uint16 srcPitch,uint16 dstPitch,uint16 objectPitch) const847 void Screen::blitCrossfade(byte *dstBuffer, byte *srcBuffer, byte *objectBuffer, int16 height, int16 width, uint16 srcPitch, uint16 dstPitch, uint16 objectPitch) const {
848 if (!_transTable)
849 error("[Screen::blitCrossfade] Transparency table buffer not initialized");
850
851 while (height--) {
852 for (int16 i = width; i; --i) {
853 if (*srcBuffer)
854 *dstBuffer = _transTable[(*srcBuffer << 8) + *objectBuffer];
855
856 dstBuffer++;
857 srcBuffer++;
858 objectBuffer++;
859 }
860
861 dstBuffer += dstPitch;
862 srcBuffer += srcPitch;
863 objectBuffer += objectPitch;
864 }
865 }
866
blitMirrored(byte * dstBuffer,byte * srcBuffer,int16 height,int16 width,uint16 srcPitch,uint16 dstPitch) const867 void Screen::blitMirrored(byte *dstBuffer, byte *srcBuffer, int16 height, int16 width, uint16 srcPitch, uint16 dstPitch) const {
868 while (height--) {
869 for (int16 i = width; i; --i) {
870 *dstBuffer = *srcBuffer;
871
872 dstBuffer++;
873 srcBuffer--;
874 }
875
876 dstBuffer += dstPitch;
877 srcBuffer += srcPitch;
878 }
879 }
880
blitMirroredColorKey(byte * dstBuffer,byte * srcBuffer,int16 height,int16 width,uint16 srcPitch,uint16 dstPitch) const881 void Screen::blitMirroredColorKey(byte *dstBuffer, byte *srcBuffer, int16 height, int16 width, uint16 srcPitch, uint16 dstPitch) const {
882 while (height--) {
883 for (int16 i = width; i; --i) {
884 if (*srcBuffer != 0)
885 *dstBuffer = *srcBuffer;
886
887 dstBuffer++;
888 srcBuffer--;
889 }
890
891 dstBuffer += dstPitch;
892 srcBuffer += srcPitch;
893 }
894 }
895
blitRaw(byte * dstBuffer,byte * srcBuffer,int16 height,int16 width,uint16 srcPitch,uint16 dstPitch) const896 void Screen::blitRaw(byte *dstBuffer, byte *srcBuffer, int16 height, int16 width, uint16 srcPitch, uint16 dstPitch) const {
897 while (height--) {
898 memcpy(dstBuffer, srcBuffer, (uint16)width);
899 dstBuffer += dstPitch;
900 srcBuffer += srcPitch;
901 }
902 }
903
blitRawColorKey(byte * dstBuffer,byte * srcBuffer,int16 height,int16 width,uint16 srcPitch,uint16 dstPitch) const904 void Screen::blitRawColorKey(byte *dstBuffer, byte *srcBuffer, int16 height, int16 width, uint16 srcPitch, uint16 dstPitch) const {
905 while (height--) {
906 for (int16 i = width; i; --i) {
907 if (*srcBuffer != 0)
908 *dstBuffer = *srcBuffer;
909
910 dstBuffer++;
911 srcBuffer++;
912 }
913
914 dstBuffer += dstPitch;
915 srcBuffer += srcPitch;
916 }
917 }
918
blitMasked(GraphicFrame * frame,Common::Rect * source,byte * maskData,Common::Rect * sourceMask,Common::Rect * destMask,uint16 maskWidth,Common::Rect * destination,int32 flags)919 void Screen::blitMasked(GraphicFrame *frame, Common::Rect *source, byte *maskData, Common::Rect *sourceMask, Common::Rect *destMask, uint16 maskWidth, Common::Rect *destination, int32 flags) {
920 byte *frameBuffer = (byte *)frame->surface.getPixels();
921 byte *mirroredBuffer = NULL;
922 int16 frameRight = frame->surface.pitch;
923 uint16 maskHeight = (uint16)sourceMask->height(); // for debugging only
924 byte nSkippedBits = ABS(sourceMask->left) % 8;
925
926 // Prepare temporary source buffer if needed
927 if (flags & kDrawFlagMirrorLeftRight) {
928 mirroredBuffer = (byte *)malloc((size_t)(source->right * source->bottom));
929 if (!mirroredBuffer)
930 error("[Screen::blitMasked] Cannot allocate buffer for mirrored surface");
931
932 blitMirrored(mirroredBuffer,
933 frameBuffer + source->right - 1,
934 source->bottom,
935 source->right,
936 (uint16)(source->right + frame->surface.pitch),
937 0);
938
939 frameBuffer = mirroredBuffer;
940 frameRight = source->right;
941
942 source->right -= source->left;
943 source->left = 0;
944 }
945
946 // Setup buffers and rectangles
947 byte *frameBufferPtr = frameBuffer + source->top * frameRight + source->left;
948 byte *maskBufferPtr = maskData + sourceMask->top * (maskWidth / 8) + sourceMask->left / 8;
949
950 // Check if we need to draw masked
951 if ((destMask->left + sourceMask->width()) < destination->left
952 || (destination->left + source->width()) < destMask->left
953 || (destMask->top + sourceMask->height()) < destination->top
954 || (destination->top + source->height()) < destMask->top) {
955
956 blitRawColorKey((byte *)_backBuffer.getPixels() + destination->top * _backBuffer.pitch + destination->left,
957 frameBufferPtr,
958 source->height(),
959 source->width(),
960 (uint16)(frameRight - source->width()),
961 (uint16)(_backBuffer.pitch - source->width()));
962
963 // cleanup
964 free(mirroredBuffer);
965
966 // Draw debug rects
967 if (g_debugDrawRects)
968 _backBuffer.frameRect(*destMask, 0x220);
969
970 return;
971 }
972
973 if (destination->left > destMask->left) {
974 nSkippedBits += ABS(destination->left - destMask->left) % 8;
975 maskBufferPtr += (destination->left - destMask->left) / 8 + nSkippedBits / 8;
976 nSkippedBits %= 8;
977 sourceMask->setWidth(sourceMask->width() + destMask->left - destination->left);
978 destMask->left = destination->left;
979 }
980
981 if (destination->top > destMask->top) {
982 maskBufferPtr += (destination->top - destMask->top) * maskWidth / 8;
983 sourceMask->setHeight(sourceMask->height() + destMask->top - destination->top);
984 destMask->top = destination->top;
985 }
986
987 //////////////////////////////////////////////////////////////////////////
988 // Left part
989 if (destination->left < destMask->left) {
990 blitRawColorKey((byte *)_backBuffer.getPixels() + destination->top * _backBuffer.pitch + destination->left,
991 frameBufferPtr,
992 source->height(),
993 destMask->left - destination->left,
994 (uint16)(frameRight + destination->left - destMask->left),
995 (uint16)(_backBuffer.pitch + destination->left - destMask->left));
996
997 if (g_debugDrawRects)
998 _backBuffer.frameRect(Common::Rect(destination->left, destination->top, destMask->left, destination->top + source->height()), 0x10);
999
1000 frameBufferPtr += destMask->left - destination->left;
1001 source->setWidth(source->width() + destination->left - destMask->left);
1002 destination->left = destMask->left;
1003 }
1004
1005 //////////////////////////////////////////////////////////////////////////
1006 // Right part
1007 if ((source->width() + destination->left) > (destMask->left + sourceMask->width())) {
1008 blitRawColorKey((byte *)_backBuffer.getPixels() + destination->top * _backBuffer.pitch + destMask->left + sourceMask->width(),
1009 frameBufferPtr + destMask->left + sourceMask->width() - destination->left,
1010 source->height(),
1011 source->width() + destination->left - (destMask->left + sourceMask->width()),
1012 (uint16)(frameRight + destMask->left + sourceMask->width() - (destination->left + source->width())),
1013 (uint16)(_backBuffer.pitch + destMask->left + sourceMask->width() - (destination->left + source->width())));
1014
1015 if (g_debugDrawRects)
1016 _backBuffer.frameRect(Common::Rect(destMask->left, destination->top, destMask->left + source->width(), destination->top + source->height()), 0x36);
1017
1018 source->setWidth(destMask->left + sourceMask->width() - destination->left);
1019 }
1020
1021 //////////////////////////////////////////////////////////////////////////
1022 // Top part
1023 if (destination->top < destMask->top) {
1024 blitRawColorKey((byte *)_backBuffer.getPixels() + destination->top * _backBuffer.pitch + destination->left,
1025 frameBufferPtr,
1026 destMask->top - destination->top,
1027 source->width(),
1028 (uint16)(frameRight - source->width()),
1029 (uint16)(_backBuffer.pitch - source->width()));
1030
1031 if (g_debugDrawRects)
1032 _backBuffer.frameRect(Common::Rect(destination->left, destination->top, destination->left + source->width(), destMask->top), 0x23);
1033
1034 frameBufferPtr += (destMask->top - destination->top) * frameRight;
1035 source->setHeight(source->height() + destination->top - destMask->top);
1036 destination->top = destMask->top;
1037 }
1038
1039 //////////////////////////////////////////////////////////////////////////
1040 // Bottom part
1041 if ((source->height() + destination->top) > (destMask->top + sourceMask->height())) {
1042 blitRawColorKey((byte *)_backBuffer.getPixels() + (destMask->top + sourceMask->height()) * _backBuffer.pitch + destination->left,
1043 frameBufferPtr + (destMask->top + sourceMask->height() - destination->top) * frameRight,
1044 destination->top + source->height() - (sourceMask->height() + destMask->top),
1045 source->width(),
1046 (uint16)(frameRight - source->width()),
1047 (uint16)(_backBuffer.pitch - source->width()));
1048
1049 source->setHeight(destMask->top + sourceMask->height() - destination->top);
1050 }
1051
1052 //////////////////////////////////////////////////////////////////////////
1053 // Masked part
1054 bltMasked(frameBufferPtr,
1055 maskBufferPtr,
1056 source->height(),
1057 source->width(),
1058 (uint16)(frameRight - source->width()),
1059 (uint16)(maskWidth - (nSkippedBits + source->width())) / 8,
1060 nSkippedBits,
1061 (byte *)_backBuffer.getPixels() + _backBuffer.pitch * destination->top + destination->left,
1062 (uint16)(_backBuffer.pitch - source->width()));
1063
1064 // Draw debug rects
1065 if (g_debugDrawRects) {
1066 _backBuffer.frameRect(*destination, 0x128);
1067 drawZoomedMask(maskData, maskHeight / 8, maskWidth / 8, maskWidth);
1068 }
1069
1070 // Cleanup
1071 free(mirroredBuffer);
1072 }
1073
1074 // DEBUG: Draw the mask (zoomed)
drawZoomedMask(byte * mask,uint16 height,uint16 width,uint16 maskPitch)1075 void Screen::drawZoomedMask(byte *mask, uint16 height, uint16 width, uint16 maskPitch) {
1076 uint16 zoom = 7;
1077
1078 byte *dstBuffer = (byte *)_backBuffer.getPixels();
1079 uint16 dstPitch = (uint16)(_backBuffer.pitch - (width * zoom));
1080 uint16 srcPitch = maskPitch;
1081 byte *srcBuffer = mask;
1082
1083 height *= zoom;
1084
1085 while (height--) {
1086 for (int16 i = 0; i < width; i++) {
1087 for (int j = 0; j < zoom; j++) {
1088 *dstBuffer = *srcBuffer;
1089 dstBuffer++;
1090 }
1091
1092 srcBuffer++;
1093 }
1094
1095 dstBuffer += dstPitch;
1096 srcBuffer += (height % zoom) ? -width : srcPitch;
1097 }
1098 }
1099
bltMasked(byte * srcBuffer,byte * maskBuffer,int16 height,int16 width,uint16 srcPitch,uint16 maskPitch,byte nSkippedBits,byte * dstBuffer,uint16 dstPitch) const1100 void Screen::bltMasked(byte *srcBuffer, byte *maskBuffer, int16 height, int16 width, uint16 srcPitch, uint16 maskPitch, byte nSkippedBits, byte *dstBuffer, uint16 dstPitch) const {
1101 if (nSkippedBits > 7)
1102 error("[Screen::bltMasked] Invalid number of skipped bits (was: %d, max: 7)", nSkippedBits);
1103
1104 while (height--) {
1105 // Calculate current run length
1106 int run = 7 - nSkippedBits;
1107 uint skip = *maskBuffer >> nSkippedBits;
1108
1109 for (int16 i = 0; i < width; i++) {
1110 // Set destination value
1111 if (*srcBuffer && !(skip & 1))
1112 *dstBuffer = *srcBuffer;
1113
1114 // Advance buffers
1115 dstBuffer++;
1116 srcBuffer++;
1117
1118 if (i == width - 1)
1119 break;
1120
1121 // Check run/skip
1122 run--;
1123 if (run < 0) {
1124 ++maskBuffer;
1125
1126 run = 7;
1127 skip = *maskBuffer;
1128 } else {
1129 skip >>= 1;
1130 }
1131 }
1132
1133 dstBuffer += dstPitch;
1134 srcBuffer += srcPitch;
1135 maskBuffer += maskPitch + 1;
1136 }
1137 }
1138
blt(Common::Rect * dest,GraphicFrame * frame,Common::Rect * source,int32 flags)1139 void Screen::blt(Common::Rect *dest, GraphicFrame* frame, Common::Rect *source, int32 flags) {
1140 if (_useColorKey) {
1141 copyToBackBufferWithTransparency((byte *)frame->surface.getPixels() + (source->top * frame->surface.w + source->left),
1142 frame->surface.w,
1143 dest->left,
1144 dest->top,
1145 (uint16)source->width(),
1146 (uint16)source->height(),
1147 (bool)(flags & kDrawFlagMirrorLeftRight));
1148 } else {
1149 copyToBackBuffer((byte *)frame->surface.getPixels() + (source->top * frame->surface.w + source->left),
1150 frame->surface.w,
1151 dest->left,
1152 dest->top,
1153 (uint16)source->width(),
1154 (uint16)source->height(),
1155 (bool)(flags & kDrawFlagMirrorLeftRight));
1156 }
1157 }
1158
bltFast(int16 dX,int16 dY,GraphicFrame * frame,Common::Rect * source)1159 void Screen::bltFast(int16 dX, int16 dY, GraphicFrame* frame, Common::Rect *source) {
1160 if (_useColorKey) {
1161 copyToBackBufferWithTransparency((byte *)frame->surface.getPixels() + (source->top * frame->surface.w + source->left),
1162 frame->surface.w,
1163 dX,
1164 dY,
1165 (uint16)source->width(),
1166 (uint16)source->height());
1167 } else {
1168 copyToBackBuffer((byte *)frame->surface.getPixels() + (source->top * frame->surface.w + source->left),
1169 frame->surface.w,
1170 dX,
1171 dY,
1172 (uint16)source->width(),
1173 (uint16)source->height());
1174 }
1175 }
1176
copyToBackBuffer(const byte * buffer,int32 pitch,int16 x,int16 y,uint16 width,uint16 height,bool mirrored)1177 void Screen::copyToBackBuffer(const byte *buffer, int32 pitch, int16 x, int16 y, uint16 width, uint16 height, bool mirrored) {
1178 byte *dest = (byte *)_backBuffer.getPixels();
1179
1180 if (!mirrored) {
1181 while (height--) {
1182 memcpy(dest + y * _backBuffer.pitch + x, buffer, width);
1183 dest += 640;
1184 buffer += pitch;
1185 }
1186 } else {
1187 error("[Screen::copyToBackBuffer] Mirrored drawing not implemented (no color key)");
1188 }
1189 }
1190
copyToBackBufferWithTransparency(byte * buffer,int32 pitch,int16 x,int16 y,uint16 width,uint16 height,bool mirrored)1191 void Screen::copyToBackBufferWithTransparency(byte *buffer, int32 pitch, int16 x, int16 y, uint16 width, uint16 height, bool mirrored) {
1192 byte *dest = (byte *)_backBuffer.getPixels();
1193
1194 int32 left = (x < 0) ? -x : 0;
1195 int32 top = (y < 0) ? -y : 0;
1196 int32 right = (x + width > 640) ? 640 - abs(x) : width;
1197 int32 bottom = (y + height > 480) ? 480 - abs(y) : height;
1198
1199 for (int32 curY = top; curY < bottom; curY++) {
1200 for (int32 curX = left; curX < right; curX++) {
1201 uint32 offset = (uint32)((mirrored ? right - (curX + 1) : curX) + curY * pitch);
1202
1203 if (buffer[offset] != 0)
1204 dest[x + curX + (y + curY) * 640] = buffer[offset];
1205 }
1206 }
1207 }
1208
1209 //////////////////////////////////////////////////////////////////////////
1210 // Debug
1211 //////////////////////////////////////////////////////////////////////////
drawLine(const Common::Point & source,const Common::Point & destination,uint32 color)1212 void Screen::drawLine(const Common::Point &source, const Common::Point &destination, uint32 color) {
1213 _backBuffer.drawLine(source.x, source.y, destination.x, destination.y, color);
1214 }
1215
drawLine(const int16 (* srcPtr)[2],const int16 (* dstPtr)[2],uint32 color)1216 void Screen::drawLine(const int16 (*srcPtr)[2], const int16 (*dstPtr)[2], uint32 color) {
1217 _backBuffer.drawLine((*srcPtr)[0], (*srcPtr)[1], (*dstPtr)[0], (*dstPtr)[1], color);
1218 }
1219
drawRect(const Common::Rect & rect,uint32 color)1220 void Screen::drawRect(const Common::Rect &rect, uint32 color) {
1221 _backBuffer.frameRect(rect, color);
1222 }
1223
copyToBackBufferClipped(Graphics::Surface * surface,int16 x,int16 y)1224 void Screen::copyToBackBufferClipped(Graphics::Surface *surface, int16 x, int16 y) {
1225 Common::Rect screenRect(getWorld()->xLeft, getWorld()->yTop, getWorld()->xLeft + 640, getWorld()->yTop + 480);
1226 Common::Rect animRect(x, y, x + (int16)surface->w, y + (int16)surface->h);
1227 animRect.clip(screenRect);
1228
1229 if (!animRect.isEmpty()) {
1230 // Translate animation rectangle
1231 animRect.translate(-(int16)getWorld()->xLeft, -(int16)getWorld()->yTop);
1232
1233 int startX = animRect.right == 640 ? 0 : surface->w - animRect.width();
1234 int startY = animRect.bottom == 480 ? 0 : surface->h - animRect.height();
1235
1236 if (surface->w > 640)
1237 startX = getWorld()->xLeft;
1238 if (surface->h > 480)
1239 startY = getWorld()->yTop;
1240
1241 _vm->screen()->copyToBackBufferWithTransparency(
1242 ((byte*)surface->getPixels()) +
1243 startY * surface->pitch +
1244 startX * surface->format.bytesPerPixel,
1245 surface->pitch,
1246 animRect.left,
1247 animRect.top,
1248 (uint16)animRect.width(),
1249 (uint16)animRect.height());
1250 }
1251 }
1252
1253 } // end of namespace Asylum
1254