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 "made/screen.h"
24 #include "made/made.h"
25 #include "made/screenfx.h"
26 #include "made/database.h"
27 
28 #include "common/system.h"
29 
30 #include "graphics/surface.h"
31 #include "graphics/palette.h"
32 #include "graphics/cursorman.h"
33 
34 namespace Made {
35 
Screen(MadeEngine * vm)36 Screen::Screen(MadeEngine *vm) : _vm(vm) {
37 
38 	_palette = new byte[768];
39 	_newPalette = new byte[768];
40 
41 	_backgroundScreen = new Graphics::Surface();
42 	_backgroundScreen->create(320, 200, Graphics::PixelFormat::createFormatCLUT8());
43 
44 	_workScreen = new Graphics::Surface();
45 	_workScreen->create(320, 200, Graphics::PixelFormat::createFormatCLUT8());
46 
47 	_backgroundScreenDrawCtx.clipRect = Common::Rect(320, 200);
48 	_workScreenDrawCtx.clipRect = Common::Rect(320, 200);
49 
50 	_backgroundScreenDrawCtx.destSurface = _backgroundScreen;
51 	_workScreenDrawCtx.destSurface = _workScreen;
52 	_clipArea.destSurface = _workScreen;
53 
54 	// Screen mask is only needed in v2 games
55 	if (_vm->getGameID() != GID_RTZ) {
56 		_screenMask = new Graphics::Surface();
57 		_screenMask->create(320, 200, Graphics::PixelFormat::createFormatCLUT8());
58 		_maskDrawCtx.clipRect = Common::Rect(320, 200);
59 		_maskDrawCtx.destSurface = _screenMask;
60 	}
61 
62 	for (int i = 0; i <= 3; i++)
63 		_excludeClipAreaEnabled[i] = false;
64 
65 	_screenLock = false;
66 	_paletteLock = false;
67 
68 	_paletteInitialized = false;
69 	_needPalette = false;
70 	_oldPaletteColorCount = 256;
71 	_paletteColorCount = 256;
72 	memset(_newPalette, 0, 768);
73 	memset(_palette, 0, 768);
74 
75 	_ground = 1;
76 	_clip = 0;
77 	_exclude = 0;
78 	_mask = 0;
79 
80 	_visualEffectNum = 0;
81 	_fx = new ScreenEffects(this);
82 
83 	_textX = 0;
84 	_textY = 0;
85 	_textColor = 0;
86 	_textRect.left = 0;
87 	_textRect.top = 0;
88 	_textRect.right = 320;
89 	_textRect.bottom = 200;
90 	_font = NULL;
91 	_currentFontNum = 0;
92 	_fontDrawCtx.clipRect = Common::Rect(320, 200);
93 	_fontDrawCtx.destSurface = _backgroundScreen;
94 	_outlineColor = 0;
95 	_dropShadowColor = 0;
96 
97 	clearChannels();
98 }
99 
~Screen()100 Screen::~Screen() {
101 
102 	delete[] _palette;
103 	delete[] _newPalette;
104 
105 	delete _backgroundScreen;
106 	delete _workScreen;
107 	if (_vm->getGameID() != GID_RTZ)
108 		delete _screenMask;
109 	delete _fx;
110 }
111 
clearScreen()112 void Screen::clearScreen() {
113 	_backgroundScreen->fillRect(Common::Rect(0, 0, 320, 200), 0);
114 	_workScreen->fillRect(Common::Rect(0, 0, 320, 200), 0);
115 	if (_vm->getGameID() != GID_RTZ)
116 		_screenMask->fillRect(Common::Rect(0, 0, 320, 200), 0);
117 	_mask = 0;
118 	_needPalette = true;
119 }
120 
setExcludeArea(uint16 x1,uint16 y1,uint16 x2,uint16 y2)121 void Screen::setExcludeArea(uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
122 
123 	_excludeClipAreaEnabled[0] = false;
124 	_excludeClipAreaEnabled[1] = false;
125 	_excludeClipAreaEnabled[2] = false;
126 	_excludeClipAreaEnabled[3] = false;
127 
128 	if (x1 == 0 && y1 == 0 && x2 == 0 && y2 == 0) {
129 		_excludeClipArea[0].clipRect = Common::Rect(320, 200);
130 		_excludeClipAreaEnabled[0] = true;
131 		return;
132 	}
133 
134 	if (y1 > 0 && y2 > 0) {
135 		_excludeClipArea[0].clipRect = Common::Rect(320, y1);
136 		_excludeClipAreaEnabled[0] = true;
137 	}
138 
139 	if (y1 < 200 && y2 < 200) {
140 		_excludeClipArea[1].clipRect = Common::Rect(0, y2, 320, 200);
141 		_excludeClipAreaEnabled[1] = true;
142 	}
143 
144 	if (x1 > 0 && x2 > 0) {
145 		_excludeClipArea[2].clipRect = Common::Rect(0, y1, x1, y2);
146 		_excludeClipAreaEnabled[2] = true;
147 	}
148 
149 	if (x1 < 320 && x2 < 320) {
150 		_excludeClipArea[3].clipRect = Common::Rect(x2, y1, 320, y2);
151 		_excludeClipAreaEnabled[3] = true;
152 	}
153 
154 }
155 
drawSurface(Graphics::Surface * sourceSurface,int x,int y,int16 flipX,int16 flipY,int16 mask,const ClipInfo & clipInfo)156 void Screen::drawSurface(Graphics::Surface *sourceSurface, int x, int y, int16 flipX, int16 flipY, int16 mask, const ClipInfo &clipInfo) {
157 
158 	byte *source, *dest, *maskp = 0;
159 	int startX = 0;
160 	int startY = 0;
161 	int clipWidth = sourceSurface->w;
162 	int clipHeight = sourceSurface->h;
163 
164 	if (x < clipInfo.clipRect.left) {
165 		startX = clipInfo.clipRect.left - x;
166 		clipWidth -= startX;
167 		x = clipInfo.clipRect.left;
168 	}
169 
170 	if (y < clipInfo.clipRect.top) {
171 		startY = clipInfo.clipRect.top - y;
172 		clipHeight -= startY;
173 		y = clipInfo.clipRect.top;
174 	}
175 
176 	if (x + clipWidth > clipInfo.clipRect.right) {
177 		clipWidth = clipInfo.clipRect.right - x;
178 	}
179 
180 	if (y + clipHeight > clipInfo.clipRect.bottom) {
181 		clipHeight = clipInfo.clipRect.bottom - y;
182 	}
183 
184 	source = (byte *)sourceSurface->getBasePtr(0, startY);
185 	dest = (byte *)clipInfo.destSurface->getBasePtr(x, y);
186 	if (_vm->getGameID() != GID_RTZ)
187 		maskp = (byte *)_maskDrawCtx.destSurface->getBasePtr(x, y);
188 
189 	int32 sourcePitch, linePtrAdd, sourceAdd;
190 	byte *linePtr;
191 
192 	if (flipX) {
193 		linePtrAdd = -1;
194 		sourceAdd = sourceSurface->w - startX - 1;
195 	} else {
196 		linePtrAdd = 1;
197 		sourceAdd = startX;
198 	}
199 
200 	if (flipY) {
201 		sourcePitch = -sourceSurface->pitch;
202 		source += (clipHeight - 1) * sourceSurface->pitch;
203 	} else {
204 		sourcePitch = sourceSurface->pitch;
205 	}
206 
207 	for (int16 yc = 0; yc < clipHeight; yc++) {
208 		linePtr = source + sourceAdd;
209 		for (int16 xc = 0; xc < clipWidth; xc++) {
210 			if (*linePtr && (_vm->getGameID() == GID_RTZ || (mask == 0 || (maskp && maskp[xc] == 0)))) {
211 				if (*linePtr)
212 					dest[xc] = *linePtr;
213 			}
214 			linePtr += linePtrAdd;
215 		}
216 
217 		source += sourcePitch;
218 		dest += clipInfo.destSurface->pitch;
219 		if (_vm->getGameID() != GID_RTZ)
220 			maskp += _maskDrawCtx.destSurface->pitch;
221 	}
222 
223 }
224 
setRGBPalette(byte * palRGB,int start,int count)225 void Screen::setRGBPalette(byte *palRGB, int start, int count) {
226 	_vm->_system->getPaletteManager()->setPalette(palRGB, start, count);
227 }
228 
updateChannel(uint16 channelIndex)229 uint16 Screen::updateChannel(uint16 channelIndex) {
230 	return channelIndex;
231 }
232 
deleteChannel(uint16 channelIndex)233 void Screen::deleteChannel(uint16 channelIndex) {
234 	if (channelIndex < 1 || channelIndex >= 100)
235 		return;
236 	_channels[channelIndex - 1].type = 0;
237 	_channels[channelIndex - 1].state = 0;
238 	_channels[channelIndex - 1].index = 0;
239 }
240 
getChannelType(uint16 channelIndex)241 int16 Screen::getChannelType(uint16 channelIndex) {
242 	if (channelIndex < 1 || channelIndex >= 100)
243 		return -1;
244 	return _channels[channelIndex - 1].type;
245 }
246 
getChannelState(uint16 channelIndex)247 int16 Screen::getChannelState(uint16 channelIndex) {
248 	if (channelIndex < 1 || channelIndex >= 100)
249 		return -1;
250 	return _channels[channelIndex - 1].state;
251 }
252 
setChannelState(uint16 channelIndex,int16 state)253 void Screen::setChannelState(uint16 channelIndex, int16 state) {
254 	if (channelIndex < 1 || channelIndex >= 100 || _channels[channelIndex - 1].type == 0)
255 		return;
256 	_channels[channelIndex - 1].state = state;
257 }
258 
setChannelLocation(uint16 channelIndex,int16 x,int16 y)259 uint16 Screen::setChannelLocation(uint16 channelIndex, int16 x, int16 y) {
260 	if (channelIndex < 1 || channelIndex >= 100 || _channels[channelIndex - 1].type == 0)
261 		return 0;
262 	_channels[channelIndex - 1].x = x;
263 	_channels[channelIndex - 1].y = y;
264 	return updateChannel(channelIndex - 1) + 1;
265 }
266 
setChannelContent(uint16 channelIndex,uint16 index)267 uint16 Screen::setChannelContent(uint16 channelIndex, uint16 index) {
268 	if (channelIndex < 1 || channelIndex >= 100 || _channels[channelIndex - 1].type == 0)
269 		return 0;
270 	_channels[channelIndex - 1].index = index;
271 	return updateChannel(channelIndex - 1) + 1;
272 }
273 
setChannelUseMask(uint16 channelIndex)274 void Screen::setChannelUseMask(uint16 channelIndex) {
275 	if (channelIndex < 1 || channelIndex >= 100)
276 		return;
277 	_channels[channelIndex - 1].mask = _mask;
278 }
279 
drawSpriteChannels(const ClipInfo & clipInfo,int16 includeStateMask,int16 excludeStateMask)280 void Screen::drawSpriteChannels(const ClipInfo &clipInfo, int16 includeStateMask, int16 excludeStateMask) {
281 
282 	for (int i = 0; i <= 3; i++)
283 		_excludeClipArea[i].destSurface = clipInfo.destSurface;
284 
285 	_clipArea.destSurface = clipInfo.destSurface;
286 
287 	for (uint16 i = 0; i < _channelsUsedCount; i++) {
288 
289 		debug(2, "drawSpriteChannels() i = %d\n", i);
290 
291 		if (((_channels[i].state & includeStateMask) == includeStateMask) && (_channels[i].state & excludeStateMask) == 0) {
292 			int16 flipX = _channels[i].state & 0x10;
293 			int16 flipY = _channels[i].state & 0x20;
294 
295 			debug(2, "drawSpriteChannels() type = %d; index = %04X\n", _channels[i].type, _channels[i].index);
296 
297 			switch (_channels[i].type) {
298 
299 			case 1: // drawFlex
300 				if (_channels[i].state & 4) {
301 					drawFlex(_channels[i].index, _channels[i].x, _channels[i].y, flipX, flipY, _channels[i].mask, _clipArea);
302 				} else if (_channels[i].state & 8) {
303 					for (int excludeIndex = 0; excludeIndex < 4; excludeIndex++) {
304 						if (_excludeClipAreaEnabled[excludeIndex]) {
305 							drawFlex(_channels[i].index, _channels[i].x, _channels[i].y, flipX, flipY, _channels[i].mask, _excludeClipArea[excludeIndex]);
306 						}
307 					}
308 				} else {
309 					drawFlex(_channels[i].index, _channels[i].x, _channels[i].y, flipX, flipY, _channels[i].mask, clipInfo);
310 				}
311 				break;
312 
313 			case 2: // drawObjectText
314 				printObjectText(_channels[i].index, _channels[i].x, _channels[i].y, _channels[i].fontNum, _channels[i].textColor, _channels[i].outlineColor, clipInfo);
315 				break;
316 
317 			case 3: // drawAnimFrame
318 				if (_channels[i].state & 4) {
319 					drawAnimFrame(_channels[i].index, _channels[i].x, _channels[i].y, _channels[i].frameNum, flipX, flipY, _clipArea);
320 				} else if (_channels[i].state & 8) {
321 					for (int excludeIndex = 0; excludeIndex < 4; excludeIndex++) {
322 						if (_excludeClipAreaEnabled[excludeIndex]) {
323 							drawAnimFrame(_channels[i].index, _channels[i].x, _channels[i].y, _channels[i].frameNum, flipX, flipY, _excludeClipArea[excludeIndex]);
324 						}
325 					}
326 				} else {
327 					drawAnimFrame(_channels[i].index, _channels[i].x, _channels[i].y, _channels[i].frameNum, flipX, flipY, clipInfo);
328 				}
329 				break;
330 
331 			case 4: // drawMenuText
332 				// Never used in any game
333 				break;
334 
335 			default:
336 				break;
337 
338 			}
339 
340 		}
341 
342 	}
343 
344 }
345 
updateSprites()346 void Screen::updateSprites() {
347 	// TODO: This needs some more work, dirty rectangles are currently not used
348 
349 	memcpy(_workScreen->getPixels(), _backgroundScreen->getPixels(), 64000);
350 
351 	drawSpriteChannels(_backgroundScreenDrawCtx, 3, 0);
352 	drawSpriteChannels(_workScreenDrawCtx, 1, 2);
353 
354 	_vm->_system->copyRectToScreen(_workScreen->getPixels(), _workScreen->pitch, 0, 0, _workScreen->w, _workScreen->h);
355 	_vm->_screen->updateScreenAndWait(10);
356 }
357 
clearChannels()358 void Screen::clearChannels() {
359 	for (uint16 i = 0; i < ARRAYSIZE(_channels); i++) {
360 		_channels[i].type = 0;
361 		_channels[i].index = 0;
362 		_channels[i].mask = 0;
363 	}
364 	_channelsUsedCount = 0;
365 }
366 
drawFlex(uint16 flexIndex,int16 x,int16 y,int16 flipX,int16 flipY,int16 mask,const ClipInfo & clipInfo)367 uint16 Screen::drawFlex(uint16 flexIndex, int16 x, int16 y, int16 flipX, int16 flipY, int16 mask, const ClipInfo &clipInfo) {
368 
369 	if (flexIndex == 0)
370 		return 0;
371 
372 	PictureResource *flex = _vm->_res->getPicture(flexIndex);
373 	if (!flex)
374 		error("Failed to find picture %d", flexIndex);
375 
376 	Graphics::Surface *sourceSurface = flex->getPicture();
377 
378 	drawSurface(sourceSurface, x, y, flipX, flipY, mask, clipInfo);
379 
380 	// Palette is set in showPage
381 	if (flex->hasPalette() && !_paletteLock && _needPalette) {
382 		byte *flexPalette = flex->getPalette();
383 		_oldPaletteColorCount = _paletteColorCount;
384 		_paletteColorCount = flex->getPaletteColorCount();
385 		memcpy(_newPalette, _palette, _oldPaletteColorCount * 3);
386 		memcpy(_palette, flexPalette, _paletteColorCount * 3);
387 		_needPalette = false;
388 	}
389 
390 	_vm->_res->freeResource(flex);
391 
392 	return 0;
393 }
394 
drawAnimFrame(uint16 animIndex,int16 x,int16 y,int16 frameNum,int16 flipX,int16 flipY,const ClipInfo & clipInfo)395 void Screen::drawAnimFrame(uint16 animIndex, int16 x, int16 y, int16 frameNum, int16 flipX, int16 flipY, const ClipInfo &clipInfo) {
396 
397 	if (frameNum < 0)
398 		return;
399 
400 	AnimationResource *anim = _vm->_res->getAnimation(animIndex);
401 	Graphics::Surface *sourceSurface = anim->getFrame(frameNum);
402 
403 	drawSurface(sourceSurface, x, y, flipX, flipY, 0, clipInfo);
404 
405 	_vm->_res->freeResource(anim);
406 }
407 
drawPic(uint16 index,int16 x,int16 y,int16 flipX,int16 flipY)408 uint16 Screen::drawPic(uint16 index, int16 x, int16 y, int16 flipX, int16 flipY) {
409 	drawFlex(index, x, y, flipX, flipY, 0, _backgroundScreenDrawCtx);
410 	return 0;
411 }
412 
drawMask(uint16 index,int16 x,int16 y)413 uint16 Screen::drawMask(uint16 index, int16 x, int16 y) {
414 	drawFlex(index, x, y, 0, 0, 0, _maskDrawCtx);
415 	return 0;
416 }
417 
drawAnimPic(uint16 animIndex,int16 x,int16 y,int16 frameNum,int16 flipX,int16 flipY)418 uint16 Screen::drawAnimPic(uint16 animIndex, int16 x, int16 y, int16 frameNum, int16 flipX, int16 flipY) {
419 	drawAnimFrame(animIndex, x, y, frameNum, flipX, flipY, _backgroundScreenDrawCtx);
420 	return 0;
421 }
422 
addSprite(uint16 spriteIndex)423 void Screen::addSprite(uint16 spriteIndex) {
424 	bool oldScreenLock = _screenLock;
425 	drawFlex(spriteIndex, 0, 0, 0, 0, 0, _backgroundScreenDrawCtx);
426 	_screenLock = oldScreenLock;
427 }
428 
drawSprite(uint16 flexIndex,int16 x,int16 y)429 uint16 Screen::drawSprite(uint16 flexIndex, int16 x, int16 y) {
430 	return placeSprite(_channelsUsedCount + 1, flexIndex, x, y);
431 }
432 
placeSprite(uint16 channelIndex,uint16 flexIndex,int16 x,int16 y)433 uint16 Screen::placeSprite(uint16 channelIndex, uint16 flexIndex, int16 x, int16 y) {
434 
435 	debug(2, "placeSprite(%d, %04X, %d, %d)\n", channelIndex, flexIndex, x, y);
436 
437 	if (channelIndex < 1 || channelIndex >= 100)
438 		return 0;
439 
440 	channelIndex--;
441 
442 	PictureResource *flex = _vm->_res->getPicture(flexIndex);
443 
444 	if (flex) {
445 		//Graphics::Surface *surf = flex->getPicture();
446 
447 		int16 state = 1;
448 		/*int16 x1, y1, x2, y2;
449 
450 		x1 = x;
451 		y1 = y;
452 		x2 = x + surf->w + 1;
453 		y2 = y + surf->h + 1;*/
454 
455 		if (_ground == 0)
456 			state |= 2;
457 		if (_clip != 0)
458 			state |= 4;
459 		if (_exclude != 0)
460 			state |= 8;
461 
462 		_channels[channelIndex].state = state;
463 		_channels[channelIndex].type = 1;
464 		_channels[channelIndex].index = flexIndex;
465 		_channels[channelIndex].x = x;
466 		_channels[channelIndex].y = y;
467 
468 		if (_channelsUsedCount <= channelIndex)
469 			_channelsUsedCount = channelIndex + 1;
470 
471 		_vm->_res->freeResource(flex);
472 	} else {
473 		_channels[channelIndex].type = 0;
474 		_channels[channelIndex].state = 0;
475 	}
476 
477 	return channelIndex + 1;
478 
479 }
480 
placeAnim(uint16 channelIndex,uint16 animIndex,int16 x,int16 y,int16 frameNum)481 uint16 Screen::placeAnim(uint16 channelIndex, uint16 animIndex, int16 x, int16 y, int16 frameNum) {
482 
483 	if (channelIndex < 1 || channelIndex >= 100)
484 		return 0;
485 
486 	channelIndex--;
487 
488 	AnimationResource *anim = _vm->_res->getAnimation(animIndex);
489 
490 	if (anim) {
491 
492 		int16 state = 1;
493 		/*int16 x1, y1, x2, y2;
494 
495 		x1 = x;
496 		y1 = y;
497 		x2 = x + anim->getWidth();
498 		y2 = y + anim->getHeight();*/
499 
500 		if (anim->getFlags() == 1 || _ground == 0)
501 			state |= 2;
502 		if (_clip != 0)
503 			state |= 4;
504 		if (_exclude != 0)
505 			state |= 8;
506 
507 		_channels[channelIndex].state = state;
508 		_channels[channelIndex].type = 3;
509 		_channels[channelIndex].index = animIndex;
510 		_channels[channelIndex].frameNum = frameNum;
511 		_channels[channelIndex].x = x;
512 		_channels[channelIndex].y = y;
513 
514 		if (_channelsUsedCount <= channelIndex)
515 			_channelsUsedCount = channelIndex + 1;
516 
517 		_vm->_res->freeResource(anim);
518 	} else {
519 		_channels[channelIndex].type = 0;
520 		_channels[channelIndex].state = 0;
521 	}
522 
523 	return channelIndex + 1;
524 
525 }
526 
setAnimFrame(uint16 channelIndex,int16 frameNum)527 int16 Screen::setAnimFrame(uint16 channelIndex, int16 frameNum) {
528 	if (channelIndex < 1 || channelIndex >= 100 || _channels[channelIndex - 1].type == 0)
529 		return 0;
530 	 channelIndex--;
531 	_channels[channelIndex].frameNum = frameNum;
532 	return updateChannel(channelIndex) + 1;
533 }
534 
getAnimFrame(uint16 channelIndex)535 int16 Screen::getAnimFrame(uint16 channelIndex) {
536 	if (channelIndex < 1 || channelIndex >= 100 || _channels[channelIndex - 1].type == 0)
537 		return -1;
538 	return _channels[channelIndex - 1].frameNum;
539 }
540 
placeText(uint16 channelIndex,uint16 textObjectIndex,int16 x,int16 y,uint16 fontNum,int16 textColor,int16 outlineColor)541 uint16 Screen::placeText(uint16 channelIndex, uint16 textObjectIndex, int16 x, int16 y, uint16 fontNum, int16 textColor, int16 outlineColor) {
542 
543 	if (channelIndex < 1 || channelIndex >= 100 || textObjectIndex == 0 || fontNum == 0)
544 		return 0;
545 
546 	channelIndex--;
547 
548 	Object *obj = _vm->_dat->getObject(textObjectIndex);
549 	const char *text = obj->getString();
550 
551 	//int16 x1, y1, x2, y2;
552 
553 	setFont(fontNum);
554 
555 	int textWidth = _font->getTextWidth(text);
556 	int textHeight = _font->getHeight();
557 
558 	if (outlineColor != -1) {
559 		textWidth += 2;
560 		textHeight += 2;
561 		x--;
562 		y--;
563 	}
564 
565 	/*x1 = x;
566 	y1 = y;
567 	x2 = x + textWidth;
568 	y2 = y + textHeight;*/
569 
570 	if (textWidth > 0 && outlineColor != -1) {
571 		x++;
572 		y++;
573 	}
574 
575 	int16 state = 1;
576 
577 	if (_ground == 0)
578 		state |= 2;
579 
580 	_channels[channelIndex].state = state;
581 	_channels[channelIndex].type = 2;
582 	_channels[channelIndex].index = textObjectIndex;
583 	_channels[channelIndex].x = x;
584 	_channels[channelIndex].y = y;
585 	_channels[channelIndex].textColor = textColor;
586 	_channels[channelIndex].fontNum = fontNum;
587 	_channels[channelIndex].outlineColor = outlineColor;
588 
589 	if (_channelsUsedCount <= channelIndex)
590 		_channelsUsedCount = channelIndex + 1;
591 
592 	return channelIndex + 1;
593 }
594 
show()595 void Screen::show() {
596 
597 	if (_screenLock)
598 		return;
599 
600 	drawSpriteChannels(_backgroundScreenDrawCtx, 3, 0);
601 	memcpy(_workScreen->getPixels(), _backgroundScreen->getPixels(), 64000);
602 	drawSpriteChannels(_workScreenDrawCtx, 1, 2);
603 
604 	_fx->run(_visualEffectNum, _workScreen, _palette, _newPalette, _paletteColorCount);
605 	_visualEffectNum = 0;
606 
607 	if (!_paletteInitialized) {
608 		memcpy(_newPalette, _palette, _paletteColorCount * 3);
609 		_oldPaletteColorCount = _paletteColorCount;
610 		_paletteInitialized = true;
611 	}
612 
613 	updateScreenAndWait(10);
614 }
615 
flash(int flashCount)616 void Screen::flash(int flashCount) {
617 	_fx->flash(flashCount, _palette, _paletteColorCount);
618 }
619 
setFont(int16 fontNum)620 void Screen::setFont(int16 fontNum) {
621 	if (fontNum == _currentFontNum)
622 		return;
623 	if (_font)
624 		_vm->_res->freeResource(_font);
625 	_font = _vm->_res->getFont(fontNum);
626 	_currentFontNum = fontNum;
627 }
628 
printChar(uint c,int16 x,int16 y,byte color)629 void Screen::printChar(uint c, int16 x, int16 y, byte color) {
630 
631 	if (!_font)
632 		return;
633 
634 	uint width = 8, height = _font->getHeight();
635 	byte *charData = _font->getChar(c);
636 
637 	if (!charData)
638 		return;
639 
640 	byte p;
641 	byte *dest = (byte *)_fontDrawCtx.destSurface->getBasePtr(x, y);
642 
643 	for (uint yc = 0; yc < height; yc++) {
644 		p = charData[yc];
645 		for (uint xc = 0; xc < width; xc++) {
646 			if (p & 0x80)
647 				dest[xc] = color;
648 			p <<= 1;
649 		}
650 		dest += _fontDrawCtx.destSurface->pitch;
651 	}
652 
653 }
654 
printText(const char * text)655 void Screen::printText(const char *text) {
656 
657 	const int tabWidth = 5;
658 
659 	if (!_font)
660 		return;
661 
662 	int textLen = strlen(text);
663 	int textHeight = _font->getHeight();
664 	int linePos = 1;
665 	int16 x = _textX;
666 	int16 y = _textY;
667 
668 	for (int textPos = 0; textPos < textLen; textPos++) {
669 
670 		uint c = ((const byte*)text)[textPos];
671 		int charWidth = _font->getCharWidth(c);
672 
673 		if (c == 9) {
674 			linePos = ((linePos / tabWidth) + 1) * tabWidth;
675 			x = _textRect.left + linePos * _font->getCharWidth(32);
676 		} else if (c == 10) {
677 			linePos = 1;
678 			x = _textRect.left;
679 			y += textHeight;
680 		} else if (c == 13) {
681 			linePos = 1;
682 			x = _textRect.left;
683 		} else if (c == 32) {
684 			int wrapPos = textPos + 1;
685 			int wrapX = x + charWidth;
686 			while (wrapPos < textLen && text[wrapPos] != 0 && text[wrapPos] != 32 && text[wrapPos] >= 28) {
687 				wrapX += _font->getCharWidth(text[wrapPos]);
688 				wrapPos++;
689 			}
690 			if (wrapX >= _textRect.right) {
691 				linePos = 1;
692 				x = _textRect.left;
693 				y += textHeight;
694 				charWidth = 0;
695 				// TODO: text[textPos] = '\x01';
696 			}
697 		}
698 
699 		if (x + charWidth > _textRect.right) {
700 			linePos = 1;
701 			x = _textRect.left;
702 			y += textHeight;
703 		}
704 
705 		if (y + textHeight > _textRect.bottom) {
706 			// TODO
707 		}
708 
709 		if (c >= 28 && c <= 255) {
710 			if (_dropShadowColor != -1) {
711 				printChar(c, x + 1, y + 1, _dropShadowColor);
712 			}
713 			if (_outlineColor != -1) {
714 				printChar(c, x, y - 1, _outlineColor);
715 				printChar(c, x, y + 1, _outlineColor);
716 				printChar(c, x - 1, y, _outlineColor);
717 				printChar(c, x + 1, y, _outlineColor);
718 				printChar(c, x - 1, y - 1, _outlineColor);
719 				printChar(c, x - 1, y + 1, _outlineColor);
720 				printChar(c, x + 1, y - 1, _outlineColor);
721 				printChar(c, x + 1, y + 1, _outlineColor);
722 			}
723 			printChar(c, x, y, _textColor);
724 			x += charWidth;
725 			linePos++;
726 		}
727 
728 	}
729 
730 	_textX = x;
731 	_textY = y;
732 
733 }
734 
printTextEx(const char * text,int16 x,int16 y,int16 fontNum,int16 textColor,int16 outlineColor,const ClipInfo & clipInfo)735 void Screen::printTextEx(const char *text, int16 x, int16 y, int16 fontNum, int16 textColor, int16 outlineColor, const ClipInfo &clipInfo) {
736 	if (*text == 0 || x < 0 || y < 0)
737 		return;
738 
739 	int16 oldFontNum = _currentFontNum;
740 	Common::Rect oldTextRect;
741 	ClipInfo oldFontDrawCtx = _fontDrawCtx;
742 
743 	_fontDrawCtx = clipInfo;
744 
745 	getTextRect(oldTextRect);
746 	setFont(fontNum);
747 	setTextColor(textColor);
748 	setOutlineColor(outlineColor);
749 	setTextXY(x, y);
750 	printText(text);
751 	setTextRect(oldTextRect);
752 	setFont(oldFontNum);
753 	_fontDrawCtx = oldFontDrawCtx;
754 
755 }
756 
printObjectText(int16 objectIndex,int16 x,int16 y,int16 fontNum,int16 textColor,int16 outlineColor,const ClipInfo & clipInfo)757 void Screen::printObjectText(int16 objectIndex, int16 x, int16 y, int16 fontNum, int16 textColor, int16 outlineColor, const ClipInfo &clipInfo) {
758 
759 	if (objectIndex == 0)
760 		return;
761 
762 	Object *obj = _vm->_dat->getObject(objectIndex);
763 	const char *text = obj->getString();
764 
765 	printTextEx(text, x, y, fontNum, textColor, outlineColor, clipInfo);
766 
767 }
768 
getTextWidth(int16 fontNum,const char * text)769 int16 Screen::getTextWidth(int16 fontNum, const char *text) {
770 	setFont(fontNum);
771 	return _font->getTextWidth(text);
772 }
773 
lockScreen()774 Graphics::Surface *Screen::lockScreen() {
775 	return _vm->_system->lockScreen();
776 }
777 
unlockScreen()778 void Screen::unlockScreen() {
779 	_vm->_system->unlockScreen();
780 }
781 
showWorkScreen()782 void Screen::showWorkScreen() {
783 	_vm->_system->copyRectToScreen(_workScreen->getPixels(), _workScreen->pitch, 0, 0, _workScreen->w, _workScreen->h);
784 }
785 
copyRectToScreen(const void * buf,int pitch,int x,int y,int w,int h)786 void Screen::copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) {
787 	_vm->_system->copyRectToScreen(buf, pitch, x, y, w, h);
788 }
789 
updateScreenAndWait(int delay)790 void Screen::updateScreenAndWait(int delay) {
791 	_vm->_system->updateScreen();
792 	uint32 startTime = _vm->_system->getMillis();
793 	while (_vm->_system->getMillis() < startTime + delay) {
794 		_vm->handleEvents();
795 		_vm->_system->delayMillis(5);
796 	}
797 }
798 
addToSpriteList(int16 index,int16 xofs,int16 yofs)799 int16 Screen::addToSpriteList(int16 index, int16 xofs, int16 yofs) {
800 	SpriteListItem item;
801 	item.index = index;
802 	item.xofs = xofs;
803 	item.yofs = yofs;
804 	_spriteList.push_back(item);
805 	return _spriteList.size();
806 }
807 
getFromSpriteList(int16 index)808 SpriteListItem Screen::getFromSpriteList(int16 index) {
809 	if (((uint) index) > _spriteList.size()) {
810 		SpriteListItem emptyItem;
811 		emptyItem.index = 0;
812 		emptyItem.xofs = 0;
813 		emptyItem.yofs = 0;
814 		return emptyItem;
815 	} else {
816 		return _spriteList[index - 1];
817 	}
818 }
819 
clearSpriteList()820 void Screen::clearSpriteList() {
821 	_spriteList.clear();
822 }
823 
setDefaultMouseCursor()824 void Screen::setDefaultMouseCursor() {
825 	CursorMan.replaceCursor(defaultMouseCursor, 16, 16, 9, 2, 0);
826 }
827 
828 } // End of namespace Made
829