mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-10 11:51:52 +00:00
4e5ca90efc
- make the animations a bit faster to reduce the amount of time for which the engine is blocked - separate the display updates from the engine delays - register user input during the animations
2055 lines
54 KiB
C++
2055 lines
54 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.
|
|
*
|
|
*/
|
|
|
|
|
|
#if !defined(ENABLE_EOB)
|
|
#include "kyra/graphics/screen.h"
|
|
#endif
|
|
|
|
#ifdef ENABLE_EOB
|
|
|
|
#include "kyra/engine/eobcommon.h"
|
|
#include "kyra/resource/resource.h"
|
|
#include "kyra/engine/util.h"
|
|
#include "kyra/graphics/screen_eob_segacd.h"
|
|
|
|
#include "common/system.h"
|
|
#include "common/memstream.h"
|
|
|
|
#include "graphics/cursorman.h"
|
|
#include "graphics/palette.h"
|
|
#include "graphics/sjis.h"
|
|
|
|
#define EXPLOSION_ANIM_DURATION 750
|
|
#define VORTEX_ANIM_DURATION 750
|
|
|
|
namespace Kyra {
|
|
|
|
Screen_EoB::Screen_EoB(EoBCoreEngine *vm, OSystem *system) : Screen(vm, system, _screenDimTable, _screenDimTableCount), _cursorColorKey16Bit(0x8000) {
|
|
_dsBackgroundFading = false;
|
|
_dsShapeFadingLevel = 0;
|
|
_dsBackgroundFadingXOffs = 0;
|
|
_dsShapeFadingTable = 0;
|
|
_dsX1 = _dsX2 = _dsY1 = _dsY2 = 0;
|
|
_gfxX = _gfxY = 0;
|
|
_gfxCol = 0;
|
|
_dsTempPage = 0;
|
|
_shpBuffer = _convertHiColorBuffer = 0;
|
|
_dsDiv = 0;
|
|
_dsRem = 0;
|
|
_dsScaleTrans = 0;
|
|
_cgaScaleTable = 0;
|
|
_gfxMaxY = 0;
|
|
_egaDitheringTable = 0;
|
|
_egaDitheringTempPage = 0;
|
|
_cgaMappingDefault = 0;
|
|
_cgaDitheringTables[0] = _cgaDitheringTables[1] = 0;
|
|
_useHiResEGADithering = false;
|
|
_cyclePalette = 0;
|
|
_cpsFilePattern = "%s.";
|
|
_activePalCycle = 0;
|
|
_segaRenderer = 0;
|
|
_segaAnimator = 0;
|
|
_segaCustomPalettes = 0;
|
|
_palFaders = 0;
|
|
_defaultRenderBuffer = 0;
|
|
_specialColorReplace = false;
|
|
memset(_segaCurPalette, 0, sizeof(_segaCurPalette));
|
|
}
|
|
|
|
Screen_EoB::~Screen_EoB() {
|
|
delete[] _dsTempPage;
|
|
delete[] _shpBuffer;
|
|
delete[] _convertHiColorBuffer;
|
|
delete[] _cgaScaleTable;
|
|
delete[] _egaDitheringTable;
|
|
delete[] _egaDitheringTempPage;
|
|
delete[] _cgaDitheringTables[0];
|
|
delete[] _cgaDitheringTables[1];
|
|
delete[] _cyclePalette;
|
|
delete[] _segaCustomPalettes;
|
|
delete[] _palFaders;
|
|
delete[] _defaultRenderBuffer;
|
|
delete _segaRenderer;
|
|
delete _segaAnimator;
|
|
}
|
|
|
|
bool Screen_EoB::init() {
|
|
if (Screen::init()) {
|
|
int temp;
|
|
_gfxMaxY = _vm->staticres()->loadRawData(kEoBBaseExpObjectY, temp);
|
|
_dsTempPage = new uint8[12000];
|
|
|
|
if (_vm->gameFlags().platform == Common::kPlatformFMTowns) {
|
|
_shpBuffer = new uint8[SCREEN_H * SCREEN_W];
|
|
_convertHiColorBuffer = new uint8[SCREEN_H * SCREEN_W];
|
|
enableHiColorMode(true);
|
|
setFontStyles(FID_SJIS_FNT, Font::kStyleFat);
|
|
_fonts[FID_SJIS_LARGE_FNT] = new SJISFontLarge(_sjisFontShared);
|
|
} else if (_vm->game() == GI_EOB1 && _vm->gameFlags().platform == Common::kPlatformPC98) {
|
|
_fonts[FID_SJIS_FNT] = new SJISFontEoB1PC98(_sjisFontShared, /*12,*/ _vm->staticres()->loadRawDataBe16(kEoB1Ascii2SjisTable1, temp), _vm->staticres()->loadRawDataBe16(kEoB1Ascii2SjisTable2, temp));
|
|
}
|
|
|
|
if (_vm->gameFlags().useHiRes && _renderMode == Common::kRenderEGA) {
|
|
_useHiResEGADithering = true;
|
|
_egaDitheringTable = new uint8[256];
|
|
_egaDitheringTempPage = new uint8[SCREEN_W * 2 * SCREEN_H * 2];
|
|
for (int i = 0; i < 256; i++)
|
|
_egaDitheringTable[i] = i & 0x0F;
|
|
} else if (_renderMode == Common::kRenderCGA) {
|
|
_cgaMappingDefault = _vm->staticres()->loadRawData(kEoB1CgaMappingDefault, temp);
|
|
_cgaDitheringTables[0] = new uint16[256];
|
|
memset(_cgaDitheringTables[0], 0, 256 * sizeof(uint16));
|
|
_cgaDitheringTables[1] = new uint16[256];
|
|
memset(_cgaDitheringTables[1], 0, 256 * sizeof(uint16));
|
|
|
|
_cgaScaleTable = new uint8[256];
|
|
memset(_cgaScaleTable, 0, 256 * sizeof(uint8));
|
|
for (int i = 0; i < 256; i++)
|
|
_cgaScaleTable[i] = ((i & 0xF0) >> 2) | (i & 0x03);
|
|
} else if (_vm->gameFlags().platform == Common::kPlatformSegaCD) {
|
|
sega_initGraphics();
|
|
_segaCustomPalettes = new uint16[128];
|
|
_palFaders = new PaletteFader[4];
|
|
_defaultRenderBufferSize = SCREEN_W * _screenHeight;
|
|
_defaultRenderBuffer = new uint8[_defaultRenderBufferSize];
|
|
memset(_defaultRenderBuffer, 0, _defaultRenderBufferSize);
|
|
sega_setTextBuffer(0, 0);
|
|
memset(_segaCustomPalettes, 0, 128 * sizeof(uint16));
|
|
}
|
|
|
|
_useShapeShading = (_bytesPerPixel != 2 && !_isAmiga && !_isSegaCD && !_use16ColorMode && _renderMode != Common::kRenderCGA && _renderMode != Common::kRenderEGA) || _useHiResEGADithering;
|
|
|
|
static const char *cpsExt[] = { "CPS", "EGA", "SHP", "BIN" };
|
|
int ci = 0;
|
|
if (_vm->game() == GI_EOB1) {
|
|
if (_vm->gameFlags().platform == Common::kPlatformPC98) {
|
|
_cyclePalette = new uint8[48];
|
|
memset(_cyclePalette, 0, 48);
|
|
ci = 3;
|
|
} else if (_renderMode == Common::kRenderEGA || _renderMode == Common::kRenderCGA) {
|
|
ci = 1;
|
|
}
|
|
} else if (_vm->gameFlags().platform == Common::kPlatformFMTowns) {
|
|
ci = 2;
|
|
}
|
|
_cpsFilePattern += cpsExt[ci];
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void Screen_EoB::setClearScreenDim(int dim) {
|
|
setScreenDim(dim);
|
|
clearCurDim();
|
|
}
|
|
|
|
void Screen_EoB::clearCurDim() {
|
|
static const uint8 amigaColorMap[16] = { 0x00, 0x06, 0x1d, 0x1b, 0x1a, 0x17, 0x18, 0x0e, 0x19, 0x1c, 0x1c, 0x1e, 0x13, 0x0a, 0x11, 0x1f };
|
|
fillRect(_curDim->sx << 3, _curDim->sy, ((_curDim->sx + _curDim->w) << 3) - 1, (_curDim->sy + _curDim->h) - 1, _isAmiga ? amigaColorMap[_curDim->unkA] : _use16ColorMode ? 0 : _curDim->unkA);
|
|
}
|
|
|
|
void Screen_EoB::clearCurDimOvl(int pageNum) {
|
|
if (pageNum > 1 || !_useOverlays)
|
|
return;
|
|
addDirtyRect(_curDim->sx << 3, _curDim->sy, _curDim->w << 3, _curDim->h);
|
|
clearOverlayRect(pageNum, _curDim->sx << 3, _curDim->sy, _curDim->w << 3, _curDim->h);
|
|
}
|
|
|
|
void Screen_EoB::setMouseCursor(int x, int y, const byte *shape) {
|
|
setMouseCursor(x, y, shape, 0);
|
|
}
|
|
|
|
void Screen_EoB::setMouseCursor(int x, int y, const byte *shape, const uint8 *ovl) {
|
|
if (!shape)
|
|
return;
|
|
|
|
int mouseW = (shape[2] << 3);
|
|
int mouseH = (shape[3]);
|
|
int colorKey = (_renderMode == Common::kRenderCGA) ? 0 : (_bytesPerPixel == 2 ? _cursorColorKey16Bit : _cursorColorKey);
|
|
|
|
int scaleFactor = _vm->gameFlags().useHiRes ? 2 : 1;
|
|
int bpp = _useHiColorScreen ? 2 : 1;
|
|
|
|
uint8 *cursor = new uint8[mouseW * scaleFactor * bpp * mouseH * scaleFactor];
|
|
|
|
if (_bytesPerPixel == 2) {
|
|
for (int s = mouseW * scaleFactor * bpp * mouseH * scaleFactor; s; s -= 2)
|
|
*(uint16*)(cursor + s - 2) = colorKey;
|
|
} else {
|
|
// We don't use fillRect here to make sure that the color key 0xFF doesn't get converted into EGA color
|
|
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);
|
|
|
|
if (_useHiResEGADithering)
|
|
ditherRect(getCPagePtr(6), cursor, mouseW * scaleFactor, mouseW, mouseH, colorKey);
|
|
else if (_useHiColorScreen)
|
|
scale2x<uint16, uint32>(cursor, mouseW * scaleFactor, getCPagePtr(6), SCREEN_W, mouseW, mouseH);
|
|
else if (_vm->gameFlags().useHiRes)
|
|
scale2x<uint8, uint16>(cursor, mouseW * scaleFactor, getCPagePtr(6), SCREEN_W, mouseW, mouseH);
|
|
else
|
|
copyRegionToBuffer(6, 0, 0, mouseW, mouseH, cursor);
|
|
|
|
// Mouse cursor post processing for EOB II Amiga
|
|
if (_dualPaletteModeSplitY) {
|
|
int len = mouseW * mouseH;
|
|
while (--len > -1)
|
|
cursor[len] |= 0x20;
|
|
}
|
|
|
|
// Mouse cursor post processing for CGA mode. Unlike the original (which uses drawShape for the mouse cursor)
|
|
// the cursor manager cannot know whether a pixel value of 0 is supposed to be black or transparent. Thus, we
|
|
// go over the transparency mask again and turn the black pixels to color 4.
|
|
if (_renderMode == Common::kRenderCGA) {
|
|
const uint8 *maskTbl = shape + 4 + ((mouseW * mouseH) >> 2);
|
|
uint8 *dst = cursor;
|
|
uint8 trans = 0;
|
|
uint8 shift = 6;
|
|
|
|
uint16 mH = mouseH;
|
|
while (mH--) {
|
|
uint16 mW = mouseW;
|
|
while (mW--) {
|
|
if (shift == 6)
|
|
trans = *maskTbl++;
|
|
if (!*dst && !((trans >> shift) & 3))
|
|
*dst = 4;
|
|
dst++;
|
|
shift = (shift - 2) & 7;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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 * scaleFactor, y * scaleFactor, colorKey, false, &pixelFormat);
|
|
if (isMouseVisible())
|
|
CursorMan.showMouse(true);
|
|
delete[] cursor;
|
|
|
|
// makes sure that the cursor is drawn
|
|
// we do not use Screen::updateScreen here
|
|
// so we can be sure that changes to page 0
|
|
// are NOT updated on the real screen here
|
|
_system->updateScreen();
|
|
}
|
|
|
|
void Screen_EoB::loadFileDataToPage(Common::SeekableReadStream *s, int pageNum, uint32 size) {
|
|
s->read(_pagePtrs[pageNum], size);
|
|
}
|
|
|
|
void Screen_EoB::printShadedText(const char *string, int x, int y, int col1, int col2, int shadowCol, int pitch) {
|
|
if (_isSegaCD && shadowCol) {
|
|
printText(string, x + 1, y + 1, shadowCol, 0, pitch);
|
|
} else if (!_isSegaCD && _vm->gameFlags().lang != Common::JA_JPN) {
|
|
printText(string, x - 1, y, shadowCol, col2);
|
|
printText(string, x, y + 1, shadowCol, 0);
|
|
printText(string, x - 1, y + 1, shadowCol, 0);
|
|
} else if (!_isSegaCD && col2) {
|
|
fillRect(x, y, x + getTextWidth(string) - 1, y + getFontHeight() - 1, col2);
|
|
}
|
|
|
|
if (_vm->gameFlags().use16ColorMode)
|
|
setFontStyles(_currentFont, Font::kStyleLeftShadow);
|
|
|
|
printText(string, x, y, col1, 0, pitch);
|
|
|
|
if (_vm->gameFlags().use16ColorMode)
|
|
setFontStyles(_currentFont, Font::kStyleNone);
|
|
}
|
|
|
|
void Screen_EoB::loadShapeSetBitmap(const char *file, int tempPage, int destPage) {
|
|
loadEoBBitmap(file, _cgaMappingDefault, tempPage, destPage, -1);
|
|
_curPage = 2;
|
|
}
|
|
|
|
void Screen_EoB::loadBitmap(const char *filename, int tempPage, int dstPage, Palette *pal, bool skip) {
|
|
if (!scumm_stricmp(filename + strlen(filename) - 3, "BIN")) {
|
|
Common::SeekableReadStream *str = _vm->resource()->createReadStream(filename);
|
|
if (!str)
|
|
error("Screen_EoB::loadBitmap(): Failed to load file '%s'", filename);
|
|
str->skip(2);
|
|
uint16 imgSize = str->readUint16LE();
|
|
assert(imgSize == str->size() - 4);
|
|
uint8 *buf = new uint8[MAX<uint16>(imgSize, SCREEN_W * SCREEN_H)];
|
|
str->read(buf, imgSize);
|
|
delete str;
|
|
|
|
decodeBIN(buf, _pagePtrs[dstPage], imgSize);
|
|
if (!skip)
|
|
decodePC98PlanarBitmap(_pagePtrs[dstPage], buf, SCREEN_W * SCREEN_H);
|
|
|
|
delete[] buf;
|
|
} else {
|
|
Screen::loadBitmap(filename, tempPage, dstPage, pal);
|
|
}
|
|
|
|
if (_isAmiga && !skip) {
|
|
Common::SeekableReadStream *str = _vm->resource()->createReadStream(filename);
|
|
str->skip(4);
|
|
uint32 imgSize = str->readUint32LE();
|
|
|
|
if (_vm->game() == GI_EOB1 && (dstPage == 3 || dstPage == 4) && imgSize == 40064) {
|
|
// Yay, this is where EOB1 Amiga hides the palette data
|
|
loadPalette(_pagePtrs[dstPage] + 40000, *_palettes[0], 64);
|
|
_palettes[0]->fill(0, 1, 0);
|
|
} else if (_vm->game() == GI_EOB2) {
|
|
uint16 palSize = str->readUint16LE();
|
|
// EOB II Amiga CPS files may contain more than one palette (each one 64 bytes,
|
|
// one after the other). We load them all...
|
|
if (pal && palSize) {
|
|
for (int i = 1; i <= palSize >> 6; ++i)
|
|
_palettes[i]->loadAmigaPalette(*str, 0, 32);
|
|
}
|
|
}
|
|
|
|
Screen::convertAmigaGfx(getPagePtr(dstPage), 320, 200);
|
|
delete str;
|
|
}
|
|
}
|
|
|
|
void Screen_EoB::loadEoBBitmap(const char *file, const uint8 *cgaMapping, int tempPage, int destPage, int convertToPage) {
|
|
Common::String tmp = Common::String::format(_cpsFilePattern.c_str(), file);
|
|
Common::SeekableReadStream *s = _vm->resource()->createReadStream(tmp);
|
|
bool loadAlternative = false;
|
|
|
|
if (_vm->gameFlags().platform == Common::kPlatformFMTowns) {
|
|
if (!s)
|
|
error("Screen_EoB::loadEoBBitmap(): Failed to load file '%s'", file);
|
|
s->read(_shpBuffer, s->size());
|
|
decodeSHP(_shpBuffer, destPage);
|
|
|
|
} else if (s) {
|
|
// This additional check is necessary since some localized versions of EOB II seem to contain invalid (size zero) cps files
|
|
if (s->size() == 0) {
|
|
loadAlternative = true;
|
|
|
|
// This check is due to EOB II Amiga German. That version simply checks
|
|
// for certain file names which aren't actual CPS files. These files use
|
|
// a different format and compression type. I check the header size
|
|
// info to identify these.
|
|
} else if (_vm->gameFlags().platform == Common::kPlatformAmiga) {
|
|
// Tolerance for size mismatches up to 2 bytes is needed in some cases
|
|
if ((((s->readUint16LE()) + 5) & ~3) != (((s->size()) + 3) & ~3))
|
|
loadAlternative = true;
|
|
}
|
|
|
|
if (!loadAlternative)
|
|
loadBitmap(tmp.c_str(), tempPage, destPage, _vm->gameFlags().platform == Common::kPlatformAmiga ? _palettes[0] : 0);
|
|
|
|
} else {
|
|
loadAlternative = true;
|
|
}
|
|
|
|
delete s;
|
|
|
|
if (loadAlternative) {
|
|
if (_vm->game() == GI_EOB1) {
|
|
tmp.insertChar('1', tmp.size() - 4);
|
|
loadBitmap(tmp.c_str(), tempPage, destPage, 0);
|
|
|
|
} else if (_vm->gameFlags().platform == Common::kPlatformAmiga) {
|
|
loadSpecialAmigaCPS(tmp.c_str(), destPage, true);
|
|
|
|
} else {
|
|
tmp.setChar('X', 0);
|
|
s = _vm->resource()->createReadStream(tmp);
|
|
|
|
if (!s)
|
|
error("Screen_EoB::loadEoBBitmap(): Failed to load file '%s'", file);
|
|
|
|
s->seek(768);
|
|
loadFileDataToPage(s, destPage, 64000);
|
|
delete s;
|
|
}
|
|
}
|
|
|
|
if (convertToPage == -1)
|
|
return;
|
|
|
|
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) {
|
|
convertPage(destPage, 2, cgaMapping);
|
|
copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
|
|
} else {
|
|
convertPage(destPage, convertToPage, cgaMapping);
|
|
}
|
|
}
|
|
|
|
void Screen_EoB::convertPage(int srcPage, int dstPage, const uint8 *cgaMapping) {
|
|
uint8 *src = getPagePtr(srcPage);
|
|
uint8 *dst = getPagePtr(dstPage);
|
|
if (src == dst)
|
|
return;
|
|
|
|
if (_renderMode == Common::kRenderCGA) {
|
|
if (cgaMapping)
|
|
generateCGADitheringTables(cgaMapping);
|
|
|
|
uint16 *d = (uint16 *)dst;
|
|
uint8 tblSwitch = 0;
|
|
for (int height = SCREEN_H; height; height--) {
|
|
const uint16 *table = _cgaDitheringTables[(tblSwitch++) & 1];
|
|
for (int width = SCREEN_W / 2; width; width--) {
|
|
WRITE_LE_UINT16(d++, table[((src[1] & 0x0F) << 4) | (src[0] & 0x0F)]);
|
|
src += 2;
|
|
}
|
|
}
|
|
} else if (_renderMode == Common::kRenderEGA && !_useHiResEGADithering) {
|
|
uint32 len = SCREEN_W * SCREEN_H;
|
|
while (len--)
|
|
*dst++ = *src++ & 0x0F;
|
|
} else {
|
|
copyPage(srcPage, dstPage);
|
|
}
|
|
|
|
if (dstPage == 0 || dstPage == 1)
|
|
_forceFullUpdate = true;
|
|
}
|
|
|
|
void Screen_EoB::setScreenPalette(const Palette &pal) {
|
|
if (_bytesPerPixel == 2) {
|
|
for (int i = 0; i < 4; i++)
|
|
createFadeTable16bit((const uint16*)(pal.getData()), &_16bitPalette[i * 256], 0, i * 85);
|
|
} else if (_useHiResEGADithering && pal.getNumColors() != 16) {
|
|
generateEGADitheringTable(pal);
|
|
} else if (_isSegaCD || (_renderMode == Common::kRenderEGA && pal.getNumColors() == 16)) {
|
|
_paletteChanged = true;
|
|
_screenPalette->copy(pal);
|
|
_system->getPaletteManager()->setPalette(_screenPalette->getData(), 0, _screenPalette->getNumColors());
|
|
} else if (_renderMode != Common::kRenderCGA && _renderMode != Common::kRenderEGA) {
|
|
Screen::setScreenPalette(pal);
|
|
}
|
|
}
|
|
|
|
void Screen_EoB::getRealPalette(int num, uint8 *dst) {
|
|
if (_renderMode == Common::kRenderCGA || _renderMode == Common::kRenderEGA) {
|
|
const uint8 *pal = _screenPalette->getData();
|
|
for (int i = 0; i < 16; ++i) {
|
|
dst[0] = (pal[0] << 2) | (pal[0] & 3);
|
|
dst[1] = (pal[1] << 2) | (pal[1] & 3);
|
|
dst[2] = (pal[2] << 2) | (pal[2] & 3);
|
|
dst += 3;
|
|
pal += 3;
|
|
}
|
|
} else {
|
|
Screen::getRealPalette(num, dst);
|
|
}
|
|
}
|
|
|
|
uint8 *Screen_EoB::encodeShape(uint16 x, uint16 y, uint16 w, uint16 h, bool encode8bit, const uint8 *cgaMapping) {
|
|
uint8 *shp = 0;
|
|
uint16 shapesize = 0;
|
|
|
|
uint8 *srcLineStart = getPagePtr(_curPage | 1) + y * 320 + (x << 3);
|
|
uint8 *src = srcLineStart;
|
|
|
|
if (_use16ColorMode || (_renderMode == Common::kRenderEGA && !_useHiResEGADithering))
|
|
encode8bit = false;
|
|
|
|
if (_bytesPerPixel == 2 && encode8bit) {
|
|
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;
|
|
shp = new uint8[shapesize];
|
|
memset(shp, 0, shapesize);
|
|
uint8 *dst = shp;
|
|
|
|
*dst++ = 4;
|
|
*dst++ = (h & 0xFF);
|
|
*dst++ = (w & 0xFF);
|
|
*dst++ = (h & 0xFF);
|
|
|
|
uint8 *dst2 = dst + (h * (w << 1));
|
|
|
|
uint8 tblSwitch = 0;
|
|
uint16 h1 = h;
|
|
while (h1--) {
|
|
uint16 w1 = w << 1;
|
|
const uint16 *table = _cgaDitheringTables[(tblSwitch++) & 1];
|
|
|
|
while (w1--) {
|
|
uint16 p0 = table[((src[1] & 0x0F) << 4) | (src[0] & 0x0F)];
|
|
uint16 p1 = table[((src[3] & 0x0F) << 4) | (src[2] & 0x0F)];
|
|
|
|
*dst++ = ((p0 & 0x0003) << 6) | ((p0 & 0x0300) >> 4) | ((p1 & 0x0003) << 2) | ((p1 & 0x0300) >> 8);
|
|
|
|
uint8 msk = 0;
|
|
for (int i = 0; i < 4; i++) {
|
|
if (!src[3 - i])
|
|
msk |= (3 << (i << 1));
|
|
}
|
|
*dst2++ = msk;
|
|
src += 4;
|
|
}
|
|
srcLineStart += SCREEN_W;
|
|
src = srcLineStart;
|
|
}
|
|
|
|
} else if (encode8bit) {
|
|
uint16 h1 = h;
|
|
while (h1--) {
|
|
uint8 *lineEnd = src + (w << 3);
|
|
do {
|
|
if (!*src++) {
|
|
shapesize++;
|
|
uint8 *startZeroPos = src;
|
|
while (src != lineEnd && *src == 0)
|
|
src++;
|
|
|
|
uint16 numZero = src - startZeroPos + 1;
|
|
if (numZero >> 8)
|
|
shapesize += 2;
|
|
}
|
|
shapesize++;
|
|
} while (src != lineEnd);
|
|
|
|
srcLineStart += SCREEN_W;
|
|
src = srcLineStart;
|
|
}
|
|
|
|
shapesize += 4;
|
|
|
|
shp = new uint8[shapesize];
|
|
memset(shp, 0, shapesize);
|
|
uint8 *dst = shp;
|
|
|
|
*dst++ = 1;
|
|
*dst++ = (h & 0xFF);
|
|
*dst++ = (w & 0xFF);
|
|
*dst++ = (h & 0xFF);
|
|
|
|
srcLineStart = getPagePtr(_curPage | 1) + y * 320 + (x << 3);
|
|
src = srcLineStart;
|
|
|
|
h1 = h;
|
|
while (h1--) {
|
|
uint8 *lineEnd = src + (w << 3);
|
|
do {
|
|
uint8 val = *src++;
|
|
if (!val) {
|
|
*dst++ = 0;
|
|
uint8 *startZeroPos = src;
|
|
|
|
while (src != lineEnd && *src == 0)
|
|
src++;
|
|
|
|
uint16 numZero = src - startZeroPos + 1;
|
|
if (numZero >> 8) {
|
|
*dst++ = 255;
|
|
*dst++ = 0;
|
|
numZero -= 255;
|
|
}
|
|
val = numZero & 0xFF;
|
|
}
|
|
*dst++ = val;
|
|
} while (src != lineEnd);
|
|
|
|
srcLineStart += SCREEN_W;
|
|
src = srcLineStart;
|
|
}
|
|
|
|
} else {
|
|
uint8 nib = 0, col = 0;
|
|
uint8 *colorMap = 0;
|
|
|
|
if (_renderMode != Common::kRenderEGA || _useHiResEGADithering) {
|
|
colorMap = new uint8[0x100];
|
|
memset(colorMap, 0xFF, 0x100);
|
|
}
|
|
|
|
shapesize = h * (w << 2) + 20;
|
|
shp = new uint8[shapesize];
|
|
memset(shp, 0, shapesize);
|
|
uint8 *dst = shp;
|
|
|
|
*dst++ = 2;
|
|
*dst++ = (h & 0xFF);
|
|
*dst++ = (w & 0xFF);
|
|
*dst++ = (h & 0xFF);
|
|
|
|
if (_renderMode != Common::kRenderEGA || _useHiResEGADithering) {
|
|
memset(dst, 0xFF, 0x10);
|
|
} else {
|
|
for (int i = 0; i < 16; i++)
|
|
dst[i] = i;
|
|
}
|
|
|
|
uint8 *pal = dst;
|
|
dst += 16;
|
|
nib = col = 0;
|
|
|
|
uint16 h1 = h;
|
|
while (h1--) {
|
|
uint16 w1 = w << 3;
|
|
while (w1--) {
|
|
uint8 s = *src++;
|
|
uint8 c = s & 0x0F;
|
|
if (colorMap) {
|
|
c = colorMap[s];
|
|
if (c == 0xFF) {
|
|
if (col < 0x10) {
|
|
*pal++ = s;
|
|
c = colorMap[s] = col++;
|
|
} else {
|
|
c = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (++nib & 1)
|
|
*dst = c << 4;
|
|
else
|
|
*dst++ |= c;
|
|
}
|
|
srcLineStart += SCREEN_W;
|
|
src = srcLineStart;
|
|
}
|
|
delete[] colorMap;
|
|
}
|
|
|
|
return shp;
|
|
}
|
|
|
|
void Screen_EoB::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int sd, int flags, ...) {
|
|
uint8 *dst = getPagePtr(pageNum);
|
|
const uint8 *src = shapeData;
|
|
|
|
if (!src)
|
|
return;
|
|
|
|
if (sd != -1) {
|
|
const ScreenDim *dm = getScreenDim(sd);
|
|
setShapeFrame(dm->sx, dm->sy, dm->sx + dm->w, dm->sy + dm->h);
|
|
x += (_dsX1 << 3);
|
|
y += _dsY1;
|
|
}
|
|
|
|
uint8 *ovl = 0;
|
|
|
|
va_list args;
|
|
va_start(args, flags);
|
|
if (flags & 2) {
|
|
ovl = va_arg(args, uint8 *);
|
|
_dsBackgroundFadingXOffs = x;
|
|
}
|
|
va_end(args);
|
|
|
|
dst += (_dsX1 << (2 + _bytesPerPixel));
|
|
int16 dX = x - (_dsX1 << 3);
|
|
int16 dY = y;
|
|
int16 dW = _dsX2 - _dsX1;
|
|
|
|
uint8 pixelsPerByte = *src++;
|
|
uint16 dH = *src++;
|
|
uint16 width = (*src++) << 3;
|
|
uint16 transOffset = (pixelsPerByte == 4) ? (dH * width) >> 2 : 0;
|
|
src++;
|
|
|
|
int rX = x;
|
|
int rY = y;
|
|
int rW = width + 8;
|
|
int rH = dH;
|
|
|
|
uint16 w2 = width;
|
|
int d = dY - _dsY1;
|
|
|
|
int pixelStep = (flags & 1) ? -1 : 1;
|
|
|
|
if (pixelsPerByte < 2) {
|
|
uint16 marginLeft = 0;
|
|
uint16 marginRight = 0;
|
|
|
|
if (d < 0) {
|
|
dH += d;
|
|
if (dH <= 0)
|
|
return;
|
|
d = -d;
|
|
|
|
for (int i = 0; i < d; i++) {
|
|
marginLeft = width;
|
|
for (int ii = 0; ii < marginLeft; ii++) {
|
|
if (!*src++)
|
|
marginLeft = marginLeft + 1 - *src++;
|
|
}
|
|
}
|
|
dY = _dsY1;
|
|
}
|
|
|
|
d = _dsY2 - dY;
|
|
|
|
if (d < 1)
|
|
return;
|
|
|
|
if (d < dH)
|
|
dH = d;
|
|
|
|
marginLeft = 0;
|
|
|
|
if (dX < 0) {
|
|
width += dX;
|
|
marginLeft = -dX;
|
|
|
|
if (marginLeft >= w2)
|
|
return;
|
|
|
|
dX = 0;
|
|
}
|
|
|
|
marginRight = 0;
|
|
d = (dW << 3) - dX;
|
|
|
|
if (d < 1)
|
|
return;
|
|
|
|
if (d < width) {
|
|
width = d;
|
|
marginRight = w2 - marginLeft - width;
|
|
}
|
|
|
|
dst += (dY * SCREEN_W * _bytesPerPixel + dX * _bytesPerPixel);
|
|
uint8 *dstL = dst;
|
|
|
|
if (pageNum == 0 || pageNum == 1)
|
|
addDirtyRect(rX, rY, rW, rH);
|
|
|
|
while (dH--) {
|
|
int16 xpos = (int16) marginLeft;
|
|
|
|
if (flags & 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) {
|
|
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);
|
|
} else {
|
|
src += (xpos * pixelStep);
|
|
xpos = 0;
|
|
}
|
|
}
|
|
|
|
dst -= xpos * _bytesPerPixel;
|
|
xpos += width;
|
|
|
|
while (xpos > 0) {
|
|
uint8 c = *src;
|
|
uint8 m = (flags & 1) ? *(src - 1) : c;
|
|
src += pixelStep;
|
|
|
|
if (m) {
|
|
drawShapeSetPixel(dst, c);
|
|
dst += _bytesPerPixel;
|
|
xpos--;
|
|
} else if (pixelsPerByte) {
|
|
uint8 len = (flags & 1) ? src[1] : src[0];
|
|
dst += len * _bytesPerPixel;
|
|
xpos -= len;
|
|
src += pixelStep;
|
|
} else {
|
|
dst += _bytesPerPixel;
|
|
xpos--;
|
|
}
|
|
}
|
|
xpos += marginRight;
|
|
|
|
if (xpos) {
|
|
do {
|
|
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;
|
|
}
|
|
} else {
|
|
src += (xpos * pixelStep);
|
|
xpos = 0;
|
|
}
|
|
} while (xpos > 0);
|
|
}
|
|
|
|
dstL += SCREEN_W * _bytesPerPixel;
|
|
dst = dstL;
|
|
if (flags & 1)
|
|
src = src2 + 1;
|
|
}
|
|
} else {
|
|
const uint8 *pal = 0;
|
|
uint8 cgaPal[4];
|
|
memset(cgaPal, 0, 4);
|
|
|
|
if (pixelsPerByte == 2) {
|
|
pal = ovl ? ovl : src;
|
|
src += 16;
|
|
} else {
|
|
static const uint8 cgaDefOvl[] = { 0x00, 0x55, 0xAA, 0xFF };
|
|
pal = ovl ? ovl : cgaDefOvl;
|
|
for (int i = 0; i < 4; i++)
|
|
cgaPal[i] = pal[i] & 3;
|
|
pal = cgaPal;
|
|
}
|
|
|
|
if (d < 0) {
|
|
d = -d;
|
|
if (d >= dH)
|
|
return;
|
|
src += (d * (width / pixelsPerByte));
|
|
d = dY + dH - _dsY1;
|
|
if (d >= 0) {
|
|
dH = d;
|
|
dY = _dsY1;
|
|
d = _dsY2 - dY;
|
|
}
|
|
} else {
|
|
d = _dsY2 - dY;
|
|
}
|
|
|
|
if (d < 1)
|
|
return;
|
|
|
|
if (d < dH)
|
|
dH = d;
|
|
|
|
bool trimL = false;
|
|
uint8 dXbitAlign = dX & (pixelsPerByte - 1);
|
|
|
|
if (dX < 0) {
|
|
width += dX;
|
|
d = -dX;
|
|
if (flags & 1)
|
|
src -= (d / pixelsPerByte);
|
|
else
|
|
src += (d / pixelsPerByte);
|
|
|
|
if (d >= w2)
|
|
return;
|
|
|
|
dX = 0;
|
|
trimL = true;
|
|
}
|
|
|
|
d = (dW << 3) - dX;
|
|
|
|
if (d < 1)
|
|
return;
|
|
|
|
if (d < width)
|
|
width = d;
|
|
|
|
dst += (dY * SCREEN_W * _bytesPerPixel + dX * _bytesPerPixel);
|
|
|
|
if (pageNum == 0 || pageNum == 1)
|
|
addDirtyRect(rX, rY, rW, rH);
|
|
|
|
int pitch = SCREEN_W - width;
|
|
int16 lineSrcStep = (w2 - width) / pixelsPerByte;
|
|
uint8 lineSrcStepRemainder = (w2 - width) % pixelsPerByte;
|
|
|
|
w2 /= pixelsPerByte;
|
|
if (flags & 1)
|
|
src += (w2 - 1);
|
|
|
|
uint8 pixelPacking = 8 / pixelsPerByte;
|
|
uint8 pixelPackingMask = 0;
|
|
|
|
for (int i = 0; i < pixelPacking; i++)
|
|
pixelPackingMask |= (1 << i);
|
|
|
|
if (trimL && (dXbitAlign > lineSrcStepRemainder))
|
|
lineSrcStep--;
|
|
|
|
uint8 bitShDef = 8 - pixelPacking;
|
|
if (flags & 1) {
|
|
lineSrcStep = (w2 << 1) - lineSrcStep;
|
|
bitShDef = 0;
|
|
}
|
|
|
|
uint8 bitShLineStart = bitShDef;
|
|
if (trimL)
|
|
bitShLineStart -= (dXbitAlign * pixelStep * pixelPacking);
|
|
|
|
while (dH--) {
|
|
int16 wd = width;
|
|
uint8 in = 0;
|
|
uint8 trans = 0;
|
|
uint8 shift = bitShLineStart;
|
|
uint8 shSwtch = bitShLineStart;
|
|
|
|
while (wd--) {
|
|
if (shift == shSwtch) {
|
|
in = *src;
|
|
trans = src[transOffset];
|
|
src += pixelStep;
|
|
shSwtch = bitShDef;
|
|
}
|
|
uint8 col = (pixelsPerByte == 2) ? pal[(in >> shift) & pixelPackingMask] : (*dst & ((trans >> shift) & (pixelPackingMask))) | pal[(in >> shift) & pixelPackingMask];
|
|
if (col || pixelsPerByte == 4)
|
|
drawShapeSetPixel(dst, col);
|
|
dst += _bytesPerPixel;
|
|
shift = ((shift - (pixelStep * pixelPacking)) & 7);
|
|
}
|
|
src += lineSrcStep;
|
|
dst += (pitch * _bytesPerPixel);
|
|
}
|
|
}
|
|
}
|
|
|
|
const uint8 *Screen_EoB::scaleShape(const uint8 *shapeData, int steps) {
|
|
setShapeFadingLevel(steps);
|
|
|
|
while (shapeData && steps--)
|
|
shapeData = scaleShapeStep(shapeData);
|
|
|
|
return shapeData;
|
|
}
|
|
|
|
const uint8 *Screen_EoB::scaleShapeStep(const uint8 *shp) {
|
|
uint8 *dst = (shp != _dsTempPage) ? _dsTempPage : _dsTempPage + 6000;
|
|
uint8 *d = dst;
|
|
uint8 pixelsPerByte = *d++ = *shp++;
|
|
assert(pixelsPerByte > 1);
|
|
|
|
uint16 h = shp[0] + 1;
|
|
d[0] = d[2] = (h << 1) / 3;
|
|
|
|
uint16 w = shp[1];
|
|
uint16 w2 = (w << 3) / pixelsPerByte;
|
|
uint16 t = ((w << 1) % 3) ? 1 : 0;
|
|
d[1] = ((w << 1) / 3) + t;
|
|
|
|
uint32 transOffsetSrc = (pixelsPerByte == 4) ? (shp[0] * shp[1]) << 1 : 0;
|
|
uint32 transOffsetDst = (pixelsPerByte == 4) ? (d[0] * d[1]) << 1 : 0;
|
|
shp += 3;
|
|
d += 3;
|
|
|
|
if (pixelsPerByte == 2) {
|
|
int i = 0;
|
|
while (i < 16) {
|
|
if (!shp[i]) {
|
|
i = -i;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
if (i >= 0)
|
|
i = 0;
|
|
else
|
|
i = -i;
|
|
|
|
_dsScaleTrans = (i << 4) | (i & 0x0F);
|
|
for (int ii = 0; ii < 16; ii++)
|
|
*d++ = *shp++;
|
|
}
|
|
|
|
_dsDiv = w2 / 3;
|
|
_dsRem = w2 % 3;
|
|
|
|
while (--h) {
|
|
if (pixelsPerByte == 2)
|
|
scaleShapeProcessLine4Bit(d, shp);
|
|
else
|
|
scaleShapeProcessLine2Bit(d, shp, transOffsetDst, transOffsetSrc);
|
|
if (!--h)
|
|
break;
|
|
if (pixelsPerByte == 2)
|
|
scaleShapeProcessLine4Bit(d, shp);
|
|
else
|
|
scaleShapeProcessLine2Bit(d, shp, transOffsetDst, transOffsetSrc);
|
|
if (!--h)
|
|
break;
|
|
shp += w2;
|
|
}
|
|
|
|
return (const uint8 *)dst;
|
|
}
|
|
|
|
const uint8 *Screen_EoB::generateShapeOverlay(const uint8 *shp, const uint8 *fadingTable) {
|
|
if (*shp != 2)
|
|
return 0;
|
|
|
|
if (_bytesPerPixel == 2) {
|
|
setFadeTable(fadingTable);
|
|
setShapeFadingLevel(1);
|
|
return 0;
|
|
}
|
|
|
|
shp += 4;
|
|
for (int i = 0; i < 16; i++)
|
|
_shapeOverlay[i] = fadingTable[shp[i]];
|
|
return _shapeOverlay;
|
|
}
|
|
|
|
void Screen_EoB::setShapeFrame(int x1, int y1, int x2, int y2) {
|
|
_dsX1 = x1;
|
|
_dsY1 = y1;
|
|
_dsX2 = x2;
|
|
_dsY2 = y2;
|
|
}
|
|
|
|
void Screen_EoB::enableShapeBackgroundFading(bool enable) {
|
|
_dsBackgroundFading = enable;
|
|
}
|
|
|
|
void Screen_EoB::setShapeFadingLevel(int level) {
|
|
_dsShapeFadingLevel = level;
|
|
}
|
|
|
|
void Screen_EoB::setGfxParameters(int x, int y, int col) {
|
|
_gfxX = x;
|
|
_gfxY = y;
|
|
_gfxCol = col;
|
|
}
|
|
|
|
void Screen_EoB::drawExplosion(int scale, int radius, int numElements, int stepSize, int aspectRatio, const uint8 *colorTable, int colorTableSize) {
|
|
int ymin = 0;
|
|
int ymax = _gfxMaxY[scale];
|
|
int xmin = -100;
|
|
int xmax = 276;
|
|
|
|
if (scale)
|
|
--scale;
|
|
|
|
hideMouse();
|
|
|
|
const ScreenDim *dm = getScreenDim(5);
|
|
int rX1 = dm->sx << 3;
|
|
int rY1 = dm->sy;
|
|
int rX2 = rX1 + (dm->w << 3);
|
|
int rY2 = rY1 + dm->h - 1;
|
|
|
|
int16 gx2 = _gfxX;
|
|
int16 gy2 = _gfxY;
|
|
|
|
int16 *ptr2 = (int16 *)_dsTempPage;
|
|
int16 *ptr3 = (int16 *)&_dsTempPage[300];
|
|
int16 *ptr4 = (int16 *)&_dsTempPage[600];
|
|
int16 *ptr5 = (int16 *)&_dsTempPage[900];
|
|
int16 *ptr6 = (int16 *)&_dsTempPage[1200];
|
|
int16 *ptr7 = (int16 *)&_dsTempPage[1500];
|
|
int16 *ptr8 = (int16 *)&_dsTempPage[1800];
|
|
|
|
if (numElements > 150)
|
|
numElements = 150;
|
|
|
|
|
|
for (int i = 0; i < numElements; i++) {
|
|
ptr2[i] = ptr3[i] = 0;
|
|
ptr4[i] = _vm->_rnd.getRandomNumberRng(0, radius) - (radius >> 1);
|
|
ptr5[i] = _vm->_rnd.getRandomNumberRng(0, radius) - (radius >> 1) - (radius >> (8 - aspectRatio));
|
|
ptr7[i] = _vm->_rnd.getRandomNumberRng(1024 / stepSize, 2048 / stepSize);
|
|
ptr8[i] = scale << 8;
|
|
}
|
|
|
|
uint32 playSpeedDelay = ((EXPLOSION_ANIM_DURATION << 15) / numElements) >> 7;
|
|
uint32 frameDelay = (1000 << 8) / 60;
|
|
uint32 playSpeedTimer = 0;
|
|
uint32 frameTimer = frameDelay;
|
|
uint32 start = _system->getMillis();
|
|
|
|
for (int l = 2; l;) {
|
|
if (l != 2) {
|
|
for (int i = numElements - 1; i >= 0; i--) {
|
|
int16 px = ((ptr2[i] >> 6) >> scale) + gx2;
|
|
int16 py = ((ptr3[i] >> 6) >> scale) + gy2;
|
|
if (py > ymax)
|
|
py = ymax;
|
|
if (posWithinRect(px, py, rX1, rY1, rX2, rY2)) {
|
|
if (_bytesPerPixel == 2)
|
|
setPagePixel16bit(0, px, py, ptr6[i]);
|
|
else
|
|
setPagePixel(0, px, py, ptr6[i]);
|
|
}
|
|
|
|
if (_system->getMillis() >= start + (frameTimer >> 8)) {
|
|
updateScreen();
|
|
frameTimer += frameDelay;
|
|
}
|
|
playSpeedTimer += playSpeedDelay;
|
|
if (_system->getMillis() < start + (playSpeedTimer >> 15))
|
|
_vm->delayUntil(start + (playSpeedTimer >> 15));
|
|
}
|
|
}
|
|
|
|
l = 0;
|
|
|
|
for (int i = 0; i < numElements; i++) {
|
|
if (ptr4[i] <= 0)
|
|
ptr4[i]++;
|
|
else
|
|
ptr4[i]--;
|
|
ptr2[i] += ptr4[i];
|
|
ptr5[i] += 5;
|
|
ptr3[i] += ptr5[i];
|
|
ptr8[i] += ptr7[i];
|
|
|
|
int16 px = ((ptr2[i] >> 6) >> scale) + gx2;
|
|
int16 py = ((ptr3[i] >> 6) >> scale) + gy2;
|
|
if (py >= ymax || py < ymin)
|
|
ptr5[i] = -(ptr5[i] >> 1);
|
|
if (px >= xmax || px < xmin)
|
|
ptr4[i] = -(ptr4[i] >> 1);
|
|
|
|
if (py > ymax)
|
|
py = ymax;
|
|
|
|
int pxVal1 = 0;
|
|
if (posWithinRect(px, py, 0, 0, 319, 199)) {
|
|
pxVal1 = getPagePixel(2, px, py);
|
|
ptr6[i] = getPagePixel(0, px, py);
|
|
}
|
|
|
|
assert((ptr8[i] >> 8) < colorTableSize);
|
|
int pxVal2 = colorTable[ptr8[i] >> 8];
|
|
if (pxVal2) {
|
|
l = 1;
|
|
if (pxVal1 == _gfxCol && posWithinRect(px, py, rX1, rY1, rX2, rY2))
|
|
setPagePixel(0, px, py, pxVal2);
|
|
} else {
|
|
ptr7[i] = 0;
|
|
}
|
|
|
|
if (_system->getMillis() >= start + (frameTimer >> 8)) {
|
|
updateScreen();
|
|
frameTimer += frameDelay;
|
|
}
|
|
playSpeedTimer += playSpeedDelay;
|
|
if (_system->getMillis() < start + (playSpeedTimer >> 15))
|
|
_vm->delayUntil(start + (playSpeedTimer >> 15));
|
|
}
|
|
}
|
|
|
|
updateScreen();
|
|
showMouse();
|
|
}
|
|
|
|
void Screen_EoB::drawVortex(int numElements, int radius, int stepSize, int, int disorder, const uint8 *colorTable, int colorTableSize) {
|
|
int16 *xCoords = (int16 *)_dsTempPage;
|
|
int16 *yCoords = (int16 *)&_dsTempPage[300];
|
|
int16 *xMod = (int16 *)&_dsTempPage[600];
|
|
int16 *yMod = (int16 *)&_dsTempPage[900];
|
|
int16 *pixBackup = (int16 *)&_dsTempPage[1200];
|
|
int16 *colTableStep = (int16 *)&_dsTempPage[1500];
|
|
int16 *colTableIndex = (int16 *)&_dsTempPage[1800];
|
|
int16 *pixDelay = (int16 *)&_dsTempPage[2100];
|
|
|
|
hideMouse();
|
|
int cp = _curPage;
|
|
|
|
if (numElements > 150)
|
|
numElements = 150;
|
|
|
|
int cx = 88;
|
|
int cy = 48;
|
|
radius <<= 6;
|
|
|
|
uint32 playSpeedDelay = ((VORTEX_ANIM_DURATION << 16) / numElements) >> 8;
|
|
uint32 frameDelay = (1000 << 8) / 60;
|
|
uint32 playSpeedTimer = 0;
|
|
uint32 frameTimer = frameDelay;
|
|
uint32 start = _system->getMillis();
|
|
|
|
for (int i = 0; i < numElements; i++) {
|
|
int16 v38 = _vm->_rnd.getRandomNumberRng(radius >> 2, radius);
|
|
int16 stepSum = 0;
|
|
int16 sqsum = 0;
|
|
while (sqsum < v38) {
|
|
stepSum += stepSize;
|
|
sqsum += stepSum;
|
|
}
|
|
|
|
switch (_vm->_rnd.getRandomNumber(255) & 3) {
|
|
case 0:
|
|
xCoords[i] = 32;
|
|
yCoords[i] = sqsum;
|
|
xMod[i] = stepSum;
|
|
yMod[i] = 0;
|
|
break;
|
|
|
|
case 1:
|
|
xCoords[i] = sqsum;
|
|
yCoords[i] = 32;
|
|
xMod[i] = 0;
|
|
yMod[i] = stepSum;
|
|
break;
|
|
|
|
case 2:
|
|
xCoords[i] = 32;
|
|
yCoords[i] = -sqsum;
|
|
xMod[i] = stepSum;
|
|
yMod[i] = 0;
|
|
break;
|
|
|
|
default:
|
|
xCoords[i] = -sqsum;
|
|
yCoords[i] = 32;
|
|
xMod[i] = 0;
|
|
yMod[i] = stepSum;
|
|
break;
|
|
}
|
|
|
|
if (_vm->_rnd.getRandomBit()) {
|
|
xMod[i] *= -1;
|
|
yMod[i] *= -1;
|
|
}
|
|
|
|
colTableStep[i] = _vm->_rnd.getRandomNumberRng(1024 / disorder, 2048 / disorder);
|
|
colTableIndex[i] = 0;
|
|
pixDelay[i] = _vm->_rnd.getRandomNumberRng(0, disorder >> 2);
|
|
}
|
|
|
|
int d = 0;
|
|
for (int i = 2; i;) {
|
|
if (i != 2) {
|
|
for (int ii = numElements - 1; ii >= 0; ii--) {
|
|
int16 px = CLIP((xCoords[ii] >> 6) + cx, 0, SCREEN_W - 1);
|
|
int16 py = CLIP((yCoords[ii] >> 6) + cy, 0, SCREEN_H - 1);
|
|
if (_bytesPerPixel == 2)
|
|
setPagePixel16bit(0, px, py, pixBackup[ii]);
|
|
else
|
|
setPagePixel(0, px, py, pixBackup[ii]);
|
|
|
|
if (_system->getMillis() >= start + (frameTimer >> 8)) {
|
|
updateScreen();
|
|
frameTimer += frameDelay;
|
|
}
|
|
playSpeedTimer += playSpeedDelay;
|
|
if (_system->getMillis() < start + (playSpeedTimer >> 16))
|
|
_vm->delayUntil(start + (playSpeedTimer >> 16));
|
|
}
|
|
}
|
|
|
|
i = 0;
|
|
int r = (stepSize >> 1) + (stepSize >> 2) + (stepSize >> 3);
|
|
|
|
for (int ii = 0; ii < numElements; ii++) {
|
|
if (pixDelay[ii] == 0) {
|
|
if (xCoords[ii] > 0) {
|
|
xMod[ii] -= ((xMod[ii] > 0) ? stepSize : r);
|
|
} else {
|
|
xMod[ii] += ((xMod[ii] < 0) ? stepSize : r);
|
|
}
|
|
|
|
if (yCoords[ii] > 0) {
|
|
yMod[ii] -= ((yMod[ii] > 0) ? stepSize : r);
|
|
} else {
|
|
yMod[ii] += ((yMod[ii] < 0) ? stepSize : r);
|
|
}
|
|
|
|
xCoords[ii] += xMod[ii];
|
|
yCoords[ii] += yMod[ii];
|
|
colTableIndex[ii] += colTableStep[ii];
|
|
|
|
} else {
|
|
pixDelay[ii]--;
|
|
}
|
|
|
|
int16 px = CLIP((xCoords[ii] >> 6) + cx, 0, SCREEN_W - 1);
|
|
int16 py = CLIP((yCoords[ii] >> 6) + cy, 0, SCREEN_H - 1);
|
|
|
|
uint8 tc1 = ((disorder >> 2) <= d) ? getPagePixel(2, px, py) : 0;
|
|
pixBackup[ii] = getPagePixel(0, px, py);
|
|
uint8 tblIndex = CLIP(colTableIndex[ii] >> 8, 0, colorTableSize - 1);
|
|
uint8 tc2 = colorTable[tblIndex];
|
|
|
|
if (tc2) {
|
|
i = 1;
|
|
if (tc1 == _gfxCol && !pixDelay[ii])
|
|
setPagePixel(0, px, py, tc2);
|
|
} else {
|
|
colTableStep[ii] = 0;
|
|
}
|
|
|
|
if (_system->getMillis() >= start + (frameTimer >> 8)) {
|
|
updateScreen();
|
|
frameTimer += frameDelay;
|
|
}
|
|
playSpeedTimer += playSpeedDelay;
|
|
if (_system->getMillis() < start + (playSpeedTimer >> 16))
|
|
_vm->delayUntil(start + (playSpeedTimer >> 16));
|
|
}
|
|
d++;
|
|
}
|
|
|
|
_curPage = cp;
|
|
updateScreen();
|
|
showMouse();
|
|
}
|
|
|
|
void Screen_EoB::fadeTextColor(Palette *pal, int color, int rate) {
|
|
assert(rate);
|
|
uint8 *col = pal->getData();
|
|
|
|
for (bool loop = true; loop;) {
|
|
uint32 end = _system->getMillis() + _vm->tickLength();
|
|
|
|
loop = false;
|
|
for (int ii = 0; ii < 3; ii++) {
|
|
uint8 c = col[color * 3 + ii];
|
|
if (c > rate) {
|
|
col[color * 3 + ii] -= rate;
|
|
loop = true;
|
|
} else if (c) {
|
|
col[color * 3 + ii] = 0;
|
|
loop = true;
|
|
}
|
|
}
|
|
|
|
if (loop) {
|
|
setScreenPalette(*pal);
|
|
updateScreen();
|
|
uint32 cur = _system->getMillis();
|
|
if (end > cur)
|
|
_system->delayMillis(end - cur);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Screen_EoB::delayedFadePalStep(Palette *fadePal, Palette *destPal, int rate) {
|
|
bool res = false;
|
|
|
|
uint8 *s = fadePal->getData();
|
|
uint8 *d = destPal->getData();
|
|
int numBytes = (fadePal->getNumColors() - 1) * 3;
|
|
|
|
for (int i = 0; i < numBytes; i++) {
|
|
int fadeVal = *s++;
|
|
int dstCur = *d;
|
|
int diff = ABS(fadeVal - dstCur);
|
|
|
|
if (diff == 0) {
|
|
d++;
|
|
continue;
|
|
}
|
|
|
|
res = true;
|
|
diff = MIN(diff, rate);
|
|
|
|
if (dstCur < fadeVal)
|
|
*d += diff;
|
|
else
|
|
*d -= diff;
|
|
d++;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
int Screen_EoB::getRectSize(int w, int h) {
|
|
return w * h;
|
|
}
|
|
|
|
void Screen_EoB::setFadeTable(const uint8 *table) {
|
|
_dsShapeFadingTable = table;
|
|
if (_bytesPerPixel == 2)
|
|
memcpy(&_16bitPalette[0x100], table, 512);
|
|
}
|
|
|
|
void Screen_EoB::createFadeTable(const uint8 *palData, uint8 *dst, uint8 rootColor, uint8 weight) {
|
|
if (!palData)
|
|
return;
|
|
|
|
const uint8 *src = palData + 3 * rootColor;
|
|
uint8 r = *src++;
|
|
uint8 g = *src++;
|
|
uint8 b = *src;
|
|
uint8 tr, tg, tb;
|
|
src = palData + 3;
|
|
|
|
*dst++ = 0;
|
|
weight >>= 1;
|
|
|
|
for (uint8 i = 1; i; i++) {
|
|
uint16 tmp = (uint16)((*src - r) * weight) << 1;
|
|
tr = *src++ - ((tmp >> 8) & 0xFF);
|
|
tmp = (uint16)((*src - g) * weight) << 1;
|
|
tg = *src++ - ((tmp >> 8) & 0xFF);
|
|
tmp = (uint16)((*src - b) * weight) << 1;
|
|
tb = *src++ - ((tmp >> 8) & 0xFF);
|
|
|
|
const uint8 *d = palData + 3;
|
|
uint16 v = 0xFFFF;
|
|
uint8 col = rootColor;
|
|
|
|
for (uint8 ii = 1; ii; ii++) {
|
|
int a = *d++ - tr;
|
|
int t = a * a;
|
|
a = *d++ - tg;
|
|
t += (a * a);
|
|
a = *d++ - tb;
|
|
t += (a * a);
|
|
|
|
if (t <= v && (ii == rootColor || ii != i)) {
|
|
v = t;
|
|
col = ii;
|
|
}
|
|
}
|
|
*dst++ = col;
|
|
}
|
|
}
|
|
|
|
void Screen_EoB::createFadeTable16bit(const uint16 *palData, uint16 *dst, uint16 rootColor, uint8 weight) {
|
|
rootColor = palData[rootColor];
|
|
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;
|
|
}
|
|
|
|
const uint8 *Screen_EoB::getEGADitheringTable() {
|
|
return _egaDitheringTable;
|
|
}
|
|
|
|
bool Screen_EoB::loadFont(FontId fontId, const char *filename) {
|
|
Font *&fnt = _fonts[fontId];
|
|
int temp = 0;
|
|
if (fnt)
|
|
delete fnt;
|
|
|
|
if (fontId == FID_SJIS_SMALL_FNT) {
|
|
if (_vm->gameFlags().platform == Common::kPlatformFMTowns)
|
|
fnt = new SJISFont12x12(_vm->staticres()->loadRawDataBe16(kEoB2FontDmpSearchTbl, temp));
|
|
else if (_vm->gameFlags().platform == Common::kPlatformPC98)
|
|
fnt = new Font12x12PC98(12, _vm->staticres()->loadRawDataBe16(kEoB1Ascii2SjisTable1, temp),
|
|
_vm->staticres()->loadRawDataBe16(kEoB1Ascii2SjisTable2, temp), _vm->staticres()->loadRawData(kEoB1FontLookupTable, temp));
|
|
} else if (_isAmiga) {
|
|
fnt = new AmigaDOSFont(_vm->resource(), _vm->game() == GI_EOB2 && _vm->gameFlags().lang == Common::DE_DEU);
|
|
} else if (_isSegaCD) {
|
|
fnt = new SegaCDFont(_vm->gameFlags().lang, _vm->staticres()->loadRawDataBe16(kEoB1Ascii2SjisTable1, temp), _vm->staticres()->loadRawDataBe16(kEoB1Ascii2SjisTable2, temp),
|
|
_vm->staticres()->loadRawData(kEoB1CharWidthTable1, temp), _vm->staticres()->loadRawData(kEoB1CharWidthTable2, temp), _vm->staticres()->loadRawData(kEoB1CharWidthTable3, temp));
|
|
} else {
|
|
// We use normal VGA rendering in EOB II, since we do the complete EGA dithering in updateScreen().
|
|
fnt = new OldDOSFont(_useHiResEGADithering ? Common::kRenderVGA : _renderMode, 12);
|
|
}
|
|
|
|
assert(fnt);
|
|
|
|
Common::SeekableReadStream *file = _vm->resource()->createReadStream(filename);
|
|
if (!file)
|
|
error("Font file '%s' is missing", filename);
|
|
|
|
bool ret = fnt->load(*file);
|
|
fnt->setColorMap(_textColorsMap);
|
|
delete file;
|
|
return ret;
|
|
}
|
|
|
|
void Screen_EoB::updateDirtyRects() {
|
|
if (!_useHiResEGADithering) {
|
|
Screen::updateDirtyRects();
|
|
return;
|
|
}
|
|
|
|
if (_forceFullUpdate) {
|
|
ditherRect(getCPagePtr(0), _egaDitheringTempPage, SCREEN_W * 2, SCREEN_W, SCREEN_H);
|
|
_system->copyRectToScreen(_egaDitheringTempPage, SCREEN_W * 2, 0, 0, SCREEN_W * 2, SCREEN_H * 2);
|
|
} else {
|
|
const uint8 *page0 = getCPagePtr(0);
|
|
Common::List<Common::Rect>::iterator it;
|
|
for (it = _dirtyRects.begin(); it != _dirtyRects.end(); ++it) {
|
|
ditherRect(page0 + it->top * SCREEN_W + it->left, _egaDitheringTempPage, SCREEN_W * 2, it->width(), it->height());
|
|
_system->copyRectToScreen(_egaDitheringTempPage, SCREEN_W * 2, it->left * 2, it->top * 2, it->width() * 2, it->height() * 2);
|
|
}
|
|
}
|
|
|
|
_forceFullUpdate = false;
|
|
_dirtyRects.clear();
|
|
}
|
|
|
|
void Screen_EoB::ditherRect(const uint8 *src, uint8 *dst, int dstPitch, int srcW, int srcH, int colorKey) {
|
|
while (srcH--) {
|
|
uint8 *dst2 = dst + dstPitch;
|
|
for (int i = 0; i < srcW; i++) {
|
|
int in = *src++;
|
|
if (in != colorKey) {
|
|
in = _egaDitheringTable[in];
|
|
*dst++ = *dst2++ = in >> 4;
|
|
*dst++ = *dst2++ = in & 0x0F;
|
|
} else {
|
|
dst[0] = dst[1] = dst2[0] = dst2[1] = colorKey;
|
|
dst += 2;
|
|
dst2 += 2;
|
|
}
|
|
}
|
|
src += (SCREEN_W - srcW);
|
|
dst += ((dstPitch - srcW) * 2);
|
|
}
|
|
}
|
|
|
|
void Screen_EoB::drawShapeSetPixel(uint8 *dst, uint8 col) {
|
|
if (_bytesPerPixel == 2) {
|
|
*(uint16*)dst = _16bitPalette[(_dsShapeFadingLevel << 8) + col];
|
|
return;
|
|
} else if (_useShapeShading) {
|
|
if (_dsBackgroundFading) {
|
|
if (_dsShapeFadingLevel) {
|
|
col = *dst;
|
|
} else {
|
|
_dsBackgroundFadingXOffs &= 7;
|
|
col = *(dst + _dsBackgroundFadingXOffs++);
|
|
}
|
|
}
|
|
|
|
if (_dsShapeFadingLevel) {
|
|
assert(_dsShapeFadingTable);
|
|
uint8 cnt = _dsShapeFadingLevel;
|
|
while (cnt--)
|
|
col = _dsShapeFadingTable[col];
|
|
}
|
|
}
|
|
|
|
*dst = col;
|
|
}
|
|
|
|
void Screen_EoB::scaleShapeProcessLine2Bit(uint8 *&shpDst, const uint8 *&shpSrc, uint32 transOffsetDst, uint32 transOffsetSrc) {
|
|
for (int i = 0; i < _dsDiv; i++) {
|
|
shpDst[0] = (_cgaScaleTable[shpSrc[0]] << 2) | (shpSrc[1] >> 6);
|
|
shpDst[1] = ((shpSrc[1] & 0x0F) << 4) | ((shpSrc[2] >> 2) & 0x0F);
|
|
shpDst[transOffsetDst] = (_cgaScaleTable[shpSrc[transOffsetSrc]] << 2) | (shpSrc[transOffsetSrc + 1] >> 6);
|
|
shpDst[transOffsetDst + 1] = ((shpSrc[transOffsetSrc + 1] & 0x0F) << 4) | ((shpSrc[transOffsetSrc + 2] >> 2) & 0x0F);
|
|
shpSrc += 3;
|
|
shpDst += 2;
|
|
}
|
|
|
|
if (_dsRem == 1) {
|
|
shpDst[0] = _cgaScaleTable[shpSrc[0]] << 2;
|
|
shpDst[1] = 0;
|
|
shpDst[transOffsetDst] = (_cgaScaleTable[shpSrc[transOffsetSrc]] << 2) | 3;
|
|
shpDst[transOffsetDst + 1] = 0xFF;
|
|
shpSrc++;
|
|
shpDst += 2;
|
|
|
|
} else if (_dsRem == 2) {
|
|
shpDst[0] = (_cgaScaleTable[shpSrc[0]] << 2) | (shpSrc[1] >> 6);
|
|
shpDst[1] = (shpSrc[1] & 0x3F) << 2;
|
|
shpDst[transOffsetDst] = (_cgaScaleTable[shpSrc[transOffsetSrc]] << 2) | (shpSrc[transOffsetSrc + 1] >> 6);
|
|
shpDst[transOffsetDst + 1] = ((shpSrc[transOffsetSrc + 1] & 0x3F) << 2) | 3;
|
|
shpSrc += 2;
|
|
shpDst += 2;
|
|
}
|
|
}
|
|
|
|
void Screen_EoB::scaleShapeProcessLine4Bit(uint8 *&dst, const uint8 *&src) {
|
|
for (int i = 0; i < _dsDiv; i++) {
|
|
*dst++ = *src++;
|
|
*dst++ = (READ_BE_UINT16(src) >> 4) & 0xFF;
|
|
src += 2;
|
|
}
|
|
|
|
if (_dsRem == 1) {
|
|
*dst++ = *src++;
|
|
*dst++ = _dsScaleTrans;
|
|
} else if (_dsRem == 2) {
|
|
*dst++ = (src[0] & 0xF0) | (src[1] >> 4);
|
|
src += 2;
|
|
*dst++ = _dsScaleTrans;
|
|
*dst++ = _dsScaleTrans;
|
|
*dst++ = _dsScaleTrans;
|
|
}
|
|
}
|
|
|
|
bool Screen_EoB::posWithinRect(int posX, int posY, int x1, int y1, int x2, int y2) {
|
|
if (posX < x1 || posX > x2 || posY < y1 || posY > y2)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
void Screen_EoB::setPagePixel16bit(int pageNum, int x, int y, uint16 color) {
|
|
assert(pageNum < SCREEN_PAGE_NUM);
|
|
assert(x >= 0 && x < SCREEN_W && y >= 0 && y < SCREEN_H);
|
|
assert(_bytesPerPixel == 2);
|
|
|
|
if (pageNum == 0 || pageNum == 1)
|
|
addDirtyRect(x, y, 1, 1);
|
|
|
|
((uint16*)_pagePtrs[pageNum])[y * SCREEN_W + x] = color;
|
|
}
|
|
|
|
void Screen_EoB::generateEGADitheringTable(const Palette &pal) {
|
|
assert(_egaDitheringTable);
|
|
const uint8 *src = pal.getData();
|
|
uint8 *dst = _egaDitheringTable;
|
|
|
|
for (int i = 256; i; i--) {
|
|
int r = *src++;
|
|
int g = *src++;
|
|
int b = *src++;
|
|
|
|
uint8 col = 0;
|
|
uint16 min = 0x2E83;
|
|
|
|
for (int ii = 256; ii; ii--) {
|
|
const uint8 *palEntry = _egaMatchTable + (ii - 1) * 3;
|
|
if (*palEntry == 0xFF)
|
|
continue;
|
|
|
|
int e_r = palEntry[0] - r;
|
|
int e_g = palEntry[1] - g;
|
|
int e_b = palEntry[2] - b;
|
|
|
|
uint16 s = (e_r * e_r) + (e_g * e_g) + (e_b * e_b);
|
|
|
|
if (s <= min) {
|
|
min = s;
|
|
col = ii - 1;
|
|
}
|
|
}
|
|
*dst++ = col;
|
|
}
|
|
}
|
|
|
|
void Screen_EoB::generateCGADitheringTables(const uint8 *mappingData) {
|
|
for (int i = 0; i < 256; i++) {
|
|
_cgaDitheringTables[0][i] = (mappingData[(i >> 4) + 16] << 8) | mappingData[i & 0x0F];
|
|
_cgaDitheringTables[1][i] = (mappingData[i >> 4] << 8) | mappingData[(i & 0x0F) + 16];
|
|
}
|
|
}
|
|
|
|
const uint8 Screen_EoB::_egaMatchTable[] = {
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x1E, 0x00, 0x00, 0x1E, 0x1E, 0x1E, 0x00, 0x00, 0x1E,
|
|
0x00, 0x1E, 0x1E, 0x0F, 0x00, 0x1E, 0x1E, 0x1E, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x2D, 0x0F, 0x2D,
|
|
0x0F, 0x0F, 0x2D, 0x2D, 0x2D, 0x0F, 0x0F, 0x2D, 0x0F, 0x2D, 0x2D, 0x2D, 0x0F, 0x2D, 0x2D, 0x2D,
|
|
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x2A, 0x00, 0x1E, 0x1E, 0x00, 0x1E, 0x2A, 0x1E, 0x00, 0x1E, 0x1E,
|
|
0x00, 0x2A, 0x1E, 0x0F, 0x1E, 0x1E, 0x1E, 0x2A, 0x0F, 0x0F, 0x21, 0x0F, 0x0F, 0x36, 0x0F, 0x2D,
|
|
0x21, 0x0F, 0x2D, 0x36, 0x2D, 0x0F, 0x21, 0x2D, 0x0F, 0x36, 0x2D, 0x2D, 0x21, 0x2D, 0x2D, 0x36,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x2A, 0x00, 0x00, 0x2A, 0x1E, 0x1E, 0x1E, 0x00, 0x1E,
|
|
0x1E, 0x1E, 0x1E, 0x21, 0x00, 0x1E, 0x2A, 0x1E, 0x0F, 0x21, 0x0F, 0x0F, 0x21, 0x2D, 0x0F, 0x36,
|
|
0x0F, 0x0F, 0x36, 0x2D, 0x2D, 0x21, 0x0F, 0x2D, 0x21, 0x2D, 0x2D, 0x36, 0x0F, 0x2D, 0x36, 0x2D,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x2A, 0x2A, 0x1E, 0x1E, 0x1E, 0x1E,
|
|
0x1E, 0x2A, 0x1E, 0x21, 0x1E, 0x1E, 0x2A, 0x2A, 0x0F, 0x21, 0x21, 0x0F, 0x21, 0x36, 0x0F, 0x36,
|
|
0x21, 0x0F, 0x36, 0x36, 0x2D, 0x21, 0x21, 0x2D, 0x21, 0x36, 0x2D, 0x36, 0x21, 0x2D, 0x36, 0x36,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2A, 0x00, 0x00, 0x2A,
|
|
0x00, 0x1E, 0x2A, 0x0F, 0x00, 0x2A, 0x1E, 0x1E, 0x21, 0x0F, 0x0F, 0x21, 0x0F, 0x2D, 0x21, 0x2D,
|
|
0x0F, 0x21, 0x2D, 0x2D, 0x36, 0x0F, 0x0F, 0x36, 0x0F, 0x2D, 0x36, 0x2D, 0x0F, 0x36, 0x2D, 0x2D,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2A,
|
|
0x00, 0x2A, 0x2A, 0x0F, 0x1E, 0x2A, 0x1E, 0x2A, 0x21, 0x0F, 0x21, 0x21, 0x0F, 0x36, 0x21, 0x2D,
|
|
0x21, 0x21, 0x2D, 0x36, 0x36, 0x0F, 0x21, 0x36, 0x0F, 0x36, 0x36, 0x2D, 0x21, 0x36, 0x2D, 0x36,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0x2A, 0x15, 0x00, 0x2A, 0x21, 0x1E, 0x21, 0x15, 0x0F, 0x21, 0x15, 0x2D, 0x21, 0x2F,
|
|
0x0F, 0x21, 0x2F, 0x2D, 0x36, 0x15, 0x0F, 0x36, 0x15, 0x2D, 0x36, 0x2F, 0x0F, 0x36, 0x2F, 0x2D,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2A, 0x2A, 0x2A, 0x21, 0x21, 0x21, 0x21, 0x21, 0x36, 0x21, 0x36,
|
|
0x21, 0x21, 0x36, 0x36, 0x36, 0x21, 0x21, 0x36, 0x21, 0x36, 0x36, 0x36, 0x21, 0x36, 0x36, 0x36,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x15, 0x15, 0x15, 0x15, 0x15, 0x2F, 0x15, 0x2F,
|
|
0x15, 0x15, 0x2F, 0x2F, 0x2F, 0x15, 0x15, 0x2F, 0x15, 0x2F, 0x2F, 0x2F, 0x15, 0x2F, 0x2F, 0x2F,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x15, 0x15, 0x3F, 0x15, 0x2F,
|
|
0x2F, 0x15, 0x2F, 0x3F, 0x2F, 0x15, 0x2F, 0x2F, 0x15, 0x3F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x3F,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x15, 0x3F,
|
|
0x15, 0x15, 0x3F, 0x2F, 0x2F, 0x2F, 0x15, 0x2F, 0x2F, 0x2F, 0x2F, 0x3F, 0x15, 0x2F, 0x3F, 0x2F,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0x15, 0x3F, 0x3F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x3F, 0x2F, 0x3F, 0x2F, 0x2F, 0x3F, 0x3F,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x15, 0x15, 0x3F, 0x15, 0x2F, 0x3F, 0x2F, 0x15, 0x3F, 0x2F, 0x2F,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x15, 0x3F, 0x3F, 0x2F, 0x2F, 0x3F, 0x2F, 0x3F,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x3F, 0x15, 0x3F, 0x3F, 0x2F,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x3F, 0x3F
|
|
};
|
|
|
|
#undef EXPLOSION_ANIM_DURATION
|
|
#undef VORTEX_ANIM_DURATION
|
|
|
|
uint16 *OldDOSFont::_cgaDitheringTable = 0;
|
|
int OldDOSFont::_numRef = 0;
|
|
|
|
OldDOSFont::OldDOSFont(Common::RenderMode mode, uint8 shadowColor) : _renderMode(mode), _shadowColor(shadowColor), _colorMap8bit(0), _colorMap16bit(0) {
|
|
_data = 0;
|
|
_width = _height = _numGlyphs = 0;
|
|
_bitmapOffsets = 0;
|
|
_style = kStyleNone;
|
|
|
|
_numRef++;
|
|
if (!_cgaDitheringTable && _numRef == 1) {
|
|
_cgaDitheringTable = new uint16[256];
|
|
memset(_cgaDitheringTable, 0, 256 * sizeof(uint16));
|
|
static const uint bits[] = { 0, 3, 12, 15 };
|
|
for (int i = 0; i < 256; i++)
|
|
_cgaDitheringTable[i] = (bits[i & 3] << 8) | (bits[(i >> 2) & 3] << 12) | (bits[(i >> 4) & 3] << 0) | (bits[(i >> 6) & 3] << 4);
|
|
}
|
|
}
|
|
|
|
OldDOSFont::~OldDOSFont() {
|
|
unload();
|
|
|
|
if (_numRef)
|
|
--_numRef;
|
|
|
|
if (_cgaDitheringTable && !_numRef) {
|
|
delete[] _cgaDitheringTable;
|
|
_cgaDitheringTable = 0;
|
|
}
|
|
}
|
|
|
|
bool OldDOSFont::load(Common::SeekableReadStream &file) {
|
|
unload();
|
|
|
|
_data = new uint8[file.size()];
|
|
assert(_data);
|
|
|
|
file.read(_data, file.size());
|
|
if (file.err())
|
|
return false;
|
|
|
|
if (file.size() - 2 != READ_LE_UINT16(_data))
|
|
return false;
|
|
|
|
_width = _data[0x103];
|
|
_height = _data[0x102];
|
|
_numGlyphs = (READ_LE_UINT16(_data + 2) / 2) - 2;
|
|
|
|
_bitmapOffsets = (uint16 *)(_data + 2);
|
|
|
|
for (int i = 0; i < _numGlyphs; ++i)
|
|
_bitmapOffsets[i] = READ_LE_UINT16(&_bitmapOffsets[i]);
|
|
|
|
return true;
|
|
}
|
|
|
|
int OldDOSFont::getCharWidth(uint16 c) const {
|
|
// Since these fonts have a fixed character width we always give a return value
|
|
// even if there is no glyph for the specified character (which can't normally
|
|
// happen anyway - you'd have to do something like importing a Japanese save file
|
|
// into the English version).
|
|
return _width;
|
|
}
|
|
|
|
void OldDOSFont::setColorMap(const uint8 *src) {
|
|
_colorMap8bit = src;
|
|
}
|
|
|
|
void OldDOSFont::drawChar(uint16 c, byte *dst, int pitch, int bpp) const {
|
|
uint16 color1 = _colorMap8bit[1];
|
|
uint16 color2 = _colorMap8bit[0];
|
|
|
|
if (_style == kStyleLeftShadow) {
|
|
drawCharIntern(c, dst + pitch, pitch, 1, _shadowColor, 0);
|
|
drawCharIntern(c, dst - 1, pitch, 1, _shadowColor, 0);
|
|
drawCharIntern(c, dst - 1 + pitch, pitch, 1, _shadowColor, 0);
|
|
}
|
|
|
|
if (bpp == 2) {
|
|
color1 = _colorMap16bit[1];
|
|
color2 = _colorMap16bit[0];
|
|
}
|
|
|
|
drawCharIntern(c, dst, pitch, bpp, color1, color2);
|
|
}
|
|
|
|
void OldDOSFont::drawCharIntern(uint16 c, byte *dst, int pitch, int bpp, int col1, int col2) const {
|
|
static const uint16 renderMaskTable[] = {
|
|
0x0000, 0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff
|
|
};
|
|
|
|
c = convert(c);
|
|
|
|
if (c >= _numGlyphs)
|
|
return;
|
|
|
|
pitch *= bpp;
|
|
const uint8 *src = &_data[_bitmapOffsets[c]];
|
|
uint8 *dst2 = dst + pitch;
|
|
|
|
int w = (_width - 1) >> 3;
|
|
pitch -= _width * bpp;
|
|
|
|
if (_renderMode == Common::kRenderCGA || _renderMode == Common::kRenderEGA) {
|
|
col1 &= 0x0F;
|
|
col2 &= 0x0F;
|
|
}
|
|
|
|
static const uint16 cgaColorMask[] = { 0, 0x5555, 0xAAAA, 0xFFFF };
|
|
uint16 cgaMask1 = cgaColorMask[col1 & 3];
|
|
uint16 cgaMask2 = cgaColorMask[col2 & 3];
|
|
|
|
int cH = _height;
|
|
while (cH--) {
|
|
int cW = w;
|
|
uint16 mask = renderMaskTable[_width];
|
|
|
|
if (_renderMode == Common::kRenderCGA) {
|
|
uint16 s = (*src++) << 8;
|
|
if (_width > 8)
|
|
s |= *src++;
|
|
|
|
uint16 cmp1 = 0;
|
|
uint16 cmp2 = 0;
|
|
|
|
if (col1) {
|
|
s &= mask;
|
|
cmp1 = _cgaDitheringTable[s >> 8];
|
|
}
|
|
|
|
if (col2) {
|
|
s = ~s & mask;
|
|
cmp2 = _cgaDitheringTable[s >> 8];
|
|
}
|
|
|
|
uint16 cDst = 0;
|
|
uint8 sh = 6;
|
|
for (int i = 0; i < _width; i++) {
|
|
cDst |= ((dst[i] & 3) << sh);
|
|
sh = (sh - 2) & 0x0F;
|
|
}
|
|
|
|
uint16 out = (~(cmp1 | cmp2) & cDst) | (cmp1 & cgaMask1) | (cmp2 & cgaMask2);
|
|
|
|
sh = 6;
|
|
for (int i = 0; i < _width; i++) {
|
|
*dst++ = (out >> sh) & 3;
|
|
sh = (sh - 2) & 0x0F;
|
|
}
|
|
} else {
|
|
for (bool runWidthLoop = true; runWidthLoop;) {
|
|
uint16 s = (*src++) << 8;
|
|
if (_width > 8)
|
|
s |= *src++;
|
|
|
|
for (uint16 i = 0x8000; i; i >>= 1) {
|
|
if (!(mask & i)) {
|
|
runWidthLoop = false;
|
|
break;
|
|
}
|
|
|
|
if (s & i) {
|
|
if (bpp == 2)
|
|
*(uint16*)dst = col1;
|
|
else if (col1)
|
|
*dst = col1;
|
|
} else {
|
|
if (bpp == 2) {
|
|
if (col2 != 0xFFFF)
|
|
*(uint16*)dst = col2;
|
|
} else if (col2) {
|
|
*dst = col2;
|
|
}
|
|
}
|
|
dst += bpp;
|
|
}
|
|
|
|
mask >>= 1;
|
|
|
|
if (cW)
|
|
cW--;
|
|
else
|
|
runWidthLoop = false;
|
|
}
|
|
}
|
|
|
|
dst += pitch;
|
|
dst2 += pitch;
|
|
}
|
|
}
|
|
|
|
uint16 OldDOSFont::convert(uint16 c) const {
|
|
if (_width == 6) {
|
|
switch (c) {
|
|
case 0x81:
|
|
case 0x9A:
|
|
c = 0x5D;
|
|
break;
|
|
case 0x84:
|
|
case 0x8E:
|
|
c = 0x5B;
|
|
break;
|
|
case 0x94:
|
|
case 0x99:
|
|
c = 0x40;
|
|
case 0xE1:
|
|
// TODO: recheck this: no conversion for 'ß' ?
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else if (_width == 8) {
|
|
switch (c) {
|
|
case 0x81:
|
|
case 0x9A:
|
|
case 0x5D:
|
|
c = 0x1D;
|
|
break;
|
|
case 0x84:
|
|
case 0x5B:
|
|
c = 0x1E;
|
|
break;
|
|
case 0x94:
|
|
case 0x40:
|
|
c = 0x1F;
|
|
break;
|
|
case 0x8E:
|
|
c = 0x1B;
|
|
break;
|
|
case 0x99:
|
|
c = 0x1C;
|
|
break;
|
|
case 0xE1:
|
|
c = 0x19;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return c;
|
|
}
|
|
|
|
void OldDOSFont::unload() {
|
|
delete[] _data;
|
|
_data = 0;
|
|
_width = _height = _numGlyphs = 0;
|
|
_bitmapOffsets = 0;
|
|
}
|
|
|
|
} // End of namespace Kyra
|
|
|
|
#endif // ENABLE_EOB
|