PageRenderTime 55ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/engines/kyra/screen_eob.cpp

http://github.com/scummvm/scummvm
C++ | 1651 lines | 1353 code | 266 blank | 32 comment | 392 complexity | b6db4b44efe3a02e4d116de4a94ac628 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, GPL-2.0
  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. #if !defined(ENABLE_EOB)
  23. #include "kyra/screen.h"
  24. #endif
  25. #ifdef ENABLE_EOB
  26. #include "kyra/eobcommon.h"
  27. #include "kyra/resource.h"
  28. #include "common/system.h"
  29. #include "graphics/cursorman.h"
  30. #include "graphics/palette.h"
  31. namespace Kyra {
  32. Screen_EoB::Screen_EoB(EoBCoreEngine *vm, OSystem *system) : Screen(vm, system, _screenDimTable, _screenDimTableCount) {
  33. _shapeFadeMode[0] = _shapeFadeMode[1] = 0;
  34. _shapeFadeInternal = 0;
  35. _fadeData = 0;
  36. _fadeDataIndex = 0;
  37. _dsX1 = _dsX2 = _dsY1 = _dsY2 = 0;
  38. _gfxX = _gfxY = 0;
  39. _gfxCol = 0;
  40. _dsTempPage = 0;
  41. _dsDiv = 0;
  42. _dsRem = 0;
  43. _dsScaleTrans = 0;
  44. _cgaScaleTable = 0;
  45. _gfxMaxY = 0;
  46. _egaDitheringTable = 0;
  47. _egaDitheringTempPage = 0;
  48. _cgaMappingDefault = 0;
  49. _cgaDitheringTables[0] = _cgaDitheringTables[1] = 0;
  50. _useHiResEGADithering = false;
  51. }
  52. Screen_EoB::~Screen_EoB() {
  53. delete[] _fadeData;
  54. delete[] _dsTempPage;
  55. delete[] _cgaScaleTable;
  56. delete[] _egaDitheringTable;
  57. delete[] _egaDitheringTempPage;
  58. delete[] _cgaDitheringTables[0];
  59. delete[] _cgaDitheringTables[1];
  60. }
  61. bool Screen_EoB::init() {
  62. if (Screen::init()) {
  63. int temp;
  64. _gfxMaxY = _vm->staticres()->loadRawData(kEoBBaseExpObjectY, temp);
  65. if (_renderMode != Common::kRenderCGA && _renderMode != Common::kRenderEGA)
  66. _fadeData = _vm->resource()->fileData("FADING.DAT", 0);
  67. if (!_fadeData) {
  68. _fadeData = new uint8[0x700];
  69. memset(_fadeData, 0, 0x700);
  70. if (_renderMode != Common::kRenderCGA && _renderMode != Common::kRenderEGA) {
  71. uint8 *pal = _vm->resource()->fileData("PALETTE1.PAL", 0);
  72. for (int i = 0; i < 7; i++)
  73. createFadeTable(pal, &_fadeData[i << 8], 18, (i + 1) * 36);
  74. delete[] pal;
  75. }
  76. }
  77. _dsTempPage = new uint8[12000];
  78. if (_vm->gameFlags().useHiRes && _renderMode == Common::kRenderEGA) {
  79. _useHiResEGADithering = true;
  80. _egaDitheringTable = new uint8[256];
  81. _egaDitheringTempPage = new uint8[SCREEN_W * 2 * SCREEN_H * 2];
  82. for (int i = 0; i < 256; i++)
  83. _egaDitheringTable[i] = i & 0x0F;
  84. } else if (_renderMode == Common::kRenderCGA) {
  85. _cgaMappingDefault = _vm->staticres()->loadRawData(kEoB1CgaMappingDefault, temp);
  86. _cgaDitheringTables[0] = new uint16[256];
  87. memset(_cgaDitheringTables[0], 0, 256 * sizeof(uint16));
  88. _cgaDitheringTables[1] = new uint16[256];
  89. memset(_cgaDitheringTables[1], 0, 256 * sizeof(uint16));
  90. _cgaScaleTable = new uint8[256];
  91. memset(_cgaScaleTable, 0, 256 * sizeof(uint8));
  92. for (int i = 0; i < 256; i++)
  93. _cgaScaleTable[i] = ((i & 0xF0) >> 2) | (i & 0x03);
  94. }
  95. return true;
  96. }
  97. return false;
  98. }
  99. void Screen_EoB::setClearScreenDim(int dim) {
  100. setScreenDim(dim);
  101. clearCurDim();
  102. }
  103. void Screen_EoB::clearCurDim() {
  104. fillRect(_curDim->sx << 3, _curDim->sy, ((_curDim->sx + _curDim->w) << 3) - 1, (_curDim->sy + _curDim->h) - 1, _curDim->unkA);
  105. }
  106. void Screen_EoB::setMouseCursor(int x, int y, const byte *shape) {
  107. setMouseCursor(x, y, shape, 0);
  108. }
  109. void Screen_EoB::setMouseCursor(int x, int y, const byte *shape, const uint8 *ovl) {
  110. if (!shape)
  111. return;
  112. int mouseW = (shape[2] << 3);
  113. int mouseH = (shape[3]);
  114. int colorKey = (_renderMode == Common::kRenderCGA) ? 0 : _cursorColorKey;
  115. int scaleFactor = _useHiResEGADithering ? 2 : 1;
  116. uint8 *cursor = new uint8[mouseW * scaleFactor * mouseH * scaleFactor];
  117. // We use memset and copyBlockToPage instead of fillRect to make sure that the
  118. // color key 0xFF doesn't get converted into EGA color
  119. memset(cursor, colorKey, mouseW * scaleFactor * mouseH * scaleFactor);
  120. copyBlockToPage(6, 0, 0, mouseW * scaleFactor, mouseH * scaleFactor, cursor);
  121. drawShape(6, shape, 0, 0, 0, 2, ovl);
  122. CursorMan.showMouse(false);
  123. if (_useHiResEGADithering)
  124. ditherRect(getCPagePtr(6), cursor, mouseW * scaleFactor, mouseW, mouseH, colorKey);
  125. else
  126. copyRegionToBuffer(6, 0, 0, mouseW, mouseH, cursor);
  127. // Mouse cursor post processing for CGA mode. Unlike the original (which uses drawShape for the mouse cursor)
  128. // the cursor manager cannot know whether a pixel value of 0 is supposed to be black or transparent. Thus, we
  129. // go over the transparency mask again and turn the black pixels to color 4.
  130. if (_renderMode == Common::kRenderCGA) {
  131. const uint8 *maskTbl = shape + 4 + ((mouseW * mouseH) >> 2);
  132. uint8 *dst = cursor;
  133. uint8 trans = 0;
  134. uint8 shift = 6;
  135. uint16 mH = mouseH;
  136. while (mH--) {
  137. uint16 mW = mouseW;
  138. while (mW--) {
  139. if (shift == 6)
  140. trans = *maskTbl++;
  141. if (!*dst && !((trans >> shift) & 3))
  142. *dst = 4;
  143. dst++;
  144. shift = (shift - 2) & 7;
  145. }
  146. }
  147. }
  148. CursorMan.replaceCursor(cursor, mouseW * scaleFactor, mouseH * scaleFactor, x, y, colorKey);
  149. if (isMouseVisible())
  150. CursorMan.showMouse(true);
  151. delete[] cursor;
  152. // makes sure that the cursor is drawn
  153. // we do not use Screen::updateScreen here
  154. // so we can be sure that changes to page 0
  155. // are NOT updated on the real screen here
  156. _system->updateScreen();
  157. }
  158. void Screen_EoB::loadFileDataToPage(Common::SeekableReadStream *s, int pageNum, uint32 size) {
  159. s->read(_pagePtrs[pageNum], size);
  160. }
  161. void Screen_EoB::printShadedText(const char *string, int x, int y, int col1, int col2) {
  162. printText(string, x - 1, y, 12, col2);
  163. printText(string, x, y + 1, 12, 0);
  164. printText(string, x - 1, y + 1, 12, 0);
  165. printText(string, x, y, col1, 0);
  166. }
  167. void Screen_EoB::loadShapeSetBitmap(const char *file, int tempPage, int destPage) {
  168. loadEoBBitmap(file, _cgaMappingDefault, tempPage, destPage, -1);
  169. _curPage = 2;
  170. }
  171. void Screen_EoB::loadEoBBitmap(const char *file, const uint8 *cgaMapping, int tempPage, int destPage, int convertToPage) {
  172. const char *filePattern = (_vm->game() == GI_EOB1 && (_renderMode == Common::kRenderEGA || _renderMode == Common::kRenderCGA)) ? "%s.EGA" : "%s.CPS";
  173. Common::String tmp = Common::String::format(filePattern, file);
  174. Common::SeekableReadStream *s = _vm->resource()->createReadStream(tmp);
  175. bool loadAlternative = false;
  176. if (s) {
  177. // This additional check is necessary since some localized versions of EOB II seem to contain invalid (size zero) cps files
  178. if (s->size())
  179. loadBitmap(tmp.c_str(), tempPage, destPage, 0);
  180. else
  181. loadAlternative = true;
  182. delete s;
  183. } else {
  184. loadAlternative = true;
  185. }
  186. if (loadAlternative) {
  187. if (_vm->game() == GI_EOB1) {
  188. tmp.insertChar('1', tmp.size() - 4);
  189. loadBitmap(tmp.c_str(), tempPage, destPage, 0);
  190. } else {
  191. tmp.setChar('X', 0);
  192. s = _vm->resource()->createReadStream(tmp);
  193. if (!s)
  194. error("Screen_EoB::loadEoBBitmap(): Failed to load file '%s'", file);
  195. s->seek(768);
  196. loadFileDataToPage(s, destPage, 64000);
  197. delete s;
  198. }
  199. }
  200. if (convertToPage == -1) {
  201. return;
  202. } else if (convertToPage == 2 && _renderMode == Common::kRenderCGA) {
  203. convertPage(destPage, 4, cgaMapping);
  204. copyRegion(0, 0, 0, 0, 320, 200, 4, 2, Screen::CR_NO_P_CHECK);
  205. } else if (convertToPage == 0) {
  206. convertPage(destPage, 2, cgaMapping);
  207. copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
  208. } else {
  209. convertPage(destPage, convertToPage, cgaMapping);
  210. }
  211. }
  212. void Screen_EoB::convertPage(int srcPage, int dstPage, const uint8 *cgaMapping) {
  213. uint8 *src = getPagePtr(srcPage);
  214. uint8 *dst = getPagePtr(dstPage);
  215. if (src == dst)
  216. return;
  217. if (_renderMode == Common::kRenderCGA) {
  218. if (cgaMapping)
  219. generateCGADitheringTables(cgaMapping);
  220. uint16 *d = (uint16 *)dst;
  221. uint8 tblSwitch = 0;
  222. for (int height = SCREEN_H; height; height--) {
  223. const uint16 *table = _cgaDitheringTables[(tblSwitch++) & 1];
  224. for (int width = SCREEN_W / 2; width; width--) {
  225. WRITE_LE_UINT16(d++, table[((src[1] & 0x0F) << 4) | (src[0] & 0x0F)]);
  226. src += 2;
  227. }
  228. }
  229. } else if (_renderMode == Common::kRenderEGA && !_useHiResEGADithering) {
  230. uint32 len = SCREEN_W * SCREEN_H;
  231. while (len--)
  232. *dst++ = *src++ & 0x0F;
  233. } else {
  234. copyPage(srcPage, dstPage);
  235. }
  236. if (dstPage == 0 || dstPage == 1)
  237. _forceFullUpdate = true;
  238. }
  239. void Screen_EoB::setScreenPalette(const Palette &pal) {
  240. if (_useHiResEGADithering && pal.getNumColors() != 16) {
  241. generateEGADitheringTable(pal);
  242. } else if (_renderMode == Common::kRenderEGA && pal.getNumColors() == 16) {
  243. _screenPalette->copy(pal);
  244. _system->getPaletteManager()->setPalette(_screenPalette->getData(), 0, _screenPalette->getNumColors());
  245. } else if (_renderMode != Common::kRenderCGA && _renderMode != Common::kRenderEGA) {
  246. Screen::setScreenPalette(pal);
  247. }
  248. }
  249. void Screen_EoB::getRealPalette(int num, uint8 *dst) {
  250. if (_renderMode == Common::kRenderCGA || _renderMode == Common::kRenderEGA) {
  251. const uint8 *pal = _screenPalette->getData();
  252. for (int i = 0; i < 16; ++i) {
  253. dst[0] = (pal[0] << 2) | (pal[0] & 3);
  254. dst[1] = (pal[1] << 2) | (pal[1] & 3);
  255. dst[2] = (pal[2] << 2) | (pal[2] & 3);
  256. dst += 3;
  257. pal += 3;
  258. }
  259. } else {
  260. Screen::getRealPalette(num, dst);
  261. }
  262. }
  263. uint8 *Screen_EoB::encodeShape(uint16 x, uint16 y, uint16 w, uint16 h, bool encode8bit, const uint8 *cgaMapping) {
  264. uint8 *shp = 0;
  265. uint16 shapesize = 0;
  266. uint8 *srcLineStart = getPagePtr(_curPage | 1) + y * 320 + (x << 3);
  267. uint8 *src = srcLineStart;
  268. if (_renderMode == Common::kRenderEGA && !_useHiResEGADithering)
  269. encode8bit = false;
  270. if (_renderMode == Common::kRenderCGA) {
  271. if (cgaMapping)
  272. generateCGADitheringTables(cgaMapping);
  273. shapesize = h * (w << 2) + 4;
  274. shp = new uint8[shapesize];
  275. memset(shp, 0, shapesize);
  276. uint8 *dst = shp;
  277. *dst++ = 4;
  278. *dst++ = (h & 0xFF);
  279. *dst++ = (w & 0xFF);
  280. *dst++ = (h & 0xFF);
  281. uint8 *dst2 = dst + (h * (w << 1));
  282. uint8 tblSwitch = 0;
  283. uint16 h1 = h;
  284. while (h1--) {
  285. uint16 w1 = w << 1;
  286. const uint16 *table = _cgaDitheringTables[(tblSwitch++) & 1];
  287. while (w1--) {
  288. uint16 p0 = table[((src[1] & 0x0F) << 4) | (src[0] & 0x0F)];
  289. uint16 p1 = table[((src[3] & 0x0F) << 4) | (src[2] & 0x0F)];
  290. *dst++ = ((p0 & 0x0003) << 6) | ((p0 & 0x0300) >> 4) | ((p1 & 0x0003) << 2) | ((p1 & 0x0300) >> 8);
  291. uint8 msk = 0;
  292. for (int i = 0; i < 4; i++) {
  293. if (!src[3 - i])
  294. msk |= (3 << (i << 1));
  295. }
  296. *dst2++ = msk;
  297. src += 4;
  298. }
  299. srcLineStart += SCREEN_W;
  300. src = srcLineStart;
  301. }
  302. } else if (encode8bit) {
  303. uint16 h1 = h;
  304. while (h1--) {
  305. uint8 *lineEnd = src + (w << 3);
  306. do {
  307. if (!*src++) {
  308. shapesize++;
  309. uint8 *startZeroPos = src;
  310. while (src != lineEnd && *src == 0)
  311. src++;
  312. uint16 numZero = src - startZeroPos + 1;
  313. if (numZero >> 8)
  314. shapesize += 2;
  315. }
  316. shapesize++;
  317. } while (src != lineEnd);
  318. srcLineStart += SCREEN_W;
  319. src = srcLineStart;
  320. }
  321. shapesize += 4;
  322. shp = new uint8[shapesize];
  323. memset(shp, 0, shapesize);
  324. uint8 *dst = shp;
  325. *dst++ = 8;
  326. *dst++ = (h & 0xFF);
  327. *dst++ = (w & 0xFF);
  328. *dst++ = (h & 0xFF);
  329. srcLineStart = getPagePtr(_curPage | 1) + y * 320 + (x << 3);
  330. src = srcLineStart;
  331. h1 = h;
  332. while (h1--) {
  333. uint8 *lineEnd = src + (w << 3);
  334. do {
  335. uint8 val = *src++;
  336. if (!val) {
  337. *dst++ = 0;
  338. uint8 *startZeroPos = src;
  339. while (src != lineEnd && *src == 0)
  340. src++;
  341. uint16 numZero = src - startZeroPos + 1;
  342. if (numZero >> 8) {
  343. *dst++ = 255;
  344. *dst++ = 0;
  345. numZero -= 255;
  346. }
  347. val = numZero & 0xFF;
  348. }
  349. *dst++ = val;
  350. } while (src != lineEnd);
  351. srcLineStart += SCREEN_W;
  352. src = srcLineStart;
  353. }
  354. } else {
  355. uint8 nib = 0, col = 0;
  356. uint8 *colorMap = 0;
  357. if (_renderMode != Common::kRenderEGA || _useHiResEGADithering) {
  358. colorMap = new uint8[0x100];
  359. memset(colorMap, 0xFF, 0x100);
  360. }
  361. shapesize = h * (w << 2) + 20;
  362. shp = new uint8[shapesize];
  363. memset(shp, 0, shapesize);
  364. uint8 *dst = shp;
  365. *dst++ = 2;
  366. *dst++ = (h & 0xFF);
  367. *dst++ = (w & 0xFF);
  368. *dst++ = (h & 0xFF);
  369. if (_renderMode != Common::kRenderEGA || _useHiResEGADithering) {
  370. memset(dst, 0xFF, 0x10);
  371. } else {
  372. for (int i = 0; i < 16; i++)
  373. dst[i] = i;
  374. }
  375. uint8 *pal = dst;
  376. dst += 16;
  377. nib = col = 0;
  378. uint16 h1 = h;
  379. while (h1--) {
  380. uint16 w1 = w << 3;
  381. while (w1--) {
  382. uint8 s = *src++;
  383. uint8 c = s & 0x0F;
  384. if (colorMap) {
  385. c = colorMap[s];
  386. if (c == 0xFF) {
  387. if (col < 0x10) {
  388. *pal++ = s;
  389. c = colorMap[s] = col++;
  390. } else {
  391. c = 0;
  392. }
  393. }
  394. }
  395. if (++nib & 1)
  396. *dst = c << 4;
  397. else
  398. *dst++ |= c;
  399. }
  400. srcLineStart += SCREEN_W;
  401. src = srcLineStart;
  402. }
  403. delete[] colorMap;
  404. }
  405. return shp;
  406. }
  407. void Screen_EoB::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int sd, int flags, ...) {
  408. uint8 *dst = getPagePtr(pageNum);
  409. const uint8 *src = shapeData;
  410. if (!src)
  411. return;
  412. va_list args;
  413. va_start(args, flags);
  414. uint8 *ovl = (flags & 2) ? va_arg(args, uint8 *) : 0;
  415. va_end(args);
  416. if (sd != -1) {
  417. const ScreenDim *dm = getScreenDim(sd);
  418. setShapeFrame(dm->sx, dm->sy, dm->sx + dm->w, dm->sy + dm->h);
  419. x += (_dsX1 << 3);
  420. y += _dsY1;
  421. }
  422. dst += (_dsX1 << 3);
  423. int16 dX = x - (_dsX1 << 3);
  424. int16 dY = y;
  425. int16 dW = _dsX2 - _dsX1;
  426. uint8 pixelsPerByte = *src++ ;
  427. uint16 dH = *src++;
  428. uint16 width = (*src++) << 3;
  429. uint16 transOffset = (pixelsPerByte == 4) ? (dH * width) >> 2 : 0;
  430. src++;
  431. int rX = x;
  432. int rY = y;
  433. int rW = width + 8;
  434. int rH = dH;
  435. uint16 w2 = width;
  436. int d = dY - _dsY1;
  437. int pixelStep = (flags & 1) ? -1 : 1;
  438. if (pixelsPerByte == 8) {
  439. uint16 marginLeft = 0;
  440. uint16 marginRight = 0;
  441. if (d < 0) {
  442. dH += d;
  443. if (dH <= 0)
  444. return;
  445. d = -d;
  446. for (int i = 0; i < d; i++) {
  447. marginLeft = width;
  448. for (int ii = 0; ii < marginLeft; ii++) {
  449. if (!*src++)
  450. marginLeft = marginLeft + 1 - *src++;
  451. }
  452. }
  453. dY = _dsY1;
  454. }
  455. d = _dsY2 - dY;
  456. if (d < 1)
  457. return;
  458. if (d < dH)
  459. dH = d;
  460. marginLeft = 0;
  461. if (dX < 0) {
  462. width += dX;
  463. marginLeft = -dX;
  464. if (marginLeft >= w2)
  465. return;
  466. dX = 0;
  467. }
  468. marginRight = 0;
  469. d = (dW << 3) - dX;
  470. if (d < 1)
  471. return;
  472. if (d < width) {
  473. width = d;
  474. marginRight = w2 - marginLeft - width;
  475. }
  476. dst += (dY * SCREEN_W + dX);
  477. uint8 *dstL = dst;
  478. if (pageNum == 0 || pageNum == 1)
  479. addDirtyRect(rX, rY, rW, rH);
  480. while (dH--) {
  481. int16 xpos = (int16) marginLeft;
  482. if (flags & 1) {
  483. for (int i = 0; i < w2; i++) {
  484. if (*src++ == 0) {
  485. i += (*src - 1);
  486. src += (*src - 1);
  487. }
  488. }
  489. src--;
  490. }
  491. const uint8 *src2 = src;
  492. if (xpos) {
  493. do {
  494. uint8 val = (flags & 1) ? *(src - 1) : *src;
  495. while (val && xpos) {
  496. src += pixelStep;
  497. xpos--;
  498. val = (flags & 1) ? *(src - 1) : *src;
  499. }
  500. val = (flags & 1) ? *(src - 1) : *src;
  501. if (!val) {
  502. src += pixelStep;
  503. uint8 bt = (flags & 1) ? src[1] : src[0];
  504. src += pixelStep;
  505. xpos = xpos - bt;
  506. }
  507. } while (xpos > 0);
  508. }
  509. dst -= xpos;
  510. xpos += width;
  511. while (xpos > 0) {
  512. uint8 c = *src;
  513. uint8 m = (flags & 1) ? *(src - 1) : c;
  514. src += pixelStep;
  515. if (m) {
  516. drawShapeSetPixel(dst, c);
  517. dst++;
  518. xpos--;
  519. } else {
  520. uint8 len = (flags & 1) ? src[1] : src[0];
  521. dst += len;
  522. xpos -= len;
  523. src += pixelStep;
  524. }
  525. }
  526. xpos += marginRight;
  527. if (xpos) {
  528. do {
  529. uint8 val = (flags & 1) ? *(src - 1) : *src;
  530. while (val && xpos) {
  531. src += pixelStep;
  532. xpos--;
  533. val = (flags & 1) ? *(src - 1) : *src;
  534. }
  535. val = (flags & 1) ? *(src - 1) : *src;
  536. if (!val) {
  537. src += pixelStep;
  538. uint8 bt = (flags & 1) ? src[1] : src[0];
  539. src += pixelStep;
  540. xpos = xpos - bt;
  541. }
  542. } while (xpos > 0);
  543. }
  544. dstL += SCREEN_W;
  545. dst = dstL;
  546. if (flags & 1)
  547. src = src2 + 1;
  548. }
  549. } else {
  550. const uint8 *pal = 0;
  551. uint8 cgaPal[4];
  552. memset(cgaPal, 0, 4);
  553. if (pixelsPerByte == 2) {
  554. pal = ovl ? ovl : src;
  555. src += 16;
  556. } else {
  557. static const uint8 cgaDefOvl[] = { 0x00, 0x55, 0xAA, 0xFF };
  558. pal = ovl ? ovl : cgaDefOvl;
  559. for (int i = 0; i < 4; i++)
  560. cgaPal[i] = pal[i] & 3;
  561. pal = cgaPal;
  562. }
  563. if (d < 0) {
  564. d = -d;
  565. if (d >= dH)
  566. return;
  567. src += (d * (width / pixelsPerByte));
  568. d = dY + dH - _dsY1;
  569. if (d >= 0) {
  570. dH = d;
  571. dY = _dsY1;
  572. d = _dsY2 - dY;
  573. }
  574. } else {
  575. d = _dsY2 - dY;
  576. }
  577. if (d < 1)
  578. return;
  579. if (d < dH)
  580. dH = d;
  581. bool trimL = false;
  582. uint8 dXbitAlign = dX & (pixelsPerByte - 1);
  583. if (dX < 0) {
  584. width += dX;
  585. d = -dX;
  586. if (flags & 1)
  587. src -= (d / pixelsPerByte);
  588. else
  589. src += (d / pixelsPerByte);
  590. if (d >= w2)
  591. return;
  592. dX = 0;
  593. trimL = true;
  594. }
  595. d = (dW << 3) - dX;
  596. if (d < 1)
  597. return;
  598. if (d < width)
  599. width = d;
  600. dst += (dY * SCREEN_W + dX);
  601. if (pageNum == 0 || pageNum == 1)
  602. addDirtyRect(rX, rY, rW, rH);
  603. int pitch = SCREEN_W - width;
  604. int16 lineSrcStep = (w2 - width) / pixelsPerByte;
  605. uint8 lineSrcStepRemainder = (w2 - width) % pixelsPerByte;
  606. w2 /= pixelsPerByte;
  607. if (flags & 1)
  608. src += (w2 - 1);
  609. uint8 pixelPacking = 8 / pixelsPerByte;
  610. uint8 pixelPackingMask = 0;
  611. for (int i = 0; i < pixelPacking; i++)
  612. pixelPackingMask |= (1 << i);
  613. if (trimL && (dXbitAlign > lineSrcStepRemainder))
  614. lineSrcStep--;
  615. uint8 bitShDef = 8 - pixelPacking;
  616. if (flags & 1) {
  617. lineSrcStep = (w2 << 1) - lineSrcStep;
  618. bitShDef = 0;
  619. }
  620. uint8 bitShLineStart = bitShDef;
  621. if (trimL)
  622. bitShLineStart -= (dXbitAlign * pixelStep * pixelPacking);
  623. while (dH--) {
  624. int16 wd = width;
  625. uint8 in = 0;
  626. uint8 trans = 0;
  627. uint8 shift = bitShLineStart;
  628. uint8 shSwtch = bitShLineStart;
  629. while (wd--) {
  630. if (shift == shSwtch) {
  631. in = *src;
  632. trans = src[transOffset];
  633. src += pixelStep;
  634. shSwtch = bitShDef;
  635. }
  636. uint8 col = (pixelsPerByte == 2) ? pal[(in >> shift) & pixelPackingMask] : (*dst & ((trans >> shift) & (pixelPackingMask))) | pal[(in >> shift) & pixelPackingMask];
  637. if (col || pixelsPerByte == 4)
  638. drawShapeSetPixel(dst, col);
  639. dst++;
  640. shift = ((shift - (pixelStep * pixelPacking)) & 7);
  641. }
  642. src += lineSrcStep;
  643. dst += pitch;
  644. }
  645. }
  646. }
  647. const uint8 *Screen_EoB::scaleShape(const uint8 *shapeData, int steps) {
  648. setShapeFadeMode(1, steps ? true : false);
  649. while (shapeData && steps--)
  650. shapeData = scaleShapeStep(shapeData);
  651. return shapeData;
  652. }
  653. const uint8 *Screen_EoB::scaleShapeStep(const uint8 *shp) {
  654. uint8 *dst = (shp != _dsTempPage) ? _dsTempPage : _dsTempPage + 6000;
  655. uint8 *d = dst;
  656. uint8 pixelsPerByte = *d++ = *shp++;
  657. assert(pixelsPerByte > 1);
  658. uint16 h = shp[0] + 1;
  659. d[0] = d[2] = (h << 1) / 3;
  660. uint16 w = shp[1];
  661. uint16 w2 = (w << 3) / pixelsPerByte;
  662. uint16 t = ((w << 1) % 3) ? 1 : 0;
  663. d[1] = ((w << 1) / 3) + t;
  664. uint32 transOffsetSrc = (pixelsPerByte == 4) ? (shp[0] * shp[1]) << 1 : 0;
  665. uint32 transOffsetDst = (pixelsPerByte == 4) ? (d[0] * d[1]) << 1 : 0;
  666. shp += 3;
  667. d += 3;
  668. if (pixelsPerByte == 2) {
  669. int i = 0;
  670. while (i < 16) {
  671. if (!shp[i]) {
  672. i = -i;
  673. break;
  674. }
  675. i++;
  676. }
  677. if (i >= 0)
  678. i = 0;
  679. else
  680. i = -i;
  681. _dsScaleTrans = (i << 4) | (i & 0x0F);
  682. for (int ii = 0; ii < 16; ii++)
  683. *d++ = *shp++;
  684. }
  685. _dsDiv = w2 / 3;
  686. _dsRem = w2 % 3;
  687. while (--h) {
  688. if (pixelsPerByte == 2)
  689. scaleShapeProcessLine4Bit(d, shp);
  690. else
  691. scaleShapeProcessLine2Bit(d, shp, transOffsetDst, transOffsetSrc);
  692. if (!--h)
  693. break;
  694. if (pixelsPerByte == 2)
  695. scaleShapeProcessLine4Bit(d, shp);
  696. else
  697. scaleShapeProcessLine2Bit(d, shp, transOffsetDst, transOffsetSrc);
  698. if (!--h)
  699. break;
  700. shp += w2;
  701. }
  702. return (const uint8 *)dst;
  703. }
  704. const uint8 *Screen_EoB::generateShapeOverlay(const uint8 *shp, int paletteOverlayIndex) {
  705. if (*shp != 2)
  706. return 0;
  707. shp += 4;
  708. uint8 *ovl = getFadeTable(paletteOverlayIndex);
  709. for (int i = 0; i < 16; i++)
  710. _shapeOverlay[i] = ovl[shp[i]];
  711. return _shapeOverlay;
  712. }
  713. void Screen_EoB::setShapeFrame(int x1, int y1, int x2, int y2) {
  714. _dsX1 = x1;
  715. _dsY1 = y1;
  716. _dsX2 = x2;
  717. _dsY2 = y2;
  718. }
  719. void Screen_EoB::setShapeFadeMode(uint8 i, bool b) {
  720. if (!i || i == 1)
  721. _shapeFadeMode[i] = b;
  722. }
  723. void Screen_EoB::setGfxParameters(int x, int y, int col) {
  724. _gfxX = x;
  725. _gfxY = y;
  726. _gfxCol = col;
  727. }
  728. void Screen_EoB::drawExplosion(int scale, int radius, int numElements, int stepSize, int aspectRatio, const uint8 *colorTable, int colorTableSize) {
  729. int ymin = 0;
  730. int ymax = _gfxMaxY[scale];
  731. int xmin = -100;
  732. int xmax = 276;
  733. if (scale)
  734. --scale;
  735. hideMouse();
  736. const ScreenDim *dm = getScreenDim(5);
  737. int rX1 = dm->sx << 3;
  738. int rY1 = dm->sy;
  739. int rX2 = rX1 + (dm->w << 3);
  740. int rY2 = rY1 + dm->h - 1;
  741. int16 gx2 = _gfxX;
  742. int16 gy2 = _gfxY;
  743. int16 *ptr2 = (int16 *)_dsTempPage;
  744. int16 *ptr3 = (int16 *)&_dsTempPage[300];
  745. int16 *ptr4 = (int16 *)&_dsTempPage[600];
  746. int16 *ptr5 = (int16 *)&_dsTempPage[900];
  747. int16 *ptr6 = (int16 *)&_dsTempPage[1200];
  748. int16 *ptr7 = (int16 *)&_dsTempPage[1500];
  749. int16 *ptr8 = (int16 *)&_dsTempPage[1800];
  750. if (numElements > 150)
  751. numElements = 150;
  752. for (int i = 0; i < numElements; i++) {
  753. ptr2[i] = ptr3[i] = 0;
  754. ptr4[i] = _vm->_rnd.getRandomNumberRng(0, radius) - (radius >> 1);
  755. ptr5[i] = _vm->_rnd.getRandomNumberRng(0, radius) - (radius >> 1) - (radius >> (8 - aspectRatio));
  756. ptr7[i] = _vm->_rnd.getRandomNumberRng(1024 / stepSize, 2048 / stepSize);
  757. ptr8[i] = scale << 8;
  758. }
  759. for (int l = 2; l;) {
  760. if (l != 2) {
  761. for (int i = numElements - 1; i >= 0; i--) {
  762. int16 px = ((ptr2[i] >> 6) >> scale) + gx2;
  763. int16 py = ((ptr3[i] >> 6) >> scale) + gy2;
  764. if (py > ymax)
  765. py = ymax;
  766. if (posWithinRect(px, py, rX1, rY1, rX2, rY2))
  767. setPagePixel(0, px, py, ptr6[i]);
  768. }
  769. }
  770. l = 0;
  771. for (int i = 0; i < numElements; i++) {
  772. uint32 end = _system->getMillis() + 1;
  773. if (ptr4[i] <= 0)
  774. ptr4[i]++;
  775. else
  776. ptr4[i]--;
  777. ptr2[i] += ptr4[i];
  778. ptr5[i] += 5;
  779. ptr3[i] += ptr5[i];
  780. ptr8[i] += ptr7[i];
  781. int16 px = ((ptr2[i] >> 6) >> scale) + gx2;
  782. int16 py = ((ptr3[i] >> 6) >> scale) + gy2;
  783. if (py >= ymax || py < ymin)
  784. ptr5[i] = -(ptr5[i] >> 1);
  785. if (px >= xmax || px < xmin)
  786. ptr4[i] = -(ptr4[i] >> 1);
  787. if (py > ymax)
  788. py = ymax;
  789. int pxVal1 = 0;
  790. if (posWithinRect(px, py, 0, 0, 319, 199)) {
  791. pxVal1 = getPagePixel(2, px, py);
  792. ptr6[i] = getPagePixel(0, px, py);
  793. }
  794. assert((ptr8[i] >> 8) < colorTableSize);
  795. int pxVal2 = colorTable[ptr8[i] >> 8];
  796. if (pxVal2) {
  797. l = 1;
  798. if (pxVal1 == _gfxCol && posWithinRect(px, py, rX1, rY1, rX2, rY2)) {
  799. setPagePixel(0, px, py, pxVal2);
  800. if (i % 5 == 0) {
  801. updateScreen();
  802. uint32 cur = _system->getMillis();
  803. if (end > cur)
  804. _system->delayMillis(end - cur);
  805. }
  806. }
  807. } else {
  808. ptr7[i] = 0;
  809. }
  810. }
  811. }
  812. showMouse();
  813. }
  814. void Screen_EoB::drawVortex(int numElements, int radius, int stepSize, int, int disorder, const uint8 *colorTable, int colorTableSize) {
  815. int16 *xCoords = (int16 *)_dsTempPage;
  816. int16 *yCoords = (int16 *)&_dsTempPage[300];
  817. int16 *xMod = (int16 *)&_dsTempPage[600];
  818. int16 *yMod = (int16 *)&_dsTempPage[900];
  819. int16 *pixBackup = (int16 *)&_dsTempPage[1200];
  820. int16 *colTableStep = (int16 *)&_dsTempPage[1500];
  821. int16 *colTableIndex = (int16 *)&_dsTempPage[1800];
  822. int16 *pixDelay = (int16 *)&_dsTempPage[2100];
  823. hideMouse();
  824. int cp = _curPage;
  825. if (numElements > 150)
  826. numElements = 150;
  827. int cx = 88;
  828. int cy = 48;
  829. radius <<= 6;
  830. for (int i = 0; i < numElements; i++) {
  831. int16 v38 = _vm->_rnd.getRandomNumberRng(radius >> 2, radius);
  832. int16 stepSum = 0;
  833. int16 sqsum = 0;
  834. while (sqsum < v38) {
  835. stepSum += stepSize;
  836. sqsum += stepSum;
  837. }
  838. switch (_vm->_rnd.getRandomNumber(255) & 3) {
  839. case 0:
  840. xCoords[i] = 32;
  841. yCoords[i] = sqsum;
  842. xMod[i] = stepSum;
  843. yMod[i] = 0;
  844. break;
  845. case 1:
  846. xCoords[i] = sqsum;
  847. yCoords[i] = 32;
  848. xMod[i] = 0;
  849. yMod[i] = stepSum;
  850. break;
  851. case 2:
  852. xCoords[i] = 32;
  853. yCoords[i] = -sqsum;
  854. xMod[i] = stepSum;
  855. yMod[i] = 0;
  856. break;
  857. default:
  858. xCoords[i] = -sqsum;
  859. yCoords[i] = 32;
  860. xMod[i] = 0;
  861. yMod[i] = stepSum;
  862. break;
  863. }
  864. if (_vm->_rnd.getRandomBit()) {
  865. xMod[i] *= -1;
  866. yMod[i] *= -1;
  867. }
  868. colTableStep[i] = _vm->_rnd.getRandomNumberRng(1024 / disorder, 2048 / disorder);
  869. colTableIndex[i] = 0;
  870. pixDelay[i] = _vm->_rnd.getRandomNumberRng(0, disorder >> 2);
  871. }
  872. int d = 0;
  873. for (int i = 2; i;) {
  874. if (i != 2) {
  875. for (int ii = numElements - 1; ii >= 0; ii--) {
  876. int16 px = CLIP((xCoords[ii] >> 6) + cx, 0, SCREEN_W - 1);
  877. int16 py = CLIP((yCoords[ii] >> 6) + cy, 0, SCREEN_H - 1);
  878. setPagePixel(0, px, py, pixBackup[ii]);
  879. }
  880. }
  881. i = 0;
  882. int r = (stepSize >> 1) + (stepSize >> 2) + (stepSize >> 3);
  883. uint32 nextDelay = _system->getMillis() + 1;
  884. for (int ii = 0; ii < numElements; ii++) {
  885. if (pixDelay[ii] == 0) {
  886. if (xCoords[ii] > 0) {
  887. xMod[ii] -= ((xMod[ii] > 0) ? stepSize : r);
  888. } else {
  889. xMod[ii] += ((xMod[ii] < 0) ? stepSize : r);
  890. }
  891. if (yCoords[ii] > 0) {
  892. yMod[ii] -= ((yMod[ii] > 0) ? stepSize : r);
  893. } else {
  894. yMod[ii] += ((yMod[ii] < 0) ? stepSize : r);
  895. }
  896. xCoords[ii] += xMod[ii];
  897. yCoords[ii] += yMod[ii];
  898. colTableIndex[ii] += colTableStep[ii];
  899. } else {
  900. pixDelay[ii]--;
  901. }
  902. int16 px = CLIP((xCoords[ii] >> 6) + cx, 0, SCREEN_W - 1);
  903. int16 py = CLIP((yCoords[ii] >> 6) + cy, 0, SCREEN_H - 1);
  904. uint8 tc1 = ((disorder >> 2) <= d) ? getPagePixel(2, px, py) : 0;
  905. pixBackup[ii] = getPagePixel(0, px, py);
  906. uint8 tblIndex = CLIP(colTableIndex[ii] >> 8, 0, colorTableSize - 1);
  907. uint8 tc2 = colorTable[tblIndex];
  908. if (tc2) {
  909. i = 1;
  910. if (tc1 == _gfxCol && !pixDelay[ii]) {
  911. setPagePixel(0, px, py, tc2);
  912. if (ii % 15 == 0) {
  913. updateScreen();
  914. uint32 cur = _system->getMillis();
  915. if (nextDelay > cur)
  916. _system->delayMillis(nextDelay - cur);
  917. nextDelay += 1;
  918. }
  919. }
  920. } else {
  921. colTableStep[ii] = 0;
  922. }
  923. }
  924. d++;
  925. }
  926. _curPage = cp;
  927. showMouse();
  928. }
  929. void Screen_EoB::fadeTextColor(Palette *pal, int color1, int rate) {
  930. uint8 *col = pal->getData();
  931. for (bool loop = true; loop;) {
  932. loop = true;
  933. uint32 end = _system->getMillis() + _vm->tickLength();
  934. loop = false;
  935. for (int ii = 0; ii < 3; ii++) {
  936. uint8 c = col[color1 * 3 + ii];
  937. if (c > rate) {
  938. col[color1 * 3 + ii] -= rate;
  939. loop = true;
  940. } else if (c) {
  941. col[color1 * 3 + ii] = 0;
  942. loop = true;
  943. }
  944. }
  945. if (loop) {
  946. setScreenPalette(*pal);
  947. updateScreen();
  948. uint32 cur = _system->getMillis();
  949. if (end > cur)
  950. _system->delayMillis(end - cur);
  951. }
  952. }
  953. }
  954. bool Screen_EoB::delayedFadePalStep(Palette *fadePal, Palette *destPal, int rate) {
  955. bool res = false;
  956. uint8 *s = fadePal->getData();
  957. uint8 *d = destPal->getData();
  958. for (int i = 0; i < 765; i++) {
  959. int fadeVal = *s++;
  960. int dstCur = *d;
  961. int diff = ABS(fadeVal - dstCur);
  962. if (diff == 0) {
  963. d++;
  964. continue;
  965. }
  966. res = true;
  967. diff = MIN(diff, rate);
  968. if (dstCur < fadeVal)
  969. *d += diff;
  970. else
  971. *d -= diff;
  972. d++;
  973. }
  974. return res;
  975. }
  976. int Screen_EoB::getRectSize(int w, int h) {
  977. return w * h;
  978. }
  979. void Screen_EoB::setFadeTableIndex(int index) {
  980. _fadeDataIndex = (CLIP(index, 0, 7) << 8);
  981. }
  982. void Screen_EoB::createFadeTable(uint8 *palData, uint8 *dst, uint8 rootColor, uint8 weight) {
  983. if (!palData)
  984. return;
  985. uint8 *src = palData + 3 * rootColor;
  986. uint8 r = *src++;
  987. uint8 g = *src++;
  988. uint8 b = *src;
  989. uint8 tr, tg, tb;
  990. src = palData + 3;
  991. *dst++ = 0;
  992. weight >>= 1;
  993. for (uint8 i = 1; i; i++) {
  994. uint16 tmp = (uint16)((*src - r) * weight) << 1;
  995. tr = *src++ - ((tmp >> 8) & 0xFF);
  996. tmp = (uint16)((*src - g) * weight) << 1;
  997. tg = *src++ - ((tmp >> 8) & 0xFF);
  998. tmp = (uint16)((*src - b) * weight) << 1;
  999. tb = *src++ - ((tmp >> 8) & 0xFF);
  1000. uint8 *d = palData + 3;
  1001. uint16 v = 0xFFFF;
  1002. uint8 col = rootColor;
  1003. for (uint8 ii = 1; ii; ii++) {
  1004. int a = *d++ - tr;
  1005. int t = a * a;
  1006. a = *d++ - tg;
  1007. t += (a * a);
  1008. a = *d++ - tb;
  1009. t += (a * a);
  1010. if (t <= v && (ii == rootColor || ii != i)) {
  1011. v = t;
  1012. col = ii ;
  1013. }
  1014. }
  1015. *dst++ = col;
  1016. }
  1017. }
  1018. uint8 *Screen_EoB::getFadeTable(int index) {
  1019. return (index >= 0 && index < 5) ? &_fadeData[index << 8] : 0;
  1020. }
  1021. const uint16 *Screen_EoB::getCGADitheringTable(int index) {
  1022. return !(index & ~1) ? _cgaDitheringTables[index] : 0;
  1023. }
  1024. const uint8 *Screen_EoB::getEGADitheringTable() {
  1025. return _egaDitheringTable;
  1026. }
  1027. void Screen_EoB::updateDirtyRects() {
  1028. if (!_useHiResEGADithering) {
  1029. Screen::updateDirtyRects();
  1030. return;
  1031. }
  1032. if (_forceFullUpdate) {
  1033. ditherRect(getCPagePtr(0), _egaDitheringTempPage, SCREEN_W * 2, SCREEN_W, SCREEN_H);
  1034. _system->copyRectToScreen(_egaDitheringTempPage, SCREEN_W * 2, 0, 0, SCREEN_W * 2, SCREEN_H * 2);
  1035. } else {
  1036. const byte *page0 = getCPagePtr(0);
  1037. Common::List<Common::Rect>::iterator it;
  1038. for (it = _dirtyRects.begin(); it != _dirtyRects.end(); ++it) {
  1039. ditherRect(page0 + it->top * SCREEN_W + it->left, _egaDitheringTempPage, SCREEN_W * 2, it->width(), it->height());
  1040. _system->copyRectToScreen(_egaDitheringTempPage, SCREEN_W * 2, it->left * 2, it->top * 2, it->width() * 2, it->height() * 2);
  1041. }
  1042. }
  1043. _forceFullUpdate = false;
  1044. _dirtyRects.clear();
  1045. }
  1046. void Screen_EoB::ditherRect(const uint8 *src, uint8 *dst, int dstPitch, int srcW, int srcH, int colorKey) {
  1047. while (srcH--) {
  1048. uint8 *dst2 = dst + dstPitch;
  1049. for (int i = 0; i < srcW; i++) {
  1050. int in = *src++;
  1051. if (in != colorKey) {
  1052. in = _egaDitheringTable[in];
  1053. *dst++ = *dst2++ = in >> 4;
  1054. *dst++ = *dst2++ = in & 0x0F;
  1055. } else {
  1056. dst[0] = dst[1] = dst2[0] = dst2[1] = colorKey;
  1057. dst += 2;
  1058. dst2 += 2;
  1059. }
  1060. }
  1061. src += (SCREEN_W - srcW);
  1062. dst += ((dstPitch - srcW) * 2);
  1063. }
  1064. }
  1065. void Screen_EoB::drawShapeSetPixel(uint8 *dst, uint8 col) {
  1066. if ((_renderMode != Common::kRenderCGA && _renderMode != Common::kRenderEGA) || _useHiResEGADithering) {
  1067. if (_shapeFadeMode[0]) {
  1068. if (_shapeFadeMode[1]) {
  1069. col = *dst;
  1070. } else {
  1071. _shapeFadeInternal &= 7;
  1072. col = *(dst + _shapeFadeInternal++);
  1073. }
  1074. }
  1075. if (_shapeFadeMode[1]) {
  1076. uint8 cnt = _shapeFadeMode[1];
  1077. while (cnt--)
  1078. col = _fadeData[_fadeDataIndex + col];
  1079. }
  1080. }
  1081. *dst = col;
  1082. }
  1083. void Screen_EoB::scaleShapeProcessLine2Bit(uint8 *&shpDst, const uint8 *&shpSrc, uint32 transOffsetDst, uint32 transOffsetSrc) {
  1084. for (int i = 0; i < _dsDiv; i++) {
  1085. shpDst[0] = (_cgaScaleTable[shpSrc[0]] << 2) | (shpSrc[1] >> 6);
  1086. shpDst[1] = ((shpSrc[1] & 0x0F) << 4) | ((shpSrc[2] >> 2) & 0x0F);
  1087. shpDst[transOffsetDst] = (_cgaScaleTable[shpSrc[transOffsetSrc]] << 2) | (shpSrc[transOffsetSrc + 1] >> 6);
  1088. shpDst[transOffsetDst + 1] = ((shpSrc[transOffsetSrc + 1] & 0x0F) << 4) | ((shpSrc[transOffsetSrc + 2] >> 2) & 0x0F);
  1089. shpSrc += 3;
  1090. shpDst += 2;
  1091. }
  1092. if (_dsRem == 1) {
  1093. shpDst[0] = _cgaScaleTable[shpSrc[0]] << 2;
  1094. shpDst[1] = 0;
  1095. shpDst[transOffsetDst] = (_cgaScaleTable[shpSrc[transOffsetSrc]] << 2) | 3;
  1096. shpDst[transOffsetDst + 1] = 0xFF;
  1097. shpSrc++;
  1098. shpDst += 2;
  1099. } else if (_dsRem == 2) {
  1100. shpDst[0] = (_cgaScaleTable[shpSrc[0]] << 2) | (shpSrc[1] >> 6);
  1101. shpDst[1] = (shpSrc[1] & 0x3F) << 2;
  1102. shpDst[transOffsetDst] = (_cgaScaleTable[shpSrc[transOffsetSrc]] << 2) | (shpSrc[transOffsetSrc + 1] >> 6);
  1103. shpDst[transOffsetDst + 1] = ((shpSrc[transOffsetSrc + 1] & 0x3F) << 2) | 3;
  1104. shpSrc += 2;
  1105. shpDst += 2;
  1106. }
  1107. }
  1108. void Screen_EoB::scaleShapeProcessLine4Bit(uint8 *&dst, const uint8 *&src) {
  1109. for (int i = 0; i < _dsDiv; i++) {
  1110. *dst++ = *src++;
  1111. *dst++ = (READ_BE_UINT16(src) >> 4) & 0xFF;
  1112. src += 2;
  1113. }
  1114. if (_dsRem == 1) {
  1115. *dst++ = *src++;
  1116. *dst++ = _dsScaleTrans;
  1117. } else if (_dsRem == 2) {
  1118. *dst++ = (src[0] & 0xF0) | (src[1] >> 4);
  1119. src += 2;
  1120. *dst++ = _dsScaleTrans;
  1121. *dst++ = _dsScaleTrans;
  1122. *dst++ = _dsScaleTrans;
  1123. }
  1124. }
  1125. bool Screen_EoB::posWithinRect(int posX, int posY, int x1, int y1, int x2, int y2) {
  1126. if (posX < x1 || posX > x2 || posY < y1 || posY > y2)
  1127. return false;
  1128. return true;
  1129. }
  1130. void Screen_EoB::generateEGADitheringTable(const Palette &pal) {
  1131. assert(_egaDitheringTable);
  1132. const uint8 *src = pal.getData();
  1133. uint8 *dst = _egaDitheringTable;
  1134. for (int i = 256; i; i--) {
  1135. int r = *src++;
  1136. int g = *src++;
  1137. int b = *src++;
  1138. uint8 col = 0;
  1139. uint16 min = 0x2E83;
  1140. for (int ii = 256; ii; ii--) {
  1141. const uint8 *palEntry = _egaMatchTable + (ii - 1) * 3;
  1142. if (*palEntry == 0xFF)
  1143. continue;
  1144. int e_r = palEntry[0] - r;
  1145. int e_g = palEntry[1] - g;
  1146. int e_b = palEntry[2] - b;
  1147. uint16 s = (e_r * e_r) + (e_g * e_g) + (e_b * e_b);
  1148. if (s <= min) {
  1149. min = s;
  1150. col = ii - 1;
  1151. }
  1152. }
  1153. *dst++ = col;
  1154. }
  1155. }
  1156. void Screen_EoB::generateCGADitheringTables(const uint8 *mappingData) {
  1157. for (int i = 0; i < 256; i++) {
  1158. _cgaDitheringTables[0][i] = (mappingData[(i >> 4) + 16] << 8) | mappingData[i & 0x0F];
  1159. _cgaDitheringTables[1][i] = (mappingData[i >> 4] << 8) | mappingData[(i & 0x0F) + 16];
  1160. }
  1161. }
  1162. const uint8 Screen_EoB::_egaMatchTable[] = {
  1163. 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x1E, 0x00, 0x00, 0x1E, 0x1E, 0x1E, 0x00, 0x00, 0x1E,
  1164. 0x00, 0x1E, 0x1E, 0x0F, 0x00, 0x1E, 0x1E, 0x1E, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x2D, 0x0F, 0x2D,
  1165. 0x0F, 0x0F, 0x2D, 0x2D, 0x2D, 0x0F, 0x0F, 0x2D, 0x0F, 0x2D, 0x2D, 0x2D, 0x0F, 0x2D, 0x2D, 0x2D,
  1166. 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x2A, 0x00, 0x1E, 0x1E, 0x00, 0x1E, 0x2A, 0x1E, 0x00, 0x1E, 0x1E,
  1167. 0x00, 0x2A, 0x1E, 0x0F, 0x1E, 0x1E, 0x1E, 0x2A, 0x0F, 0x0F, 0x21, 0x0F, 0x0F, 0x36, 0x0F, 0x2D,
  1168. 0x21, 0x0F, 0x2D, 0x36, 0x2D, 0x0F, 0x21, 0x2D, 0x0F, 0x36, 0x2D, 0x2D, 0x21, 0x2D, 0x2D, 0x36,
  1169. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x2A, 0x00, 0x00, 0x2A, 0x1E, 0x1E, 0x1E, 0x00, 0x1E,
  1170. 0x1E, 0x1E, 0x1E, 0x21, 0x00, 0x1E, 0x2A, 0x1E, 0x0F, 0x21, 0x0F, 0x0F, 0x21, 0x2D, 0x0F, 0x36,
  1171. 0x0F, 0x0F, 0x36, 0x2D, 0x2D, 0x21, 0x0F, 0x2D, 0x21, 0x2D, 0x2D, 0x36, 0x0F, 0x2D, 0x36, 0x2D,
  1172. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x2A, 0x2A, 0x1E, 0x1E, 0x1E, 0x1E,
  1173. 0x1E, 0x2A, 0x1E, 0x21, 0x1E, 0x1E, 0x2A, 0x2A, 0x0F, 0x21, 0x21, 0x0F, 0x21, 0x36, 0x0F, 0x36,
  1174. 0x21, 0x0F, 0x36, 0x36, 0x2D, 0x21, 0x21, 0x2D, 0x21, 0x36, 0x2D, 0x36, 0x21, 0x2D, 0x36, 0x36,
  1175. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2A, 0x00, 0x00, 0x2A,
  1176. 0x00, 0x1E, 0x2A, 0x0F, 0x00, 0x2A, 0x1E, 0x1E, 0x21, 0x0F, 0x0F, 0x21, 0x0F, 0x2D, 0x21, 0x2D,
  1177. 0x0F, 0x21, 0x2D, 0x2D, 0x36, 0x0F, 0x0F, 0x36, 0x0F, 0x2D, 0x36, 0x2D, 0x0F, 0x36, 0x2D, 0x2D,
  1178. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2A,
  1179. 0x00, 0x2A, 0x2A, 0x0F, 0x1E, 0x2A, 0x1E, 0x2A, 0x21, 0x0F, 0x21, 0x21, 0x0F, 0x36, 0x21, 0x2D,
  1180. 0x21, 0x21, 0x2D, 0x36, 0x36, 0x0F, 0x21, 0x36, 0x0F, 0x36, 0x36, 0x2D, 0x21, 0x36, 0x2D, 0x36,
  1181. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1182. 0xFF, 0xFF, 0x2A, 0x15, 0x00, 0x2A, 0x21, 0x1E, 0x21, 0x15, 0x0F, 0x21, 0x15, 0x2D, 0x21, 0x2F,
  1183. 0x0F, 0x21, 0x2F, 0x2D, 0x36, 0x15, 0x0F, 0x36, 0x15, 0x2D, 0x36, 0x2F, 0x0F, 0x36, 0x2F, 0x2D,
  1184. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1185. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2A, 0x2A, 0x2A, 0x21, 0x21, 0x21, 0x21, 0x21, 0x36, 0x21, 0x36,
  1186. 0x21, 0x21, 0x36, 0x36, 0x36, 0x21, 0x21, 0x36, 0x21, 0x36, 0x36, 0x36, 0x21, 0x36, 0x36, 0x36,
  1187. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1188. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x15, 0x15, 0x15, 0x15, 0x15, 0x2F, 0x15, 0x2F,
  1189. 0x15, 0x15, 0x2F, 0x2F, 0x2F, 0x15, 0x15, 0x2F, 0x15, 0x2F, 0x2F, 0x2F, 0x15, 0x2F, 0x2F, 0x2F,
  1190. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1191. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x15, 0x15, 0x3F, 0x15, 0x2F,
  1192. 0x2F, 0x15, 0x2F, 0x3F, 0x2F, 0x15, 0x2F, 0x2F, 0x15, 0x3F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x3F,
  1193. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1194. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x15, 0x3F,
  1195. 0x15, 0x15, 0x3F, 0x2F, 0x2F, 0x2F, 0x15, 0x2F, 0x2F, 0x2F, 0x2F, 0x3F, 0x15, 0x2F, 0x3F, 0x2F,
  1196. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1197. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1198. 0xFF, 0x15, 0x3F, 0x3F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x3F, 0x2F, 0x3F, 0x2F, 0x2F, 0x3F, 0x3F,
  1199. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1200. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1201. 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x15, 0x15, 0x3F, 0x15, 0x2F, 0x3F, 0x2F, 0x15, 0x3F, 0x2F, 0x2F,
  1202. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1203. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1204. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x15, 0x3F, 0x3F, 0x2F, 0x2F, 0x3F, 0x2F, 0x3F,
  1205. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1206. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1207. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x3F, 0x15, 0x3F, 0x3F, 0x2F,
  1208. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1209. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  1210. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x3F, 0x3F
  1211. };
  1212. uint16 *OldDOSFont::_cgaDitheringTable = 0;
  1213. int OldDOSFont::_numRef = 0;
  1214. OldDOSFont::OldDOSFont(Common::RenderMode mode) : _renderMode(mode) {
  1215. _data = 0;
  1216. _width = _height = _numGlyphs = 0;
  1217. _bitmapOffsets = 0;
  1218. _numRef++;
  1219. if (!_cgaDitheringTable && _numRef == 1) {
  1220. _cgaDitheringTable = new uint16[256];
  1221. memset(_cgaDitheringTable, 0, 256 * sizeof(uint16));
  1222. static const uint bits[] = { 0, 3, 12, 15 };
  1223. for (int i = 0; i < 256; i++)
  1224. _cgaDitheringTable[i] = (bits[i & 3] << 8) | (bits[(i >> 2) & 3] << 12) | (bits[(i >> 4) & 3] << 0) | (bits[(i >> 6) & 3] << 4);
  1225. }
  1226. }
  1227. OldDOSFont::~OldDOSFont() {
  1228. unload();
  1229. if (_numRef)
  1230. --_numRef;
  1231. if (_cgaDitheringTable && !_numRef) {
  1232. delete[] _cgaDitheringTable;
  1233. _cgaDitheringTable = 0;
  1234. }
  1235. }
  1236. bool OldDOSFont::load(Common::SeekableReadStream &file) {
  1237. unload();
  1238. _data = new uint8[file.size()];
  1239. assert(_data);
  1240. file.read(_data, file.size());
  1241. if (file.err())
  1242. return false;
  1243. if (file.size() - 2 != READ_LE_UINT16(_data))
  1244. return false;
  1245. _width = _data[0x103];
  1246. _height = _data[0x102];
  1247. _numGlyphs = 255;
  1248. _bitmapOffsets = (uint16 *)(_data + 2);
  1249. for (int i = 0; i < _numGlyphs; ++i)
  1250. _bitmapOffsets[i] = READ_LE_UINT16(&_bitmapOffsets[i]);
  1251. return true;
  1252. }
  1253. int OldDOSFont::getCharWidth(uint16 c) const {
  1254. if (c >= _numGlyphs)
  1255. return 0;
  1256. return _width;
  1257. }
  1258. void OldDOSFont::drawChar(uint16 c, byte *dst, int pitch) const {
  1259. static const uint8 renderMaskTable6[] = { 0xFC, 0x00, 0x7E, 0x00, 0x3F, 0x00, 0x1F, 0x80, 0x0F, 0xC0, 0x07, 0xE0, 0x03, 0xF0, 0x01, 0xF8 };
  1260. static const uint8 renderMaskTable8[] = { 0xFF, 0x00, 0x7F, 0x80, 0x3F, 0xC0, 0x1F, 0xE0, 0x0F, 0xF0, 0x07, 0xF8, 0x03, 0xFC, 0x01, 0xFE };
  1261. if (_width != 8 && _width != 6)
  1262. error("EOB font rendering not implemented for other font widths than 6 and 8.");
  1263. if (_width == 6) {
  1264. switch (c) {
  1265. case 0x81:
  1266. case 0x9A:
  1267. c = 0x5D;
  1268. break;
  1269. case 0x84:
  1270. case 0x8E:
  1271. c = 0x5B;
  1272. break;
  1273. case 0x94:
  1274. case 0x99:
  1275. c = 0x40;
  1276. case 0xE1:
  1277. // TODO: recheck this: no conversion for 'ß' ?
  1278. break;
  1279. }
  1280. } else if (_width == 8) {
  1281. switch (c) {
  1282. case 0x81:
  1283. case 0x9A:
  1284. case 0x5D:
  1285. c = 0x1D;
  1286. break;
  1287. case 0x84:
  1288. case 0x5B:
  1289. c = 0x1E;
  1290. break;
  1291. case 0x94:
  1292. case 0x40:
  1293. c = 0x1F;
  1294. break;
  1295. case 0x8E:
  1296. c = 0x1B;
  1297. break;
  1298. case 0x99:
  1299. c = 0x1C;
  1300. break;
  1301. case 0xE1:
  1302. c = 0x19;
  1303. break;
  1304. }
  1305. }
  1306. const uint8 *src = &_data[_bitmapOffsets[c]];
  1307. uint8 *dst2 = dst + pitch;
  1308. int w = (_width - 1) >> 3;
  1309. pitch -= _width;
  1310. uint8 color1 = _colorMap[1];
  1311. uint8 color2 = _colorMap[0];
  1312. static const uint16 cgaColorMask[] = { 0, 0x5555, 0xAAAA, 0xFFFF };
  1313. uint16 cgaMask1 = cgaColorMask[color1 & 3];
  1314. uint16 cgaMask2 = cgaColorMask[color2 & 3];
  1315. if (_renderMode == Common::kRenderCGA || _renderMode == Common::kRenderEGA) {
  1316. color1 &= 0x0F;
  1317. color2 &= 0x0F;
  1318. }
  1319. int cH = _height;
  1320. while (cH--) {
  1321. int cW = w;
  1322. uint8 last = 0;
  1323. const uint8 *mtbl = _width == 8 ? renderMaskTable8 : renderMaskTable6;
  1324. if (_renderMode == Common::kRenderCGA) {
  1325. uint8 s = *src++;
  1326. uint8 m = *mtbl++;
  1327. uint8 in = s | last;
  1328. uint16 cmp1 = 0;
  1329. uint16 cmp2 = 0;
  1330. if (color1) {
  1331. in &= m;
  1332. cmp1 = _cgaDitheringTable[in];
  1333. }
  1334. if (color2) {
  1335. in = ~in & m;
  1336. cmp2 = _cgaDitheringTable[in];
  1337. }
  1338. uint16 cDst = 0;
  1339. uint8 sh = 6;
  1340. for (int i = 0; i < _width; i++) {
  1341. cDst |= ((dst[i] & 3) << sh);
  1342. sh = (sh - 2) & 0x0F;
  1343. }
  1344. uint16 out = (~(cmp1 | cmp2) & cDst) | (cmp1 & cgaMask1) | (cmp2 & cgaMask2);
  1345. sh = 6;
  1346. for (int i = 0; i < _width; i++) {
  1347. *dst++ = (out >> sh) & 3;
  1348. sh = (sh - 2) & 0x0F;
  1349. }
  1350. last = s;
  1351. } else {
  1352. for (bool runWidthLoop = true; runWidthLoop;) {
  1353. uint8 s = *src++;
  1354. uint8 m = *mtbl++;
  1355. for (uint8 i = 0x80; i; i >>= 1) {
  1356. if (!(m & i)) {
  1357. runWidthLoop = false;
  1358. break;
  1359. }
  1360. if (s & i) {
  1361. if (color1)
  1362. *dst = color1;
  1363. } else if (color2) {
  1364. *dst = color2;
  1365. }
  1366. dst++;
  1367. }
  1368. if (cW)
  1369. cW--;
  1370. else
  1371. runWidthLoop = false;
  1372. }
  1373. }
  1374. dst += pitch;
  1375. dst2 += pitch;
  1376. }
  1377. }
  1378. void OldDOSFont::unload() {
  1379. delete[] _data;
  1380. _data = 0;
  1381. _width = _height = _numGlyphs = 0;
  1382. _bitmapOffsets = 0;
  1383. }
  1384. } // End of namespace Kyra
  1385. #endif // ENABLE_EOB