mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-28 04:34:50 +00:00
34c5751948
This fixes some slowdowns in Kyra2 with the OpenGL backend for me. Most of the updateScreen calls saved were introduced by us implementing the original behavior of hiding the mouse before drawing onto the screen and showing it again afterwards, since the mouse cursor is not drawn on the game screen in our implementation (and unlike in the original) this is not necessary.
448 lines
11 KiB
C++
448 lines
11 KiB
C++
/* 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/screen_lok.h"
|
|
#include "kyra/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
|