From 16ead6f58a041adaa7fedb9f08d8435fff24f3ae Mon Sep 17 00:00:00 2001 From: athrxx Date: Sat, 9 Jan 2016 21:57:47 +0100 Subject: KYRA: add 16bit mode required for EOB II FM-TOWNS --- engines/kyra/detection_tables.h | 81 ++++----- engines/kyra/kyra_v1.h | 1 + engines/kyra/screen.cpp | 366 ++++++++++++++++++++++++++++++---------- engines/kyra/screen.h | 41 ++++- engines/kyra/screen_eob.cpp | 293 ++++++++++++++++++++++++-------- engines/kyra/screen_eob.h | 6 +- 6 files changed, 585 insertions(+), 203 deletions(-) (limited to 'engines/kyra') diff --git a/engines/kyra/detection_tables.h b/engines/kyra/detection_tables.h index 43dc0cc881..0b45977d22 100644 --- a/engines/kyra/detection_tables.h +++ b/engines/kyra/detection_tables.h @@ -22,45 +22,46 @@ namespace { -#define FLAGS(x, y, z, a, b, c, d, e, id) { Common::UNK_LANG, Common::UNK_LANG, Common::UNK_LANG, Common::kPlatformUnknown, x, y, z, a, b, c, d, e, id } -#define FLAGS_FAN(fanLang, repLang, x, y, z, a, b, c, d, e, id) { Common::UNK_LANG, fanLang, repLang, Common::kPlatformUnknown, x, y, z, a, b, c, d, e, id } - -#define KYRA1_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, false, false, Kyra::GI_KYRA1) -#define KYRA1_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, false, false, true, Kyra::GI_KYRA1) -#define KYRA1_OLDFLOPPY_FLAGS FLAGS(false, false, false, true, false, false, false, false, Kyra::GI_KYRA1) -#define KYRA1_AMIGA_FLAGS FLAGS(false, false, false, false, false, false, false, false, Kyra::GI_KYRA1) -#define KYRA1_TOWNS_FLAGS FLAGS(false, true, false, false, false, false, false, false, Kyra::GI_KYRA1) -#define KYRA1_TOWNS_SJIS_FLAGS FLAGS(false, true, false, false, true, false, false, false, Kyra::GI_KYRA1) -#define KYRA1_CD_FLAGS FLAGS(false, true, true, false, false, false, false, false, Kyra::GI_KYRA1) -#define KYRA1_DEMO_FLAGS FLAGS(true, false, false, false, false, false, false, false, Kyra::GI_KYRA1) -#define KYRA1_DEMO_CD_FLAGS FLAGS(true, true, true, false, false, false, false, false, Kyra::GI_KYRA1) - -#define KYRA2_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, false, false, Kyra::GI_KYRA2) -#define KYRA2_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, false, false, true, Kyra::GI_KYRA2) -#define KYRA2_FLOPPY_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, false, false, false, false, false, false, Kyra::GI_KYRA2) -#define KYRA2_CD_FLAGS FLAGS(false, false, true, false, false, false, false, false, Kyra::GI_KYRA2) -#define KYRA2_CD_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, true, false, false, false, false, false, Kyra::GI_KYRA2) -#define KYRA2_CD_DEMO_FLAGS FLAGS(true, false, true, false, false, false, false, false, Kyra::GI_KYRA2) -#define KYRA2_DEMO_FLAGS FLAGS(true, false, false, false, false, false, false, false, Kyra::GI_KYRA2) -#define KYRA2_TOWNS_FLAGS FLAGS(false, false, false, false, false, false, false, false, Kyra::GI_KYRA2) -#define KYRA2_TOWNS_SJIS_FLAGS FLAGS(false, false, false, false, true, false, false, false, Kyra::GI_KYRA2) - -#define KYRA3_CD_FLAGS FLAGS(false, false, true, false, false, false, true, true, Kyra::GI_KYRA3) -#define KYRA3_CD_INS_FLAGS FLAGS(false, false, true, false, false, false, true, false, Kyra::GI_KYRA3) -#define KYRA3_CD_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, true, false, false, false, true, false, Kyra::GI_KYRA3) - -#define LOL_CD_FLAGS FLAGS(false, false, true, false, false, false, false, false, Kyra::GI_LOL) -#define LOL_CD_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, true, false, false, false, false, false, Kyra::GI_LOL) -#define LOL_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, false, false, Kyra::GI_LOL) -#define LOL_FLOPPY_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, false, false, false, false, false, false, Kyra::GI_LOL) -#define LOL_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, false, false, true, Kyra::GI_LOL) -#define LOL_PC9801_FLAGS FLAGS(false, false, false, false, true, true, false, false, Kyra::GI_LOL) -#define LOL_FMTOWNS_FLAGS FLAGS(false, false, false, false, true, false, false, false, Kyra::GI_LOL) -#define LOL_DEMO_FLAGS FLAGS(true, true, false, false, false, false, false, false, Kyra::GI_LOL) -#define LOL_KYRA2_DEMO_FLAGS FLAGS(true, false, false, false, false, false, false, false, Kyra::GI_KYRA2) - -#define EOB_FLAGS FLAGS(false, false, false, false, false, false, false, false, Kyra::GI_EOB1) -#define EOB2_FLAGS FLAGS(false, false, false, false, false, false, false, false, Kyra::GI_EOB2) +#define EOB2_SJIS_FLAGS FLAGS(false, false, false, false, true, false, false, false, Kyra::GI_EOB2) +#define FLAGS(x, y, z, a, b, c, d, e, f, id) { Common::UNK_LANG, Common::UNK_LANG, Common::UNK_LANG, Common::kPlatformUnknown, x, y, z, a, b, c, d, e, f, id } +#define FLAGS_FAN(fanLang, repLang, x, y, z, a, b, c, d, e, f, id) { Common::UNK_LANG, fanLang, repLang, Common::kPlatformUnknown, x, y, z, a, b, c, d, e, f, id } + +#define KYRA1_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, false, false, false, Kyra::GI_KYRA1) +#define KYRA1_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, false, false, false, true, Kyra::GI_KYRA1) +#define KYRA1_OLDFLOPPY_FLAGS FLAGS(false, false, false, true, false, false, false, false, false, Kyra::GI_KYRA1) +#define KYRA1_AMIGA_FLAGS FLAGS(false, false, false, false, false, false, false, false, false, Kyra::GI_KYRA1) +#define KYRA1_TOWNS_FLAGS FLAGS(false, true, false, false, false, false, false, false, false, Kyra::GI_KYRA1) +#define KYRA1_TOWNS_SJIS_FLAGS FLAGS(false, true, false, false, true, false, false, false, false, Kyra::GI_KYRA1) +#define KYRA1_CD_FLAGS FLAGS(false, true, true, false, false, false, false, false, false, Kyra::GI_KYRA1) +#define KYRA1_DEMO_FLAGS FLAGS(true, false, false, false, false, false, false, false, false, Kyra::GI_KYRA1) +#define KYRA1_DEMO_CD_FLAGS FLAGS(true, true, true, false, false, false, false, false, false, Kyra::GI_KYRA1) + +#define KYRA2_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, false, false, false, true, Kyra::GI_KYRA2) +#define KYRA2_FLOPPY_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, false, false, false, false, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_CD_FLAGS FLAGS(false, false, true, false, false, false, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_CD_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, true, false, false, false, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_CD_DEMO_FLAGS FLAGS(true, false, true, false, false, false, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_DEMO_FLAGS FLAGS(true, false, false, false, false, false, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_TOWNS_FLAGS FLAGS(false, false, false, false, false, false, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_TOWNS_SJIS_FLAGS FLAGS(false, false, false, false, true, false, false, false, false, Kyra::GI_KYRA2) + +#define KYRA3_CD_FLAGS FLAGS(false, false, true, false, false, false, false, true, true, Kyra::GI_KYRA3) +#define KYRA3_CD_INS_FLAGS FLAGS(false, false, true, false, false, false, false, true, false, Kyra::GI_KYRA3) +#define KYRA3_CD_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, true, false, false, false, false, true, false, Kyra::GI_KYRA3) + +#define LOL_CD_FLAGS FLAGS(false, false, true, false, false, false, false, false, false, Kyra::GI_LOL) +#define LOL_CD_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, true, false, false, false, false, false, false, Kyra::GI_LOL) +#define LOL_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, false, false, false, Kyra::GI_LOL) +#define LOL_FLOPPY_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, false, false, false, false, false, false, false, Kyra::GI_LOL) +#define LOL_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, false, false, false, true, Kyra::GI_LOL) +#define LOL_PC9801_FLAGS FLAGS(false, false, false, false, true, true, false, false, false, Kyra::GI_LOL) +#define LOL_FMTOWNS_FLAGS FLAGS(false, false, false, false, true, false, false, false, false, Kyra::GI_LOL) +#define LOL_DEMO_FLAGS FLAGS(true, true, false, false, false, false, false, false, false, Kyra::GI_LOL) +#define LOL_KYRA2_DEMO_FLAGS FLAGS(true, false, false, false, false, false, false, false, false, Kyra::GI_KYRA2) + +#define EOB_FLAGS FLAGS(false, false, false, false, false, false, false, false, false, Kyra::GI_EOB1) +#define EOB2_FLAGS FLAGS(false, false, false, false, false, false, false, false, false, Kyra::GI_EOB2) #define GAMEOPTION_KYRA3_AUDIENCE GUIO_GAMEOPTIONS1 #define GAMEOPTION_KYRA3_SKIP GUIO_GAMEOPTIONS2 @@ -1685,7 +1686,7 @@ const KYRAGameDescription adGameDescs[] = { }, #endif // ENABLE_EOB - { AD_TABLE_END_MARKER, FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0) } + { AD_TABLE_END_MARKER, FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0, 0) } }; const PlainGameDescriptor gameList[] = { diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h index bbbd59a4b8..9fdddb89a9 100644 --- a/engines/kyra/kyra_v1.h +++ b/engines/kyra/kyra_v1.h @@ -122,6 +122,7 @@ struct GameFlags { bool isOldFloppy : 1; bool useHiRes : 1; bool use16ColorMode : 1; + bool useHiColorMode : 1; bool useDigSound : 1; bool useInstallerPackage : 1; diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp index bce45b2514..a0cab913b9 100644 --- a/engines/kyra/screen.cpp +++ b/engines/kyra/screen.cpp @@ -58,6 +58,13 @@ Screen::Screen(KyraEngine_v1 *vm, OSystem *system, const ScreenDim *dimTable, co _renderMode = Common::kRenderDefault; _sjisMixedFontMode = false; + _useHiColorScreen = _vm->gameFlags().useHiColorMode; + _screenPageSize = SCREEN_PAGE_SIZE; + _16bitPalette = 0; + _16bitConversionPalette = 0; + _16bitShadingLevel = 0; + _bytesPerPixel = 1; + _currentFont = FID_8_FNT; _paletteChanged = true; _curDim = 0; @@ -76,6 +83,8 @@ Screen::~Screen() { delete _internFadePalette; delete[] _decodeShapeBuffer; delete[] _animBlockPtr; + delete[] _16bitPalette; + delete[] _16bitConversionPalette; for (uint i = 0; i < _palettes.size(); ++i) delete _palettes[i]; @@ -127,7 +136,17 @@ bool Screen::init() { _sjisInvisibleColor = (_vm->game() == GI_KYRA1) ? 0x80 : 0xF6; _sjisMixedFontMode = !_use16ColorMode; - for (int i = 0; i < SCREEN_OVLS_NUM; ++i) { + if (!_sjisOverlayPtrs[0]) { + // We alway assume 2 bytes per pixel here when the backend is in hicolor mode, since this is the surface that is passed to the backend. + // We do this regardsless of the paramater sent to enableHiColorMode() so as not to have to change the backend color mode. + // Conversions from 8bit to 16bit have to take place when copying data to this surface here. + int bpp = _useHiColorScreen ? 2 : 1; + _sjisOverlayPtrs[0] = new uint8[SCREEN_OVL_SJIS_SIZE * bpp]; + assert(_sjisOverlayPtrs[0]); + memset(_sjisOverlayPtrs[0], _sjisInvisibleColor, SCREEN_OVL_SJIS_SIZE * bpp); + } + + for (int i = 1; i < SCREEN_OVLS_NUM; ++i) { if (!_sjisOverlayPtrs[i]) { _sjisOverlayPtrs[i] = new uint8[SCREEN_OVL_SJIS_SIZE]; assert(_sjisOverlayPtrs[i]); @@ -147,27 +166,7 @@ bool Screen::init() { _curPage = 0; - Common::Array realPages; - for (int i = 0; i < SCREEN_PAGE_NUM; i++) { - if (Common::find(realPages.begin(), realPages.end(), _pageMapping[i]) == realPages.end()) - realPages.push_back(_pageMapping[i]); - } - - int numPages = realPages.size(); - uint32 bufferSize = numPages * SCREEN_PAGE_SIZE; - - uint8 *pagePtr = new uint8[bufferSize]; - memset(pagePtr, 0, bufferSize); - - memset(_pagePtrs, 0, sizeof(_pagePtrs)); - for (int i = 0; i < SCREEN_PAGE_NUM; i++) { - if (_pagePtrs[_pageMapping[i]]) { - _pagePtrs[i] = _pagePtrs[_pageMapping[i]]; - } else { - _pagePtrs[i] = pagePtr; - pagePtr += SCREEN_PAGE_SIZE; - } - } + enableHiColorMode(false); memset(_shapePages, 0, sizeof(_shapePages)); @@ -223,6 +222,7 @@ bool Screen::init() { _charOffset = 0; for (int i = 0; i < ARRAYSIZE(_textColorsMap); ++i) _textColorsMap[i] = i; + _textColorsMap16bit[0] = _textColorsMap16bit[1] = 0; _decodeShapeBuffer = NULL; _decodeShapeBufferSize = 0; _animBlockPtr = NULL; @@ -249,8 +249,9 @@ bool Screen::enableScreenDebug(bool enable) { } void Screen::setResolution() { - byte palette[3*256]; - _system->getPaletteManager()->grabPalette(palette, 0, 256); + byte palette[3 * 256]; + if (!_useHiColorScreen) + _system->getPaletteManager()->grabPalette(palette, 0, 256); int width = 320, height = 200; @@ -268,9 +269,49 @@ void Screen::setResolution() { width = 320; } - initGraphics(width, height); + if (_useHiColorScreen) { + Graphics::PixelFormat px(2, 5, 5, 5, 0, 10, 5, 0, 0); + Common::List tryModes = _system->getSupportedFormats(); + for (Common::List::iterator g = tryModes.begin(); g != tryModes.end(); ++g) { + if (g->bytesPerPixel != 2 || g->aBits()) { + g = tryModes.reverse_erase(g); + } else if (*g == px) { + tryModes.clear(); + tryModes.push_back(px); + break; + } + } + initGraphics(width, height, tryModes); + if (_system->getScreenFormat().bytesPerPixel != 2) + error("Required graphics mode not supported by platform."); + + } else { + initGraphics(width, height); + _system->getPaletteManager()->setPalette(palette, 0, 256); + } +} + +void Screen::enableHiColorMode(bool enabled) { + if (_useHiColorScreen && enabled) { + if (!_16bitPalette) + _16bitPalette = new uint16[1024]; + memset(_16bitPalette, 0, 1024 * sizeof(uint16)); + delete[] _16bitConversionPalette; + _16bitConversionPalette = 0; + _bytesPerPixel = 2; + } else { + if (_useHiColorScreen) { + if (!_16bitConversionPalette) + _16bitConversionPalette = new uint16[256]; + memset(_16bitConversionPalette, 0, 256 * sizeof(uint16)); + } + + delete[] _16bitPalette; + _16bitPalette = 0; + _bytesPerPixel = 1; + } - _system->getPaletteManager()->setPalette(palette, 0, 256); + resetPagePtrsAndBuffers(SCREEN_PAGE_SIZE * _bytesPerPixel); } void Screen::updateScreen() { @@ -386,22 +427,22 @@ void Screen::updateDirtyRectsOvl() { if (_forceFullUpdate) { const byte *src = getCPagePtr(0); byte *dst = _sjisOverlayPtrs[0]; - scale2x(dst, 640, src, SCREEN_W, SCREEN_W, SCREEN_H); mergeOverlay(0, 0, 640, 400); - _system->copyRectToScreen(dst, 640, 0, 0, 640, 400); + _system->copyRectToScreen(dst, _useHiColorScreen ? 1280 : 640, 0, 0, 640, 400); } else { const byte *page0 = getCPagePtr(0); byte *ovl0 = _sjisOverlayPtrs[0]; + int dstBpp = _useHiColorScreen ? 2 : 1; Common::List::iterator it; for (it = _dirtyRects.begin(); it != _dirtyRects.end(); ++it) { - byte *dst = ovl0 + it->top * 1280 + (it->left<<1); - const byte *src = page0 + it->top * SCREEN_W + it->left; + byte *dst = ovl0 + it->top * 1280 * dstBpp + (it->left << dstBpp); + const byte *src = page0 + it->top * SCREEN_W * _bytesPerPixel + it->left * _bytesPerPixel; scale2x(dst, 640, src, SCREEN_W, it->width(), it->height()); mergeOverlay(it->left<<1, it->top<<1, it->width()<<1, it->height()<<1); - _system->copyRectToScreen(dst, 640, it->left<<1, it->top<<1, it->width()<<1, it->height()<<1); + _system->copyRectToScreen(dst, _useHiColorScreen ? 1280 : 640, it->left << 1, it->top << 1, it->width() << 1, it->height() << 1); } } @@ -410,18 +451,31 @@ void Screen::updateDirtyRectsOvl() { } void Screen::scale2x(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h) { + int srcBpp = _bytesPerPixel; + int dstBpp = _useHiColorScreen ? 2 : 1; + byte *dstL1 = dst; - byte *dstL2 = dst + dstPitch; + byte *dstL2 = dst + dstPitch * dstBpp; - int dstAdd = dstPitch * 2 - w * 2; - int srcAdd = srcPitch - w; + int dstAdd = (dstPitch * 2 - w * 2) * dstBpp; + int srcAdd = (srcPitch - w) * srcBpp; + int dstInc = 2 * dstBpp; while (h--) { - for (int x = 0; x < w; ++x, dstL1 += 2, dstL2 += 2) { - uint16 col = *src++; - col |= col << 8; - *(uint16 *)(dstL1) = col; - *(uint16 *)(dstL2) = col; + for (int x = 0; x < w; x++, src += srcBpp, dstL1 += dstInc, dstL2 += dstInc) { + if (dstBpp == 1) { + uint16 col = *src; + col |= col << 8; + *(uint16 *)(dstL1) = *(uint16 *)(dstL2) = col; + } else if (dstBpp == srcBpp) { + uint32 col = *(const uint16 *)src; + col |= col << 16; + *(uint32 *)(dstL1) = *(uint32 *)(dstL2) = col; + } else if (dstBpp == 2) { + uint32 col = _16bitConversionPalette[*src]; + col |= col << 16; + *(uint32 *)(dstL1) = *(uint32 *)(dstL2) = col; + } } dstL1 += dstAdd; dstL2 += dstAdd; src += srcAdd; @@ -429,18 +483,24 @@ void Screen::scale2x(byte *dst, int dstPitch, const byte *src, int srcPitch, int } void Screen::mergeOverlay(int x, int y, int w, int h) { - byte *dst = _sjisOverlayPtrs[0] + y * 640 + x; + int bpp = _useHiColorScreen ? 2 : 1; + byte *dst = _sjisOverlayPtrs[0] + y * 640 * bpp + x * bpp; const byte *src = _sjisOverlayPtrs[1] + y * 640 + x; + uint16 *p16 = _16bitPalette ? _16bitPalette : (_16bitConversionPalette ? _16bitConversionPalette : 0); int add = 640 - w; while (h--) { - for (x = 0; x < w; ++x, ++dst) { + for (x = 0; x < w; ++x, dst += bpp) { byte col = *src++; - if (col != _sjisInvisibleColor) - *dst = col; + if (col != _sjisInvisibleColor) { + if (bpp == 2) + *(uint16*)dst = p16[col]; + else + *dst = col; + } } - dst += add; + dst += add * bpp; src += add; } } @@ -468,6 +528,35 @@ void Screen::setScreenDim(int dim) { _curDimIndex = dim; } +void Screen::resetPagePtrsAndBuffers(int pageSize) { + _screenPageSize = pageSize; + + delete[] _pagePtrs[0]; + memset(_pagePtrs, 0, sizeof(_pagePtrs)); + + Common::Array realPages; + for (int i = 0; i < SCREEN_PAGE_NUM; i++) { + if (Common::find(realPages.begin(), realPages.end(), _pageMapping[i]) == realPages.end()) + realPages.push_back(_pageMapping[i]); + } + + int numPages = realPages.size(); + uint32 bufferSize = numPages * _screenPageSize; + + uint8 *pagePtr = new uint8[bufferSize]; + memset(pagePtr, 0, bufferSize); + + memset(_pagePtrs, 0, sizeof(_pagePtrs)); + for (int i = 0; i < SCREEN_PAGE_NUM; i++) { + if (_pagePtrs[_pageMapping[i]]) { + _pagePtrs[i] = _pagePtrs[_pageMapping[i]]; + } else { + _pagePtrs[i] = pagePtr; + pagePtr += _screenPageSize; + } + } +} + uint8 *Screen::getPagePtr(int pageNum) { assert(pageNum < SCREEN_PAGE_NUM); return _pagePtrs[pageNum]; @@ -489,7 +578,7 @@ void Screen::clearPage(int pageNum) { assert(pageNum < SCREEN_PAGE_NUM); if (pageNum == 0 || pageNum == 1) _forceFullUpdate = true; - memset(getPagePtr(pageNum), 0, SCREEN_PAGE_SIZE); + memset(getPagePtr(pageNum), 0, _screenPageSize); clearOverlayPage(pageNum); } @@ -503,7 +592,7 @@ int Screen::setCurPage(int pageNum) { void Screen::clearCurPage() { if (_curPage == 0 || _curPage == 1) _forceFullUpdate = true; - memset(getPagePtr(_curPage), 0, SCREEN_PAGE_SIZE); + memset(getPagePtr(_curPage), 0, _screenPageSize); clearOverlayPage(_curPage); } @@ -670,9 +759,13 @@ void Screen::setPagePixel(int pageNum, int x, int y, uint8 color) { color &= 0x03; } else if (_renderMode == Common::kRenderEGA && !_useHiResEGADithering) { color &= 0x0F; + } + + if (_bytesPerPixel == 2) { + *(uint16*)(&_pagePtrs[pageNum][y * SCREEN_W * 2 + x * 2]) = _16bitPalette[color]; + } else { + _pagePtrs[pageNum][y * SCREEN_W + x] = color; } - - _pagePtrs[pageNum][y * SCREEN_W + x] = color; } void Screen::fadeFromBlack(int delay, const UpdateFunctor *upFunc) { @@ -707,6 +800,8 @@ void Screen::fadePalette(const Palette &pal, int delay, const UpdateFunctor *upF if (upFunc && upFunc->isValid()) (*upFunc)(); + else if (_useHiColorScreen) + updateScreen(); else _system->updateScreen(); @@ -821,6 +916,22 @@ void Screen::setScreenPalette(const Palette &pal) { } _paletteChanged = true; + + if (_useHiColorScreen) { + if (_16bitPalette) + memcpy(_16bitPalette, pal.getData(), 512); + + // Generate 16bit palette for the 8bit/16 bit conversion in scale2x() + if (_16bitConversionPalette) { + Graphics::PixelFormat pixelFormat = _system->getScreenFormat(); + for (int i = 0; i < 256; ++i) + _16bitConversionPalette[i] = pixelFormat.RGBToColor(screenPal[i * 3], screenPal[i * 3 + 1], screenPal[i * 3 + 2]); + // The whole Surface has to be converted again after each palette chance + _forceFullUpdate = true; + } + return; + } + _system->getPaletteManager()->setPalette(screenPal, 0, pal.getNumColors()); } @@ -908,8 +1019,8 @@ void Screen::copyRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPag h = SCREEN_H - y2; } - const uint8 *src = getPagePtr(srcPage) + y1 * SCREEN_W + x1; - uint8 *dst = getPagePtr(dstPage) + y2 * SCREEN_W + x2; + const uint8 *src = getPagePtr(srcPage) + y1 * SCREEN_W * _bytesPerPixel + x1 * _bytesPerPixel; + uint8 *dst = getPagePtr(dstPage) + y2 * SCREEN_W * _bytesPerPixel + x2 * _bytesPerPixel; if (src == dst) return; @@ -921,18 +1032,24 @@ void Screen::copyRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPag if (flags & CR_NO_P_CHECK) { while (h--) { - memmove(dst, src, w); - src += SCREEN_W; - dst += SCREEN_W; + memmove(dst, src, w * _bytesPerPixel); + src += SCREEN_W * _bytesPerPixel; + dst += SCREEN_W * _bytesPerPixel; } } else { while (h--) { for (int i = 0; i < w; ++i) { - if (src[i]) - dst[i] = src[i]; + if (_bytesPerPixel == 2) { + uint px = *(const uint16*)&src[i << 1]; + if (px) + *(uint16*)&dst[i << 1] = px; + } else { + if (src[i]) + dst[i] = src[i]; + } } - src += SCREEN_W; - dst += SCREEN_W; + src += SCREEN_W * _bytesPerPixel; + dst += SCREEN_W * _bytesPerPixel; } } } @@ -960,14 +1077,14 @@ void Screen::copyRegionToBuffer(int pageNum, int x, int y, int w, int h, uint8 * uint8 *pagePtr = getPagePtr(pageNum); for (int i = y; i < y + h; ++i) - memcpy(dest + (i - y) * w, pagePtr + i * SCREEN_W + x, w); + memcpy(dest + (i - y) * w * _bytesPerPixel, pagePtr + i * SCREEN_W * _bytesPerPixel + x * _bytesPerPixel, w * _bytesPerPixel); } void Screen::copyPage(uint8 srcPage, uint8 dstPage) { uint8 *src = getPagePtr(srcPage); uint8 *dst = getPagePtr(dstPage); if (src != dst) - memcpy(dst, src, SCREEN_W * SCREEN_H); + memcpy(dst, src, SCREEN_W * SCREEN_H * _bytesPerPixel); copyOverlayRegion(0, 0, 0, 0, SCREEN_W, SCREEN_H, srcPage, dstPage); if (dstPage == 0 || dstPage == 1) @@ -994,7 +1111,7 @@ void Screen::copyBlockToPage(int pageNum, int x, int y, int w, int h, const uint if (w < 0 || h < 0) return; - uint8 *dst = getPagePtr(pageNum) + y * SCREEN_W + x; + uint8 *dst = getPagePtr(pageNum) + y * SCREEN_W * _bytesPerPixel + x * _bytesPerPixel; if (pageNum == 0 || pageNum == 1) addDirtyRect(x, y, w, h); @@ -1002,9 +1119,9 @@ void Screen::copyBlockToPage(int pageNum, int x, int y, int w, int h, const uint clearOverlayRect(pageNum, x, y, w, h); while (h--) { - memcpy(dst, src, w); - dst += SCREEN_W; - src += w; + memcpy(dst, src, w * _bytesPerPixel); + dst += SCREEN_W * _bytesPerPixel; + src += w * _bytesPerPixel; } } @@ -1066,10 +1183,11 @@ void Screen::shuffleScreen(int sx, int sy, int w, int h, int srcPage, int dstPag void Screen::fillRect(int x1, int y1, int x2, int y2, uint8 color, int pageNum, bool xored) { assert(x2 < SCREEN_W && y2 < SCREEN_H); + uint16 color16 = 0; if (pageNum == -1) pageNum = _curPage; - uint8 *dst = getPagePtr(pageNum) + y1 * SCREEN_W + x1; + uint8 *dst = getPagePtr(pageNum) + y1 * SCREEN_W * _bytesPerPixel + x1 * _bytesPerPixel; if (pageNum == 0 || pageNum == 1) addDirtyRect(x1, y1, x2-x1+1, y2-y1+1); @@ -1083,9 +1201,11 @@ void Screen::fillRect(int x1, int y1, int x2, int y2, uint8 color, int pageNum, color &= 0x03; } else if (_renderMode == Common::kRenderEGA && !_useHiResEGADithering) { color &= 0x0F; - } + } else if (_bytesPerPixel == 2) + color16 = shade16bitColor(_16bitPalette[color]); if (xored) { + // no 16 bit support for this (unneeded) for (; y1 <= y2; ++y1) { for (int x = x1; x <= x2; ++x) dst[x] ^= color; @@ -1093,8 +1213,14 @@ void Screen::fillRect(int x1, int y1, int x2, int y2, uint8 color, int pageNum, } } else { for (; y1 <= y2; ++y1) { - memset(dst, color, x2 - x1 + 1); - dst += SCREEN_W; + if (_bytesPerPixel == 2) { + uint16 *ptr = (uint16*)dst; + for (int i = 0; i < x2 - x1 + 1; i++) + *ptr++ = color16; + } else { + memset(dst, color, x2 - x1 + 1); + } + dst += SCREEN_W * _bytesPerPixel; } } } @@ -1151,7 +1277,7 @@ void Screen::drawClippedLine(int x1, int y1, int x2, int y2, int color) { } void Screen::drawLine(bool vertical, int x, int y, int length, int color) { - uint8 *ptr = getPagePtr(_curPage) + y * SCREEN_W + x; + uint8 *ptr = getPagePtr(_curPage) + y * SCREEN_W * _bytesPerPixel + x * _bytesPerPixel; if (_use16ColorMode) { color &= 0x0F; @@ -1160,19 +1286,30 @@ void Screen::drawLine(bool vertical, int x, int y, int length, int color) { color &= 0x03; } else if (_renderMode == Common::kRenderEGA && !_useHiResEGADithering) { color &= 0x0F; - } + } else if (_bytesPerPixel == 2) + color = shade16bitColor(_16bitPalette[color]); if (vertical) { assert((y + length) <= SCREEN_H); int currLine = 0; while (currLine < length) { - *ptr = color; - ptr += SCREEN_W; + if (_bytesPerPixel == 2) + *(uint16*)ptr = color; + else + *ptr = color; + ptr += SCREEN_W * _bytesPerPixel; currLine++; } } else { assert((x + length) <= SCREEN_W); - memset(ptr, color, length); + if (_bytesPerPixel == 2) { + for (int i = 0; i < length; i++) { + *(uint16*)ptr = color; + ptr += 2; + } + } else { + memset(ptr, color, length); + } } if (_curPage == 0 || _curPage == 1) @@ -1189,14 +1326,25 @@ void Screen::setAnimBlockPtr(int size) { _animBlockSize = size; } -void Screen::setTextColor(const uint8 *cmap, int a, int b) { - memcpy(&_textColorsMap[a], cmap, b-a+1); +void Screen::setTextColor(const uint8 *cmap8, int a, int b) { + memcpy(&_textColorsMap[a], cmap8, (b - a + 1)); + // We need to update the color tables of all fonts, we + // setup so far here. + for (int i = 0; i < FID_NUM; ++i) { + if (_fonts[i]) + _fonts[i]->setColorMap(_textColorsMap); + } +} +void Screen::setTextColor16bit(const uint16 *cmap16) { + assert(cmap16); + _textColorsMap16bit[0] = cmap16[0]; + _textColorsMap16bit[1] = cmap16[1]; // We need to update the color tables of all fonts, we // setup so far here. for (int i = 0; i < FID_NUM; ++i) { if (_fonts[i]) - _fonts[i]->setColorMap(_textColorsMap); + _fonts[i]->set16bitColorMap(_textColorsMap16bit); } } @@ -1281,10 +1429,17 @@ int Screen::getTextWidth(const char *str) { } void Screen::printText(const char *str, int x, int y, uint8 color1, uint8 color2) { - uint8 cmap[2]; - cmap[0] = color2; - cmap[1] = color1; - setTextColor(cmap, 0, 1); + uint16 cmap16[2]; + if (_16bitPalette) { + cmap16[0] = color2 ? shade16bitColor(_16bitPalette[color2]) : 0xFFFF; + cmap16[1] = _16bitPalette[color1]; + setTextColor16bit(cmap16); + } + + uint8 cmap8[2]; + cmap8[0] = color2; + cmap8[1] = color1; + setTextColor(cmap8, 0, 1); FontId curFont = _currentFont; @@ -1360,11 +1515,12 @@ void Screen::drawChar(uint16 c, int x, int y) { return; } - destPage += (y * 2) * 640 + (x * 2); + int bpp = (_currentFont == Screen::FID_SJIS_FNT) ? 1 : 2; + destPage += (y * 2) * 640 * bpp + (x * 2 * bpp); - fnt->drawChar(c, destPage, 640); + fnt->drawChar(c, destPage, 640, bpp); } else { - fnt->drawChar(c, getPagePtr(_curPage) + y * SCREEN_W + x, SCREEN_W); + fnt->drawChar(c, getPagePtr(_curPage) + y * SCREEN_W * _bytesPerPixel + x * _bytesPerPixel, SCREEN_W, _bytesPerPixel); } if (_curPage == 0 || _curPage == 1) @@ -2846,6 +3002,18 @@ int16 Screen::encodeShapeAndCalculateSize(uint8 *from, uint8 *to, int size_to) { return (to - toPtr); } +uint16 Screen::shade16bitColor(uint16 col) { + uint8 r = (col & 0x1f); + uint8 g = (col & 0x3E0) >> 5; + uint8 b = (col & 0x7C00) >> 10; + + r = (r > _16bitShadingLevel) ? r - _16bitShadingLevel : 0; + g = (g > _16bitShadingLevel) ? g - _16bitShadingLevel : 0; + b = (b > _16bitShadingLevel) ? b - _16bitShadingLevel : 0; + + return (b << 10) | (g << 5) | r; +} + void Screen::hideMouse() { ++_mouseLockCount; CursorMan.showMouse(false); @@ -3072,7 +3240,7 @@ void Screen::loadBitmap(const char *filename, int tempPage, int dstPage, Palette uint8 *srcPtr = srcData + 10 + palSize; uint8 *dstData = getPagePtr(dstPage); - memset(dstData, 0, SCREEN_PAGE_SIZE); + memset(dstData, 0, _screenPageSize); if (dstPage == 0 || tempPage == 0) _forceFullUpdate = true; @@ -3117,7 +3285,7 @@ bool Screen::loadPalette(const char *filename, Palette &pal) { debugC(3, kDebugLevelScreen, "Screen::loadPalette('%s', %p)", filename, (const void *)&pal); - const int maxCols = pal.getNumColors(); + const int maxCols = _16bitPalette ? 256 : pal.getNumColors(); int numCols = 0; if (_isAmiga) { @@ -3133,8 +3301,15 @@ bool Screen::loadPalette(const char *filename, Palette &pal) { numCols /= Palette::kVGABytesPerColor; pal.loadVGAPalette(*stream, 0, numCols); } else { - numCols = stream->size() / Palette::kVGABytesPerColor; - pal.loadVGAPalette(*stream, 0, MIN(maxCols, numCols)); + if (_bytesPerPixel == 2) { + numCols = stream->size() / 2; + pal.loadHiColorPalette(*stream, 0, numCols); + } else if (!_16bitPalette) { + numCols = stream->size() / Palette::kVGABytesPerColor; + pal.loadVGAPalette(*stream, 0, MIN(maxCols, numCols)); + } else { + error("Screen::loadPalette(): Failed to load file '%s' with invalid size %d in HiColor mode", filename, stream->size()); + } } if (numCols > maxCols) @@ -3407,7 +3582,7 @@ int DOSFont::getCharWidth(uint16 c) const { return _widthTable[c]; } -void DOSFont::drawChar(uint16 c, byte *dst, int pitch) const { +void DOSFont::drawChar(uint16 c, byte *dst, int pitch, int) const { if (c >= _numGlyphs) return; @@ -3549,7 +3724,7 @@ int AMIGAFont::getCharWidth(uint16 c) const { return _chars[c].width; } -void AMIGAFont::drawChar(uint16 c, byte *dst, int pitch) const { +void AMIGAFont::drawChar(uint16 c, byte *dst, int pitch, int) const { if (c >= 255) return; @@ -3624,7 +3799,7 @@ void SJISFont::setColorMap(const uint8 *src) { } } -void SJISFont::drawChar(uint16 c, byte *dst, int pitch) const { +void SJISFont::drawChar(uint16 c, byte *dst, int pitch, int) const { uint8 color1, color2; if (_is16Color) { @@ -3672,6 +3847,19 @@ void Palette::loadVGAPalette(Common::ReadStream &stream, int startIndex, int col *pos++ = stream.readByte() & 0x3F; } +void Palette::loadHiColorPalette(Common::ReadStream &stream, int startIndex, int colors) { + uint16 *pos = (uint16*)(_palData + startIndex * 2); + + Graphics::PixelFormat currentFormat = g_system->getScreenFormat(); + Graphics::PixelFormat originalFormat(2, 5, 5, 5, 0, 5, 10, 0, 0); + + for (int i = 0; i < colors; i++) { + uint8 r, g, b; + originalFormat.colorToRGB(stream.readUint16LE(), r, g, b); + *pos++ = currentFormat.RGBToColor(r, g, b); + } +} + void Palette::loadEGAPalette(Common::ReadStream &stream, int startIndex, int colors) { assert(startIndex + colors <= 16); diff --git a/engines/kyra/screen.h b/engines/kyra/screen.h index 0b287aa8bc..bac93ae49c 100644 --- a/engines/kyra/screen.h +++ b/engines/kyra/screen.h @@ -93,6 +93,11 @@ public: */ virtual void setColorMap(const uint8 *src) = 0; + /** + * Sets a text 16bit palette map. Only used in in EOB II FM-Towns. The map contains 2 entries. + */ + virtual void set16bitColorMap(const uint16 *src) {} + /** * Draws a specific character. * @@ -101,7 +106,7 @@ public: * We use this API, since it's hard to assure dirty rect * handling from outside Screen. */ - virtual void drawChar(uint16 c, byte *dst, int pitch) const = 0; + virtual void drawChar(uint16 c, byte *dst, int pitch, int bpp) const = 0; }; /** @@ -120,7 +125,7 @@ public: int getWidth() const { return _width; } int getCharWidth(uint16 c) const; void setColorMap(const uint8 *src) { _colorMap = src; } - void drawChar(uint16 c, byte *dst, int pitch) const; + void drawChar(uint16 c, byte *dst, int pitch, int) const; private: void unload(); @@ -153,8 +158,9 @@ public: int getHeight() const { return _height; } int getWidth() const { return _width; } int getCharWidth(uint16 c) const; - void setColorMap(const uint8 *src) { _colorMap = src; } - void drawChar(uint16 c, byte *dst, int pitch) const; + void setColorMap(const uint8 *src) { _colorMap8bit = src; } + void set16bitColorMap(const uint16 *src) { _colorMap16bit = src; } + void drawChar(uint16 c, byte *dst, int pitch, int bpp) const; private: void unload(); @@ -163,7 +169,8 @@ private: uint16 *_bitmapOffsets; int _width, _height; - const uint8 *_colorMap; + const uint8 *_colorMap8bit; + const uint16 *_colorMap16bit; int _numGlyphs; @@ -187,7 +194,7 @@ public: int getWidth() const { return _width; } int getCharWidth(uint16 c) const; void setColorMap(const uint8 *src) {} - void drawChar(uint16 c, byte *dst, int pitch) const; + void drawChar(uint16 c, byte *dst, int pitch, int) const; private: void unload(); @@ -221,7 +228,7 @@ public: int getWidth() const; int getCharWidth(uint16 c) const; void setColorMap(const uint8 *src); - virtual void drawChar(uint16 c, byte *dst, int pitch) const; + virtual void drawChar(uint16 c, byte *dst, int pitch, int) const; protected: void unload(); @@ -275,6 +282,11 @@ public: */ void loadVGAPalette(Common::ReadStream &stream, int startIndex, int colors); + /** + * Load a HiColor palette from the given stream. + */ + void loadHiColorPalette(Common::ReadStream &stream, int startIndex, int colors); + /** * Load a EGA palette from the given stream. */ @@ -423,6 +435,7 @@ public: // init virtual bool init(); virtual void setResolution(); + virtual void enableHiColorMode(bool enabled); void updateScreen(); @@ -499,6 +512,7 @@ public: virtual void setTextColorMap(const uint8 *cmap) = 0; void setTextColor(const uint8 *cmap, int a, int b); + void setTextColor16bit(const uint16 *cmap16); const ScreenDim *getScreenDim(int dim) const; void modifyScreenDim(int dim, int x, int y, int w, int h); @@ -570,7 +584,10 @@ public: // RPG specific, this does not belong here void crossFadeRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPage, int dstPage); + void set16bitShadingLevel(int lvl) { _16bitShadingLevel = lvl; } + protected: + void resetPagePtrsAndBuffers(int pageSize); uint8 *getPagePtr(int pageNum); virtual void updateDirtyRects(); void updateDirtyRectsAmiga(); @@ -602,8 +619,11 @@ protected: bool _useSJIS; bool _use16ColorMode; bool _useHiResEGADithering; + bool _useHiColorScreen; bool _isAmiga; Common::RenderMode _renderMode; + int _bytesPerPixel; + int _screenPageSize; uint8 _sjisInvisibleColor; bool _sjisMixedFontMode; @@ -612,8 +632,15 @@ protected: Common::Array _palettes; Palette *_internFadePalette; + uint16 shade16bitColor(uint16 col); + + uint16 *_16bitPalette; + uint16 *_16bitConversionPalette; + uint8 _16bitShadingLevel; + Font *_fonts[FID_NUM]; uint8 _textColorsMap[16]; + uint16 _textColorsMap16bit[2]; uint8 *_decodeShapeBuffer; int _decodeShapeBufferSize; diff --git a/engines/kyra/screen_eob.cpp b/engines/kyra/screen_eob.cpp index 6553ffa76c..88c53fdb7b 100644 --- a/engines/kyra/screen_eob.cpp +++ b/engines/kyra/screen_eob.cpp @@ -46,6 +46,7 @@ Screen_EoB::Screen_EoB(EoBCoreEngine *vm, OSystem *system) : Screen(vm, system, _gfxX = _gfxY = 0; _gfxCol = 0; _dsTempPage = 0; + _convertHiColorBuffer = 0; _dsDiv = 0; _dsRem = 0; _dsScaleTrans = 0; @@ -60,6 +61,7 @@ Screen_EoB::Screen_EoB(EoBCoreEngine *vm, OSystem *system) : Screen(vm, system, Screen_EoB::~Screen_EoB() { delete[] _dsTempPage; + delete[] _convertHiColorBuffer; delete[] _cgaScaleTable; delete[] _egaDitheringTable; delete[] _egaDitheringTempPage; @@ -74,6 +76,9 @@ bool Screen_EoB::init() { _dsTempPage = new uint8[12000]; + if (_vm->gameFlags().platform == Common::kPlatformFMTowns) { + _convertHiColorBuffer = new uint8[SCREEN_H * SCREEN_W]; + } if (_vm->gameFlags().useHiRes && _renderMode == Common::kRenderEGA) { _useHiResEGADithering = true; _egaDitheringTable = new uint8[256]; @@ -120,11 +125,12 @@ void Screen_EoB::setMouseCursor(int x, int y, const byte *shape, const uint8 *ov int colorKey = (_renderMode == Common::kRenderCGA) ? 0 : _cursorColorKey; int scaleFactor = _useHiResEGADithering ? 2 : 1; + int bpp = _useHiColorScreen ? 2 : 1; - uint8 *cursor = new uint8[mouseW * scaleFactor * mouseH * scaleFactor]; + uint8 *cursor = new uint8[mouseW * scaleFactor * bpp * mouseH * scaleFactor]; // We use memset and copyBlockToPage instead of fillRect to make sure that the // color key 0xFF doesn't get converted into EGA color - memset(cursor, colorKey, mouseW * scaleFactor * mouseH * scaleFactor); + memset(cursor, colorKey, mouseW * scaleFactor * bpp * mouseH * scaleFactor); copyBlockToPage(6, 0, 0, mouseW * scaleFactor, mouseH * scaleFactor, cursor); drawShape(6, shape, 0, 0, 0, 2, ovl); CursorMan.showMouse(false); @@ -156,8 +162,13 @@ void Screen_EoB::setMouseCursor(int x, int y, const byte *shape, const uint8 *ov } } } + + // Convert color key to 16 bit after drawing the mouse cursor. + // The cursor has been converted to 16 bit in scale2x(). + colorKey = _16bitConversionPalette ? _16bitConversionPalette[colorKey] : colorKey; + Graphics::PixelFormat pixelFormat = _system->getScreenFormat(); - CursorMan.replaceCursor(cursor, mouseW * scaleFactor, mouseH * scaleFactor, x, y, colorKey); + CursorMan.replaceCursor(cursor, mouseW * scaleFactor, mouseH * scaleFactor, x, y, colorKey, false, &pixelFormat); if (isMouseVisible()) CursorMan.showMouse(true); delete[] cursor; @@ -217,9 +228,13 @@ void Screen_EoB::loadEoBBitmap(const char *file, const uint8 *cgaMapping, int te } } - if (convertToPage == -1) { + if (convertToPage == -1) return; - } else if (convertToPage == 2 && _renderMode == Common::kRenderCGA) { + + if (_16bitPalette) + convertToHiColor(destPage); + + if (convertToPage == 2 && _renderMode == Common::kRenderCGA) { convertPage(destPage, 4, cgaMapping); copyRegion(0, 0, 0, 0, 320, 200, 4, 2, Screen::CR_NO_P_CHECK); } else if (convertToPage == 0) { @@ -262,7 +277,10 @@ void Screen_EoB::convertPage(int srcPage, int dstPage, const uint8 *cgaMapping) } void Screen_EoB::setScreenPalette(const Palette &pal) { - if (_useHiResEGADithering && pal.getNumColors() != 16) { + if (_bytesPerPixel == 2) { + for (int i = 0; i < 4; i++) + createFadeTable16bit((const uint16*)(pal.getData()), &_16bitPalette[i * 256], 0, i * 53); + }else if (_useHiResEGADithering && pal.getNumColors() != 16) { generateEGADitheringTable(pal); } else if (_renderMode == Common::kRenderEGA && pal.getNumColors() == 16) { _screenPalette->copy(pal); @@ -297,7 +315,26 @@ uint8 *Screen_EoB::encodeShape(uint16 x, uint16 y, uint16 w, uint16 h, bool enco if (_renderMode == Common::kRenderEGA && !_useHiResEGADithering) encode8bit = false; - if (_renderMode == Common::kRenderCGA) { + if (_bytesPerPixel == 2) { + shapesize = h * (w << 3) + 4; + shp = new uint8[shapesize]; + memset(shp, 0, shapesize); + uint8 *dst = shp; + + *dst++ = 0; + *dst++ = (h & 0xFF); + *dst++ = (w & 0xFF); + *dst++ = (h & 0xFF); + + w <<= 3; + + for (int i = 0; i < h; ++i) { + memcpy(dst, src, w); + srcLineStart += SCREEN_W; + src = srcLineStart; + dst += w; + } + } else if (_renderMode == Common::kRenderCGA) { if (cgaMapping) generateCGADitheringTables(cgaMapping); shapesize = h * (w << 2) + 4; @@ -485,7 +522,7 @@ void Screen_EoB::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, } va_end(args); - dst += (_dsX1 << 3); + dst += (_dsX1 << (2 + _bytesPerPixel)); int16 dX = x - (_dsX1 << 3); int16 dY = y; int16 dW = _dsX2 - _dsX1; @@ -506,7 +543,7 @@ void Screen_EoB::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int pixelStep = (flags & 1) ? -1 : 1; - if (pixelsPerByte == 1) { + if (pixelsPerByte < 2) { uint16 marginLeft = 0; uint16 marginRight = 0; @@ -557,7 +594,7 @@ void Screen_EoB::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, marginRight = w2 - marginLeft - width; } - dst += (dY * SCREEN_W + dX); + dst += (dY * SCREEN_W * _bytesPerPixel + dX * _bytesPerPixel); uint8 *dstL = dst; if (pageNum == 0 || pageNum == 1) @@ -567,36 +604,45 @@ void Screen_EoB::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int16 xpos = (int16) marginLeft; if (flags & 1) { - for (int i = 0; i < w2; i++) { - if (*src++ == 0) { - i += (*src - 1); - src += (*src - 1); + if (pixelsPerByte == 1) { + for (int i = 0; i < w2; i++) { + if (*src++ == 0) { + i += (*src - 1); + src += (*src - 1); + } } + } else { + src += w2; } src--; } const uint8 *src2 = src; if (xpos) { - do { - uint8 val = (flags & 1) ? *(src - 1) : *src; - while (val && xpos) { - src += pixelStep; - xpos--; - val = (flags & 1) ? *(src - 1) : *src; - } + if (pixelsPerByte == 1) { + do { + uint8 val = (flags & 1) ? *(src - 1) : *src; + while (val && xpos) { + src += pixelStep; + xpos--; + val = (flags & 1) ? *(src - 1) : *src; + } - val = (flags & 1) ? *(src - 1) : *src; - if (!val) { - src += pixelStep; - uint8 bt = (flags & 1) ? src[1] : src[0]; - src += pixelStep; - xpos = xpos - bt; - } - } while (xpos > 0); + val = (flags & 1) ? *(src - 1) : *src; + if (!val) { + src += pixelStep; + uint8 bt = (flags & 1) ? src[1] : src[0]; + src += pixelStep; + xpos = xpos - bt; + } + } while (xpos > 0); + } else { + src += (xpos * pixelStep); + xpos = 0; + } } - dst -= xpos; + dst -= xpos * _bytesPerPixel; xpos += width; while (xpos > 0) { @@ -606,37 +652,45 @@ void Screen_EoB::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, if (m) { drawShapeSetPixel(dst, c); - dst++; + dst += _bytesPerPixel; xpos--; - } else { + } else if (pixelsPerByte) { uint8 len = (flags & 1) ? src[1] : src[0]; - dst += len; + dst += len * _bytesPerPixel; xpos -= len; src += pixelStep; + } else { + dst += _bytesPerPixel; + xpos--; } } xpos += marginRight; if (xpos) { do { - uint8 val = (flags & 1) ? *(src - 1) : *src; - while (val && xpos) { - src += pixelStep; - xpos--; - val = (flags & 1) ? *(src - 1) : *src; - } + if (pixelsPerByte == 1) { + uint8 val = (flags & 1) ? *(src - 1) : *src; + while (val && xpos) { + src += pixelStep; + xpos--; + val = (flags & 1) ? *(src - 1) : *src; + } - val = (flags & 1) ? *(src - 1) : *src; - if (!val) { - src += pixelStep; - uint8 bt = (flags & 1) ? src[1] : src[0]; - src += pixelStep; - xpos = xpos - bt; + val = (flags & 1) ? *(src - 1) : *src; + if (!val) { + src += pixelStep; + uint8 bt = (flags & 1) ? src[1] : src[0]; + src += pixelStep; + xpos = xpos - bt; + } + } else { + src += (xpos * pixelStep); + xpos = 0; } } while (xpos > 0); } - dstL += SCREEN_W; + dstL += SCREEN_W * _bytesPerPixel; dst = dstL; if (flags & 1) src = src2 + 1; @@ -704,7 +758,7 @@ void Screen_EoB::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, if (d < width) width = d; - dst += (dY * SCREEN_W + dX); + dst += (dY * SCREEN_W * _bytesPerPixel + dX * _bytesPerPixel); if (pageNum == 0 || pageNum == 1) addDirtyRect(rX, rY, rW, rH); @@ -753,11 +807,11 @@ void Screen_EoB::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, uint8 col = (pixelsPerByte == 2) ? pal[(in >> shift) & pixelPackingMask] : (*dst & ((trans >> shift) & (pixelPackingMask))) | pal[(in >> shift) & pixelPackingMask]; if (col || pixelsPerByte == 4) drawShapeSetPixel(dst, col); - dst++; + dst += _bytesPerPixel; shift = ((shift - (pixelStep * pixelPacking)) & 7); } src += lineSrcStep; - dst += pitch; + dst += (pitch * _bytesPerPixel); } } } @@ -1167,11 +1221,11 @@ void Screen_EoB::setFadeTable(const uint8 *table) { _dsShapeFadingTable = table; } -void Screen_EoB::createFadeTable(uint8 *palData, uint8 *dst, uint8 rootColor, uint8 weight) { +void Screen_EoB::createFadeTable(const uint8 *palData, uint8 *dst, uint8 rootColor, uint8 weight) { if (!palData) return; - uint8 *src = palData + 3 * rootColor; + const uint8 *src = palData + 3 * rootColor; uint8 r = *src++; uint8 g = *src++; uint8 b = *src; @@ -1189,7 +1243,7 @@ void Screen_EoB::createFadeTable(uint8 *palData, uint8 *dst, uint8 rootColor, ui tmp = (uint16)((*src - b) * weight) << 1; tb = *src++ - ((tmp >> 8) & 0xFF); - uint8 *d = palData + 3; + const uint8 *d = palData + 3; uint16 v = 0xFFFF; uint8 col = rootColor; @@ -1210,6 +1264,65 @@ void Screen_EoB::createFadeTable(uint8 *palData, uint8 *dst, uint8 rootColor, ui } } +void Screen_EoB::createFadeTable16bit(const uint16 *palData, uint16 *dst, uint16 rootColor, uint8 weight) { + uint8 r8 = (rootColor & 0x1f); + uint8 g8 = (rootColor & 0x3E0) >> 5; + uint8 b8 = (rootColor & 0x7C00) >> 10; + + int root_r = r8 << 4; + int root_g = g8 << 4; + int root_b = b8 << 4; + + *dst++ = palData[0]; + + for (uint8 i = 1; i; i++) { + r8 = (palData[i] & 0x1f); + g8 = (palData[i] & 0x3E0) >> 5; + b8 = (palData[i] & 0x7C00) >> 10; + + int red = r8 << 4; + int green = g8 << 4; + int blue = b8 << 4; + + if (red > root_r) { + red -= weight; + if (root_r > red) + red = root_r; + } else { + red += weight; + if (root_r < red) + red = root_r; + } + + if (green > root_g) { + green -= weight; + if (root_g > green) + green = root_g; + } else { + green += weight; + if (root_g < green) + green = root_g; + } + + if (blue > root_b) { + blue -= weight; + if (root_b > blue) + blue = root_b; + } else { + blue += weight; + if (root_b < blue) + blue = root_b; + } + + r8 = red >> 4; + g8 = green >> 4; + b8 = blue >> 4; + + *dst++ = (b8 << 10) | (g8 << 5) | r8; + } + +} + const uint16 *Screen_EoB::getCGADitheringTable(int index) { return !(index & ~1) ? _cgaDitheringTables[index] : 0; } @@ -1218,6 +1331,40 @@ const uint8 *Screen_EoB::getEGADitheringTable() { return _egaDitheringTable; } +void Screen_EoB::convertToHiColor(int page) { + if (!_16bitPalette) + return; + uint16 *dst = (uint16 *)getCPagePtr(page); + memcpy(_convertHiColorBuffer, dst, SCREEN_H * SCREEN_W); + uint8 *src = _convertHiColorBuffer; + for (int s = SCREEN_H * SCREEN_W; s; --s) + *dst++ = _16bitPalette[*src++]; +} + +void Screen_EoB::shadeRect(int x1, int y1, int x2, int y2, int shadingLevel) { + if (!_16bitPalette) + return; + + int l = _16bitShadingLevel; + _16bitShadingLevel = shadingLevel; + + if (_curPage == 0 || _curPage == 1) + addDirtyRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1); + + uint16 *dst = (uint16*)(getPagePtr(_curPage) + y1 * SCREEN_W * _bytesPerPixel + x1 * _bytesPerPixel); + + for (; y1 < y2; ++y1) { + uint16 *ptr = dst; + for (int i = 0; i < x2 - x1; i++) { + *ptr = shade16bitColor(*ptr); + ptr++; + } + dst += SCREEN_W; + } + + _16bitShadingLevel = l; +} + void Screen_EoB::updateDirtyRects() { if (!_useHiResEGADithering) { Screen::updateDirtyRects(); @@ -1260,7 +1407,10 @@ void Screen_EoB::ditherRect(const uint8 *src, uint8 *dst, int dstPitch, int srcW } void Screen_EoB::drawShapeSetPixel(uint8 *dst, uint8 col) { - if ((_renderMode != Common::kRenderCGA && _renderMode != Common::kRenderEGA) || _useHiResEGADithering) { + if (_bytesPerPixel == 2) { + *(uint16*)dst = _16bitPalette[(_dsShapeFadingLevel << 8) + col]; + return; + } else if ((_renderMode != Common::kRenderCGA && _renderMode != Common::kRenderEGA) || _useHiResEGADithering) { if (_dsBackgroundFading) { if (_dsShapeFadingLevel) { col = *dst; @@ -1485,7 +1635,7 @@ int OldDOSFont::getCharWidth(uint16 c) const { return _width; } -void OldDOSFont::drawChar(uint16 c, byte *dst, int pitch) const { +void OldDOSFont::drawChar(uint16 c, byte *dst, int pitch, int bpp) const { static const uint8 renderMaskTable6[] = { 0xFC, 0x00, 0x7E, 0x00, 0x3F, 0x00, 0x1F, 0x80, 0x0F, 0xC0, 0x07, 0xE0, 0x03, 0xF0, 0x01, 0xF8 }; static const uint8 renderMaskTable8[] = { 0xFF, 0x00, 0x7F, 0x80, 0x3F, 0xC0, 0x1F, 0xE0, 0x0F, 0xF0, 0x07, 0xF8, 0x03, 0xFC, 0x01, 0xFE }; @@ -1536,24 +1686,28 @@ void OldDOSFont::drawChar(uint16 c, byte *dst, int pitch) const { } } + pitch *= bpp; const uint8 *src = &_data[_bitmapOffsets[c]]; uint8 *dst2 = dst + pitch; int w = (_width - 1) >> 3; - pitch -= _width; + pitch -= _width * bpp; - uint8 color1 = _colorMap[1]; - uint8 color2 = _colorMap[0]; + uint16 color1 = _colorMap8bit[1]; + uint16 color2 = _colorMap8bit[0]; - static const uint16 cgaColorMask[] = { 0, 0x5555, 0xAAAA, 0xFFFF }; - uint16 cgaMask1 = cgaColorMask[color1 & 3]; - uint16 cgaMask2 = cgaColorMask[color2 & 3]; - - if (_renderMode == Common::kRenderCGA || _renderMode == Common::kRenderEGA) { + if (bpp == 2) { + color1 = _colorMap16bit[1]; + color2 = _colorMap16bit[0]; + } else if (_renderMode == Common::kRenderCGA || _renderMode == Common::kRenderEGA) { color1 &= 0x0F; color2 &= 0x0F; } + static const uint16 cgaColorMask[] = { 0, 0x5555, 0xAAAA, 0xFFFF }; + uint16 cgaMask1 = cgaColorMask[color1 & 3]; + uint16 cgaMask2 = cgaColorMask[color2 & 3]; + int cH = _height; while (cH--) { int cW = w; @@ -1607,12 +1761,19 @@ void OldDOSFont::drawChar(uint16 c, byte *dst, int pitch) const { } if (s & i) { - if (color1) + if (bpp == 2) + *(uint16*)dst = color1; + else if (color1) *dst = color1; - } else if (color2) { - *dst = color2; + } else { + if (bpp == 2) { + if (color2 != 0xFFFF) + *(uint16*)dst = color2; + } else if (color2) { + *dst = color2; + } } - dst++; + dst += bpp; } if (cW) diff --git a/engines/kyra/screen_eob.h b/engines/kyra/screen_eob.h index 42c7e59e28..7c2a31e9d3 100644 --- a/engines/kyra/screen_eob.h +++ b/engines/kyra/screen_eob.h @@ -76,11 +76,14 @@ public: int getRectSize(int w, int h); void setFadeTable(const uint8 *table); - void createFadeTable(uint8 *palData, uint8 *dst, uint8 rootColor, uint8 weight); + void createFadeTable(const uint8 *palData, uint8 *dst, uint8 rootColor, uint8 weight); + void createFadeTable16bit(const uint16 *palData, uint16 *dst, uint16 rootColor, uint8 weight); const uint16 *getCGADitheringTable(int index); const uint8 *getEGADitheringTable(); + void convertToHiColor(int page); + void shadeRect(int x1, int y1, int x2, int y2, int shadingLevel); private: void updateDirtyRects(); void ditherRect(const uint8 *src, uint8 *dst, int dstPitch, int srcW, int srcH, int colorKey = -1); @@ -106,6 +109,7 @@ private: uint8 _shapeOverlay[16]; uint8 *_dsTempPage; + uint8 *_convertHiColorBuffer; uint16 *_cgaDitheringTables[2]; const uint8 *_cgaMappingDefault; -- cgit v1.2.3