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