diff options
Diffstat (limited to 'engines/kyra/graphics/screen_lok.cpp')
-rw-r--r-- | engines/kyra/graphics/screen_lok.cpp | 447 |
1 files changed, 447 insertions, 0 deletions
diff --git a/engines/kyra/graphics/screen_lok.cpp b/engines/kyra/graphics/screen_lok.cpp new file mode 100644 index 0000000000..114382b487 --- /dev/null +++ b/engines/kyra/graphics/screen_lok.cpp @@ -0,0 +1,447 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "kyra/graphics/screen_lok.h" +#include "kyra/engine/kyra_lok.h" + +#include "common/system.h" + +#include "graphics/palette.h" + +namespace Kyra { + +Screen_LoK::Screen_LoK(KyraEngine_LoK *vm, OSystem *system) + : Screen(vm, system, _screenDimTable, _screenDimTableCount) { + _vm = vm; + _unkPtr1 = _unkPtr2 = 0; + _bitBlitNum = 0; +} + +Screen_LoK::~Screen_LoK() { + for (int i = 0; i < ARRAYSIZE(_saveLoadPage); ++i) { + delete[] _saveLoadPage[i]; + _saveLoadPage[i] = 0; + } + + for (int i = 0; i < ARRAYSIZE(_saveLoadPageOvl); ++i) { + delete[] _saveLoadPageOvl[i]; + _saveLoadPageOvl[i] = 0; + } + + delete[] _unkPtr1; + delete[] _unkPtr2; +} + +bool Screen_LoK::init() { + if (!Screen::init()) + return false; + + memset(_bitBlitRects, 0, sizeof(_bitBlitRects)); + _bitBlitNum = 0; + memset(_saveLoadPage, 0, sizeof(_saveLoadPage)); + memset(_saveLoadPageOvl, 0, sizeof(_saveLoadPageOvl)); + + _unkPtr1 = new uint8[getRectSize(1, 144)]; + assert(_unkPtr1); + memset(_unkPtr1, 0, getRectSize(1, 144)); + _unkPtr2 = new uint8[getRectSize(1, 144)]; + assert(_unkPtr2); + memset(_unkPtr2, 0, getRectSize(1, 144)); + + return true; +} + +void Screen_LoK::fadeSpecialPalette(int palIndex, int startIndex, int size, int fadeTime) { + if (_vm->gameFlags().platform == Common::kPlatformAmiga) + return; + + assert(_vm->palTable1()[palIndex]); + + Palette tempPal(getPalette(0).getNumColors()); + tempPal.copy(getPalette(0)); + tempPal.copy(_vm->palTable1()[palIndex], 0, size, startIndex); + + fadePalette(tempPal, fadeTime * 18); + + getPalette(0).copy(tempPal, startIndex, size); + setScreenPalette(getPalette(0)); + _system->updateScreen(); +} + +void Screen_LoK::addBitBlitRect(int x, int y, int w, int h) { + if (_bitBlitNum >= kNumBitBlitRects) + error("too many bit blit rects"); + + _bitBlitRects[_bitBlitNum].left = x; + _bitBlitRects[_bitBlitNum].top = y; + _bitBlitRects[_bitBlitNum].right = x + w; + _bitBlitRects[_bitBlitNum].bottom = y + h; + ++_bitBlitNum; +} + +void Screen_LoK::bitBlitRects() { + Common::Rect *cur = _bitBlitRects; + while (_bitBlitNum) { + _bitBlitNum--; + copyRegion(cur->left, cur->top, cur->left, cur->top, cur->width(), cur->height(), 2, 0); + ++cur; + } +} + +void Screen_LoK::savePageToDisk(const char *file, int page) { + if (!_saveLoadPage[page / 2]) { + _saveLoadPage[page / 2] = new uint8[SCREEN_W * SCREEN_H]; + assert(_saveLoadPage[page / 2]); + } + memcpy(_saveLoadPage[page / 2], getPagePtr(page), SCREEN_W * SCREEN_H); + + if (_useOverlays) { + if (!_saveLoadPageOvl[page / 2]) { + _saveLoadPageOvl[page / 2] = new uint8[SCREEN_OVL_SJIS_SIZE]; + assert(_saveLoadPageOvl[page / 2]); + } + + uint8 *srcPage = getOverlayPtr(page); + if (!srcPage) { + warning("trying to save unsupported overlay page %d", page); + return; + } + + memcpy(_saveLoadPageOvl[page / 2], srcPage, SCREEN_OVL_SJIS_SIZE); + } +} + +void Screen_LoK::loadPageFromDisk(const char *file, int page) { + if (!_saveLoadPage[page / 2]) { + warning("trying to restore page %d, but no backup found", page); + return; + } + + copyBlockToPage(page, 0, 0, SCREEN_W, SCREEN_H, _saveLoadPage[page / 2]); + delete[] _saveLoadPage[page / 2]; + _saveLoadPage[page / 2] = 0; + + if (_saveLoadPageOvl[page / 2]) { + uint8 *dstPage = getOverlayPtr(page); + if (!dstPage) { + warning("trying to restore unsupported overlay page %d", page); + return; + } + + memcpy(dstPage, _saveLoadPageOvl[page / 2], SCREEN_OVL_SJIS_SIZE); + delete[] _saveLoadPageOvl[page / 2]; + _saveLoadPageOvl[page / 2] = 0; + } +} + +void Screen_LoK::queryPageFromDisk(const char *file, int page, uint8 *buffer) { + if (!_saveLoadPage[page / 2]) { + warning("trying to query page %d, but no backup found", page); + return; + } + + memcpy(buffer, _saveLoadPage[page / 2], SCREEN_W * SCREEN_H); +} + +void Screen_LoK::deletePageFromDisk(int page) { + delete[] _saveLoadPage[page / 2]; + _saveLoadPage[page / 2] = 0; + + if (_saveLoadPageOvl[page / 2]) { + delete[] _saveLoadPageOvl[page / 2]; + _saveLoadPageOvl[page / 2] = 0; + } +} + +void Screen_LoK::copyBackgroundBlock(int x, int page, int flag) { + if (x < 1) + return; + + int height = 128; + if (flag) + height += 8; + if (!(x & 1)) + ++x; + if (x == 19) + x = 17; + + uint8 *ptr1 = _unkPtr1; + uint8 *ptr2 = _unkPtr2; + int oldVideoPage = _curPage; + _curPage = page; + + int curX = x; + copyRegionToBuffer(_curPage, 8, 8, 8, height, ptr2); + for (int i = 0; i < 19; ++i) { + int tempX = curX + 1; + copyRegionToBuffer(_curPage, tempX << 3, 8, 8, height, ptr1); + copyBlockToPage(_curPage, tempX << 3, 8, 8, height, ptr2); + int newXPos = curX + x; + if (newXPos > 37) + newXPos = newXPos % 38; + + tempX = newXPos + 1; + copyRegionToBuffer(_curPage, tempX << 3, 8, 8, height, ptr2); + copyBlockToPage(_curPage, tempX << 3, 8, 8, height, ptr1); + curX += x * 2; + if (curX > 37) { + curX = curX % 38; + } + } + _curPage = oldVideoPage; +} + +void Screen_LoK::copyBackgroundBlock2(int x) { + copyBackgroundBlock(x, 4, 1); +} + +void Screen_LoK::setTextColorMap(const uint8 *cmap) { + setTextColor(cmap, 0, 11); +} + +int Screen_LoK::getRectSize(int x, int y) { + if (x < 1) + x = 1; + else if (x > 40) + x = 40; + + if (y < 1) + y = 1; + else if (y > 200) + y = 200; + + return ((x * y) << 3); +} + +void Screen_LoK::postProcessCursor(uint8 *data, int width, int height, int pitch) { + if (_vm->gameFlags().platform == Common::kPlatformAmiga && _interfacePaletteEnabled) { + pitch -= width; + + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + if (*data != _cursorColorKey) + *data += 32; + ++data; + } + + data += pitch; + } + } +} + +#pragma mark - + +Screen_LoK_16::Screen_LoK_16(KyraEngine_LoK *vm, OSystem *system) : Screen_LoK(vm, system) { + memset(_paletteDither, 0, sizeof(_paletteDither)); +} + +void Screen_LoK_16::setScreenPalette(const Palette &pal) { + _screenPalette->copy(pal); + + for (int i = 0; i < 256; ++i) + paletteMap(i, pal[i * 3 + 0] << 2, pal[i * 3 + 1] << 2, pal[i * 3 + 2] << 2); + + set16ColorPalette(_palette16); + _forceFullUpdate = true; +} + +void Screen_LoK_16::fadePalette(const Palette &pal, int delay, const UpdateFunctor *upFunc) { + uint8 notBlackFlag = 0; + for (int i = 0; i < 768; ++i) { + if ((*_screenPalette)[i]) + notBlackFlag |= 1; + if (pal[i]) + notBlackFlag |= 2; + } + + if (notBlackFlag == 1 || notBlackFlag == 2) { + bool upFade = false; + + for (int i = 0; i < 768; ++i) { + if ((*_screenPalette)[i] < pal[i]) { + upFade = true; + break; + } + } + + if (upFade) { + for (int i = 0; i < 256; ++i) + paletteMap(i, pal[i * 3 + 0] << 2, pal[i * 3 + 1] << 2, pal[i * 3 + 2] << 2); + _forceFullUpdate = true; + } + + uint8 color16Palette[16 * 3]; + + if (upFade) + memset(color16Palette, 0, sizeof(color16Palette)); + else + memcpy(color16Palette, _palette16, sizeof(color16Palette)); + + set16ColorPalette(color16Palette); + updateScreen(); + + for (int i = 0; i < 16; ++i) { + set16ColorPalette(color16Palette); + + for (int k = 0; k < 48; ++k) { + if (upFade) { + if (color16Palette[k] < _palette16[k]) + ++color16Palette[k]; + } else { + if (color16Palette[k] > 0) + --color16Palette[k]; + } + } + + if (upFunc && upFunc->isValid()) + (*upFunc)(); + else + _system->updateScreen(); + + _vm->delay((delay >> 5) * _vm->tickLength()); + } + } + + setScreenPalette(pal); +} + +void Screen_LoK_16::getFadeParams(const Palette &pal, int delay, int &delayInc, int &diff) { + error("Screen_LoK_16::getFadeParams called"); +} + +int Screen_LoK_16::fadePalStep(const Palette &pal, int diff) { + error("Screen_LoK_16::fadePalStep called"); + return 0; // for compilers that don't support NORETURN +} + +void Screen_LoK_16::paletteMap(uint8 idx, int r, int g, int b) { + const int red = r; + const int green = g; + const int blue = b; + + uint16 rgbDiff = 1000; + int rDiff = 0, gDiff = 0, bDiff = 0; + + int index1 = -1; + + for (int i = 0; i < 16; ++i) { + const int realR = _palette16[i * 3 + 0] << 4; + const int realG = _palette16[i * 3 + 1] << 4; + const int realB = _palette16[i * 3 + 2] << 4; + + uint16 diff = ABS(r - realR) + ABS(g - realG) + ABS(b - realB); + + if (diff < rgbDiff) { + rgbDiff = diff; + index1 = i; + + rDiff = r - realR; + gDiff = g - realG; + bDiff = b - realB; + } + } + + r = rDiff / 4 + red; + g = gDiff / 4 + green; + b = bDiff / 4 + blue; + + rgbDiff = 1000; + int index2 = -1; + + for (int i = 0; i < 16; ++i) { + const int realR = _palette16[i * 3 + 0] << 4; + const int realG = _palette16[i * 3 + 1] << 4; + const int realB = _palette16[i * 3 + 2] << 4; + + uint16 diff = ABS(r - realR) + ABS(g - realG) + ABS(b - realB); + + if (diff < rgbDiff) { + rgbDiff = diff; + index2 = i; + } + } + + _paletteDither[idx].bestMatch = index1; + _paletteDither[idx].invertMatch = index2; +} + +void Screen_LoK_16::convertTo16Colors(uint8 *page, int w, int h, int pitch, int keyColor) { + const int rowAdd = pitch * 2 - w; + + uint8 *row1 = page; + uint8 *row2 = page + pitch; + + for (int i = 0; i < h; i += 2) { + for (int k = 0; k < w; k += 2) { + if (keyColor == -1 || keyColor != *row1) { + const PaletteDither &dither = _paletteDither[*row1]; + + *row1++ = dither.bestMatch; + *row1++ = dither.invertMatch; + *row2++ = dither.invertMatch; + *row2++ = dither.bestMatch; + } else { + row1 += 2; + row2 += 2; + } + } + + row1 += rowAdd; + row2 += rowAdd; + } +} + +void Screen_LoK_16::mergeOverlay(int x, int y, int w, int h) { + byte *dst = _sjisOverlayPtrs[0] + y * 640 + x; + + // We do a game screen rect to 16 color dithering here. It is + // important that we do not dither the overlay, since else the + // japanese fonts will look wrong. + convertTo16Colors(dst, w, h, 640); + + const byte *src = _sjisOverlayPtrs[1] + y * 640 + x; + + int add = 640 - w; + + while (h--) { + for (x = 0; x < w; ++x, ++dst) { + byte col = *src++; + if (col != _sjisInvisibleColor) + *dst = _paletteDither[col].bestMatch; + } + dst += add; + src += add; + } +} + +void Screen_LoK_16::set16ColorPalette(const uint8 *pal) { + uint8 palette[16 * 3]; + for (int i = 0; i < 16; ++i) { + palette[i * 3 + 0] = (pal[i * 3 + 0] * 0xFF) / 0x0F; + palette[i * 3 + 1] = (pal[i * 3 + 1] * 0xFF) / 0x0F; + palette[i * 3 + 2] = (pal[i * 3 + 2] * 0xFF) / 0x0F; + } + + _system->getPaletteManager()->setPalette(palette, 0, 16); +} + +} // End of namespace Kyra |