From 540d081a6fd4daa31f746ddf30ccc91fb88ea04b Mon Sep 17 00:00:00 2001 From: athrxx Date: Sun, 11 Dec 2011 01:57:03 +0100 Subject: KYRA: (EOB) - initial code base commit --- engines/kyra/screen_eob.cpp | 965 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 965 insertions(+) create mode 100644 engines/kyra/screen_eob.cpp (limited to 'engines/kyra/screen_eob.cpp') diff --git a/engines/kyra/screen_eob.cpp b/engines/kyra/screen_eob.cpp new file mode 100644 index 0000000000..eb5a52477b --- /dev/null +++ b/engines/kyra/screen_eob.cpp @@ -0,0 +1,965 @@ +/* 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/screen.h" +#endif + +#ifdef ENABLE_EOB + +#include "kyra/eobcommon.h" +#include "kyra/resource.h" + +#include "common/system.h" + +#include "graphics/cursorman.h" + +namespace Kyra { + +Screen_Eob::Screen_Eob(EobCoreEngine *vm, OSystem *system) : Screen(vm, system) { + _shapeFadeMode[0] = _shapeFadeMode[1] = 0; + _shapeFadeInternal = 0; + _fadeData = 0; + _fadeDataIndex = 0; + _dsX1 = _dsX2 = _dsY1 = _dsY2 = 0; + _customDimTable = 0; + _dsTempPage = 0; +} + +Screen_Eob::~Screen_Eob() { + delete[] _fadeData; + delete[] _customDimTable; + delete[] _dsTempPage; +} + +bool Screen_Eob::init() { + if (Screen::init()) { + _customDimTable = new ScreenDim*[_screenDimTableCount]; + memset(_customDimTable, 0, sizeof(ScreenDim *)* _screenDimTableCount); + + _fadeData = _vm->resource()->fileData("FADING.DAT", 0); + + if (!_fadeData) { + _fadeData = new uint8[0x700]; + memset(_fadeData, 0, 0x700); + uint8 *pal = _vm->resource()->fileData("palette1.pal", 0); // EGA: palette0.pal + for (int i = 0; i < 7; i++) + createFadeTable(pal, &_fadeData[i << 8], 18, (i + 1) * 36); + delete[] pal; + } + + _dsTempPage = new uint8[6000]; + + return true; + } + return false; +} + +void Screen_Eob::setScreenDim(int dim) { + assert(dim < _screenDimTableCount); + _curDim = _customDimTable[dim] ? (const ScreenDim *)_customDimTable[dim] : &_screenDimTable[dim]; + _curDimIndex = dim; +} + +const ScreenDim *Screen_Eob::getScreenDim(int dim) { + assert(dim < _screenDimTableCount); + return _customDimTable[dim] ? (const ScreenDim *)_customDimTable[dim] : &_screenDimTable[dim]; +} + +void Screen_Eob::modifyScreenDim(int dim, int x, int y, int w, int h) { + delete _customDimTable[dim]; + _customDimTable[dim] = new ScreenDim; + memcpy(_customDimTable[dim], &_screenDimTable[dim], sizeof(ScreenDim)); + _customDimTable[dim]->sx = x; + _customDimTable[dim]->sy = y; + _customDimTable[dim]->w = w; + _customDimTable[dim]->h = h; + if (dim == _curDimIndex) + setScreenDim(dim); +} + +void Screen_Eob::setClearScreenDim(int dim) { + setScreenDim(dim); + clearCurDim(); +} + +void Screen_Eob::clearCurDim() { + fillRect(_curDim->sx << 3, _curDim->sy, ((_curDim->sx + _curDim->w) << 3) - 1, (_curDim->sy + _curDim->h) - 1, _curDim->unkA); +} + +void Screen_Eob::setMouseCursor(int x, int y, const byte *shape) { + if (!shape) + return; + int mouseW = shape[2] << 3; + int mouseH = shape[3]; + uint8 *cursor = new uint8[mouseW * mouseH]; + fillRect(0, 0, mouseW, mouseH, _cursorColorKey, 8); + drawShape(8, shape, 0, 0, 0); + CursorMan.showMouse(false); + copyRegionToBuffer(8, 0, 0, mouseW, mouseH, cursor); + CursorMan.replaceCursor(cursor, mouseW, mouseH, x, y, _cursorColorKey); + 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) { + printText(string, x - 1, y, 12, col2); + printText(string, x, y + 1, 12, 0); + printText(string, x - 1, y + 1, 12, 0); + printText(string, x, y, col1, 0); +} + +void Screen_Eob::loadEobBitmap(const char *file, int tempPage, int destPage) { + loadEobCpsFileToPage(file, 0, tempPage, destPage, -1); + _curPage = 2; +} + +void Screen_Eob::loadEobCpsFileToPage(const char *file, const uint8 *ditheringData, int tempPage, int destPage, int copyToPage) { + char tmp[13]; + sprintf(tmp, "%s.CPS", file); + + Common::SeekableReadStream *s = _vm->resource()->createReadStream(tmp); + bool loadAlternative = false; + 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()) + loadBitmap(tmp, tempPage, destPage, 0); + else + loadAlternative = true; + + delete s; + } else { + loadAlternative = true; + } + + if (loadAlternative) { + tmp[0] = 'X'; + s = _vm->resource()->createReadStream(tmp); + if (!s) + error("Screen_Eob::loadEobCpsFileToPage(): CPS file loading failed."); + s->seek(768); + loadFileDataToPage(s, destPage, 64000); + delete s; + } + + if (copyToPage == -1) { + return; + } else if (copyToPage == 0) { + copyPage(destPage, 2); + copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK); + } else { + copyPage(destPage, copyToPage); + } +} + +uint8 *Screen_Eob::encodeShape(uint16 x, uint16 y, uint16 w, uint16 h, bool flag) { + uint8 *shp = 0; + uint16 shapesize = 0; + + uint8 *srcPage = getPagePtr(_curPage) + y * 320 + (x << 3); + uint8 *src = srcPage; + + if (flag) { + 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); + + srcPage += 320; + src = srcPage; + } + + shapesize += 4; + + shp = new uint8[shapesize]; + memset (shp, 0, shapesize); + uint8 *dst = shp; + + *dst++ = 0; + *dst++ = (h & 0xff); + *dst++ = (w & 0xff); + *dst++ = (h & 0xff); + + srcPage = getPagePtr(_curPage) + y * 320 + (x << 3); + src = srcPage; + + h1 = h; + while (h1--) { + uint8 *lineEnd = src + (w << 3); + do { + uint8 val = *src++; + if (!val) { + *dst++ = val; + uint8 *startZeroPos = src; + while (src != lineEnd && *src == 0) + src++; + + uint16 numZero = src - startZeroPos + 1; + if (numZero >> 8) { + numZero -= 0xff; + *dst++ = 0xff; + *dst++ = 0; + } + val = (numZero & 0xff); + } + *dst++ = val; + } while (src != lineEnd); + + srcPage += 320; + src = srcPage; + } + + } else { + uint8 nib = 0, col = 0; + uint8 *colorMap = new uint8[0x100]; + memset (colorMap, 0xff, 0x100); + + shapesize = h * (w << 2) + 0x14; + shp = new uint8[shapesize]; + memset (shp, 0, shapesize); + uint8 *dst = shp; + + *dst++ = 1; + *dst++ = (h & 0xff); + *dst++ = (w & 0xff); + *dst++ = (h & 0xff); + memset (dst, 0xff, 0x10); + + uint8 *pal = dst; + dst += 0x10; + + srcPage = getPagePtr(_curPage) + y * 320 + (x << 3); + src = srcPage; + nib = col = 0; + + uint16 h1 = h; + while (h1--) { + uint16 w1 = w << 3; + while (w1--) { + uint8 s = *src++; + uint8 c = colorMap[s]; + if (c == 0xff) { + if (col < 0x10) { + *pal++ = s; + c = colorMap[s] = col++; + if (!col) + c = 0; + } else { + c = 0; + } + } + + if(++nib & 1) { + *dst = c << 4; + } else { + *dst++ |= c; + } + } + srcPage += 320; + src = srcPage; + } + 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; + + va_list args; + va_start(args, flags); + uint8 *ovl = (flags & 2) ? va_arg(args, uint8*) : 0; + va_end(args); + + 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; + } + + dst += (_dsX1 << 3); + int16 dX = x - (_dsX1 << 3); + int16 dY = y; + int16 dW = _dsX2 - _dsX1; + uint8 flag = *src++; + + uint16 dH = *src++; + uint16 width = (*src++) << 3; + 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 (flag) { + const uint8 *pal = ovl ? ovl : src; + src += 16; + + if (d < 0) { + d = -d; + if (d >= dH) + return; + src += (d * (width >> 1)); + 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; + + int16 cnt1 = 0; + int16 cnt2 = 0; + int16 dXbit1 = dX & 1; + + if (dX < 0) { + width += dX; + d = -dX; + if ((flags & 1)) + src -= (d >> 1); + else + src += (d >> 1); + + if (d >= w2) + return; + + dX = 0; + cnt1++; + } + + d = (dW << 3) - dX; + + if (d < 1) + return; + + if (d < width) { + width = d; + cnt2++; + } + + dst += (dY * 320 + dX); + + if (pageNum == 0 || pageNum == 1) + addDirtyRect(rX, rY, rW, rH); + + int w3 = w2; + dY = 320 - width; + width >>= 1; + w2 >>= 1; + if ((flags & 1)) + src += (w2 - 1); + + int16 w1shr = width; + + if (cnt1 && (dXbit1 & 1)) { + w1shr++; + w2++; + if (!cnt2) + dY += 2; + } + + if (cnt2 && (dXbit1 & 1)) + w1shr++; + + int lineSrcStep = (w2 - w1shr); + if ((flags & 1)) + lineSrcStep = w3 - lineSrcStep; + + while (dH--) { + int16 hpos = width; + uint8 col = 0; + uint8 b = 0; + uint8 nextloop = 0; + + if (cnt1 && dXbit1) { + if (!hpos) + return; + b = *src; + src += pixelStep; + nextloop = 2; + } else { + nextloop = hpos ? 1 : 3; + } + + while (nextloop) { + switch (nextloop) { + case 1: + b = *src; + src += pixelStep; + col = pal[(flags & 1) ? (b & 0x0f) : (b >> 4)]; + if (col) + drawShapeSetPixel(dst, col); + dst++; + + case 2: + col = pal[(flags & 1) ? (b >> 4) : (b & 0x0f)]; + + if (!col) { + nextloop = 4; + break; + } + + drawShapeSetPixel(dst++, col); + nextloop = --hpos ? 1 : 3; + break; + + case 3: + if (cnt2 && dXbit1) { + col = pal[(flags & 1) ? (*src & 0x0f) : (*src >> 4)]; + src += pixelStep; + if (col) + drawShapeSetPixel(dst, col); + dst++; + } + + src += lineSrcStep; + dst += dY; + nextloop = 0; + break; + + case 4: + dst++; + nextloop = --hpos ? 1 : 3; + break; + } + } + } + } else { + uint16 marginLeft = 0; + uint16 marginRight = 0; + + if (d < 0) { + dH += d; + if (dH <= 0) + return; + d = -d; + + for (int ii = 0; ii < d; ii++) { + marginLeft = width; + int i = 0; + do { + for (i = 0; i < marginLeft; i++) + if (!*src++) + break; + + if (!*(src-1) || i < marginLeft) + marginLeft = ++marginLeft - *src++; + else + marginLeft = 0; + + } while (marginLeft); + } + 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 += (y * 320 + dX); + uint8 * dstL = dst; + + if (pageNum == 0 || pageNum == 1) + addDirtyRect(rX, rY, rW, rH); + + while (dH--) { + int16 xpos = (int16) marginLeft; + + if (xpos) { + do { + while (*src && xpos) { + src++; + xpos--; + } + + if (!*src) { + uint8 bt = *++src; + src++; + xpos = xpos - bt; + } + } while (xpos > 0); + } + + dst -= xpos; + xpos += width; + + while (xpos > 0) { + uint8 c = *src++; + + if (c) { + drawShapeSetPixel(dst++, c); + xpos--; + } else { + dst += *src; + xpos -= *src++; + } + } + xpos += marginRight; + + if (xpos) { + do { + while (*src && xpos) { + src++; + xpos--; + } + + if (!*src) { + uint8 bt = *++src; + src++; + xpos = xpos - bt; + } + } while (xpos > 0); + } + + dstL += 320; + dst = dstL; + } + } +} + +void Screen_Eob::drawShapeSetPixel(uint8 * dst, uint8 c) { + if (_shapeFadeMode[0]) { + if (_shapeFadeMode[1]) { + c = *dst; + } else { + _shapeFadeInternal &= 7; + c = *(dst + _shapeFadeInternal++); + } + } + + if (_shapeFadeMode[1]) { + uint8 cnt = _shapeFadeMode[1]; + while (cnt--) + c = _fadeData[_fadeDataIndex + c]; + } + + *dst = c; +} + +const uint8 *Screen_Eob::scaleShape(const uint8 *shapeData, int steps) { + setShapeFadeMode(1, steps ? true : false); + + while (shapeData && steps--) + shapeData = scaleShapeStep(shapeData); + + return shapeData; +} + +const uint8 *Screen_Eob::scaleShapeStep(const uint8 *shp) { + uint8 *d = _dsTempPage; + *d++ = *shp++; + + uint16 h = (*shp++) + 1; + d[0] = d[2] = (h << 1) / 3; + d++; + + uint16 w = *shp++; + uint16 w2 = w << 2; + uint16 t = ((w << 1) % 3) ? 1 : 0; + *d++ = ((w << 1) / 3) + t; + + shp++; + d++; + + int i = 0; + while (i < 16) { + if (!shp[i]) { + i = -i; + break; + } + i++; + } + + if (i >= 0) + i = 0; + else + i = -i; + + _dsScaleTmp = (i << 4) | (i & 0x0f); + memcpy(d, shp, 16); + d += 16; + shp += 16; + + _dsDiv = w2 / 3; + _dsRem = w2 % 3; + + do { + scaleShapeProcessLine(d, shp); + if (!--h) + break; + scaleShapeProcessLine(d, shp); + if (!--h) + break; + shp += w2; + } while (--h); + + return (const uint8 *) _dsTempPage; +} + +void Screen_Eob::replaceShapePalette(uint8 *shp, const uint8 *pal) { + if (*shp != 1) + return; + shp += 4; + memcpy(shp, pal, 16); +} + +void Screen_Eob::applyShapeOverlay(uint8 *shp, int ovlIndex) { + if (*shp != 1) + return; + shp += 4; + uint8 *ovl = getFadeTable(ovlIndex); + for (int i = 0; i < 16; i++) + shp[i] = ovl[shp[i]]; +} + +void Screen_Eob::scaleShapeProcessLine(uint8 *&dst, const uint8 *&src) { + for (int i = 0; i < _dsDiv; i++) { + *dst++ = *src++; + *dst++ = READ_BE_UINT16(src) >> 4; + src += 2; + } + + if (_dsRem == 1) { + *dst++ = *src++; + *dst++ = _dsScaleTmp; + + } if (_dsRem == 2) { + *dst++ = (src[0] & 0xf0) | (src[1] >> 4); + src += 2; + *dst++ = _dsScaleTmp; + *dst++ = _dsScaleTmp; + *dst++ = _dsScaleTmp; + } +} + +void Screen_Eob::fadeTextColor(Palette *pal, int color1, int rate) { + uint8 *col = pal->getData(); + + for (bool loop = true; loop; ) { + loop = true; + uint32 end = _system->getMillis() + 16; + + loop = false; + for (int ii = 0; ii < 3; ii++) { + uint8 c = col[color1 * 3 + ii]; + if (c > rate) { + col[color1 * 3 + ii] -= rate; + loop = true; + } else if (c) { + col[color1 * 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(); + + for (int i = 0; i < 765; 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; +} + +void Screen_Eob::createFadeTable(uint8 *palData, uint8 *dst, uint8 rootColor, uint8 weight) { + if (!palData) + return; + + 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); + + 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; + } +} + +OldDOSFont::OldDOSFont() { + _data = 0; + _width = _height = _numGlyphs = 0; + _bitmapOffsets = 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 = 255; + + _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 { + if (c >= _numGlyphs) + return 0; + return _width; +} + +void OldDOSFont::drawChar(uint16 c, byte *dst, int pitch) 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 }; + + if (_width != 8 && _width != 6) + error("EOB font rendering not implemented for other font widths than 6 and 8."); + + 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; + } + } 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; + } + } + + const uint8 *src = &_data[_bitmapOffsets[c]]; + + int w = (_width - 1) >> 3; + pitch -= _width; + + uint8 color1 = _colorMap[1]; + uint8 color2 = _colorMap[0]; + + int cH = _height; + while (cH--) { + int cW = w; + const uint8 *mtbl = _width == 8 ? renderMaskTable8 : renderMaskTable6; + + for (bool runWidthLoop = true; runWidthLoop; ) { + uint8 s = *src++; + uint8 m = *mtbl++; + + for (uint8 i = 0x80; i; i >>= 1) { + if (!(m & i)) { + runWidthLoop = false; + break; + } + + if (s & i) { + if (color1) + *dst = color1; + } else if (color2) { + *dst = color2; + } + dst++; + } + + if (cW) + cW--; + else + runWidthLoop = false; + } + + dst += pitch; + } +} + +void OldDOSFont::unload() { + delete[] _data; + _data = 0; + _width = _height = _numGlyphs = 0; + _bitmapOffsets = 0; +} + +} // End of namespace Kyra + +#endif // ENABLE_EOB -- cgit v1.2.3