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 "voyeur/screen.h"
24 #include "voyeur/voyeur.h"
25 #include "voyeur/staticres.h"
26 #include "engines/util.h"
27 #include "graphics/palette.h"
28 #include "graphics/surface.h"
29 
30 namespace Voyeur {
31 
32 /*------------------------------------------------------------------------*/
33 
DrawInfo(int penColor,const Common::Point & pos)34 DrawInfo::DrawInfo(int penColor, const Common::Point &pos) {
35 	_penColor = penColor;
36 	_pos = pos;
37 }
38 
39 /*------------------------------------------------------------------------*/
40 
Screen(VoyeurEngine * vm)41 Screen::Screen(VoyeurEngine *vm) : Graphics::Screen(), _vm(vm), _drawPtr(&_defaultDrawInfo),
42 		_defaultDrawInfo(1, Common::Point()) {
43 	_SVGAMode = 0;
44 	_planeSelect = 0;
45 	_saveBack = true;
46 	_clipPtr = NULL;
47 	_viewPortListPtr = NULL;
48 	_backgroundPage = NULL;
49 	_vPort = NULL;
50 	_fontPtr = NULL;
51 	Common::fill(&_VGAColors[0], &_VGAColors[PALETTE_SIZE], 0);
52 	_fontChar = new PictureResource(DISPFLAG_NONE, 0xff, 0xff, 0, Common::Rect(), 0, NULL, 0);
53 	_backColors = nullptr;
54 }
55 
sInitGraphics()56 void Screen::sInitGraphics() {
57 	initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
58 	create(SCREEN_WIDTH, SCREEN_HEIGHT);
59 	clearPalette();
60 }
61 
~Screen()62 Screen::~Screen() {
63 	delete _fontChar;
64 }
65 
setupMCGASaveRect(ViewPortResource * viewPort)66 void Screen::setupMCGASaveRect(ViewPortResource *viewPort) {
67 	if (viewPort->_activePage) {
68 		viewPort->_activePage->_flags |= DISPFLAG_1;
69 		Common::Rect *clipRect = _clipPtr;
70 		_clipPtr = &viewPort->_clipRect;
71 
72 		sDrawPic(viewPort->_activePage, viewPort->_currentPic, Common::Point());
73 
74 		_clipPtr = clipRect;
75 	}
76 
77 	viewPort->_rectListCount[1] = -1;
78 }
79 
addRectOptSaveRect(ViewPortResource * viewPort,int idx,const Common::Rect & bounds)80 void Screen::addRectOptSaveRect(ViewPortResource *viewPort, int idx, const Common::Rect &bounds) {
81 	if (viewPort->_rectListCount[idx] == -1)
82 		return;
83 
84 	// TODO: Lots of code in original, which I suspect may be overlapping rect merging
85 	viewPort->_rectListPtr[idx]->push_back(bounds);
86 	++viewPort->_rectListCount[idx];
87 }
88 
restoreMCGASaveRect(ViewPortResource * viewPort)89 void Screen::restoreMCGASaveRect(ViewPortResource *viewPort) {
90 	if (viewPort->_rectListCount[0] != -1) {
91 		for (int i = 0; i < viewPort->_rectListCount[0]; ++i) {
92 			addRectOptSaveRect(viewPort, 1, (*viewPort->_rectListPtr[0])[i]);
93 		}
94 	} else {
95 		viewPort->_rectListCount[1] = -1;
96 	}
97 
98 	restoreBack(*viewPort->_rectListPtr[1], viewPort->_rectListCount[1], viewPort->_pages[0],
99 		viewPort->_pages[1]);
100 
101 	int count = viewPort->_rectListCount[0];
102 	restoreBack(*viewPort->_rectListPtr[0], viewPort->_rectListCount[0],
103 		viewPort->_activePage, viewPort->_currentPic);
104 
105 	SWAP(viewPort->_rectListPtr[0], viewPort->_rectListPtr[1]);
106 	viewPort->_rectListCount[1] = count;
107 }
108 
addRectNoSaveBack(ViewPortResource * viewPort,int idx,const Common::Rect & bounds)109 void Screen::addRectNoSaveBack(ViewPortResource *viewPort, int idx, const Common::Rect &bounds) {
110 	// Stubbed/dummy method in the original.
111 }
112 
sDrawPic(DisplayResource * srcDisplay,DisplayResource * destDisplay,const Common::Point & initialOffset)113 void Screen::sDrawPic(DisplayResource *srcDisplay, DisplayResource *destDisplay,
114 		const Common::Point &initialOffset) {
115 	int width1, width2;
116 	int widthDiff, widthDiff2;
117 	int height1;
118 	int srcOffset;
119 	int screenOffset;
120 	int srcFlags, destFlags;
121 	ViewPortResource *destViewPort = NULL;
122 	Common::Rect newBounds;
123 	Common::Rect backBounds;
124 	int tmpWidth = 0;
125 	int tmpHeight = 0;
126 	bool isClipped = false;
127 	byte pixel = 0;
128 	int runLength;
129 
130 	byte *srcImgData, *destImgData;
131 	const byte *srcP;
132 	byte *destP;
133 	byte byteVal, byteVal2;
134 
135 	PictureResource *srcPic;
136 	PictureResource *destPic;
137 
138 	// Get the picture parameters, or deference viewport pointers to get their pictures
139 	if (srcDisplay->_flags & DISPFLAG_VIEWPORT) {
140 		// A viewport was passed, not a picture
141 		srcPic = ((ViewPortResource *)srcDisplay)->_currentPic;
142 	} else {
143 		srcPic = (PictureResource *)srcDisplay;
144 	}
145 
146 	if (destDisplay->_flags & DISPFLAG_VIEWPORT) {
147 		// A viewport was passed, not a picture
148 		destViewPort = (ViewPortResource *)destDisplay;
149 		destPic = destViewPort->_currentPic;
150 	} else {
151 		destPic = (PictureResource *)destDisplay;
152 	}
153 
154 	Common::Point offset = Common::Point(initialOffset.x + srcPic->_bounds.left - destPic->_bounds.left,
155 		initialOffset.y + srcPic->_bounds.top - destPic->_bounds.top);
156 	width1 = width2 = srcPic->_bounds.width();
157 	height1 = srcPic->_bounds.height();
158 	srcOffset = 0;
159 	srcFlags = srcPic->_flags;
160 	destFlags = destPic->_flags;
161 	byte *cursorData = NULL;
162 
163 	if (srcFlags & DISPFLAG_1) {
164 		if (_clipPtr) {
165 			int xs = _clipPtr->left - destPic->_bounds.left;
166 			int ys = _clipPtr->top - destPic->_bounds.top;
167 			newBounds = Common::Rect(xs, ys, xs + _clipPtr->width(), ys + _clipPtr->height());
168 		} else if (destViewPort) {
169 			int xs = destViewPort->_clipRect.left - destPic->_bounds.left;
170 			int ys = destViewPort->_clipRect.top - destPic->_bounds.top;
171 			newBounds = Common::Rect(xs, ys, xs + destViewPort->_clipRect.width(),
172 				ys + destViewPort->_clipRect.height());
173 		} else {
174 			newBounds = Common::Rect(0, 0, destPic->_bounds.width(), destPic->_bounds.height());
175 		}
176 
177 		tmpHeight = offset.y - newBounds.top;
178 		if (tmpHeight < 0) {
179 			srcOffset -= tmpHeight * width2;
180 			height1 += tmpHeight;
181 			offset.y = newBounds.top;
182 
183 			if (height1 <= 0)
184 				return;
185 
186 			isClipped = true;
187 		}
188 
189 		int yMin = newBounds.bottom - (offset.y + height1);
190 		if (yMin < 0) {
191 			height1 += yMin;
192 			if (height1 <= 0)
193 				return;
194 		}
195 
196 		tmpWidth = offset.x - newBounds.left;
197 		if (tmpWidth < 0) {
198 			srcOffset -= tmpWidth;
199 			width2 += tmpWidth;
200 			offset.x = newBounds.left;
201 
202 			if (width2 <= 0)
203 				return;
204 
205 			isClipped = true;
206 		}
207 
208 		int xMin = newBounds.right - (offset.x + width2);
209 		if (xMin < 0) {
210 			width2 += xMin;
211 			if (width2 <= 0)
212 				return;
213 
214 			isClipped = true;
215 		}
216 	}
217 
218 	screenOffset = offset.y * destPic->_bounds.width() + offset.x;
219 	widthDiff = width1 - width2;
220 	widthDiff2 = destPic->_bounds.width() - width2;
221 
222 	if (destViewPort) {
223 		if (!_saveBack || (srcPic->_flags & DISPFLAG_800)) {
224 			backBounds.left = destPic->_bounds.left + offset.x;
225 			backBounds.top = destPic->_bounds.top + offset.y;
226 			backBounds.setWidth(width2);
227 			backBounds.setHeight(height1);
228 			addRectOptSaveRect(destViewPort, 1, backBounds);
229 
230 		} else if (!destViewPort->_addFn) {
231 			if (destViewPort->_rectListCount[destViewPort->_pageIndex] < -1) {
232 				Common::Rect r;
233 				r.left = destPic->_bounds.left + offset.x;
234 				r.top = destPic->_bounds.top + offset.y;
235 				r.setWidth(width2);
236 				r.setHeight(height1);
237 
238 				(*destViewPort->_rectListPtr[destViewPort->_pageIndex]).push_back(r);
239 				++destViewPort->_rectListCount[destViewPort->_pageIndex];
240 			}
241 		} else {
242 			int xs = offset.x + destPic->_bounds.left;
243 			int ys = offset.y + destPic->_bounds.top;
244 			backBounds = Common::Rect(xs, ys, xs + width2, ys + height1);
245 
246 			(this->*destViewPort->_addFn)(destViewPort, destViewPort->_bounds.top, backBounds);
247 		}
248 	}
249 
250 	if (srcFlags & DISPFLAG_1000) {
251 		int imageDataShift = 0;
252 		srcImgData = srcPic->_imgData + (imageDataShift << 14);
253 		for (uint idx = 0; idx < srcPic->_maskData; ++idx) {
254 			if (imageDataShift < 4)
255 				++imageDataShift;
256 		}
257 
258 		destImgData = destPic->_imgData + (imageDataShift << 14);
259 		for (uint idx = 0; idx < srcPic->_maskData; ++idx) {
260 			if (imageDataShift < 4)
261 				++imageDataShift;
262 		}
263 	} else {
264 		srcImgData = srcPic->_imgData;
265 		destImgData = destPic->_imgData;
266 	}
267 
268 	if (srcPic->_select != 0xff)
269 		return;
270 
271 	if (destFlags & DISPFLAG_CURSOR) {
272 		cursorData = new byte[width2 * height1];
273 		Common::fill(cursorData, cursorData + width2 * height1, 0);
274 		destImgData = cursorData;
275 	}
276 
277 	if (srcPic->_pick == 0xff) {
278 		if (srcFlags & DISPFLAG_8) {
279 			error("TODO: sDrawPic variation");
280 		} else {
281 			// loc_258B8
282 			srcP = srcImgData + srcOffset;
283 
284 			if (destFlags & DISPFLAG_8) {
285 				// loc_258D8
286 				destP = destImgData + screenOffset;
287 
288 				if (srcFlags & DISPFLAG_2) {
289 					// loc_25652
290 					srcP = srcImgData + srcOffset;
291 
292 					if (destFlags & DISPFLAG_8) {
293 						// loc_2566F
294 						if (srcFlags & DISPFLAG_2) {
295 							// loc_256FA
296 							srcP = (const byte *)getPixels() + srcOffset;
297 
298 							for (int yp = 0; yp < height1; ++yp) {
299 								for (int xp = 0; xp < width2; ++xp, ++srcP, ++destP) {
300 									pixel = *srcP;
301 									if (pixel)
302 										*destP = pixel;
303 								}
304 
305 								srcP += widthDiff;
306 								destP += widthDiff2;
307 							}
308 						} else {
309 							// loc_25706
310 							for (int yp = 0; yp < height1; ++yp) {
311 								Common::copy(srcP, srcP + width2, destP);
312 								srcP += width2 + widthDiff;
313 								destP += width2 + widthDiff2;
314 							}
315 						}
316 					} else {
317 						// loc_25773
318 						destP = destImgData + screenOffset;
319 
320 						if (srcFlags & DISPFLAG_2) {
321 							// loc_25793
322 							for (int yp = 0; yp < height1; ++yp) {
323 								Common::copy(srcP, srcP + width2, destP);
324 								srcP += width2 + widthDiff;
325 								destP += width2 + widthDiff2;
326 							}
327 						} else {
328 							// loc_25829
329 							destP = (byte *)getPixels() + screenOffset;
330 
331 							for (int yp = 0; yp < height1; ++yp) {
332 								Common::copy(srcP, srcP + width2, destP);
333 								srcP += width2 + widthDiff;
334 								destP += width2 + widthDiff2;
335 							}
336 
337 							addDirtyRect(Common::Rect(offset.x, offset.y, offset.x + width2,
338 								offset.y + height1));
339 						}
340 					}
341 				} else {
342 					// loc_25D40
343 					if (srcFlags & DISPFLAG_100) {
344 						// loc_25D4A
345 						error("TODO: sDrawPic variation");
346 					} else {
347 						// loc_2606D
348 						destP = (byte *)getPixels() + screenOffset;
349 
350 						for (int yp = 0; yp < height1; ++yp) {
351 							Common::copy(srcP, srcP + width2, destP);
352 							destP += width2 + widthDiff2;
353 							srcP += width2 + widthDiff;
354 						}
355 
356 						addDirtyRect(Common::Rect(offset.x, offset.y, offset.x + width2,
357 							offset.y + height1));
358 					}
359 				}
360 			} else {
361 				// loc_2615E
362 				destP = destImgData + screenOffset;
363 
364 				if (srcFlags & DISPFLAG_2) {
365 					// loc_2617e
366 					if (srcFlags & DISPFLAG_100) {
367 						// loc_26188
368 						srcP = srcImgData;
369 						if (isClipped) {
370 							// loc_26199
371 							tmpWidth = (tmpWidth < 0) ? -tmpWidth : 0;
372 							int xMax = tmpWidth + width2;
373 							tmpHeight = (tmpHeight < 0) ? -tmpHeight : 0;
374 
375 							width2 = srcPic->_bounds.width();
376 							height1 = tmpHeight + height1;
377 
378 							for (int yp = 0; yp < height1; ++yp) {
379 								runLength = 0;
380 
381 								for (int xp = 0; xp < width2; ++xp, --runLength) {
382 									if (runLength <= 0) {
383 										pixel = *srcP++;
384 										if (pixel & 0x80) {
385 											pixel &= 0x7f;
386 											runLength = *srcP++;
387 											if (!runLength)
388 												runLength = width2;
389 										}
390 									}
391 
392 									if (yp >= tmpHeight && xp >= tmpWidth && xp < xMax) {
393 										if (pixel > 0)
394 											*destP = pixel;
395 										++destP;
396 									}
397 								}
398 
399 								if (yp >= tmpHeight)
400 									destP += widthDiff2;
401 							}
402 						} else {
403 							// loc_262BE
404 							byteVal = 0;
405 							for (int yp = 0; yp < height1; ++yp) {
406 								for (int xp = 0; xp < width2; ++xp) {
407 									byteVal2 = 0;
408 									if (!byteVal2) {
409 										byteVal = *++srcP;
410 										if (byteVal & 0x80) {
411 											byteVal &= 0x7f;
412 											byteVal2 = *srcP++;
413 
414 											if (!byteVal2)
415 												byteVal2 = width2;
416 										}
417 									}
418 
419 									if (byteVal > 0)
420 										*destP = byteVal;
421 
422 									++destP;
423 									--byteVal2;
424 								}
425 
426 								destP += widthDiff2;
427 							}
428 						}
429 					} else {
430 						// loc_2637F
431 						// Copy with transparency
432 						for (int yp = 0; yp < height1; ++yp) {
433 							for (int xp = 0; xp < width2; ++xp, ++srcP, ++destP) {
434 								if (*srcP != 0)
435 									*destP = *srcP;
436 							}
437 
438 							destP += widthDiff2;
439 							srcP += widthDiff;
440 						}
441 					}
442 				} else {
443 					if (srcFlags & DISPFLAG_100) {
444 						// Simple run-length encoded image
445 						srcP = srcImgData;
446 
447 						if (isClipped) {
448 							// loc_26424
449 							tmpWidth = (tmpWidth < 0) ? -tmpWidth : 0;
450 							int xMax = tmpWidth + width2;
451 							tmpHeight = (tmpHeight < 0) ? -tmpHeight : 0;
452 							width2 = srcPic->_bounds.width();
453 							height1 = tmpHeight + height1;
454 
455 							for (int yp = 0; yp < height1; ++yp) {
456 								runLength = 0;
457 								for (int xp = 0; xp < width2; ++xp, --runLength) {
458 									if (runLength <= 0) {
459 										pixel = *srcP++;
460 										if (pixel & 0x80) {
461 											pixel &= 0x7F;
462 											runLength = *srcP++;
463 
464 											if (!runLength)
465 												runLength = width2;
466 										}
467 									}
468 
469 									if (yp >= tmpHeight && xp >= tmpWidth && xp < xMax) {
470 										*destP++ = pixel;
471 									}
472 								}
473 
474 								if (yp >= tmpHeight)
475 									destP += widthDiff2;
476 							}
477 						} else {
478 							// loc_26543
479 							for (int yp = 0; yp < height1; ++yp) {
480 								int runLen = 0;
481 								for (int xp = 0; xp < width2; ++xp, --runLen) {
482 									if (runLen <= 0) {
483 										// Start of run length, so get pixel and repeat length
484 										pixel = *srcP++;
485 										if (pixel & 0x80) {
486 											pixel &= 0x7f;
487 											runLen = *srcP++;
488 											if (runLen == 0)
489 												runLen = width2;
490 										}
491 									}
492 
493 									// Copy pixel to output
494 									*destP++ = pixel;
495 								}
496 
497 								destP += widthDiff2;
498 							}
499 						}
500 					} else {
501 						for (int yp = 0; yp < height1; ++yp) {
502 							Common::copy(srcP, srcP + width2, destP);
503 							destP += width2 + widthDiff2;
504 							srcP += width2 + widthDiff;
505 						}
506 					}
507 				}
508 			}
509 		}
510 	} else {
511 		// loc_26666
512 		if (srcPic->_pick == 0) {
513 			// loc_2727A
514 			byte onOff = srcPic->_onOff;
515 
516 			if (srcFlags & DISPFLAG_2) {
517 				if (!(srcFlags & DISPFLAG_8)) {
518 					srcP = srcImgData + srcOffset;
519 
520 					if (destFlags & DISPFLAG_8) {
521 						// loc_272C3
522 						error("TODO: sDrawPic variation");
523 					} else {
524 						destP = destImgData + screenOffset;
525 						for (int yp = 0; yp < height1; ++yp) {
526 							for (int xp = 0; xp < width2; ++xp, ++destP) {
527 								if ((int8)*srcP++ < 0)
528 									*destP = onOff;
529 							}
530 
531 							destP += widthDiff2;
532 							srcP += widthDiff;
533 						}
534 					}
535 				}
536 			} else {
537 				// loc_27477
538 				if (destFlags & DISPFLAG_8) {
539 					// loc_27481
540 					destP = (byte *)getPixels() + screenOffset;
541 					for (int yp = 0; yp < height1; ++yp) {
542 						Common::fill(destP, destP + width2, onOff);
543 						destP += width2 + widthDiff2;
544 					}
545 
546 					addDirtyRect(Common::Rect(offset.x, offset.y, offset.x + width2,
547 						offset.y + height1));
548 				} else {
549 					// loc_2753C
550 					destP = destImgData + screenOffset;
551 
552 					for (int yp = 0; yp < height1; ++yp) {
553 						Common::fill(destP, destP + width2, onOff);
554 						destP += width2 + widthDiff2;
555 					}
556 				}
557 			}
558 
559 		} else {
560 			// loc_26673
561 			byte pick = srcPic->_pick;
562 			byte onOff = srcPic->_onOff;
563 
564 			if (!(srcFlags & PICFLAG_PIC_OFFSET)) {
565 				srcP = srcImgData += srcOffset;
566 				pixel = 0;
567 
568 				if (destFlags & PICFLAG_PIC_OFFSET) {
569 					destP = destImgData + screenOffset;
570 					if (srcFlags & PICFLAG_2) {
571 						if (srcFlags & PICFLAG_100) {
572 							if (isClipped) {
573 								// loc_266E3
574 								destP = (byte *)getPixels() + screenOffset;
575 								tmpWidth = (tmpWidth < 0) ? -tmpWidth : 0;
576 								int xMax = tmpWidth + width2;
577 								tmpHeight = (tmpHeight < 0) ? -tmpHeight : 0;
578 								pick = 0x7F;
579 								width2 = srcPic->_bounds.width();
580 								height1 = tmpHeight + height1;
581 
582 								for (int yp = 0; yp < height1; ++yp) {
583 									int runLen = 0;
584 									for (int xp = 0; xp < width2; ++xp, --runLen) {
585 										if (runLen <= 0) {
586 											pixel = *srcP++;
587 											if (pixel & 0x80) {
588 												pixel &= 0x7F;
589 												runLen = *srcP++;
590 												if (!runLen)
591 													runLen = width2;
592 											}
593 										}
594 
595 										if (yp >= tmpHeight && xp >= tmpWidth && xp < xMax) {
596 											if (pixel) {
597 												*destP = (pixel & pick) ^ onOff;
598 											}
599 											++destP;
600 										}
601 									}
602 									if (yp >= tmpHeight)
603 										destP += widthDiff2;
604 								}
605 
606 								addDirtyRect(Common::Rect(offset.x, offset.y, offset.x + width2,
607 									offset.y + height1));
608 							} else {
609 								// loc_26815
610 								destP = (byte *)getPixels() + screenOffset;
611 
612 								for (int yp = 0; yp < height1; ++yp) {
613 									for (int xi = 0; xi < width2; ++xi, ++destP) {
614 										byteVal2 = 0;
615 										for (int xp = 0; xp < width2; ++xp, ++destP, --byteVal2) {
616 											if (!byteVal2) {
617 												pixel = *srcP++;
618 												if (pixel & 0x80) {
619 													pixel &= 0x7F;
620 													byteVal2 = *srcP++;
621 													if (!byteVal2) {
622 														byteVal2 = width2;
623 													}
624 												}
625 											}
626 
627 											if (pixel)
628 												*destP = (pixel & pick) ^ onOff;
629 										}
630 									}
631 
632 									destP += widthDiff2;
633 								}
634 
635 								addDirtyRect(Common::Rect(offset.x, offset.y, offset.x + width2,
636 									offset.y + height1));
637 							}
638 						} else {
639 							// Direct screen write
640 							destP = (byte *)getPixels() + screenOffset;
641 
642 							for (int yp = 0; yp < height1; ++yp) {
643 								for (int xp = 0; xp < width2; ++xp, ++srcP, ++destP) {
644 									if (*srcP)
645 										*destP = (*srcP & pick) ^ onOff;
646 								}
647 								destP += widthDiff2;
648 								srcP += widthDiff;
649 							}
650 
651 							addDirtyRect(Common::Rect(offset.x, offset.y, offset.x + width2,
652 								offset.y + height1));
653 						}
654 					} else if (srcFlags & PICFLAG_100) {
655 						srcP = srcImgData;
656 						if (isClipped) {
657 							// loc_269FD
658 							tmpWidth = (tmpWidth < 0) ? -tmpWidth : 0;
659 							int xMax = tmpWidth + width2;
660 							tmpHeight = (tmpHeight < 0) ? -tmpHeight : 0;
661 							width2 = srcPic->_bounds.width();
662 							height1 = tmpHeight + height1;
663 
664 							for (int yp = 0; yp < height1; ++yp) {
665 								runLength = 0;
666 								for (int xp = 0; xp < width2; ++xp, --runLength) {
667 									if (runLength <= 0) {
668 										pixel = *srcP++;
669 										if (pixel & 0x80) {
670 											pixel &= 0x7F;
671 											runLength = *srcP++;
672 
673 											if (!runLength)
674 												runLength = width2;
675 										}
676 									}
677 
678 									if (yp >= tmpHeight && xp >= tmpWidth && xp < xMax) {
679 										*destP++ = (pixel & 0x80) ^ onOff;
680 									}
681 								}
682 							}
683 						} else {
684 							// loc_26BD5
685 							destP = (byte *)getPixels() + screenOffset;
686 
687 							for (int yp = 0; yp < height1; ++yp) {
688 								byteVal2 = 0;
689 
690 								for (int xp = 0; xp < width2; ++xp, ++destP) {
691 									if (!byteVal2) {
692 										pixel = *srcP++;
693 										if (pixel & 0x80) {
694 											pixel &= 0x7F;
695 											byteVal2 = *srcP++;
696 											if (!byteVal2)
697 												byteVal2 = width2;
698 										}
699 									}
700 
701 									*destP = (pixel & pick) ^ onOff;
702 								}
703 
704 								destP += widthDiff2;
705 							}
706 
707 							addDirtyRect(Common::Rect(offset.x, offset.y, offset.x + width2,
708 								offset.y + height1));
709 						}
710 					} else {
711 						// loc_26C9A
712 						destP = (byte *)getPixels() + screenOffset;
713 
714 						for (int yp = 0; yp < height1; ++yp) {
715 							for (int xp = 0; xp < width2; ++xp, ++srcP, ++destP) {
716 								*destP = (*srcP & pick) ^ onOff;
717 							}
718 							destP += widthDiff2;
719 							srcP += widthDiff;
720 						}
721 
722 						addDirtyRect(Common::Rect(offset.x, offset.y, offset.x + width2,
723 							offset.y + height1));
724 					}
725 				} else {
726 					// loc_26D2F
727 					destP = destImgData + screenOffset;
728 
729 					if (srcFlags & PICFLAG_2) {
730 						// loc_26D4F
731 						if (srcFlags & PICFLAG_100) {
732 							srcP = srcImgData;
733 
734 							if (isClipped) {
735 								// loc_26D6A
736 								tmpWidth = (tmpWidth < 0) ? -tmpWidth : 0;
737 								int xMax = tmpWidth + width2;
738 								tmpHeight = (tmpHeight < 0) ? -tmpHeight : 0;
739 								width2 = srcPic->_bounds.width();
740 								height1 = tmpHeight + height1;
741 
742 								for (int yp = 0; yp < height1; ++yp) {
743 									runLength = 0;
744 
745 									for (int xp = 0; xp < width2; ++xp, --runLength) {
746 										if (runLength <= 0) {
747 											pixel = *srcP++;
748 											if (pixel & 0x80) {
749 												pixel &= 0x7F;
750 												runLength = *srcP++;
751 												if (!runLength)
752 													runLength = width2;
753 											}
754 										}
755 
756 										if (yp >= tmpHeight && xp >= tmpWidth && xp < xMax) {
757 											if (pixel)
758 												*destP = (pixel & pick) ^ onOff;
759 
760 											++destP;
761 										}
762 									}
763 
764 									if (yp >= tmpHeight)
765 										destP += widthDiff2;
766 								}
767 							} else {
768 								// loc_26E95
769 								for (int yp = 0; yp < height1; ++yp) {
770 									byteVal2 = 0;
771 									for (int xp = 0; xp < width2; ++xp, ++destP, --byteVal2) {
772 										if (!byteVal2) {
773 											pixel = *srcP++;
774 											if (pixel & 0x80) {
775 												pixel &= 0x7F;
776 												byteVal2 = *srcP++;
777 												if (!byteVal2)
778 													byteVal2 = width2;
779 											}
780 										}
781 
782 										if (pixel)
783 											*destP = (pixel & pick) ^ onOff;
784 									}
785 
786 									destP += widthDiff2;
787 								}
788 							}
789 						} else {
790 							// loc_26F5D
791 							for (int yp = 0; yp < height1; ++yp) {
792 								for (int xp = 0; xp < width2; ++xp, ++srcP, ++destP) {
793 									if (*srcP)
794 										*destP = (*srcP & pick) ^ onOff;
795 								}
796 								destP += widthDiff2;
797 								srcP += widthDiff;
798 							}
799 						}
800 					} else {
801 						// loc_26FEF
802 						if (srcFlags & PICFLAG_100) {
803 							// loc_26FF9
804 							for (int yp = 0; yp < height1; ++yp) {
805 								for (int xp = 0; xp < width2; ++xp, ++srcP, ++destP) {
806 									*destP = (*srcP & pick) ^ onOff;
807 								}
808 								destP += widthDiff2;
809 								srcP += widthDiff;
810 							}
811 						} else {
812 							// loc_271F0
813 							srcP = srcImgData;
814 
815 							if (isClipped) {
816 								// loc_2700A
817 								tmpWidth = (tmpWidth < 0) ? -tmpWidth : 0;
818 								int xMax = tmpWidth + width2;
819 								tmpHeight = (tmpHeight < 0) ? -tmpHeight : 0;
820 								width2 = srcPic->_bounds.width();
821 								height1 = tmpHeight + height1;
822 
823 								for (int yp = 0; yp < height1; ++yp) {
824 									runLength = 0;
825 
826 									for (int xp = 0; xp < width2; ++xp, --runLength) {
827 										if (runLength <= 0) {
828 											pixel = *srcP++;
829 											if (pixel & 0x80) {
830 												pixel &= 0x7F;
831 												runLength = *srcP++;
832 												if (!runLength)
833 													runLength = width2;
834 											}
835 										}
836 
837 										if (yp >= tmpHeight && xp >= tmpWidth && xp < xMax) {
838 											*destP++ = (pixel & pick) ^ onOff;
839 										}
840 									}
841 
842 									if (yp >= tmpHeight)
843 										destP += widthDiff2;
844 								}
845 							} else {
846 								// loc_2712F
847 								for (int yp = 0; yp < height1; ++yp) {
848 									byteVal2 = 0;
849 									for (int xp = 0; xp < width2; ++xp, ++destP, --byteVal2) {
850 										if (!byteVal2) {
851 											pixel = *srcP++;
852 											if (pixel & 0x80) {
853 												pixel &= 0x7F;
854 												byteVal2 = *srcP++;
855 												if (!byteVal2)
856 													byteVal2 = width2;
857 											}
858 										}
859 
860 										*destP = (*srcP & pick) ^ onOff;
861 									}
862 									destP += widthDiff2;
863 								}
864 							}
865 						}
866 					}
867 				}
868 			}
869 		}
870 	}
871 
872 	if (cursorData) {
873 		_vm->_eventsManager->setCursor(cursorData, width2, height1, srcPic->_keyColor);
874 		delete[] cursorData;
875 	}
876 }
877 
drawANumber(DisplayResource * display,int num,const Common::Point & pt)878 void Screen::drawANumber(DisplayResource *display, int num, const Common::Point &pt) {
879 	PictureResource *pic = _vm->_bVoy->boltEntry(num + 261)._picResource;
880 	sDrawPic(pic, display, pt);
881 }
882 
fillPic(DisplayResource * display,byte onOff)883 void Screen::fillPic(DisplayResource *display, byte onOff) {
884 	PictureResource *pic;
885 	if (display->_flags & DISPFLAG_VIEWPORT) {
886 		pic = ((ViewPortResource *)display)->_currentPic;
887 	} else {
888 		pic = (PictureResource *)display;
889 	}
890 
891 	PictureResource picResource;
892 	picResource._flags = DISPFLAG_NONE;
893 	picResource._select = 0xff;
894 	picResource._pick = 0;
895 	picResource._onOff = onOff;
896 	picResource._bounds = pic->_bounds;
897 
898 	sDrawPic(&picResource, display, Common::Point());
899 }
900 
901 /**
902  * Queues the given picture for display
903  */
sDisplayPic(PictureResource * pic)904 void Screen::sDisplayPic(PictureResource *pic) {
905 	_vm->_eventsManager->_intPtr._flipWait = true;
906 }
907 
flipPage()908 void Screen::flipPage() {
909 	Common::Array<ViewPortResource *> &viewPorts = _viewPortListPtr->_entries;
910 	bool flipFlag = false;
911 
912 	for (uint idx = 0; idx < viewPorts.size(); ++idx) {
913 		if (viewPorts[idx]->_flags & DISPFLAG_20) {
914 			flipFlag = false;
915 			if ((viewPorts[idx]->_flags & DISPFLAG_8) && (viewPorts[idx]->_flags & DISPFLAG_1)) {
916 				if (_planeSelect == idx)
917 					sDisplayPic(viewPorts[idx]->_currentPic);
918 				flipFlag = true;
919 			}
920 		}
921 
922 		if (flipFlag) {
923 			ViewPortResource &viewPort = *viewPorts[idx];
924 
925 			viewPort._lastPage = viewPort._pageIndex;
926 			++viewPort._pageIndex;
927 
928 			if (viewPort._pageIndex >= viewPort._pageCount)
929 				viewPort._pageIndex = 0;
930 
931 			assert(viewPort._pageIndex < 2);
932 			viewPort._currentPic = viewPort._pages[viewPort._pageIndex];
933 			viewPort._flags = (viewPort._flags & ~DISPFLAG_8) | DISPFLAG_40;
934 		}
935 	}
936 }
937 
restoreBack(Common::Array<Common::Rect> & rectList,int rectListCount,PictureResource * srcPic,PictureResource * destPic)938 void Screen::restoreBack(Common::Array<Common::Rect> &rectList, int rectListCount,
939 		PictureResource *srcPic, PictureResource *destPic) {
940 	// WORKAROUND: Since _backgroundPage can point to a resource freed at the end of display methods,
941 	// I'm now explicitly resetting it to null in screenReset(), so at this point it can be null
942 	if (!srcPic)
943 		return;
944 
945 	bool saveBack = _saveBack;
946 	_saveBack = false;
947 
948 	if (rectListCount == -1) {
949 		sDrawPic(srcPic, destPic, Common::Point());
950 	} else {
951 		for (int i = rectListCount - 1; i >= 0; --i) {
952 			_clipPtr = &rectList[i];
953 			sDrawPic(srcPic, destPic, Common::Point());
954 		}
955 	}
956 
957 	_saveBack = saveBack;
958 }
959 
setPalette(const byte * palette,int start,int count)960 void Screen::setPalette(const byte *palette, int start, int count) {
961 	Graphics::Screen::setPalette(palette, start, count);
962 	_vm->_eventsManager->_gameData._hasPalette = false;
963 }
964 
setPalette128(const byte * palette,int start,int count)965 void Screen::setPalette128(const byte *palette, int start, int count) {
966 	byte rgb[3];
967 	getPalette(&rgb[0], 128, 1);
968 	Graphics::Screen::setPalette(palette, start, count);
969 	Graphics::Screen::setPalette(&rgb[0], 128, 1);
970 }
971 
resetPalette()972 void Screen::resetPalette() {
973 	for (int i = 0; i < 256; ++i)
974 		setColor(i, 0, 0, 0);
975 
976 	_vm->_eventsManager->_intPtr._hasPalette = true;
977 }
978 
setColor(int idx,byte r,byte g,byte b)979 void Screen::setColor(int idx, byte r, byte g, byte b) {
980 	byte *vgaP = &_VGAColors[idx * 3];
981 	vgaP[0] = r;
982 	vgaP[1] = g;
983 	vgaP[2] = b;
984 
985 	_vm->_eventsManager->_intPtr._palStartIndex = MIN(_vm->_eventsManager->_intPtr._palStartIndex, idx);
986 	_vm->_eventsManager->_intPtr._palEndIndex = MAX(_vm->_eventsManager->_intPtr._palEndIndex, idx);
987 }
988 
setOneColor(int idx,byte r,byte g,byte b)989 void Screen::setOneColor(int idx, byte r, byte g, byte b) {
990 	byte palEntry[3];
991 	palEntry[0] = r;
992 	palEntry[1] = g;
993 	palEntry[2] = b;
994 	g_system->getPaletteManager()->setPalette(&palEntry[0], idx, 1);
995 }
996 
setColors(int start,int count,const byte * pal)997 void Screen::setColors(int start, int count, const byte *pal) {
998 	for (int i = 0; i < count; ++i) {
999 		if ((i + start) != 128) {
1000 			const byte *rgb = pal + i * 3;
1001 			setColor(i + start, rgb[0], rgb[1], rgb[2]);
1002 		}
1003 	}
1004 
1005 	_vm->_eventsManager->_intPtr._hasPalette = true;
1006 }
1007 
screenReset()1008 void Screen::screenReset() {
1009 	resetPalette();
1010 
1011 	_backgroundPage = NULL;
1012 	_vPort->setupViewPort(NULL);
1013 	fillPic(_vPort, 0);
1014 
1015 	_vm->flipPageAndWait();
1016 }
1017 
fadeDownICF1(int steps)1018 void Screen::fadeDownICF1(int steps) {
1019 	if (steps > 0) {
1020 		int stepAmount = _vm->_voy->_fadingAmount2 / steps;
1021 
1022 		for (int idx = 0; idx < steps; ++idx) {
1023 			_vm->_voy->_fadingAmount2 -= stepAmount;
1024 			_vm->_eventsManager->delay(1);
1025 		}
1026 	}
1027 
1028 	_vm->_voy->_fadingAmount2 = 0;
1029 }
1030 
fadeUpICF1(int steps)1031 void Screen::fadeUpICF1(int steps) {
1032 	if (steps > 0) {
1033 		int stepAmount = (63 - _vm->_voy->_fadingAmount2) / steps;
1034 
1035 		for (int idx = 0; idx < steps; ++idx) {
1036 			_vm->_voy->_fadingAmount2 += stepAmount;
1037 			_vm->_eventsManager->delay(1);
1038 		}
1039 	}
1040 
1041 	_vm->_voy->_fadingAmount2 = 63;
1042 }
1043 
fadeDownICF(int steps)1044 void Screen::fadeDownICF(int steps) {
1045 	if (steps > 0) {
1046 		_vm->_eventsManager->hideCursor();
1047 		int stepAmount1 = _vm->_voy->_fadingAmount1 / steps;
1048 		int stepAmount2 = _vm->_voy->_fadingAmount2 / steps;
1049 
1050 		for (int idx = 0; idx < steps; ++idx) {
1051 			_vm->_voy->_fadingAmount1 -= stepAmount1;
1052 			_vm->_voy->_fadingAmount2 -= stepAmount2;
1053 			_vm->_eventsManager->delay(1);
1054 		}
1055 	}
1056 
1057 	_vm->_voy->_fadingAmount1 = 0;
1058 	_vm->_voy->_fadingAmount2 = 0;
1059 }
1060 
drawDot()1061 void Screen::drawDot() {
1062 	for (int idx = 0; idx < 9; ++idx) {
1063 		uint offset = DOT_LINE_START[idx] + DOT_LINE_OFFSET[idx];
1064 		int xp = offset % SCREEN_WIDTH;
1065 		int yp = offset / SCREEN_WIDTH;
1066 
1067 		byte *pDest = (byte *)getPixels() + offset;
1068 		Common::fill(pDest, pDest + DOT_LINE_LENGTH[idx], 0x80);
1069 		addDirtyRect(Common::Rect(xp, yp, xp + DOT_LINE_LENGTH[idx], yp + 1));
1070 	}
1071 }
1072 
synchronize(Common::Serializer & s)1073 void Screen::synchronize(Common::Serializer &s) {
1074 	s.syncBytes(&_VGAColors[0], PALETTE_SIZE);
1075 }
1076 
1077 } // End of namespace Voyeur
1078