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