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 
24 #if !defined(ENABLE_EOB)
25 #include "kyra/graphics/screen.h"
26 #endif
27 
28 #ifdef ENABLE_EOB
29 
30 #include "kyra/engine/eobcommon.h"
31 #include "kyra/resource/resource.h"
32 #include "kyra/engine/util.h"
33 #include "kyra/graphics/screen_eob_segacd.h"
34 
35 #include "common/system.h"
36 #include "common/memstream.h"
37 
38 #include "graphics/cursorman.h"
39 #include "graphics/palette.h"
40 #include "graphics/sjis.h"
41 
42 #define EXPLOSION_ANIM_DURATION 750
43 #define VORTEX_ANIM_DURATION 750
44 
45 namespace Kyra {
46 
Screen_EoB(EoBCoreEngine * vm,OSystem * system)47 Screen_EoB::Screen_EoB(EoBCoreEngine *vm, OSystem *system) : Screen(vm, system, _screenDimTable, _screenDimTableCount), _cursorColorKey16Bit(0x8000) {
48 	_dsBackgroundFading = false;
49 	_dsShapeFadingLevel = 0;
50 	_dsBackgroundFadingXOffs = 0;
51 	_dsShapeFadingTable = 0;
52 	_dsX1 = _dsX2 = _dsY1 = _dsY2 = 0;
53 	_gfxX = _gfxY = 0;
54 	_gfxCol = 0;
55 	_dsTempPage = 0;
56 	_shpBuffer = _convertHiColorBuffer = 0;
57 	_dsDiv = 0;
58 	_dsRem = 0;
59 	_dsScaleTrans = 0;
60 	_cgaScaleTable = 0;
61 	_gfxMaxY = 0;
62 	_egaDitheringTable = 0;
63 	_egaDitheringTempPage = 0;
64 	_cgaMappingDefault = 0;
65 	_cgaDitheringTables[0] = _cgaDitheringTables[1] = 0;
66 	_useHiResEGADithering = false;
67 	_cyclePalette = 0;
68 	_cpsFilePattern = "%s.";
69 	_activePalCycle = 0;
70 	_segaRenderer = 0;
71 	_segaAnimator = 0;
72 	_segaCustomPalettes = 0;
73 	_palFaders = 0;
74 	_defaultRenderBuffer = 0;
75 	_specialColorReplace = false;
76 	memset(_segaCurPalette, 0, sizeof(_segaCurPalette));
77 }
78 
~Screen_EoB()79 Screen_EoB::~Screen_EoB() {
80 	delete[] _dsTempPage;
81 	delete[] _shpBuffer;
82 	delete[] _convertHiColorBuffer;
83 	delete[] _cgaScaleTable;
84 	delete[] _egaDitheringTable;
85 	delete[] _egaDitheringTempPage;
86 	delete[] _cgaDitheringTables[0];
87 	delete[] _cgaDitheringTables[1];
88 	delete[] _cyclePalette;
89 	delete[] _segaCustomPalettes;
90 	delete[] _palFaders;
91 	delete[] _defaultRenderBuffer;
92 	delete _segaRenderer;
93 	delete _segaAnimator;
94 }
95 
init()96 bool Screen_EoB::init() {
97 	if (Screen::init()) {
98 		int temp;
99 		_gfxMaxY = _vm->staticres()->loadRawData(kEoBBaseExpObjectY, temp);
100 		_dsTempPage = new uint8[12000];
101 
102 		if (_vm->gameFlags().platform == Common::kPlatformFMTowns) {
103 			_shpBuffer = new uint8[SCREEN_H * SCREEN_W];
104 			_convertHiColorBuffer = new uint8[SCREEN_H * SCREEN_W];
105 			enableHiColorMode(true);
106 			setFontStyles(FID_SJIS_FNT, Font::kStyleFat);
107 			_fonts[FID_SJIS_LARGE_FNT] = new SJISFontLarge(_sjisFontShared);
108 		} else if (_vm->game() == GI_EOB1 && _vm->gameFlags().platform == Common::kPlatformPC98) {
109 			_fonts[FID_SJIS_FNT] = new SJISFontEoB1PC98(_sjisFontShared, /*12,*/ _vm->staticres()->loadRawDataBe16(kEoB1Ascii2SjisTable1, temp), _vm->staticres()->loadRawDataBe16(kEoB1Ascii2SjisTable2, temp));
110 		}
111 
112 		if (_vm->gameFlags().useHiRes && _renderMode == Common::kRenderEGA) {
113 			_useHiResEGADithering = true;
114 			_egaDitheringTable = new uint8[256];
115 			_egaDitheringTempPage = new uint8[SCREEN_W * 2 * SCREEN_H * 2];
116 			for (int i = 0; i < 256; i++)
117 				_egaDitheringTable[i] = i & 0x0F;
118 		} else if (_renderMode == Common::kRenderCGA) {
119 			_cgaMappingDefault = _vm->staticres()->loadRawData(kEoB1CgaMappingDefault, temp);
120 			_cgaDitheringTables[0] = new uint16[256];
121 			memset(_cgaDitheringTables[0], 0, 256 * sizeof(uint16));
122 			_cgaDitheringTables[1] = new uint16[256];
123 			memset(_cgaDitheringTables[1], 0, 256 * sizeof(uint16));
124 
125 			_cgaScaleTable = new uint8[256];
126 			memset(_cgaScaleTable, 0, 256 * sizeof(uint8));
127 			for (int i = 0; i < 256; i++)
128 				_cgaScaleTable[i] = ((i & 0xF0) >> 2) | (i & 0x03);
129 		} else if (_vm->gameFlags().platform == Common::kPlatformSegaCD) {
130 			sega_initGraphics();
131 			_segaCustomPalettes = new uint16[128];
132 			_palFaders = new PaletteFader[4];
133 			_defaultRenderBufferSize = SCREEN_W * _screenHeight;
134 			_defaultRenderBuffer = new uint8[_defaultRenderBufferSize];
135 			memset(_defaultRenderBuffer, 0, _defaultRenderBufferSize);
136 			sega_setTextBuffer(0, 0);
137 			memset(_segaCustomPalettes, 0, 128 * sizeof(uint16));
138 		}
139 
140 		_useShapeShading = (_bytesPerPixel != 2 && !_isAmiga && !_isSegaCD && !_use16ColorMode && _renderMode != Common::kRenderCGA && _renderMode != Common::kRenderEGA) || _useHiResEGADithering;
141 
142 		static const char *cpsExt[] = { "CPS", "EGA", "SHP", "BIN" };
143 		int ci = 0;
144 		if (_vm->game() == GI_EOB1) {
145 			if (_vm->gameFlags().platform == Common::kPlatformPC98) {
146 				_cyclePalette = new uint8[48];
147 				memset(_cyclePalette, 0, 48);
148 				ci = 3;
149 			} else if (_renderMode == Common::kRenderEGA || _renderMode == Common::kRenderCGA) {
150 				ci = 1;
151 			}
152 		} else if (_vm->gameFlags().platform == Common::kPlatformFMTowns) {
153 			ci = 2;
154 		}
155 		_cpsFilePattern += cpsExt[ci];
156 
157 		return true;
158 	}
159 	return false;
160 }
161 
setClearScreenDim(int dim)162 void Screen_EoB::setClearScreenDim(int dim) {
163 	setScreenDim(dim);
164 	clearCurDim();
165 }
166 
clearCurDim()167 void Screen_EoB::clearCurDim() {
168 	static const uint8 amigaColorMap[16] = { 0x00, 0x06, 0x1d, 0x1b, 0x1a, 0x17, 0x18, 0x0e, 0x19, 0x1c, 0x1c, 0x1e, 0x13, 0x0a, 0x11, 0x1f };
169 	fillRect(_curDim->sx << 3, _curDim->sy, ((_curDim->sx + _curDim->w) << 3) - 1, (_curDim->sy + _curDim->h) - 1, _isAmiga ? amigaColorMap[_curDim->unkA] : _use16ColorMode ? 0 : _curDim->unkA);
170 }
171 
clearCurDimOvl(int pageNum)172 void Screen_EoB::clearCurDimOvl(int pageNum) {
173 	if (pageNum > 1 || !_useOverlays)
174 		return;
175 	addDirtyRect(_curDim->sx << 3, _curDim->sy, _curDim->w << 3, _curDim->h);
176 	clearOverlayRect(pageNum, _curDim->sx << 3, _curDim->sy, _curDim->w << 3, _curDim->h);
177 }
178 
setMouseCursor(int x,int y,const byte * shape)179 void Screen_EoB::setMouseCursor(int x, int y, const byte *shape) {
180 	setMouseCursor(x, y, shape, 0);
181 }
182 
setMouseCursor(int x,int y,const byte * shape,const uint8 * ovl)183 void Screen_EoB::setMouseCursor(int x, int y, const byte *shape, const uint8 *ovl) {
184 	if (!shape)
185 		return;
186 
187 	int mouseW = (shape[2] << 3);
188 	int mouseH = (shape[3]);
189 	int colorKey = (_renderMode == Common::kRenderCGA) ? 0 : (_bytesPerPixel == 2 ? _cursorColorKey16Bit : _cursorColorKey);
190 
191 	int scaleFactor = _vm->gameFlags().useHiRes ? 2 : 1;
192 	int bpp = _useHiColorScreen ? 2 : 1;
193 
194 	uint8 *cursor = new uint8[mouseW * scaleFactor * bpp * mouseH * scaleFactor];
195 
196 	if (_bytesPerPixel == 2) {
197 		for (int s = mouseW * scaleFactor * bpp * mouseH * scaleFactor; s; s -= 2)
198 			*(uint16*)(cursor + s - 2) = colorKey;
199 	} else {
200 		// We don't use fillRect here to make sure that the color key 0xFF doesn't get converted into EGA color
201 		memset(cursor, colorKey, mouseW * scaleFactor * bpp * mouseH * scaleFactor);
202 	}
203 
204 	copyBlockToPage(6, 0, 0, mouseW * scaleFactor, mouseH * scaleFactor, cursor);
205 	drawShape(6, shape, 0, 0, 0, 2, ovl);
206 	CursorMan.showMouse(false);
207 
208 	if (_useHiResEGADithering)
209 		ditherRect(getCPagePtr(6), cursor, mouseW * scaleFactor, mouseW, mouseH, colorKey);
210 	else if (_useHiColorScreen)
211 		scale2x<uint16, uint32>(cursor, mouseW * scaleFactor, getCPagePtr(6), SCREEN_W, mouseW, mouseH);
212 	else if (_vm->gameFlags().useHiRes)
213 		scale2x<uint8, uint16>(cursor, mouseW * scaleFactor, getCPagePtr(6), SCREEN_W, mouseW, mouseH);
214 	else
215 		copyRegionToBuffer(6, 0, 0, mouseW, mouseH, cursor);
216 
217 	// Mouse cursor post processing for EOB II Amiga
218 	if (_dualPaletteModeSplitY) {
219 		int len = mouseW * mouseH;
220 		while (--len > -1)
221 			cursor[len] |= 0x20;
222 	}
223 
224 	// Mouse cursor post processing for CGA mode. Unlike the original (which uses drawShape for the mouse cursor)
225 	// the cursor manager cannot know whether a pixel value of 0 is supposed to be black or transparent. Thus, we
226 	// go over the transparency mask again and turn the black pixels to color 4.
227 	if (_renderMode == Common::kRenderCGA) {
228 		const uint8 *maskTbl = shape + 4 + ((mouseW * mouseH) >> 2);
229 		uint8 *dst = cursor;
230 		uint8 trans = 0;
231 		uint8 shift = 6;
232 
233 		uint16 mH = mouseH;
234 		while (mH--) {
235 			uint16 mW = mouseW;
236 			while (mW--) {
237 				if (shift == 6)
238 					trans = *maskTbl++;
239 				if (!*dst && !((trans >> shift) & 3))
240 					*dst = 4;
241 				dst++;
242 				shift = (shift - 2) & 7;
243 			}
244 		}
245 	}
246 
247 	// Convert color key to 16 bit after drawing the mouse cursor.
248 	// The cursor has been converted to 16 bit in scale2x().
249 	colorKey = _16bitConversionPalette ? _16bitConversionPalette[colorKey] : colorKey;
250 	Graphics::PixelFormat pixelFormat = _system->getScreenFormat();
251 
252 	CursorMan.replaceCursor(cursor, mouseW * scaleFactor, mouseH * scaleFactor, x * scaleFactor, y * scaleFactor, colorKey, false, &pixelFormat);
253 	if (isMouseVisible())
254 		CursorMan.showMouse(true);
255 	delete[] cursor;
256 
257 	// makes sure that the cursor is drawn
258 	// we do not use Screen::updateScreen here
259 	// so we can be sure that changes to page 0
260 	// are NOT updated on the real screen here
261 	_system->updateScreen();
262 }
263 
loadFileDataToPage(Common::SeekableReadStream * s,int pageNum,uint32 size)264 void Screen_EoB::loadFileDataToPage(Common::SeekableReadStream *s, int pageNum, uint32 size) {
265 	s->read(_pagePtrs[pageNum], size);
266 }
267 
printShadedText(const char * string,int x,int y,int col1,int col2,int shadowCol,int pitch)268 void Screen_EoB::printShadedText(const char *string, int x, int y, int col1, int col2, int shadowCol, int pitch) {
269 	if (_isSegaCD && shadowCol) {
270 		printText(string, x + 1, y + 1, shadowCol, 0, pitch);
271 	} else if (!_isSegaCD && _vm->gameFlags().lang != Common::JA_JPN) {
272 		printText(string, x - 1, y, shadowCol, col2);
273 		printText(string, x, y + 1, shadowCol, 0);
274 		printText(string, x - 1, y + 1, shadowCol, 0);
275 	} else if (!_isSegaCD && col2) {
276 		fillRect(x, y, x + getTextWidth(string) - 1, y + getFontHeight() - 1, col2);
277 	}
278 
279 	if (_vm->gameFlags().use16ColorMode)
280 		setFontStyles(_currentFont, Font::kStyleLeftShadow);
281 
282 	printText(string, x, y, col1, 0, pitch);
283 
284 	if (_vm->gameFlags().use16ColorMode)
285 		setFontStyles(_currentFont, Font::kStyleNone);
286 }
287 
loadShapeSetBitmap(const char * file,int tempPage,int destPage)288 void Screen_EoB::loadShapeSetBitmap(const char *file, int tempPage, int destPage) {
289 	loadEoBBitmap(file, _cgaMappingDefault, tempPage, destPage, -1);
290 	_curPage = 2;
291 }
292 
loadBitmap(const char * filename,int tempPage,int dstPage,Palette * pal,bool skip)293 void Screen_EoB::loadBitmap(const char *filename, int tempPage, int dstPage, Palette *pal, bool skip) {
294 	if (!scumm_stricmp(filename + strlen(filename) - 3, "BIN")) {
295 		Common::SeekableReadStream *str = _vm->resource()->createReadStream(filename);
296 		if (!str)
297 			error("Screen_EoB::loadBitmap(): Failed to load file '%s'", filename);
298 		str->skip(2);
299 		uint16 imgSize = str->readUint16LE();
300 		assert(imgSize == str->size() - 4);
301 		uint8 *buf = new uint8[MAX<uint16>(imgSize, SCREEN_W * SCREEN_H)];
302 		str->read(buf, imgSize);
303 		delete str;
304 
305 		decodeBIN(buf, _pagePtrs[dstPage], imgSize);
306 		if (!skip)
307 			decodePC98PlanarBitmap(_pagePtrs[dstPage], buf, SCREEN_W * SCREEN_H);
308 
309 		delete[] buf;
310 	} else {
311 		Screen::loadBitmap(filename, tempPage, dstPage, pal);
312 	}
313 
314 	if (_isAmiga && !skip) {
315 		Common::SeekableReadStream *str = _vm->resource()->createReadStream(filename);
316 		str->skip(4);
317 		uint32 imgSize = str->readUint32LE();
318 
319 		if (_vm->game() == GI_EOB1 && (dstPage == 3 || dstPage == 4) && imgSize == 40064) {
320 			// Yay, this is where EOB1 Amiga hides the palette data
321 			loadPalette(_pagePtrs[dstPage] + 40000, *_palettes[0], 64);
322 			_palettes[0]->fill(0, 1, 0);
323 		} else if (_vm->game() == GI_EOB2) {
324 			uint16 palSize = str->readUint16LE();
325 			// EOB II Amiga CPS files may contain more than one palette (each one 64 bytes,
326 			// one after the other). We load them all...
327 			if (pal && palSize) {
328 				for (int i = 1; i <= palSize >> 6; ++i)
329 					_palettes[i]->loadAmigaPalette(*str, 0, 32);
330 			}
331 		}
332 
333 		Screen::convertAmigaGfx(getPagePtr(dstPage), 320, 200);
334 		delete str;
335 	}
336 }
337 
loadEoBBitmap(const char * file,const uint8 * cgaMapping,int tempPage,int destPage,int convertToPage)338 void Screen_EoB::loadEoBBitmap(const char *file, const uint8 *cgaMapping, int tempPage, int destPage, int convertToPage) {
339 	Common::String tmp = Common::String::format(_cpsFilePattern.c_str(), file);
340 	Common::SeekableReadStream *s = _vm->resource()->createReadStream(tmp);
341 	bool loadAlternative = false;
342 
343 	if (_vm->gameFlags().platform == Common::kPlatformFMTowns) {
344 		if (!s)
345 			error("Screen_EoB::loadEoBBitmap(): Failed to load file '%s'", file);
346 		s->read(_shpBuffer, s->size());
347 		decodeSHP(_shpBuffer, destPage);
348 
349 	} else if (s) {
350 		// This additional check is necessary since some localized versions of EOB II seem to contain invalid (size zero) cps files
351 		if (s->size() == 0) {
352 			loadAlternative = true;
353 
354 		// This check is due to EOB II Amiga German. That version simply checks
355 		// for certain file names which aren't actual CPS files. These files use
356 		// a different format and compression type. I check the header size
357 		// info to identify these.
358 		} else if (_vm->gameFlags().platform == Common::kPlatformAmiga) {
359 			// Tolerance for size mismatches up to 2 bytes is needed in some cases
360 			if ((((s->readUint16LE()) + 5) & ~3) != (((s->size()) + 3) & ~3))
361 				loadAlternative = true;
362 		}
363 
364 		if (!loadAlternative)
365 			loadBitmap(tmp.c_str(), tempPage, destPage, _vm->gameFlags().platform == Common::kPlatformAmiga ? _palettes[0] : 0);
366 
367 	} else {
368 		loadAlternative = true;
369 	}
370 
371 	delete s;
372 
373 	if (loadAlternative) {
374 		if (_vm->game() == GI_EOB1) {
375 			tmp.insertChar('1', tmp.size() - 4);
376 			loadBitmap(tmp.c_str(), tempPage, destPage, 0);
377 
378 		} else if (_vm->gameFlags().platform == Common::kPlatformAmiga) {
379 			loadSpecialAmigaCPS(tmp.c_str(), destPage, true);
380 
381 		} else {
382 			tmp.setChar('X', 0);
383 			s = _vm->resource()->createReadStream(tmp);
384 
385 			if (!s)
386 				error("Screen_EoB::loadEoBBitmap(): Failed to load file '%s'", file);
387 
388 			s->seek(768);
389 			loadFileDataToPage(s, destPage, 64000);
390 			delete s;
391 		}
392 	}
393 
394 	if (convertToPage == -1)
395 		return;
396 
397 	if (_16bitPalette)
398 		convertToHiColor(destPage);
399 
400 	if (convertToPage == 2 && _renderMode == Common::kRenderCGA) {
401 		convertPage(destPage, 4, cgaMapping);
402 		copyRegion(0, 0, 0, 0, 320, 200, 4, 2, Screen::CR_NO_P_CHECK);
403 	} else if (convertToPage == 0) {
404 		convertPage(destPage, 2, cgaMapping);
405 		copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
406 	} else {
407 		convertPage(destPage, convertToPage, cgaMapping);
408 	}
409 }
410 
convertPage(int srcPage,int dstPage,const uint8 * cgaMapping)411 void Screen_EoB::convertPage(int srcPage, int dstPage, const uint8 *cgaMapping) {
412 	uint8 *src = getPagePtr(srcPage);
413 	uint8 *dst = getPagePtr(dstPage);
414 	if (src == dst)
415 		return;
416 
417 	if (_renderMode == Common::kRenderCGA) {
418 		if (cgaMapping)
419 			generateCGADitheringTables(cgaMapping);
420 
421 		uint16 *d = (uint16 *)dst;
422 		uint8 tblSwitch = 0;
423 		for (int height = SCREEN_H; height; height--) {
424 			const uint16 *table = _cgaDitheringTables[(tblSwitch++) & 1];
425 			for (int width = SCREEN_W / 2; width; width--) {
426 				WRITE_LE_UINT16(d++, table[((src[1] & 0x0F) << 4) | (src[0] & 0x0F)]);
427 				src += 2;
428 			}
429 		}
430 	} else if (_renderMode == Common::kRenderEGA && !_useHiResEGADithering) {
431 		uint32 len = SCREEN_W * SCREEN_H;
432 		while (len--)
433 			*dst++ = *src++ & 0x0F;
434 	} else {
435 		copyPage(srcPage, dstPage);
436 	}
437 
438 	if (dstPage == 0 || dstPage == 1)
439 		_forceFullUpdate = true;
440 }
441 
setScreenPalette(const Palette & pal)442 void Screen_EoB::setScreenPalette(const Palette &pal) {
443 	if (_bytesPerPixel == 2) {
444 		for (int i = 0; i < 4; i++)
445 			createFadeTable16bit((const uint16*)(pal.getData()), &_16bitPalette[i * 256], 0, i * 85);
446 	} else if (_useHiResEGADithering && pal.getNumColors() != 16) {
447 		generateEGADitheringTable(pal);
448 	} else if (_isSegaCD || (_renderMode == Common::kRenderEGA && pal.getNumColors() == 16)) {
449 		_paletteChanged = true;
450 		_screenPalette->copy(pal);
451 		_system->getPaletteManager()->setPalette(_screenPalette->getData(), 0, _screenPalette->getNumColors());
452 	} else if (_renderMode != Common::kRenderCGA && _renderMode != Common::kRenderEGA) {
453 		Screen::setScreenPalette(pal);
454 	}
455 }
456 
getRealPalette(int num,uint8 * dst)457 void Screen_EoB::getRealPalette(int num, uint8 *dst) {
458 	if (_renderMode == Common::kRenderCGA || _renderMode == Common::kRenderEGA) {
459 		const uint8 *pal = _screenPalette->getData();
460 		for (int i = 0; i < 16; ++i) {
461 			dst[0] = (pal[0] << 2) | (pal[0] & 3);
462 			dst[1] = (pal[1] << 2) | (pal[1] & 3);
463 			dst[2] = (pal[2] << 2) | (pal[2] & 3);
464 			dst += 3;
465 			pal += 3;
466 		}
467 	} else {
468 		Screen::getRealPalette(num, dst);
469 	}
470 }
471 
encodeShape(uint16 x,uint16 y,uint16 w,uint16 h,bool encode8bit,const uint8 * cgaMapping)472 uint8 *Screen_EoB::encodeShape(uint16 x, uint16 y, uint16 w, uint16 h, bool encode8bit, const uint8 *cgaMapping) {
473 	uint8 *shp = 0;
474 	uint16 shapesize = 0;
475 
476 	uint8 *srcLineStart = getPagePtr(_curPage | 1) + y * 320 + (x << 3);
477 	uint8 *src = srcLineStart;
478 
479 	if (_use16ColorMode || (_renderMode == Common::kRenderEGA && !_useHiResEGADithering))
480 		encode8bit = false;
481 
482 	if (_bytesPerPixel == 2 && encode8bit) {
483 		shapesize = h * (w << 3) + 4;
484 		shp = new uint8[shapesize];
485 		memset(shp, 0, shapesize);
486 		uint8 *dst = shp;
487 
488 		*dst++ = 0;
489 		*dst++ = (h & 0xFF);
490 		*dst++ = (w & 0xFF);
491 		*dst++ = (h & 0xFF);
492 
493 		w <<= 3;
494 
495 		for (int i = 0; i < h; ++i) {
496 			memcpy(dst, src, w);
497 			srcLineStart += SCREEN_W;
498 			src = srcLineStart;
499 			dst += w;
500 		}
501 	} else if (_renderMode == Common::kRenderCGA) {
502 		if (cgaMapping)
503 			generateCGADitheringTables(cgaMapping);
504 		shapesize = h * (w << 2) + 4;
505 		shp = new uint8[shapesize];
506 		memset(shp, 0, shapesize);
507 		uint8 *dst = shp;
508 
509 		*dst++ = 4;
510 		*dst++ = (h & 0xFF);
511 		*dst++ = (w & 0xFF);
512 		*dst++ = (h & 0xFF);
513 
514 		uint8 *dst2 = dst + (h * (w << 1));
515 
516 		uint8 tblSwitch = 0;
517 		uint16 h1 = h;
518 		while (h1--) {
519 			uint16 w1 = w << 1;
520 			const uint16 *table = _cgaDitheringTables[(tblSwitch++) & 1];
521 
522 			while (w1--) {
523 				uint16 p0 = table[((src[1] & 0x0F) << 4) | (src[0] & 0x0F)];
524 				uint16 p1 = table[((src[3] & 0x0F) << 4) | (src[2] & 0x0F)];
525 
526 				*dst++ = ((p0 & 0x0003) << 6) | ((p0 & 0x0300) >> 4) | ((p1 & 0x0003) << 2) | ((p1 & 0x0300) >> 8);
527 
528 				uint8 msk = 0;
529 				for (int i = 0; i < 4; i++) {
530 					if (!src[3 - i])
531 						msk |= (3 << (i << 1));
532 				}
533 				*dst2++ = msk;
534 				src += 4;
535 			}
536 			srcLineStart += SCREEN_W;
537 			src = srcLineStart;
538 		}
539 
540 	} else if (encode8bit) {
541 		uint16 h1 = h;
542 		while (h1--) {
543 			uint8 *lineEnd = src + (w << 3);
544 			do {
545 				if (!*src++) {
546 					shapesize++;
547 					uint8 *startZeroPos = src;
548 					while (src != lineEnd && *src == 0)
549 						src++;
550 
551 					uint16 numZero = src - startZeroPos + 1;
552 					if (numZero >> 8)
553 						shapesize += 2;
554 				}
555 				shapesize++;
556 			} while (src != lineEnd);
557 
558 			srcLineStart += SCREEN_W;
559 			src = srcLineStart;
560 		}
561 
562 		shapesize += 4;
563 
564 		shp = new uint8[shapesize];
565 		memset(shp, 0, shapesize);
566 		uint8 *dst = shp;
567 
568 		*dst++ = 1;
569 		*dst++ = (h & 0xFF);
570 		*dst++ = (w & 0xFF);
571 		*dst++ = (h & 0xFF);
572 
573 		srcLineStart = getPagePtr(_curPage | 1) + y * 320 + (x << 3);
574 		src = srcLineStart;
575 
576 		h1 = h;
577 		while (h1--) {
578 			uint8 *lineEnd = src + (w << 3);
579 			do {
580 				uint8 val = *src++;
581 				if (!val) {
582 					*dst++ = 0;
583 					uint8 *startZeroPos = src;
584 
585 					while (src != lineEnd && *src == 0)
586 						src++;
587 
588 					uint16 numZero = src - startZeroPos + 1;
589 					if (numZero >> 8) {
590 						*dst++ = 255;
591 						*dst++ = 0;
592 						numZero -= 255;
593 					}
594 					val = numZero & 0xFF;
595 				}
596 				*dst++ = val;
597 			} while (src != lineEnd);
598 
599 			srcLineStart += SCREEN_W;
600 			src = srcLineStart;
601 		}
602 
603 	} else {
604 		uint8 nib = 0, col = 0;
605 		uint8 *colorMap = 0;
606 
607 		if (_renderMode != Common::kRenderEGA || _useHiResEGADithering) {
608 			colorMap = new uint8[0x100];
609 			memset(colorMap, 0xFF, 0x100);
610 		}
611 
612 		shapesize = h * (w << 2) + 20;
613 		shp = new uint8[shapesize];
614 		memset(shp, 0, shapesize);
615 		uint8 *dst = shp;
616 
617 		*dst++ = 2;
618 		*dst++ = (h & 0xFF);
619 		*dst++ = (w & 0xFF);
620 		*dst++ = (h & 0xFF);
621 
622 		if (_renderMode != Common::kRenderEGA || _useHiResEGADithering) {
623 			memset(dst, 0xFF, 0x10);
624 		} else {
625 			for (int i = 0; i < 16; i++)
626 				dst[i] = i;
627 		}
628 
629 		uint8 *pal = dst;
630 		dst += 16;
631 		nib = col = 0;
632 
633 		uint16 h1 = h;
634 		while (h1--) {
635 			uint16 w1 = w << 3;
636 			while (w1--) {
637 				uint8 s = *src++;
638 				uint8 c = s & 0x0F;
639 				if (colorMap) {
640 					c = colorMap[s];
641 					if (c == 0xFF) {
642 						if (col < 0x10) {
643 							*pal++ = s;
644 							c = colorMap[s] = col++;
645 						} else {
646 							c = 0;
647 						}
648 					}
649 				}
650 
651 				if (++nib & 1)
652 					*dst = c << 4;
653 				else
654 					*dst++ |= c;
655 			}
656 			srcLineStart += SCREEN_W;
657 			src = srcLineStart;
658 		}
659 		delete[] colorMap;
660 	}
661 
662 	return shp;
663 }
664 
drawShape(uint8 pageNum,const uint8 * shapeData,int x,int y,int sd,int flags,...)665 void Screen_EoB::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int sd, int flags, ...) {
666 	uint8 *dst = getPagePtr(pageNum);
667 	const uint8 *src = shapeData;
668 
669 	if (!src)
670 		return;
671 
672 	if (sd != -1) {
673 		const ScreenDim *dm = getScreenDim(sd);
674 		setShapeFrame(dm->sx, dm->sy, dm->sx + dm->w, dm->sy + dm->h);
675 		x += (_dsX1 << 3);
676 		y += _dsY1;
677 	}
678 
679 	uint8 *ovl = 0;
680 
681 	va_list args;
682 	va_start(args, flags);
683 	if (flags & 2) {
684 		ovl = va_arg(args, uint8 *);
685 		_dsBackgroundFadingXOffs = x;
686 	}
687 	va_end(args);
688 
689 	dst += (_dsX1 << (2 + _bytesPerPixel));
690 	int16 dX = x - (_dsX1 << 3);
691 	int16 dY = y;
692 	int16 dW = _dsX2 - _dsX1;
693 
694 	uint8 pixelsPerByte = *src++;
695 	uint16 dH = *src++;
696 	uint16 width = (*src++) << 3;
697 	uint16 transOffset = (pixelsPerByte == 4) ? (dH * width) >> 2 : 0;
698 	src++;
699 
700 	int rX = x;
701 	int rY = y;
702 	int rW = width + 8;
703 	int rH = dH;
704 
705 	uint16 w2 = width;
706 	int d = dY - _dsY1;
707 
708 	int pixelStep = (flags & 1) ? -1 : 1;
709 
710 	if (pixelsPerByte < 2)  {
711 		uint16 marginLeft = 0;
712 		uint16 marginRight = 0;
713 
714 		if (d < 0) {
715 			dH += d;
716 			if (dH <= 0)
717 				return;
718 			d = -d;
719 
720 			for (int i = 0; i < d; i++) {
721 				marginLeft = width;
722 				for (int ii = 0; ii < marginLeft; ii++) {
723 					if (!*src++)
724 						marginLeft = marginLeft + 1 - *src++;
725 				}
726 			}
727 			dY = _dsY1;
728 		}
729 
730 		d = _dsY2 - dY;
731 
732 		if (d < 1)
733 			return;
734 
735 		if (d < dH)
736 			dH = d;
737 
738 		marginLeft = 0;
739 
740 		if (dX < 0) {
741 			width += dX;
742 			marginLeft = -dX;
743 
744 			if (marginLeft >= w2)
745 				return;
746 
747 			dX = 0;
748 		}
749 
750 		marginRight = 0;
751 		d = (dW << 3) - dX;
752 
753 		if (d < 1)
754 			return;
755 
756 		if (d < width) {
757 			width = d;
758 			marginRight = w2 - marginLeft - width;
759 		}
760 
761 		dst += (dY * SCREEN_W * _bytesPerPixel + dX * _bytesPerPixel);
762 		uint8 *dstL = dst;
763 
764 		if (pageNum == 0 || pageNum == 1)
765 			addDirtyRect(rX, rY, rW, rH);
766 
767 		while (dH--) {
768 			int16 xpos = (int16) marginLeft;
769 
770 			if (flags & 1) {
771 				if (pixelsPerByte == 1) {
772 					for (int i = 0; i < w2; i++) {
773 						if (*src++ == 0) {
774 							i += (*src - 1);
775 							src += (*src - 1);
776 						}
777 					}
778 				} else {
779 					src += w2;
780 				}
781 				src--;
782 			}
783 			const uint8 *src2 = src;
784 
785 			if (xpos) {
786 				if (pixelsPerByte == 1) {
787 					do {
788 						uint8 val = (flags & 1) ? *(src - 1) : *src;
789 						while (val && xpos) {
790 							src += pixelStep;
791 							xpos--;
792 							val = (flags & 1) ? *(src - 1) : *src;
793 						}
794 
795 						val = (flags & 1) ? *(src - 1) : *src;
796 						if (!val) {
797 							src += pixelStep;
798 							uint8 bt = (flags & 1) ? src[1] : src[0];
799 							src += pixelStep;
800 							xpos = xpos - bt;
801 						}
802 					} while (xpos > 0);
803 				} else {
804 					src += (xpos * pixelStep);
805 					xpos = 0;
806 				}
807 			}
808 
809 			dst -= xpos * _bytesPerPixel;
810 			xpos += width;
811 
812 			while (xpos > 0) {
813 				uint8 c = *src;
814 				uint8 m = (flags & 1) ? *(src - 1) : c;
815 				src += pixelStep;
816 
817 				if (m) {
818 					drawShapeSetPixel(dst, c);
819 					dst += _bytesPerPixel;
820 					xpos--;
821 				} else if (pixelsPerByte) {
822 					uint8 len = (flags & 1) ? src[1] : src[0];
823 					dst += len * _bytesPerPixel;
824 					xpos -= len;
825 					src += pixelStep;
826 				} else {
827 					dst += _bytesPerPixel;
828 					xpos--;
829 				}
830 			}
831 			xpos += marginRight;
832 
833 			if (xpos) {
834 				do {
835 					if (pixelsPerByte == 1) {
836 						uint8 val = (flags & 1) ? *(src - 1) : *src;
837 						while (val && xpos) {
838 							src += pixelStep;
839 							xpos--;
840 							val = (flags & 1) ? *(src - 1) : *src;
841 						}
842 
843 						val = (flags & 1) ? *(src - 1) : *src;
844 						if (!val) {
845 							src += pixelStep;
846 							uint8 bt = (flags & 1) ? src[1] : src[0];
847 							src += pixelStep;
848 							xpos = xpos - bt;
849 						}
850 					} else {
851 						src += (xpos * pixelStep);
852 						xpos = 0;
853 					}
854 				} while (xpos > 0);
855 			}
856 
857 			dstL += SCREEN_W * _bytesPerPixel;
858 			dst = dstL;
859 			if (flags & 1)
860 				src = src2 + 1;
861 		}
862 	} else {
863 		const uint8 *pal = 0;
864 		uint8 cgaPal[4];
865 		memset(cgaPal, 0, 4);
866 
867 		if (pixelsPerByte == 2) {
868 			pal = ovl ? ovl : src;
869 			src += 16;
870 		} else {
871 			static const uint8 cgaDefOvl[] = { 0x00, 0x55, 0xAA, 0xFF };
872 			pal = ovl ? ovl : cgaDefOvl;
873 			for (int i = 0; i < 4; i++)
874 				cgaPal[i] = pal[i] & 3;
875 			pal = cgaPal;
876 		}
877 
878 		if (d < 0) {
879 			d = -d;
880 			if (d >= dH)
881 				return;
882 			src += (d * (width / pixelsPerByte));
883 			d = dY + dH - _dsY1;
884 			if (d >= 0) {
885 				dH = d;
886 				dY = _dsY1;
887 				d = _dsY2 - dY;
888 			}
889 		} else {
890 			d = _dsY2 - dY;
891 		}
892 
893 		if (d < 1)
894 			return;
895 
896 		if (d < dH)
897 			dH = d;
898 
899 		bool trimL = false;
900 		uint8 dXbitAlign = dX & (pixelsPerByte - 1);
901 
902 		if (dX < 0) {
903 			width += dX;
904 			d = -dX;
905 			if (flags & 1)
906 				src -= (d / pixelsPerByte);
907 			else
908 				src += (d / pixelsPerByte);
909 
910 			if (d >= w2)
911 				return;
912 
913 			dX = 0;
914 			trimL = true;
915 		}
916 
917 		d = (dW << 3) - dX;
918 
919 		if (d < 1)
920 			return;
921 
922 		if (d < width)
923 			width = d;
924 
925 		dst += (dY * SCREEN_W * _bytesPerPixel + dX * _bytesPerPixel);
926 
927 		if (pageNum == 0 || pageNum == 1)
928 			addDirtyRect(rX, rY, rW, rH);
929 
930 		int pitch = SCREEN_W - width;
931 		int16 lineSrcStep = (w2 - width) / pixelsPerByte;
932 		uint8 lineSrcStepRemainder = (w2 - width) % pixelsPerByte;
933 
934 		w2 /= pixelsPerByte;
935 		if (flags & 1)
936 			src += (w2 - 1);
937 
938 		uint8 pixelPacking = 8 / pixelsPerByte;
939 		uint8 pixelPackingMask = 0;
940 
941 		for (int i = 0; i < pixelPacking; i++)
942 			pixelPackingMask |= (1 << i);
943 
944 		if (trimL && (dXbitAlign > lineSrcStepRemainder))
945 			lineSrcStep--;
946 
947 		uint8 bitShDef = 8 - pixelPacking;
948 		if (flags & 1) {
949 			lineSrcStep = (w2 << 1) - lineSrcStep;
950 			bitShDef = 0;
951 		}
952 
953 		uint8 bitShLineStart = bitShDef;
954 		if (trimL)
955 			bitShLineStart -= (dXbitAlign * pixelStep * pixelPacking);
956 
957 		while (dH--) {
958 			int16 wd = width;
959 			uint8 in = 0;
960 			uint8 trans = 0;
961 			uint8 shift = bitShLineStart;
962 			uint8 shSwtch = bitShLineStart;
963 
964 			while (wd--) {
965 				if (shift == shSwtch) {
966 					in = *src;
967 					trans = src[transOffset];
968 					src += pixelStep;
969 					shSwtch = bitShDef;
970 				}
971 				uint8 col = (pixelsPerByte == 2) ? pal[(in >> shift) & pixelPackingMask] : (*dst & ((trans >> shift) & (pixelPackingMask))) | pal[(in >> shift) & pixelPackingMask];
972 				if (col || pixelsPerByte == 4)
973 					drawShapeSetPixel(dst, col);
974 				dst += _bytesPerPixel;
975 				shift = ((shift - (pixelStep * pixelPacking)) & 7);
976 			}
977 			src += lineSrcStep;
978 			dst += (pitch * _bytesPerPixel);
979 		}
980 	}
981 }
982 
scaleShape(const uint8 * shapeData,int steps)983 const uint8 *Screen_EoB::scaleShape(const uint8 *shapeData, int steps) {
984 	setShapeFadingLevel(steps);
985 
986 	while (shapeData && steps--)
987 		shapeData = scaleShapeStep(shapeData);
988 
989 	return shapeData;
990 }
991 
scaleShapeStep(const uint8 * shp)992 const uint8 *Screen_EoB::scaleShapeStep(const uint8 *shp) {
993 	uint8 *dst = (shp != _dsTempPage) ? _dsTempPage : _dsTempPage + 6000;
994 	uint8 *d = dst;
995 	uint8 pixelsPerByte = *d++ = *shp++;
996 	assert(pixelsPerByte > 1);
997 
998 	uint16 h = shp[0] + 1;
999 	d[0] = d[2] = (h << 1) / 3;
1000 
1001 	uint16 w = shp[1];
1002 	uint16 w2 = (w << 3) / pixelsPerByte;
1003 	uint16 t = ((w << 1) % 3) ? 1 : 0;
1004 	d[1] = ((w << 1) / 3) + t;
1005 
1006 	uint32 transOffsetSrc = (pixelsPerByte == 4) ? (shp[0] * shp[1]) << 1 : 0;
1007 	uint32 transOffsetDst = (pixelsPerByte == 4) ? (d[0] * d[1]) << 1 : 0;
1008 	shp += 3;
1009 	d += 3;
1010 
1011 	if (pixelsPerByte == 2) {
1012 		int i = 0;
1013 		while (i < 16) {
1014 			if (!shp[i]) {
1015 				i = -i;
1016 				break;
1017 			}
1018 			i++;
1019 		}
1020 
1021 		if (i >= 0)
1022 			i = 0;
1023 		else
1024 			i = -i;
1025 
1026 		_dsScaleTrans = (i << 4) | (i & 0x0F);
1027 		for (int ii = 0; ii < 16; ii++)
1028 			*d++ = *shp++;
1029 	}
1030 
1031 	_dsDiv = w2 / 3;
1032 	_dsRem = w2 % 3;
1033 
1034 	while (--h) {
1035 		if (pixelsPerByte == 2)
1036 			scaleShapeProcessLine4Bit(d, shp);
1037 		else
1038 			scaleShapeProcessLine2Bit(d, shp, transOffsetDst, transOffsetSrc);
1039 		if (!--h)
1040 			break;
1041 		if (pixelsPerByte == 2)
1042 			scaleShapeProcessLine4Bit(d, shp);
1043 		else
1044 			scaleShapeProcessLine2Bit(d, shp, transOffsetDst, transOffsetSrc);
1045 		if (!--h)
1046 			break;
1047 		shp += w2;
1048 	}
1049 
1050 	return (const uint8 *)dst;
1051 }
1052 
generateShapeOverlay(const uint8 * shp,const uint8 * fadingTable)1053 const uint8 *Screen_EoB::generateShapeOverlay(const uint8 *shp, const uint8 *fadingTable) {
1054 	if (*shp != 2)
1055 		return 0;
1056 
1057 	if (_bytesPerPixel == 2) {
1058 		setFadeTable(fadingTable);
1059 		setShapeFadingLevel(1);
1060 		return 0;
1061 	}
1062 
1063 	shp += 4;
1064 	for (int i = 0; i < 16; i++)
1065 		_shapeOverlay[i] = fadingTable[shp[i]];
1066 	return _shapeOverlay;
1067 }
1068 
setShapeFrame(int x1,int y1,int x2,int y2)1069 void Screen_EoB::setShapeFrame(int x1, int y1, int x2, int y2) {
1070 	_dsX1 = x1;
1071 	_dsY1 = y1;
1072 	_dsX2 = x2;
1073 	_dsY2 = y2;
1074 }
1075 
enableShapeBackgroundFading(bool enable)1076 void Screen_EoB::enableShapeBackgroundFading(bool enable) {
1077 	_dsBackgroundFading = enable;
1078 }
1079 
setShapeFadingLevel(int level)1080 void Screen_EoB::setShapeFadingLevel(int level) {
1081 	_dsShapeFadingLevel = level;
1082 }
1083 
setGfxParameters(int x,int y,int col)1084 void Screen_EoB::setGfxParameters(int x, int y, int col) {
1085 	_gfxX = x;
1086 	_gfxY = y;
1087 	_gfxCol = col;
1088 }
1089 
drawExplosion(int scale,int radius,int numElements,int stepSize,int aspectRatio,const uint8 * colorTable,int colorTableSize)1090 void Screen_EoB::drawExplosion(int scale, int radius, int numElements, int stepSize, int aspectRatio, const uint8 *colorTable, int colorTableSize) {
1091 	int ymin = 0;
1092 	int ymax = _gfxMaxY[scale];
1093 	int xmin = -100;
1094 	int xmax = 276;
1095 
1096 	if (scale)
1097 		--scale;
1098 
1099 	hideMouse();
1100 
1101 	const ScreenDim *dm = getScreenDim(5);
1102 	int rX1 = dm->sx << 3;
1103 	int rY1 = dm->sy;
1104 	int rX2 = rX1 + (dm->w << 3);
1105 	int rY2 = rY1 + dm->h - 1;
1106 
1107 	int16 gx2 = _gfxX;
1108 	int16 gy2 = _gfxY;
1109 
1110 	int16 *ptr2 = (int16 *)_dsTempPage;
1111 	int16 *ptr3 = (int16 *)&_dsTempPage[300];
1112 	int16 *ptr4 = (int16 *)&_dsTempPage[600];
1113 	int16 *ptr5 = (int16 *)&_dsTempPage[900];
1114 	int16 *ptr6 = (int16 *)&_dsTempPage[1200];
1115 	int16 *ptr7 = (int16 *)&_dsTempPage[1500];
1116 	int16 *ptr8 = (int16 *)&_dsTempPage[1800];
1117 
1118 	if (numElements > 150)
1119 		numElements = 150;
1120 
1121 
1122 	for (int i = 0; i < numElements; i++) {
1123 		ptr2[i] = ptr3[i] = 0;
1124 		ptr4[i] = _vm->_rnd.getRandomNumberRng(0, radius) - (radius >> 1);
1125 		ptr5[i] = _vm->_rnd.getRandomNumberRng(0, radius) - (radius >> 1) - (radius >> (8 - aspectRatio));
1126 		ptr7[i] = _vm->_rnd.getRandomNumberRng(1024 / stepSize, 2048 / stepSize);
1127 		ptr8[i] = scale << 8;
1128 	}
1129 
1130 	uint32 playSpeedDelay = ((EXPLOSION_ANIM_DURATION << 15) / numElements) >> 7;
1131 	uint32 frameDelay = (1000 << 8) / 60;
1132 	uint32 playSpeedTimer = 0;
1133 	uint32 frameTimer = frameDelay;
1134 	uint32 start = _system->getMillis();
1135 
1136 	for (int l = 2; l;) {
1137 		if (l != 2) {
1138 			for (int i = numElements - 1; i >= 0; i--) {
1139 				int16 px = ((ptr2[i] >> 6) >> scale) + gx2;
1140 				int16 py = ((ptr3[i] >> 6) >> scale) + gy2;
1141 				if (py > ymax)
1142 					py = ymax;
1143 				if (posWithinRect(px, py, rX1, rY1, rX2, rY2)) {
1144 					if (_bytesPerPixel == 2)
1145 						setPagePixel16bit(0, px, py, ptr6[i]);
1146 					else
1147 						setPagePixel(0, px, py, ptr6[i]);
1148 				}
1149 
1150 				if (_system->getMillis() >= start + (frameTimer >> 8)) {
1151 					updateScreen();
1152 					frameTimer += frameDelay;
1153 				}
1154 				playSpeedTimer += playSpeedDelay;
1155 				if (_system->getMillis() < start + (playSpeedTimer >> 15))
1156 					_vm->delayUntil(start + (playSpeedTimer >> 15));
1157 			}
1158 		}
1159 
1160 		l = 0;
1161 
1162 		for (int i = 0; i < numElements; i++) {
1163 			if (ptr4[i] <= 0)
1164 				ptr4[i]++;
1165 			else
1166 				ptr4[i]--;
1167 			ptr2[i] += ptr4[i];
1168 			ptr5[i] += 5;
1169 			ptr3[i] += ptr5[i];
1170 			ptr8[i] += ptr7[i];
1171 
1172 			int16 px = ((ptr2[i] >> 6) >> scale) + gx2;
1173 			int16 py = ((ptr3[i] >> 6) >> scale) + gy2;
1174 			if (py >= ymax || py < ymin)
1175 				ptr5[i] = -(ptr5[i] >> 1);
1176 			if (px >= xmax || px < xmin)
1177 				ptr4[i] = -(ptr4[i] >> 1);
1178 
1179 			if (py > ymax)
1180 				py = ymax;
1181 
1182 			int pxVal1 = 0;
1183 			if (posWithinRect(px, py, 0, 0, 319, 199)) {
1184 				pxVal1 = getPagePixel(2, px, py);
1185 				ptr6[i] = getPagePixel(0, px, py);
1186 			}
1187 
1188 			assert((ptr8[i] >> 8) < colorTableSize);
1189 			int pxVal2 = colorTable[ptr8[i] >> 8];
1190 			if (pxVal2) {
1191 				l = 1;
1192 				if (pxVal1 == _gfxCol && posWithinRect(px, py, rX1, rY1, rX2, rY2))
1193 					setPagePixel(0, px, py, pxVal2);
1194 			} else {
1195 				ptr7[i] = 0;
1196 			}
1197 
1198 			if (_system->getMillis() >= start + (frameTimer >> 8)) {
1199 				updateScreen();
1200 				frameTimer += frameDelay;
1201 			}
1202 			playSpeedTimer += playSpeedDelay;
1203 			if (_system->getMillis() < start + (playSpeedTimer >> 15))
1204 				_vm->delayUntil(start + (playSpeedTimer >> 15));
1205 		}
1206 	}
1207 
1208 	updateScreen();
1209 	showMouse();
1210 }
1211 
drawVortex(int numElements,int radius,int stepSize,int,int disorder,const uint8 * colorTable,int colorTableSize)1212 void Screen_EoB::drawVortex(int numElements, int radius, int stepSize, int, int disorder, const uint8 *colorTable, int colorTableSize) {
1213 	int16 *xCoords = (int16 *)_dsTempPage;
1214 	int16 *yCoords = (int16 *)&_dsTempPage[300];
1215 	int16 *xMod = (int16 *)&_dsTempPage[600];
1216 	int16 *yMod = (int16 *)&_dsTempPage[900];
1217 	int16 *pixBackup = (int16 *)&_dsTempPage[1200];
1218 	int16 *colTableStep = (int16 *)&_dsTempPage[1500];
1219 	int16 *colTableIndex = (int16 *)&_dsTempPage[1800];
1220 	int16 *pixDelay = (int16 *)&_dsTempPage[2100];
1221 
1222 	hideMouse();
1223 	int cp = _curPage;
1224 
1225 	if (numElements > 150)
1226 		numElements = 150;
1227 
1228 	int cx = 88;
1229 	int cy = 48;
1230 	radius <<= 6;
1231 
1232 	uint32 playSpeedDelay = ((VORTEX_ANIM_DURATION << 16) / numElements) >> 8;
1233 	uint32 frameDelay = (1000 << 8) / 60;
1234 	uint32 playSpeedTimer = 0;
1235 	uint32 frameTimer = frameDelay;
1236 	uint32 start = _system->getMillis();
1237 
1238 	for (int i = 0; i < numElements; i++) {
1239 		int16 v38 = _vm->_rnd.getRandomNumberRng(radius >> 2, radius);
1240 		int16 stepSum = 0;
1241 		int16 sqsum = 0;
1242 		while (sqsum < v38) {
1243 			stepSum += stepSize;
1244 			sqsum += stepSum;
1245 		}
1246 
1247 		switch (_vm->_rnd.getRandomNumber(255) & 3) {
1248 		case 0:
1249 			xCoords[i] = 32;
1250 			yCoords[i] = sqsum;
1251 			xMod[i] = stepSum;
1252 			yMod[i] = 0;
1253 			break;
1254 
1255 		case 1:
1256 			xCoords[i] = sqsum;
1257 			yCoords[i] = 32;
1258 			xMod[i] = 0;
1259 			yMod[i] = stepSum;
1260 			break;
1261 
1262 		case 2:
1263 			xCoords[i] = 32;
1264 			yCoords[i] = -sqsum;
1265 			xMod[i] = stepSum;
1266 			yMod[i] = 0;
1267 			break;
1268 
1269 		default:
1270 			xCoords[i] = -sqsum;
1271 			yCoords[i] = 32;
1272 			xMod[i] = 0;
1273 			yMod[i] = stepSum;
1274 			break;
1275 		}
1276 
1277 		if (_vm->_rnd.getRandomBit()) {
1278 			xMod[i] *= -1;
1279 			yMod[i] *= -1;
1280 		}
1281 
1282 		colTableStep[i] = _vm->_rnd.getRandomNumberRng(1024 / disorder, 2048 / disorder);
1283 		colTableIndex[i] = 0;
1284 		pixDelay[i] = _vm->_rnd.getRandomNumberRng(0, disorder >> 2);
1285 	}
1286 
1287 	int d = 0;
1288 	for (int i = 2; i;) {
1289 		if (i != 2) {
1290 			for (int ii = numElements - 1; ii >= 0; ii--) {
1291 				int16 px = CLIP((xCoords[ii] >> 6) + cx, 0, SCREEN_W - 1);
1292 				int16 py = CLIP((yCoords[ii] >> 6) + cy, 0, SCREEN_H - 1);
1293 				if (_bytesPerPixel == 2)
1294 					setPagePixel16bit(0, px, py, pixBackup[ii]);
1295 				else
1296 					setPagePixel(0, px, py, pixBackup[ii]);
1297 
1298 				if (_system->getMillis() >= start + (frameTimer >> 8)) {
1299 					updateScreen();
1300 					frameTimer += frameDelay;
1301 				}
1302 				playSpeedTimer += playSpeedDelay;
1303 				if (_system->getMillis() < start + (playSpeedTimer >> 16))
1304 					_vm->delayUntil(start + (playSpeedTimer >> 16));
1305 			}
1306 		}
1307 
1308 		i = 0;
1309 		int r = (stepSize >> 1) + (stepSize >> 2) + (stepSize >> 3);
1310 
1311 		for (int ii = 0; ii < numElements; ii++) {
1312 			if (pixDelay[ii] == 0) {
1313 				if (xCoords[ii] > 0) {
1314 					xMod[ii] -= ((xMod[ii] > 0) ? stepSize : r);
1315 				} else {
1316 					xMod[ii] += ((xMod[ii] < 0) ? stepSize : r);
1317 				}
1318 
1319 				if (yCoords[ii] > 0) {
1320 					yMod[ii] -= ((yMod[ii] > 0) ? stepSize : r);
1321 				} else {
1322 					yMod[ii] += ((yMod[ii] < 0) ? stepSize : r);
1323 				}
1324 
1325 				xCoords[ii] += xMod[ii];
1326 				yCoords[ii] += yMod[ii];
1327 				colTableIndex[ii] += colTableStep[ii];
1328 
1329 			} else {
1330 				pixDelay[ii]--;
1331 			}
1332 
1333 			int16 px = CLIP((xCoords[ii] >> 6) + cx, 0, SCREEN_W - 1);
1334 			int16 py = CLIP((yCoords[ii] >> 6) + cy, 0, SCREEN_H - 1);
1335 
1336 			uint8 tc1 = ((disorder >> 2) <= d) ? getPagePixel(2, px, py) : 0;
1337 			pixBackup[ii] = getPagePixel(0, px, py);
1338 			uint8 tblIndex = CLIP(colTableIndex[ii] >> 8, 0, colorTableSize - 1);
1339 			uint8 tc2 = colorTable[tblIndex];
1340 
1341 			if (tc2) {
1342 				i = 1;
1343 				if (tc1 == _gfxCol && !pixDelay[ii])
1344 					setPagePixel(0, px, py, tc2);
1345 			} else {
1346 				colTableStep[ii] = 0;
1347 			}
1348 
1349 			if (_system->getMillis() >= start + (frameTimer >> 8)) {
1350 				updateScreen();
1351 				frameTimer += frameDelay;
1352 			}
1353 			playSpeedTimer += playSpeedDelay;
1354 			if (_system->getMillis() < start + (playSpeedTimer >> 16))
1355 				_vm->delayUntil(start + (playSpeedTimer >> 16));
1356 		}
1357 		d++;
1358 	}
1359 
1360 	_curPage = cp;
1361 	updateScreen();
1362 	showMouse();
1363 }
1364 
fadeTextColor(Palette * pal,int color,int rate)1365 void Screen_EoB::fadeTextColor(Palette *pal, int color, int rate) {
1366 	assert(rate);
1367 	uint8 *col = pal->getData();
1368 
1369 	for (bool loop = true; loop;) {
1370 		uint32 end = _system->getMillis() + _vm->tickLength();
1371 
1372 		loop = false;
1373 		for (int ii = 0; ii < 3; ii++) {
1374 			uint8 c = col[color * 3 + ii];
1375 			if (c > rate) {
1376 				col[color * 3 + ii] -= rate;
1377 				loop = true;
1378 			} else if (c) {
1379 				col[color * 3 + ii] = 0;
1380 				loop = true;
1381 			}
1382 		}
1383 
1384 		if (loop) {
1385 			setScreenPalette(*pal);
1386 			updateScreen();
1387 			uint32 cur = _system->getMillis();
1388 			if (end > cur)
1389 				_system->delayMillis(end - cur);
1390 		}
1391 	}
1392 }
1393 
delayedFadePalStep(Palette * fadePal,Palette * destPal,int rate)1394 bool Screen_EoB::delayedFadePalStep(Palette *fadePal, Palette *destPal, int rate) {
1395 	bool res = false;
1396 
1397 	uint8 *s = fadePal->getData();
1398 	uint8 *d = destPal->getData();
1399 	int numBytes = (fadePal->getNumColors() - 1) * 3;
1400 
1401 	for (int i = 0; i < numBytes; i++) {
1402 		int fadeVal = *s++;
1403 		int dstCur = *d;
1404 		int diff = ABS(fadeVal - dstCur);
1405 
1406 		if (diff == 0) {
1407 			d++;
1408 			continue;
1409 		}
1410 
1411 		res = true;
1412 		diff = MIN(diff, rate);
1413 
1414 		if (dstCur < fadeVal)
1415 			*d += diff;
1416 		else
1417 			*d -= diff;
1418 		d++;
1419 	}
1420 
1421 	return res;
1422 }
1423 
getRectSize(int w,int h)1424 int Screen_EoB::getRectSize(int w, int h) {
1425 	return w * h;
1426 }
1427 
setFadeTable(const uint8 * table)1428 void Screen_EoB::setFadeTable(const uint8 *table) {
1429 	_dsShapeFadingTable = table;
1430 	if (_bytesPerPixel == 2)
1431 		memcpy(&_16bitPalette[0x100], table, 512);
1432 }
1433 
createFadeTable(const uint8 * palData,uint8 * dst,uint8 rootColor,uint8 weight)1434 void Screen_EoB::createFadeTable(const uint8 *palData, uint8 *dst, uint8 rootColor, uint8 weight) {
1435 	if (!palData)
1436 		return;
1437 
1438 	const uint8 *src = palData + 3 * rootColor;
1439 	uint8 r = *src++;
1440 	uint8 g = *src++;
1441 	uint8 b = *src;
1442 	uint8 tr, tg, tb;
1443 	src = palData + 3;
1444 
1445 	*dst++ = 0;
1446 	weight >>= 1;
1447 
1448 	for (uint8 i = 1; i; i++) {
1449 		uint16 tmp = (uint16)((*src - r) * weight) << 1;
1450 		tr = *src++ - ((tmp >> 8) & 0xFF);
1451 		tmp = (uint16)((*src - g) * weight) << 1;
1452 		tg = *src++ - ((tmp >> 8) & 0xFF);
1453 		tmp = (uint16)((*src - b) * weight) << 1;
1454 		tb = *src++ - ((tmp >> 8) & 0xFF);
1455 
1456 		const uint8 *d = palData + 3;
1457 		uint16 v = 0xFFFF;
1458 		uint8 col = rootColor;
1459 
1460 		for (uint8 ii = 1; ii; ii++) {
1461 			int a = *d++ - tr;
1462 			int t = a * a;
1463 			a = *d++ - tg;
1464 			t += (a * a);
1465 			a = *d++ - tb;
1466 			t += (a * a);
1467 
1468 			if (t <= v && (ii == rootColor || ii != i)) {
1469 				v = t;
1470 				col = ii;
1471 			}
1472 		}
1473 		*dst++ = col;
1474 	}
1475 }
1476 
createFadeTable16bit(const uint16 * palData,uint16 * dst,uint16 rootColor,uint8 weight)1477 void Screen_EoB::createFadeTable16bit(const uint16 *palData, uint16 *dst, uint16 rootColor, uint8 weight) {
1478 	rootColor = palData[rootColor];
1479 	uint8 r8 = (rootColor & 0x1f);
1480 	uint8 g8 = (rootColor & 0x3E0) >> 5;
1481 	uint8 b8 = (rootColor & 0x7C00) >> 10;
1482 
1483 	int root_r = r8 << 4;
1484 	int root_g = g8 << 4;
1485 	int root_b = b8 << 4;
1486 
1487 	*dst++ = palData[0];
1488 
1489 	for (uint8 i = 1; i; i++) {
1490 		r8 = (palData[i] & 0x1f);
1491 		g8 = (palData[i] & 0x3E0) >> 5;
1492 		b8 = (palData[i] & 0x7C00) >> 10;
1493 
1494 		int red = r8 << 4;
1495 		int green = g8 << 4;
1496 		int blue = b8 << 4;
1497 
1498 		if (red > root_r) {
1499 			red -= weight;
1500 			if (root_r > red)
1501 				red = root_r;
1502 		} else {
1503 			red += weight;
1504 			if (root_r < red)
1505 				red = root_r;
1506 		}
1507 
1508 		if (green > root_g) {
1509 			green -= weight;
1510 			if (root_g > green)
1511 				green = root_g;
1512 		} else {
1513 			green += weight;
1514 			if (root_g < green)
1515 				green = root_g;
1516 		}
1517 
1518 		if (blue > root_b) {
1519 			blue -= weight;
1520 			if (root_b > blue)
1521 				blue = root_b;
1522 		} else {
1523 			blue += weight;
1524 			if (root_b < blue)
1525 				blue = root_b;
1526 		}
1527 
1528 		r8 = red >> 4;
1529 		g8 = green >> 4;
1530 		b8 = blue >> 4;
1531 
1532 		*dst++ = (b8 << 10) | (g8 << 5) | r8;
1533 	}
1534 }
1535 
getCGADitheringTable(int index)1536 const uint16 *Screen_EoB::getCGADitheringTable(int index) {
1537 	return !(index & ~1) ? _cgaDitheringTables[index] : 0;
1538 }
1539 
getEGADitheringTable()1540 const uint8 *Screen_EoB::getEGADitheringTable() {
1541 	return _egaDitheringTable;
1542 }
1543 
loadFont(FontId fontId,const char * filename)1544 bool Screen_EoB::loadFont(FontId fontId, const char *filename) {
1545 	Font *&fnt = _fonts[fontId];
1546 	int temp = 0;
1547 	if (fnt)
1548 		delete fnt;
1549 
1550 	if (fontId == FID_SJIS_SMALL_FNT) {
1551 		if (_vm->gameFlags().platform == Common::kPlatformFMTowns)
1552 			fnt = new SJISFont12x12(_vm->staticres()->loadRawDataBe16(kEoB2FontDmpSearchTbl, temp));
1553 		else if (_vm->gameFlags().platform == Common::kPlatformPC98)
1554 			fnt = new Font12x12PC98(12, _vm->staticres()->loadRawDataBe16(kEoB1Ascii2SjisTable1, temp),
1555 				_vm->staticres()->loadRawDataBe16(kEoB1Ascii2SjisTable2, temp), _vm->staticres()->loadRawData(kEoB1FontLookupTable, temp));
1556 	} else if (_isAmiga) {
1557 		fnt = new AmigaDOSFont(_vm->resource(), _vm->game() == GI_EOB2 && _vm->gameFlags().lang == Common::DE_DEU);
1558 	} else if (_isSegaCD) {
1559 		fnt = new SegaCDFont(_vm->gameFlags().lang, _vm->staticres()->loadRawDataBe16(kEoB1Ascii2SjisTable1, temp), _vm->staticres()->loadRawDataBe16(kEoB1Ascii2SjisTable2, temp),
1560 			_vm->staticres()->loadRawData(kEoB1CharWidthTable1, temp), _vm->staticres()->loadRawData(kEoB1CharWidthTable2, temp), _vm->staticres()->loadRawData(kEoB1CharWidthTable3, temp));
1561 	} else {
1562 		// We use normal VGA rendering in EOB II, since we do the complete EGA dithering in updateScreen().
1563 		fnt = new OldDOSFont(_useHiResEGADithering ? Common::kRenderVGA : _renderMode, 12);
1564 	}
1565 
1566 	assert(fnt);
1567 
1568 	Common::SeekableReadStream *file = _vm->resource()->createReadStream(filename);
1569 	if (!file)
1570 		error("Font file '%s' is missing", filename);
1571 
1572 	bool ret = fnt->load(*file);
1573 	fnt->setColorMap(_textColorsMap);
1574 	delete file;
1575 	return ret;
1576 }
1577 
updateDirtyRects()1578 void Screen_EoB::updateDirtyRects() {
1579 	if (!_useHiResEGADithering) {
1580 		Screen::updateDirtyRects();
1581 		return;
1582 	}
1583 
1584 	if (_forceFullUpdate) {
1585 		ditherRect(getCPagePtr(0), _egaDitheringTempPage, SCREEN_W * 2, SCREEN_W, SCREEN_H);
1586 		_system->copyRectToScreen(_egaDitheringTempPage, SCREEN_W * 2, 0, 0, SCREEN_W * 2, SCREEN_H * 2);
1587 	} else {
1588 		const uint8 *page0 = getCPagePtr(0);
1589 		Common::List<Common::Rect>::iterator it;
1590 		for (it = _dirtyRects.begin(); it != _dirtyRects.end(); ++it) {
1591 			ditherRect(page0 + it->top * SCREEN_W + it->left, _egaDitheringTempPage, SCREEN_W * 2, it->width(), it->height());
1592 			_system->copyRectToScreen(_egaDitheringTempPage, SCREEN_W * 2, it->left * 2, it->top * 2, it->width() * 2, it->height() * 2);
1593 		}
1594 	}
1595 
1596 	_forceFullUpdate = false;
1597 	_dirtyRects.clear();
1598 }
1599 
ditherRect(const uint8 * src,uint8 * dst,int dstPitch,int srcW,int srcH,int colorKey)1600 void Screen_EoB::ditherRect(const uint8 *src, uint8 *dst, int dstPitch, int srcW, int srcH, int colorKey) {
1601 	while (srcH--) {
1602 		uint8 *dst2 = dst + dstPitch;
1603 		for (int i = 0; i < srcW; i++) {
1604 			int in = *src++;
1605 			if (in != colorKey) {
1606 				in = _egaDitheringTable[in];
1607 				*dst++ = *dst2++ = in >> 4;
1608 				*dst++ = *dst2++ = in & 0x0F;
1609 			} else {
1610 				dst[0] = dst[1] = dst2[0] = dst2[1] = colorKey;
1611 				dst += 2;
1612 				dst2 += 2;
1613 			}
1614 		}
1615 		src += (SCREEN_W - srcW);
1616 		dst += ((dstPitch - srcW) * 2);
1617 	}
1618 }
1619 
drawShapeSetPixel(uint8 * dst,uint8 col)1620 void Screen_EoB::drawShapeSetPixel(uint8 *dst, uint8 col) {
1621 	if (_bytesPerPixel == 2) {
1622 		*(uint16*)dst = _16bitPalette[(_dsShapeFadingLevel << 8) + col];
1623 		return;
1624 	} else if (_useShapeShading) {
1625 		if (_dsBackgroundFading) {
1626 			if (_dsShapeFadingLevel) {
1627 				col = *dst;
1628 			} else {
1629 				_dsBackgroundFadingXOffs &= 7;
1630 				col = *(dst + _dsBackgroundFadingXOffs++);
1631 			}
1632 		}
1633 
1634 		if (_dsShapeFadingLevel) {
1635 			assert(_dsShapeFadingTable);
1636 			uint8 cnt = _dsShapeFadingLevel;
1637 			while (cnt--)
1638 				col = _dsShapeFadingTable[col];
1639 		}
1640 	}
1641 
1642 	*dst = col;
1643 }
1644 
scaleShapeProcessLine2Bit(uint8 * & shpDst,const uint8 * & shpSrc,uint32 transOffsetDst,uint32 transOffsetSrc)1645 void Screen_EoB::scaleShapeProcessLine2Bit(uint8 *&shpDst, const uint8 *&shpSrc, uint32 transOffsetDst, uint32 transOffsetSrc) {
1646 	for (int i = 0; i < _dsDiv; i++) {
1647 		shpDst[0] = (_cgaScaleTable[shpSrc[0]] << 2) | (shpSrc[1] >> 6);
1648 		shpDst[1] = ((shpSrc[1] & 0x0F) << 4) | ((shpSrc[2] >> 2) & 0x0F);
1649 		shpDst[transOffsetDst] = (_cgaScaleTable[shpSrc[transOffsetSrc]] << 2) | (shpSrc[transOffsetSrc + 1] >> 6);
1650 		shpDst[transOffsetDst + 1] = ((shpSrc[transOffsetSrc + 1] & 0x0F) << 4) | ((shpSrc[transOffsetSrc + 2] >> 2) & 0x0F);
1651 		shpSrc += 3;
1652 		shpDst += 2;
1653 	}
1654 
1655 	if (_dsRem == 1) {
1656 		shpDst[0] = _cgaScaleTable[shpSrc[0]] << 2;
1657 		shpDst[1] = 0;
1658 		shpDst[transOffsetDst] = (_cgaScaleTable[shpSrc[transOffsetSrc]] << 2) | 3;
1659 		shpDst[transOffsetDst + 1] = 0xFF;
1660 		shpSrc++;
1661 		shpDst += 2;
1662 
1663 	} else if (_dsRem == 2) {
1664 		shpDst[0] = (_cgaScaleTable[shpSrc[0]] << 2) | (shpSrc[1] >> 6);
1665 		shpDst[1] = (shpSrc[1] & 0x3F) << 2;
1666 		shpDst[transOffsetDst] = (_cgaScaleTable[shpSrc[transOffsetSrc]] << 2) | (shpSrc[transOffsetSrc + 1] >> 6);
1667 		shpDst[transOffsetDst + 1] = ((shpSrc[transOffsetSrc + 1] & 0x3F) << 2) | 3;
1668 		shpSrc += 2;
1669 		shpDst += 2;
1670 	}
1671 }
1672 
scaleShapeProcessLine4Bit(uint8 * & dst,const uint8 * & src)1673 void Screen_EoB::scaleShapeProcessLine4Bit(uint8 *&dst, const uint8 *&src) {
1674 	for (int i = 0; i < _dsDiv; i++) {
1675 		*dst++ = *src++;
1676 		*dst++ = (READ_BE_UINT16(src) >> 4) & 0xFF;
1677 		src += 2;
1678 	}
1679 
1680 	if (_dsRem == 1) {
1681 		*dst++ = *src++;
1682 		*dst++ = _dsScaleTrans;
1683 	} else if (_dsRem == 2) {
1684 		*dst++ = (src[0] & 0xF0) | (src[1] >> 4);
1685 		src += 2;
1686 		*dst++ = _dsScaleTrans;
1687 		*dst++ = _dsScaleTrans;
1688 		*dst++ = _dsScaleTrans;
1689 	}
1690 }
1691 
posWithinRect(int posX,int posY,int x1,int y1,int x2,int y2)1692 bool Screen_EoB::posWithinRect(int posX, int posY, int x1, int y1, int x2, int y2) {
1693 	if (posX < x1 || posX > x2 || posY < y1 || posY > y2)
1694 		return false;
1695 	return true;
1696 }
1697 
setPagePixel16bit(int pageNum,int x,int y,uint16 color)1698 void Screen_EoB::setPagePixel16bit(int pageNum, int x, int y, uint16 color) {
1699 	assert(pageNum < SCREEN_PAGE_NUM);
1700 	assert(x >= 0 && x < SCREEN_W && y >= 0 && y < SCREEN_H);
1701 	assert(_bytesPerPixel == 2);
1702 
1703 	if (pageNum == 0 || pageNum == 1)
1704 		addDirtyRect(x, y, 1, 1);
1705 
1706 	((uint16*)_pagePtrs[pageNum])[y * SCREEN_W + x] = color;
1707 }
1708 
generateEGADitheringTable(const Palette & pal)1709 void Screen_EoB::generateEGADitheringTable(const Palette &pal) {
1710 	assert(_egaDitheringTable);
1711 	const uint8 *src = pal.getData();
1712 	uint8 *dst = _egaDitheringTable;
1713 
1714 	for (int i = 256; i; i--) {
1715 		int r = *src++;
1716 		int g = *src++;
1717 		int b = *src++;
1718 
1719 		uint8 col = 0;
1720 		uint16 min = 0x2E83;
1721 
1722 		for (int ii = 256; ii; ii--) {
1723 			const uint8 *palEntry = _egaMatchTable + (ii - 1) * 3;
1724 			if (*palEntry == 0xFF)
1725 				continue;
1726 
1727 			int e_r = palEntry[0] - r;
1728 			int e_g = palEntry[1] - g;
1729 			int e_b = palEntry[2] - b;
1730 
1731 			uint16 s = (e_r * e_r) + (e_g * e_g) + (e_b * e_b);
1732 
1733 			if (s <= min) {
1734 				min = s;
1735 				col = ii - 1;
1736 			}
1737 		}
1738 		*dst++ = col;
1739 	}
1740 }
1741 
generateCGADitheringTables(const uint8 * mappingData)1742 void Screen_EoB::generateCGADitheringTables(const uint8 *mappingData) {
1743 	for (int i = 0; i < 256; i++) {
1744 		_cgaDitheringTables[0][i] = (mappingData[(i >> 4) + 16] << 8) | mappingData[i & 0x0F];
1745 		_cgaDitheringTables[1][i] = (mappingData[i >> 4] << 8) | mappingData[(i & 0x0F) + 16];
1746 	}
1747 }
1748 
1749 const uint8 Screen_EoB::_egaMatchTable[] = {
1750 	0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x1E, 0x00, 0x00, 0x1E, 0x1E, 0x1E, 0x00, 0x00, 0x1E,
1751 	0x00, 0x1E, 0x1E, 0x0F, 0x00, 0x1E, 0x1E, 0x1E, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x2D, 0x0F, 0x2D,
1752 	0x0F, 0x0F, 0x2D, 0x2D, 0x2D, 0x0F, 0x0F, 0x2D, 0x0F, 0x2D, 0x2D, 0x2D, 0x0F, 0x2D, 0x2D, 0x2D,
1753 	0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x2A, 0x00, 0x1E, 0x1E, 0x00, 0x1E, 0x2A, 0x1E, 0x00, 0x1E, 0x1E,
1754 	0x00, 0x2A, 0x1E, 0x0F, 0x1E, 0x1E, 0x1E, 0x2A, 0x0F, 0x0F, 0x21, 0x0F, 0x0F, 0x36, 0x0F, 0x2D,
1755 	0x21, 0x0F, 0x2D, 0x36, 0x2D, 0x0F, 0x21, 0x2D, 0x0F, 0x36, 0x2D, 0x2D, 0x21, 0x2D, 0x2D, 0x36,
1756 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x2A, 0x00, 0x00, 0x2A, 0x1E, 0x1E, 0x1E, 0x00, 0x1E,
1757 	0x1E, 0x1E, 0x1E, 0x21, 0x00, 0x1E, 0x2A, 0x1E, 0x0F, 0x21, 0x0F, 0x0F, 0x21, 0x2D, 0x0F, 0x36,
1758 	0x0F, 0x0F, 0x36, 0x2D, 0x2D, 0x21, 0x0F, 0x2D, 0x21, 0x2D, 0x2D, 0x36, 0x0F, 0x2D, 0x36, 0x2D,
1759 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x2A, 0x2A, 0x1E, 0x1E, 0x1E, 0x1E,
1760 	0x1E, 0x2A, 0x1E, 0x21, 0x1E, 0x1E, 0x2A, 0x2A, 0x0F, 0x21, 0x21, 0x0F, 0x21, 0x36, 0x0F, 0x36,
1761 	0x21, 0x0F, 0x36, 0x36, 0x2D, 0x21, 0x21, 0x2D, 0x21, 0x36, 0x2D, 0x36, 0x21, 0x2D, 0x36, 0x36,
1762 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2A, 0x00, 0x00, 0x2A,
1763 	0x00, 0x1E, 0x2A, 0x0F, 0x00, 0x2A, 0x1E, 0x1E, 0x21, 0x0F, 0x0F, 0x21, 0x0F, 0x2D, 0x21, 0x2D,
1764 	0x0F, 0x21, 0x2D, 0x2D, 0x36, 0x0F, 0x0F, 0x36, 0x0F, 0x2D, 0x36, 0x2D, 0x0F, 0x36, 0x2D, 0x2D,
1765 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2A,
1766 	0x00, 0x2A, 0x2A, 0x0F, 0x1E, 0x2A, 0x1E, 0x2A, 0x21, 0x0F, 0x21, 0x21, 0x0F, 0x36, 0x21, 0x2D,
1767 	0x21, 0x21, 0x2D, 0x36, 0x36, 0x0F, 0x21, 0x36, 0x0F, 0x36, 0x36, 0x2D, 0x21, 0x36, 0x2D, 0x36,
1768 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1769 	0xFF, 0xFF, 0x2A, 0x15, 0x00, 0x2A, 0x21, 0x1E, 0x21, 0x15, 0x0F, 0x21, 0x15, 0x2D, 0x21, 0x2F,
1770 	0x0F, 0x21, 0x2F, 0x2D, 0x36, 0x15, 0x0F, 0x36, 0x15, 0x2D, 0x36, 0x2F, 0x0F, 0x36, 0x2F, 0x2D,
1771 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1772 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2A, 0x2A, 0x2A, 0x21, 0x21, 0x21, 0x21, 0x21, 0x36, 0x21, 0x36,
1773 	0x21, 0x21, 0x36, 0x36, 0x36, 0x21, 0x21, 0x36, 0x21, 0x36, 0x36, 0x36, 0x21, 0x36, 0x36, 0x36,
1774 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1775 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x15, 0x15, 0x15, 0x15, 0x15, 0x2F, 0x15, 0x2F,
1776 	0x15, 0x15, 0x2F, 0x2F, 0x2F, 0x15, 0x15, 0x2F, 0x15, 0x2F, 0x2F, 0x2F, 0x15, 0x2F, 0x2F, 0x2F,
1777 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1778 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x15, 0x15, 0x3F, 0x15, 0x2F,
1779 	0x2F, 0x15, 0x2F, 0x3F, 0x2F, 0x15, 0x2F, 0x2F, 0x15, 0x3F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x3F,
1780 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1781 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x15, 0x3F,
1782 	0x15, 0x15, 0x3F, 0x2F, 0x2F, 0x2F, 0x15, 0x2F, 0x2F, 0x2F, 0x2F, 0x3F, 0x15, 0x2F, 0x3F, 0x2F,
1783 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1784 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1785 	0xFF, 0x15, 0x3F, 0x3F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x3F, 0x2F, 0x3F, 0x2F, 0x2F, 0x3F, 0x3F,
1786 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1787 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1788 	0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x15, 0x15, 0x3F, 0x15, 0x2F, 0x3F, 0x2F, 0x15, 0x3F, 0x2F, 0x2F,
1789 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1790 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1791 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x15, 0x3F, 0x3F, 0x2F, 0x2F, 0x3F, 0x2F, 0x3F,
1792 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1793 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1794 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x3F, 0x15, 0x3F, 0x3F, 0x2F,
1795 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1796 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1797 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x3F, 0x3F
1798 };
1799 
1800 #undef EXPLOSION_ANIM_DURATION
1801 #undef VORTEX_ANIM_DURATION
1802 
1803 uint16 *OldDOSFont::_cgaDitheringTable = 0;
1804 int OldDOSFont::_numRef = 0;
1805 
OldDOSFont(Common::RenderMode mode,uint8 shadowColor)1806 OldDOSFont::OldDOSFont(Common::RenderMode mode, uint8 shadowColor) : _renderMode(mode), _shadowColor(shadowColor), _colorMap8bit(0), _colorMap16bit(0) {
1807 	_data = 0;
1808 	_width = _height = _numGlyphs = 0;
1809 	_bitmapOffsets = 0;
1810 	_style = kStyleNone;
1811 
1812 	_numRef++;
1813 	if (!_cgaDitheringTable && _numRef == 1) {
1814 		_cgaDitheringTable = new uint16[256];
1815 		memset(_cgaDitheringTable, 0, 256 * sizeof(uint16));
1816 		static const uint bits[] = { 0, 3, 12, 15 };
1817 		for (int i = 0; i < 256; i++)
1818 			_cgaDitheringTable[i] = (bits[i & 3] << 8) | (bits[(i >> 2) & 3] << 12) | (bits[(i >> 4) & 3] << 0) | (bits[(i >> 6) & 3] << 4);
1819 	}
1820 }
1821 
~OldDOSFont()1822 OldDOSFont::~OldDOSFont() {
1823 	unload();
1824 
1825 	if (_numRef)
1826 		--_numRef;
1827 
1828 	if (_cgaDitheringTable && !_numRef) {
1829 		delete[] _cgaDitheringTable;
1830 		_cgaDitheringTable = 0;
1831 	}
1832 }
1833 
load(Common::SeekableReadStream & file)1834 bool OldDOSFont::load(Common::SeekableReadStream &file) {
1835 	unload();
1836 
1837 	_data = new uint8[file.size()];
1838 	assert(_data);
1839 
1840 	file.read(_data, file.size());
1841 	if (file.err())
1842 		return false;
1843 
1844 	if (file.size() - 2 != READ_LE_UINT16(_data))
1845 		return false;
1846 
1847 	_width = _data[0x103];
1848 	_height = _data[0x102];
1849 	_numGlyphs = (READ_LE_UINT16(_data + 2) / 2) - 2;
1850 
1851 	_bitmapOffsets = (uint16 *)(_data + 2);
1852 
1853 	for (int i = 0; i < _numGlyphs; ++i)
1854 		_bitmapOffsets[i] = READ_LE_UINT16(&_bitmapOffsets[i]);
1855 
1856 	return true;
1857 }
1858 
getCharWidth(uint16 c) const1859 int OldDOSFont::getCharWidth(uint16 c) const {
1860 	// Since these fonts have a fixed character width we always give a return value
1861 	// even if there is no glyph for the specified character (which can't normally
1862 	// happen anyway - you'd have to do something like importing a Japanese save file
1863 	// into the English version).
1864 	return _width;
1865 }
1866 
setColorMap(const uint8 * src)1867 void OldDOSFont::setColorMap(const uint8 *src) {
1868 	_colorMap8bit = src;
1869 }
1870 
drawChar(uint16 c,byte * dst,int pitch,int bpp) const1871 void OldDOSFont::drawChar(uint16 c, byte *dst, int pitch, int bpp) const {
1872 	uint16 color1 = _colorMap8bit[1];
1873 	uint16 color2 = _colorMap8bit[0];
1874 
1875 	if (_style == kStyleLeftShadow) {
1876 		drawCharIntern(c, dst + pitch, pitch, 1, _shadowColor, 0);
1877 		drawCharIntern(c, dst - 1, pitch, 1, _shadowColor, 0);
1878 		drawCharIntern(c, dst - 1 + pitch, pitch, 1, _shadowColor, 0);
1879 	}
1880 
1881 	if (bpp == 2) {
1882 		color1 = _colorMap16bit[1];
1883 		color2 = _colorMap16bit[0];
1884 	}
1885 
1886 	drawCharIntern(c, dst, pitch, bpp, color1, color2);
1887 }
1888 
drawCharIntern(uint16 c,byte * dst,int pitch,int bpp,int col1,int col2) const1889 void OldDOSFont::drawCharIntern(uint16 c, byte *dst, int pitch, int bpp, int col1, int col2) const {
1890 	static const uint16 renderMaskTable[] = {
1891 		0x0000, 0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff
1892 	};
1893 
1894 	c = convert(c);
1895 
1896 	if (c >= _numGlyphs)
1897 		return;
1898 
1899 	pitch *= bpp;
1900 	const uint8 *src = &_data[_bitmapOffsets[c]];
1901 	uint8 *dst2 = dst + pitch;
1902 
1903 	int w = (_width - 1) >> 3;
1904 	pitch -= _width * bpp;
1905 
1906 	if (_renderMode == Common::kRenderCGA || _renderMode == Common::kRenderEGA) {
1907 		col1 &= 0x0F;
1908 		col2 &= 0x0F;
1909 	}
1910 
1911 	static const uint16 cgaColorMask[] = { 0, 0x5555, 0xAAAA, 0xFFFF };
1912 	uint16 cgaMask1 = cgaColorMask[col1 & 3];
1913 	uint16 cgaMask2 = cgaColorMask[col2 & 3];
1914 
1915 	int cH = _height;
1916 	while (cH--) {
1917 		int cW = w;
1918 		uint16 mask = renderMaskTable[_width];
1919 
1920 		if (_renderMode == Common::kRenderCGA) {
1921 			uint16 s = (*src++) << 8;
1922 			if (_width > 8)
1923 				s |= *src++;
1924 
1925 			uint16 cmp1 = 0;
1926 			uint16 cmp2 = 0;
1927 
1928 			if (col1) {
1929 				s &= mask;
1930 				cmp1 = _cgaDitheringTable[s >> 8];
1931 			}
1932 
1933 			if (col2) {
1934 				s = ~s & mask;
1935 				cmp2 = _cgaDitheringTable[s >> 8];
1936 			}
1937 
1938 			uint16 cDst = 0;
1939 			uint8 sh = 6;
1940 			for (int i = 0; i < _width; i++) {
1941 				cDst |= ((dst[i] & 3) << sh);
1942 				sh = (sh - 2) & 0x0F;
1943 			}
1944 
1945 			uint16 out = (~(cmp1 | cmp2) & cDst) | (cmp1 & cgaMask1) | (cmp2 & cgaMask2);
1946 
1947 			sh = 6;
1948 			for (int i = 0; i < _width; i++) {
1949 				*dst++ = (out >> sh) & 3;
1950 				sh = (sh - 2) & 0x0F;
1951 			}
1952 		} else {
1953 			for (bool runWidthLoop = true; runWidthLoop;) {
1954 				uint16 s = (*src++) << 8;
1955 				if (_width > 8)
1956 					s |= *src++;
1957 
1958 				for (uint16 i = 0x8000; i; i >>= 1) {
1959 					if (!(mask & i)) {
1960 						runWidthLoop = false;
1961 						break;
1962 					}
1963 
1964 					if (s & i) {
1965 						if (bpp == 2)
1966 							*(uint16*)dst = col1;
1967 						else if (col1)
1968 							*dst = col1;
1969 					} else {
1970 						if (bpp == 2) {
1971 							if (col2 != 0xFFFF)
1972 								*(uint16*)dst = col2;
1973 						} else if (col2) {
1974 							*dst = col2;
1975 						}
1976 					}
1977 					dst += bpp;
1978 				}
1979 
1980 				mask >>= 1;
1981 
1982 				if (cW)
1983 					cW--;
1984 				else
1985 					runWidthLoop = false;
1986 			}
1987 		}
1988 
1989 		dst += pitch;
1990 		dst2 += pitch;
1991 	}
1992 }
1993 
convert(uint16 c) const1994 uint16 OldDOSFont::convert(uint16 c) const {
1995 	if (_width == 6) {
1996 		switch (c) {
1997 		case 0x81:
1998 		case 0x9A:
1999 			c = 0x5D;
2000 			break;
2001 		case 0x84:
2002 		case 0x8E:
2003 			c = 0x5B;
2004 			break;
2005 		case 0x94:
2006 		case 0x99:
2007 			c = 0x40;
2008 		case 0xE1:
2009 			// TODO: recheck this: no conversion for 'ß' ?
2010 			break;
2011 		default:
2012 			break;
2013 		}
2014 	} else if (_width == 8) {
2015 		switch (c) {
2016 		case 0x81:
2017 		case 0x9A:
2018 		case 0x5D:
2019 			c = 0x1D;
2020 			break;
2021 		case 0x84:
2022 		case 0x5B:
2023 			c = 0x1E;
2024 			break;
2025 		case 0x94:
2026 		case 0x40:
2027 			c = 0x1F;
2028 			break;
2029 		case 0x8E:
2030 			c = 0x1B;
2031 			break;
2032 		case 0x99:
2033 			c = 0x1C;
2034 			break;
2035 		case 0xE1:
2036 			c = 0x19;
2037 			break;
2038 		default:
2039 			break;
2040 		}
2041 	}
2042 	return c;
2043 }
2044 
unload()2045 void OldDOSFont::unload() {
2046 	delete[] _data;
2047 	_data = 0;
2048 	_width = _height = _numGlyphs = 0;
2049 	_bitmapOffsets = 0;
2050 }
2051 
2052 } // End of namespace Kyra
2053 
2054 #endif // ENABLE_EOB
2055