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  * Additional copyright for this file:
8  * Copyright (C) 1994-1998 Revolution Software Ltd.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  */
24 
25 #include "common/endian.h"
26 
27 #include "sword2/sword2.h"
28 #include "sword2/defs.h"
29 #include "sword2/screen.h"
30 
31 namespace Sword2 {
32 
33 /**
34  * This function takes a sprite and creates a mirror image of it.
35  * @param dst destination buffer
36  * @param src source buffer
37  * @param w width of the sprite
38  * @param h height of the sprite
39  */
40 
mirrorSprite(byte * dst,byte * src,int16 w,int16 h)41 void Screen::mirrorSprite(byte *dst, byte *src, int16 w, int16 h) {
42 	for (int y = 0; y < h; y++) {
43 		for (int x = 0; x < w; x++) {
44 			*dst++ = *(src + w - x - 1);
45 		}
46 		src += w;
47 	}
48 }
49 
50 /**
51  * This function takes a compressed frame of a sprite with up to 256 colors
52  * and decompresses it.
53  * @param dst destination buffer
54  * @param src source buffer
55  * @param decompSize the expected size of the decompressed sprite
56  */
57 
decompressRLE256(byte * dst,byte * src,int32 decompSize)58 int32 Screen::decompressRLE256(byte *dst, byte *src, int32 decompSize) {
59 	// PARAMETERS:
60 	// source	points to the start of the sprite data for input
61 	// decompSize	gives size of decompressed data in bytes
62 	// dest		points to start of destination buffer for decompressed
63 	//		data
64 
65 	byte headerByte;			// block header byte
66 	byte *endDest = dst + decompSize;	// pointer to byte after end of decomp buffer
67 	int32 rv;
68 
69 	while (1) {
70 		// FLAT block
71 		// read FLAT block header & increment 'scan' to first pixel
72 		// of block
73 		headerByte = *src++;
74 
75 		// if this isn't a zero-length block
76 		if (headerByte) {
77 			if (dst + headerByte > endDest) {
78 				rv = 1;
79 				break;
80 			}
81 
82 			// set the next 'headerByte' pixels to the next color
83 			// at 'source'
84 			memset(dst, *src, headerByte);
85 
86 			// increment destination pointer to just after this
87 			// block
88 			dst += headerByte;
89 
90 			// increment source pointer to just after this color
91 			src++;
92 
93 			// if we've decompressed all of the data
94 			if (dst == endDest) {
95 				rv = 0;		// return "OK"
96 				break;
97 			}
98 		}
99 
100 		// RAW block
101 		// read RAW block header & increment 'scan' to first pixel of
102 		// block
103 		headerByte = *src++;
104 
105 		// if this isn't a zero-length block
106 		if (headerByte) {
107 			if (dst + headerByte > endDest) {
108 				rv = 1;
109 				break;
110 			}
111 
112 			// copy the next 'headerByte' pixels from source to
113 			// destination
114 			memcpy(dst, src, headerByte);
115 
116 			// increment destination pointer to just after this
117 			// block
118 			dst += headerByte;
119 
120 			// increment source pointer to just after this block
121 			src += headerByte;
122 
123 			// if we've decompressed all of the data
124 			if (dst == endDest) {
125 				rv = 0;		// return "OK"
126 				break;
127 			}
128 		}
129 	}
130 
131 	return rv;
132 }
133 
134 /**
135  * Unwinds a run of 16-color data into 256-color palette data.
136  */
137 
unwindRaw16(byte * dst,byte * src,uint16 blockSize,byte * colTable)138 void Screen::unwindRaw16(byte *dst, byte *src, uint16 blockSize, byte *colTable) {
139 	// for each pair of pixels
140 	while (blockSize > 1) {
141 
142 		if (Sword2Engine::isPsx()) {
143 			// 1st color = number in table at position given by upper
144 			// nibble of source byte
145 			*dst++ = colTable[(*src) & 0x0f];
146 
147 			// 2nd color = number in table at position given by lower
148 			// nibble of source byte
149 			*dst++ = colTable[(*src) >> 4];
150 		} else {
151 			*dst++ = colTable[(*src) >> 4];
152 			*dst++ = colTable[(*src) & 0x0f];
153 		}
154 
155 
156 		// point to next source byte
157 		src++;
158 
159 		// decrement count of how many pixels left to read
160 		blockSize -= 2;
161 	}
162 
163 	// if there's a final odd pixel
164 	if (blockSize) {
165 		// color = number in table at position given by upper nibble
166 		// of source byte
167 		*dst++ = colTable[(*src) >> 4];
168 	}
169 }
170 
171 /**
172  * This function takes a compressed frame of a sprite (with up to 16 colors)
173  * and decompresses it.
174  * @param dst destination buffer
175  * @param src source buffer
176  * @param decompSize the expected size of the uncompressed sprite
177  * @param colTable mapping from the 16 encoded colors to the current palette
178  */
179 
decompressRLE16(byte * dst,byte * src,int32 decompSize,byte * colTable)180 int32 Screen::decompressRLE16(byte *dst, byte *src, int32 decompSize, byte *colTable) {
181 	byte headerByte;			// block header byte
182 	byte *endDest = dst + decompSize;	// pointer to byte after end of decomp buffer
183 	int32 rv;
184 
185 	while (1) {
186 		// FLAT block
187 		// read FLAT block header & increment 'scan' to first pixel
188 		// of block
189 		headerByte = *src++;
190 
191 		// if this isn't a zero-length block
192 		if (headerByte) {
193 			if (dst + headerByte > endDest) {
194 				rv = 1;
195 				break;
196 			}
197 
198 			// set the next 'headerByte' pixels to the next
199 			// color at 'source'
200 			memset(dst, *src, headerByte);
201 
202 			// increment destination pointer to just after this
203 			// block
204 			dst += headerByte;
205 
206 			// increment source pointer to just after this color
207 			src++;
208 
209 			// if we've decompressed all of the data
210 			if (dst == endDest) {
211 				rv = 0;		// return "OK"
212 				break;
213 			}
214 		}
215 
216 		// RAW block
217 		// read RAW block header & increment 'scan' to first pixel of
218 		// block
219 		headerByte = *src++;
220 
221 		// if this isn't a zero-length block
222 		if (headerByte) {
223 			if (dst + headerByte > endDest) {
224 				rv = 1;
225 				break;
226 			}
227 
228 			// copy the next 'headerByte' pixels from source to
229 			// destination (NB. 2 pixels per byte)
230 			unwindRaw16(dst, src, headerByte, colTable);
231 
232 			// increment destination pointer to just after this
233 			// block
234 			dst += headerByte;
235 
236 			// increment source pointer to just after this block
237 			// (NB. headerByte gives pixels, so /2 for bytes)
238 			src += (headerByte + 1) / 2;
239 
240 			// if we've decompressed all of the data
241 			if (dst >= endDest) {
242 				rv = 0;		// return "OK"
243 				break;
244 			}
245 		}
246 	}
247 
248 	return rv;
249 }
250 
251 /**
252  * This function takes a compressed HIF image and decompresses it.
253  * Used for PSX version sprites.
254  * @param dst destination buffer
255  * @param src source buffer
256  * @param skipData if pointer != NULL, value of pointed var
257  * is set to number of bytes composing the compressed data.
258  */
259 
decompressHIF(byte * src,byte * dst,uint32 * skipData)260 uint32 Screen::decompressHIF(byte *src, byte *dst, uint32 *skipData) {
261 	uint32 decompSize = 0;
262 	uint32 readByte = 0;
263 
264 	for (;;) { // Main loop
265 		byte control_byte = *src++;
266 		readByte++;
267 		uint32 byte_count = 0;
268 		while (byte_count < 8) {
269 			if (control_byte & 0x80) {
270 				uint16 info_word = READ_BE_UINT16(src); // Read the info word
271 				src += 2;
272 				readByte += 2;
273 				if (info_word == 0xFFFF) { // Got 0xFFFF code, finished.
274 					if (skipData != NULL) *(skipData) = readByte;
275 					return decompSize;
276 				}
277 
278 				int32 repeat_count = (info_word >> 12) + 2; // How many time data needs to be refetched
279 				while (repeat_count >= 0) {
280 					uint16 refetchData = (info_word & 0xFFF) + 1;
281 					if (refetchData > decompSize) return 0; // We have a problem here...
282 					uint8 *old_data_src = dst - refetchData;
283 					*dst++ = *old_data_src;
284 					decompSize++;
285 					repeat_count--;
286 				}
287 			} else {
288 				*dst++ = *src++;
289 				readByte++;
290 				decompSize++;
291 			}
292 			byte_count++;
293 			control_byte <<= 1; // Shifting left the control code one bit
294 		}
295 	}
296 }
297 
298 // Double line image to keep aspect ratio.
299 // Used in PSX version.
resizePsxSprite(byte * dst,byte * src,uint16 destW,uint16 destH)300 void Screen::resizePsxSprite(byte *dst, byte *src, uint16 destW, uint16 destH) {
301 	for (int i = 0; i < destH / 2; i++) {
302 		memcpy(dst + i * destW * 2, src + i * destW, destW);
303 		memcpy(dst + i * destW * 2 + destW, src + i * destW, destW);
304 	}
305 }
306 
307 // Sprites wider than 254px in PSX version are divided
308 // into slices, this recomposes the image.
recomposePsxSprite(SpriteInfo * s)309 void Screen::recomposePsxSprite(SpriteInfo *s) {
310 	if (!s)
311 		return;
312 
313 	uint16 noStripes = (s->w / 254) + ((s->w % 254) ? 1 : 0);
314 	uint16 lastStripeSize = (s->w % 254) ? s->w % 254 : 254;
315 	byte *buffer = (byte *)malloc(s->w * s->h / 2);
316 
317 	memset(buffer, 0, s->w * s->h / 2);
318 
319 	for (int idx = 0; idx < noStripes; idx++) {
320 		uint16 stripeSize = (idx == noStripes - 1) ? lastStripeSize : 254;
321 		for (int line = 0; line < s->h / 2; line++) {
322 			memcpy(buffer + idx * 254 + line * s->w, s->data, stripeSize);
323 			s->data += stripeSize;
324 		}
325 	}
326 
327 	s->data = buffer;
328 
329 }
330 
331 // Recomposes sprites wider than 254 pixels but also
332 // compressed with HIF.
333 // Used in PSX version.
recomposeCompPsxSprite(SpriteInfo * s)334 void Screen::recomposeCompPsxSprite(SpriteInfo *s) {
335 	if (!s)
336 		return;
337 
338 	uint16 noStripes = (s->w / 254) + ((s->w % 254) ? 1 : 0);
339 	uint16 lastStripeSize = (s->w % 254) ? s->w % 254 : 254;
340 	byte *buffer = (byte *)malloc(s->w * s->h / 2);
341 	byte *stripeBuffer = (byte *)malloc(254 * s->h);
342 
343 	memset(buffer, 0, s->w * s->h / 2);
344 	uint32 skipData = 0;
345 	uint32 compBytes = 0;
346 
347 	for (int idx = 0; idx < noStripes; idx++) {
348 		uint16 stripeSize = (idx == noStripes - 1) ? lastStripeSize : 254;
349 
350 		decompressHIF((s->data) + skipData, stripeBuffer, &compBytes);
351 		skipData += compBytes;
352 
353 		for (int line = 0; line < s->h / 2; line++) {
354 			memcpy(buffer + idx * 254 + line * s->w, stripeBuffer + line * stripeSize, stripeSize);
355 		}
356 	}
357 
358 	free(stripeBuffer);
359 	s->data = buffer;
360 
361 }
362 
363 /**
364  * Creates a sprite surface. Sprite surfaces are used by the in-game dialogs
365  * and for displaying cutscene subtitles, which makes them much easier to draw
366  * than standard sprites.
367  * @param s information about how to decode the sprite
368  * @param sprite the buffer that will be created to store the surface
369  * @return RD_OK, or an error code
370  */
371 
createSurface(SpriteInfo * s,byte ** sprite)372 int32 Screen::createSurface(SpriteInfo *s, byte **sprite) {
373 	*sprite = (byte *)malloc(s->w * s->h);
374 	if (!*sprite)
375 		return RDERR_OUTOFMEMORY;
376 
377 	// Surfaces are either uncompressed or RLE256-compressed. No need to
378 	// test for anything else.
379 
380 	if (s->type & RDSPR_NOCOMPRESSION) {
381 		memcpy(*sprite, s->data, s->w * s->h);
382 	} else if (decompressRLE256(*sprite, s->data, s->w * s->h)) {
383 		free(*sprite);
384 		return RDERR_DECOMPRESSION;
385 	}
386 
387 	return RD_OK;
388 }
389 
390 /**
391  * Draws the sprite surface created earlier.
392  * @param s information about how to place the sprite
393  * @param surface pointer to the surface created earlier
394  * @param clipRect the clipping rectangle
395  */
396 
drawSurface(SpriteInfo * s,byte * surface,Common::Rect * clipRect)397 void Screen::drawSurface(SpriteInfo *s, byte *surface, Common::Rect *clipRect) {
398 	Common::Rect rd, rs;
399 	uint16 x, y;
400 	byte *src, *dst;
401 
402 	rs.left = 0;
403 	rs.right = s->w;
404 	rs.top = 0;
405 	rs.bottom = s->h;
406 
407 	rd.left = s->x;
408 	rd.right = rd.left + rs.right;
409 	rd.top = s->y;
410 	rd.bottom = rd.top + rs.bottom;
411 
412 	Common::Rect defClipRect(0, 0, _screenWide, _screenDeep);
413 
414 	if (!clipRect) {
415 		clipRect = &defClipRect;
416 	}
417 
418 	if (clipRect->left > rd.left) {
419 		rs.left += (clipRect->left - rd.left);
420 		rd.left = clipRect->left;
421 	}
422 
423 	if (clipRect->top > rd.top) {
424 		rs.top += (clipRect->top - rd.top);
425 		rd.top = clipRect->top;
426 	}
427 
428 	if (clipRect->right < rd.right) {
429 		rd.right = clipRect->right;
430 	}
431 
432 	if (clipRect->bottom < rd.bottom) {
433 		rd.bottom = clipRect->bottom;
434 	}
435 
436 	if (rd.width() <= 0 || rd.height() <= 0)
437 		return;
438 
439 	src = surface + rs.top * s->w + rs.left;
440 	dst = _buffer + _screenWide * rd.top + rd.left;
441 
442 	// Surfaces are always transparent.
443 
444 	for (y = 0; y < rd.height(); y++) {
445 		for (x = 0; x < rd.width(); x++) {
446 			if (src[x])
447 				dst[x] = src[x];
448 		}
449 		src += s->w;
450 		dst += _screenWide;
451 	}
452 
453 	updateRect(&rd);
454 }
455 
456 /**
457  * Destroys a surface.
458  */
459 
deleteSurface(byte * surface)460 void Screen::deleteSurface(byte *surface) {
461 	free(surface);
462 }
463 
464 /**
465  * Draws a sprite onto the screen. The type of the sprite can be a combination
466  * of the following flags, some of which are mutually exclusive:
467  * RDSPR_DISPLAYALIGN	The sprite is drawn relative to the top left corner
468  *			of the screen
469  * RDSPR_FLIP		The sprite is mirrored
470  * RDSPR_TRANS		The sprite has a transparent color zero
471  * RDSPR_BLEND		The sprite is translucent
472  * RDSPR_SHADOW		The sprite is affected by the light mask. (Scaled
473  *			sprites always are.)
474  * RDSPR_NOCOMPRESSION	The sprite data is not compressed
475  * RDSPR_RLE16		The sprite data is a 16-color compressed sprite
476  * RDSPR_RLE256		The sprite data is a 256-color compressed sprite
477  * @param s all the information needed to draw the sprite
478  * @warning Sprites will only be drawn onto the background, not over menubar
479  * areas.
480  */
481 
482 // FIXME: I'm sure this could be optimized. There's plenty of data copying and
483 // mallocing here.
484 
drawSprite(SpriteInfo * s)485 int32 Screen::drawSprite(SpriteInfo *s) {
486 	byte *src, *dst;
487 	byte *sprite, *newSprite;
488 	uint16 scale;
489 	int16 i, j;
490 	uint16 srcPitch;
491 	bool freeSprite = false;
492 	Common::Rect rd, rs;
493 
494 	// -----------------------------------------------------------------
495 	// Decompression and mirroring
496 	// -----------------------------------------------------------------
497 	if (s->type & RDSPR_NOCOMPRESSION) {
498 		if (Sword2Engine::isPsx()) { // PSX Uncompressed sprites
499 			if (s->w > 254 && !s->isText) { // We need to recompose these frames
500 				recomposePsxSprite(s);
501 			}
502 
503 			// If the height is not an even value, fix it.
504 			// Apparently it's a problem in the data of a few sprites
505 			// of the PSX version. This should fix an evident problem
506 			// in the foyer at the beginning of the game, where a line
507 			// of pixels is missing near the stairs. But it should also
508 			// fix a more subtle one in the glease gallery and in quaramonte
509 			// police office.
510 			if (s->h % 2)
511 				s->h++;
512 
513 			freeSprite = true;
514 			byte *tempBuf = (byte *)malloc(s->w * s->h * 2);
515 			memset(tempBuf, 0, s->w * s->h * 2);
516 			resizePsxSprite(tempBuf, s->data, s->w, s->h);
517 
518 			if (s->w > 254 && !s->isText) {
519 				free(s->data);
520 			}
521 
522 			sprite = tempBuf;
523 		} else { // PC Uncompressed sprites
524 			sprite = s->data;
525 		}
526 	} else {
527 		freeSprite = true;
528 
529 		if ((s->type & 0xff00) == RDSPR_RLE16) {
530 			if (Sword2Engine::isPsx()) { // PSX HIF16 sprites
531 				uint32 decompData;
532 				byte *tempBuf = (byte *)malloc(s->w * s->h);
533 				memset(tempBuf, 0, s->w * s->h);
534 
535 				decompData = decompressHIF(s->data, tempBuf);
536 
537 				// Check that we correctly decompressed data
538 				if (!decompData) {
539 					free(tempBuf);
540 
541 					return RDERR_DECOMPRESSION;
542 				}
543 
544 				s->w = (decompData / (s->h / 2)) * 2;
545 				byte *tempBuf2 = (byte *)malloc(s->w * s->h * 10);
546 				memset(tempBuf2, 0, s->w * s->h * 2);
547 
548 				unwindRaw16(tempBuf2, tempBuf, (s->w * (s->h / 2)), s->colorTable);
549 				sprite = (byte *)malloc(s->w * s->h);
550 
551 				if (!sprite) {
552 					free(tempBuf2);
553 					free(tempBuf);
554 					return RDERR_OUTOFMEMORY;
555 				}
556 
557 				resizePsxSprite(sprite, tempBuf2, s->w, s->h);
558 
559 				free(tempBuf2);
560 				free(tempBuf);
561 			} else { // PC RLE16 sprites
562 				sprite = (byte *)malloc(s->w * s->h);
563 
564 				if (!sprite)
565 					return RDERR_OUTOFMEMORY;
566 
567 				if (decompressRLE16(sprite, s->data, s->w * s->h, s->colorTable)) {
568 					free(sprite);
569 					return RDERR_DECOMPRESSION;
570 				}
571 			}
572 		} else {
573 			if (Sword2Engine::isPsx()) { // PSX HIF256 sprites
574 				if (s->w > 255) {
575 					sprite = (byte *)malloc(s->w * s->h);
576 					recomposeCompPsxSprite(s);
577 					resizePsxSprite(sprite, s->data, s->w, s->h);
578 					free(s->data);
579 				} else {
580 					byte *tempBuf = (byte *)malloc(s->w * s->h);
581 					uint32 decompData = decompressHIF(s->data, tempBuf);
582 
583 					// Check that we correctly decompressed data
584 					if (!decompData) {
585 						free(tempBuf);
586 
587 						return RDERR_DECOMPRESSION;
588 					}
589 
590 					s->w = (decompData / (s->h / 2));
591 					sprite = (byte *)malloc(s->w * s->h);
592 
593 					if (!sprite) {
594 						free(tempBuf);
595 
596 						return RDERR_OUTOFMEMORY;
597 					}
598 
599 					resizePsxSprite(sprite, tempBuf, s->w, s->h);
600 					free(tempBuf);
601 				}
602 			} else { // PC RLE256 sprites
603 				sprite = (byte *)malloc(s->w * s->h);
604 
605 				if (!sprite)
606 					return RDERR_OUTOFMEMORY;
607 
608 				if (decompressRLE256(sprite, s->data, s->w * s->h)) {
609 					free(sprite);
610 					return RDERR_DECOMPRESSION;
611 				}
612 			}
613 		}
614 	}
615 
616 	if (s->type & RDSPR_FLIP) {
617 		newSprite = (byte *)malloc(s->w * s->h);
618 		if (newSprite == NULL) {
619 			if (freeSprite)
620 				free(sprite);
621 			return RDERR_OUTOFMEMORY;
622 		}
623 		mirrorSprite(newSprite, sprite, s->w, s->h);
624 		if (freeSprite)
625 			free(sprite);
626 		sprite = newSprite;
627 		freeSprite = true;
628 	}
629 
630 	// -----------------------------------------------------------------
631 	// Positioning and clipping.
632 	// -----------------------------------------------------------------
633 
634 	int16 spriteX = s->x;
635 	int16 spriteY = s->y;
636 
637 	if (!(s->type & RDSPR_DISPLAYALIGN)) {
638 		spriteX += _parallaxScrollX;
639 		spriteY += _parallaxScrollY;
640 	}
641 
642 	spriteY += MENUDEEP;
643 
644 	// A scale factor 0 or 256 means don't scale. Why do they use two
645 	// different values to mean the same thing? Normalize it here for
646 	// convenience.
647 
648 	scale = (s->scale == 0) ? 256 : s->scale;
649 
650 	rs.top = 0;
651 	rs.left = 0;
652 
653 	if (scale != 256) {
654 		rs.right = s->scaledWidth;
655 		rs.bottom = s->scaledHeight;
656 		srcPitch = s->scaledWidth;
657 	} else {
658 		rs.right = s->w;
659 		rs.bottom = s->h;
660 		srcPitch = s->w;
661 	}
662 
663 	rd.top = spriteY;
664 	rd.left = spriteX;
665 
666 	if (!(s->type & RDSPR_DISPLAYALIGN)) {
667 		rd.top -= _scrollY;
668 		rd.left -= _scrollX;
669 	}
670 
671 	rd.right = rd.left + rs.right;
672 	rd.bottom = rd.top + rs.bottom;
673 
674 	// Check if the sprite would end up completely outside the screen.
675 
676 	if (rd.left > RENDERWIDE || rd.top > RENDERDEEP + MENUDEEP || rd.right < 0 || rd.bottom < MENUDEEP) {
677 		if (freeSprite)
678 			free(sprite);
679 		return RD_OK;
680 	}
681 
682 	if (rd.top < MENUDEEP) {
683 		rs.top = MENUDEEP - rd.top;
684 		rd.top = MENUDEEP;
685 	}
686 	if (rd.bottom > RENDERDEEP + MENUDEEP) {
687 		rd.bottom = RENDERDEEP + MENUDEEP;
688 		rs.bottom = rs.top + (rd.bottom - rd.top);
689 	}
690 	if (rd.left < 0) {
691 		rs.left = -rd.left;
692 		rd.left = 0;
693 	}
694 	if (rd.right > RENDERWIDE) {
695 		rd.right = RENDERWIDE;
696 		rs.right = rs.left + (rd.right - rd.left);
697 	}
698 
699 	// -----------------------------------------------------------------
700 	// Scaling
701 	// -----------------------------------------------------------------
702 
703 	if (scale != 256) {
704 		if (s->scaledWidth > SCALE_MAXWIDTH || s->scaledHeight > SCALE_MAXHEIGHT) {
705 			if (freeSprite)
706 				free(sprite);
707 			return RDERR_NOTIMPLEMENTED;
708 		}
709 
710 		newSprite = (byte *)malloc(s->scaledWidth * s->scaledHeight);
711 		if (newSprite == NULL) {
712 			if (freeSprite)
713 				free(sprite);
714 			return RDERR_OUTOFMEMORY;
715 		}
716 
717 		// We cannot use good scaling for PSX version, as we are missing
718 		// some required data.
719 		if (_renderCaps & RDBLTFX_EDGEBLEND && !Sword2Engine::isPsx())
720 			scaleImageGood(newSprite, s->scaledWidth, s->scaledWidth, s->scaledHeight, sprite, s->w, s->w, s->h, _buffer, rd.left, rd.top);
721 		else
722 			scaleImageFast(newSprite, s->scaledWidth, s->scaledWidth, s->scaledHeight, sprite, s->w, s->w, s->h);
723 
724 		if (freeSprite)
725 			free(sprite);
726 		sprite = newSprite;
727 		freeSprite = true;
728 	}
729 
730 	// -----------------------------------------------------------------
731 	// Light masking
732 	// -----------------------------------------------------------------
733 
734 	// The light mask is an optional layer that covers the entire room
735 	// and which is used to simulate light and shadows. Scaled sprites
736 	// (actors, presumably) are always affected.
737 	// Light masking makes use of palette match table, so it's unavailable
738 	// in PSX version.
739 
740 	if ((_renderCaps & RDBLTFX_SHADOWBLEND) && _lightMask && (scale != 256 || ((s->type & RDSPR_SHADOW) && !Sword2Engine::isPsx()) )) {
741 		byte *lightMap;
742 
743 		// Make sure that we never apply the shadow to the original
744 		// resource data. This could only ever happen in the
745 		// RDSPR_NOCOMPRESSION case.
746 
747 		if (!freeSprite) {
748 			newSprite = (byte *)malloc(s->w * s->h);
749 			memcpy(newSprite, sprite, s->w * s->h);
750 			sprite = newSprite;
751 			freeSprite = true;
752 		}
753 
754 		src = sprite + rs.top * srcPitch + rs.left;
755 		lightMap = _lightMask + (rd.top + _scrollY - MENUDEEP) * _locationWide + rd.left + _scrollX;
756 
757 		for (i = 0; i < rs.height(); i++) {
758 			for (j = 0; j < rs.width(); j++) {
759 				if (src[j] && lightMap[j]) {
760 					uint8 r = ((32 - lightMap[j]) * _palette[src[j] * 3 + 0]) >> 5;
761 					uint8 g = ((32 - lightMap[j]) * _palette[src[j] * 3 + 1]) >> 5;
762 					uint8 b = ((32 - lightMap[j]) * _palette[src[j] * 3 + 2]) >> 5;
763 					src[j] = quickMatch(r, g, b);
764 				}
765 			}
766 			src += srcPitch;
767 			lightMap += _locationWide;
768 		}
769 	}
770 
771 	// -----------------------------------------------------------------
772 	// Drawing
773 	// -----------------------------------------------------------------
774 
775 	src = sprite + rs.top * srcPitch + rs.left;
776 	dst = _buffer + _screenWide * rd.top + rd.left;
777 
778 	if (s->type & RDSPR_BLEND) {
779 		// The original code had two different blending cases. One for
780 		// s->blend & 0x01 and one for s->blend & 0x02. However, the
781 		// only values that actually appear in the cluster files are
782 		// 0, 513 and 1025 so the s->blend & 0x02 case was never used.
783 		// Which is just as well since that code made no sense to me.
784 
785 		// TODO: In PSX version, blending is done through hardware transparency.
786 		// The only correct way to simulate this would be using 16-bit mode.
787 		// As this is not yet available for this engine, fake transparency is used
788 		// as placeholder.
789 		if (!(_renderCaps & RDBLTFX_SPRITEBLEND) || Sword2Engine::isPsx()) {
790 			for (i = 0; i < rs.height(); i++) {
791 				for (j = 0; j < rs.width(); j++) {
792 					if (src[j] && ((i & 1) == (j & 1)))
793 						dst[j] = src[j];
794 				}
795 				src += srcPitch;
796 				dst += _screenWide;
797 			}
798 		} else {
799 			uint8 n = s->blend >> 8;
800 
801 			for (i = 0; i < rs.height(); i++) {
802 				for (j = 0; j < rs.width(); j++) {
803 					if (src[j]) {
804 						uint8 r1 = _palette[src[j] * 3 + 0];
805 						uint8 g1 = _palette[src[j] * 3 + 1];
806 						uint8 b1 = _palette[src[j] * 3 + 2];
807 						uint8 r2 = _palette[dst[j] * 3 + 0];
808 						uint8 g2 = _palette[dst[j] * 3 + 1];
809 						uint8 b2 = _palette[dst[j] * 3 + 2];
810 
811 						uint8 r = (r1 * n + r2 * (8 - n)) >> 3;
812 						uint8 g = (g1 * n + g2 * (8 - n)) >> 3;
813 						uint8 b = (b1 * n + b2 * (8 - n)) >> 3;
814 						dst[j] = quickMatch(r, g, b);
815 					}
816 				}
817 				src += srcPitch;
818 				dst += _screenWide;
819 			}
820 		}
821 	} else {
822 		if (s->type & RDSPR_TRANS) {
823 			for (i = 0; i < rs.height(); i++) {
824 				for (j = 0; j < rs.width(); j++) {
825 					if (src[j])
826 						dst[j] = src[j];
827 				}
828 				src += srcPitch;
829 				dst += _screenWide;
830 			}
831 		} else {
832 			for (i = 0; i < rs.height(); i++) {
833 				memcpy(dst, src, rs.width());
834 				src += srcPitch;
835 				dst += _screenWide;
836 			}
837 		}
838 	}
839 
840 	if (freeSprite)
841 		free(sprite);
842 
843 	markAsDirty(rd.left, rd.top, rd.right - 1, rd.bottom - 1);
844 	return RD_OK;
845 }
846 
847 /**
848  * Opens the light masking sprite for a room.
849  */
850 
openLightMask(SpriteInfo * s)851 int32 Screen::openLightMask(SpriteInfo *s) {
852 	// FIXME: The light mask is only needed on higher graphics detail
853 	// settings, so to save memory we could simply ignore it on lower
854 	// settings. But then we need to figure out how to ensure that it
855 	// is properly loaded if the user changes the settings in mid-game.
856 
857 	if (_lightMask)
858 		return RDERR_NOTCLOSED;
859 
860 	_lightMask = (byte *)malloc(s->w * s->h);
861 	if (!_lightMask)
862 		return RDERR_OUTOFMEMORY;
863 
864 	if (s->data == NULL) // Check, as there's no mask in psx version
865 		return RDERR_NOTOPEN;
866 
867 	if (decompressRLE256(_lightMask, s->data, s->w * s->h))
868 		return RDERR_DECOMPRESSION;
869 
870 	return RD_OK;
871 }
872 
873 /**
874  * Closes the light masking sprite for a room.
875  */
876 
closeLightMask()877 int32 Screen::closeLightMask() {
878 	if (!_lightMask)
879 		return RDERR_NOTOPEN;
880 
881 	free(_lightMask);
882 	_lightMask = NULL;
883 	return RD_OK;
884 }
885 
886 } // End of namespace Sword2
887