aboutsummaryrefslogtreecommitdiff
path: root/engines/kyra/screen_v2.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/kyra/screen_v2.cpp')
-rw-r--r--engines/kyra/screen_v2.cpp561
1 files changed, 561 insertions, 0 deletions
diff --git a/engines/kyra/screen_v2.cpp b/engines/kyra/screen_v2.cpp
new file mode 100644
index 0000000000..83c75585a8
--- /dev/null
+++ b/engines/kyra/screen_v2.cpp
@@ -0,0 +1,561 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "common/endian.h"
+
+#include "kyra/kyra_v2.h"
+#include "kyra/screen_v2.h"
+
+namespace Kyra {
+
+Screen_v2::Screen_v2(KyraEngine_v2 *vm, OSystem *system)
+ : Screen(vm, system) {
+ _vm = vm;
+}
+
+Screen_v2::~Screen_v2() {
+}
+
+void Screen_v2::setScreenDim(int dim) {
+ debugC(9, kDebugLevelScreen, "Screen_v2::setScreenDim(%d)", dim);
+ if (_vm->game() == GI_KYRA2) {
+ assert(dim < _screenDimTableCount);
+ _curDim = &_screenDimTable[dim];
+ } else {
+ assert(dim < _screenDimTableCountK3);
+ _curDim = &_screenDimTableK3[dim];
+ }
+}
+
+const ScreenDim *Screen_v2::getScreenDim(int dim) {
+ debugC(9, kDebugLevelScreen, "Screen_v2::getScreenDim(%d)", dim);
+ if (_vm->game() == GI_KYRA2) {
+ assert(dim < _screenDimTableCount);
+ return &_screenDimTable[dim];
+ } else {
+ assert(dim < _screenDimTableCountK3);
+ return &_screenDimTableK3[dim];
+ }
+}
+
+void Screen_v2::k2IntroFadeToGrey(int delay) {
+ debugC(9, kDebugLevelScreen, "Screen_v2::k2IntroFadeToGrey(%d)", delay);
+
+ for (int i = 0; i <= 50; ++i) {
+ if (i <= 8 || i >= 30) {
+ _currentPalette[3 * i + 0] = (_currentPalette[3 * i + 0] +
+ _currentPalette[3 * i + 1] +
+ _currentPalette[3 * i + 2]) / 3;
+ _currentPalette[3 * i + 1] = _currentPalette[3 * i + 0];
+ _currentPalette[3 * i + 2] = _currentPalette[3 * i + 0];
+ }
+ }
+
+ // color 71 is the same in both the overview and closeup scenes
+ // Converting it to greyscale makes the trees in the closeup look dull
+ for (int i = 71; i < 200; ++i) {
+ _currentPalette[3 * i + 0] = (_currentPalette[3 * i + 0] +
+ _currentPalette[3 * i + 1] +
+ _currentPalette[3 * i + 2]) / 3;
+ _currentPalette[3 * i + 1] = _currentPalette[3 * i + 0];
+ _currentPalette[3 * i + 2] = _currentPalette[3 * i + 0];
+ }
+ fadePalette(_currentPalette, delay);
+ // Make the font color white again
+ setPaletteIndex(254, 254, 254, 254);
+}
+
+void Screen_v2::copyWsaRect(int x, int y, int w, int h, int dimState, int plotFunc, const uint8 *src,
+ int unk1, const uint8 *unkPtr1, const uint8 *unkPtr2) {
+ uint8 *dstPtr = getPagePtr(_curPage);
+ uint8 *origDst = dstPtr;
+
+ const ScreenDim *dim = getScreenDim(dimState);
+ int dimX1 = dim->sx << 3;
+ int dimX2 = dim->w << 3;
+ dimX2 += dimX1;
+
+ int dimY1 = dim->sy;
+ int dimY2 = dim->h;
+ dimY2 += dimY1;
+
+ int temp = y - dimY1;
+ if (temp < 0) {
+ if ((temp += h) <= 0)
+ return;
+ else {
+ SWAP(temp, h);
+ y += temp - h;
+ src += (temp - h) * w;
+ }
+ }
+
+ temp = dimY2 - y;
+ if (temp <= 0)
+ return;
+
+ if (temp < h)
+ h = temp;
+
+ int srcOffset = 0;
+ temp = x - dimX1;
+ if (temp < 0) {
+ temp = -temp;
+ srcOffset = temp;
+ x += temp;
+ w -= temp;
+ }
+
+ int srcAdd = 0;
+
+ temp = dimX2 - x;
+ if (temp <= 0)
+ return;
+
+ if (temp < w) {
+ SWAP(w, temp);
+ temp -= w;
+ srcAdd = temp;
+ }
+
+ dstPtr += y * SCREEN_W + x;
+ uint8 *dst = dstPtr;
+
+ if (_curPage == 0 || _curPage == 1)
+ addDirtyRect(x, y, w, h);
+
+ clearOverlayRect(_curPage, x, y, w, h);
+
+ temp = h;
+ while (h--) {
+ src += srcOffset;
+ int cW = w;
+
+ switch (plotFunc) {
+ case 0:
+ memcpy(dst, src, cW);
+ dst += cW; src += cW;
+ break;
+
+ case 1:
+ while (cW--) {
+ uint8 d = *src++;
+ uint8 t = unkPtr1[d];
+ if (t != 0xFF)
+ d = unkPtr2[*dst + (t << 8)];
+ *dst++ = d;
+ }
+ break;
+
+ case 4:
+ while (cW--) {
+ uint8 d = *src++;
+ if (d)
+ *dst = d;
+ ++dst;
+ }
+ break;
+
+ case 5:
+ while (cW--) {
+ uint8 d = *src++;
+ if (d) {
+ uint8 t = unkPtr1[d];
+ if (t != 0xFF)
+ d = unkPtr2[*dst + (t << 8)];
+ *dst = d;
+ }
+ ++dst;
+ }
+ break;
+
+ case 8:
+ case 9:
+ while (cW--) {
+ uint8 d = *src++;
+ uint8 t = _shapePages[0][dst - origDst] & 7;
+ if (unk1 < t)
+ d = _shapePages[1][dst - origDst];
+ *dst++ = d;
+ }
+ break;
+
+ case 12:
+ case 13:
+ while (cW--) {
+ uint8 d = *src++;
+ if (d) {
+ uint8 t = _shapePages[0][dst - origDst] & 7;
+ if (unk1 < t)
+ d = _shapePages[1][dst - origDst];
+ *dst++ = d;
+ } else {
+ d = _shapePages[1][dst - origDst];
+ *dst++ = d;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ dst = (dstPtr += SCREEN_W);
+ src += srcAdd;
+ }
+}
+
+const uint8 *Screen_v2::getPtrToShape(const uint8 *shpFile, int shape) {
+ debugC(9, kDebugLevelScreen, "Screen_v2::getPtrToShape(%p, %d)", (const void *)shpFile, shape);
+ uint16 shapes = READ_LE_UINT16(shpFile);
+
+ if (shapes <= shape)
+ return 0;
+
+ uint32 offset = READ_LE_UINT32(shpFile + (shape << 2) + 2);
+
+ return shpFile + offset + 2;
+}
+
+uint8 *Screen_v2::getPtrToShape(uint8 *shpFile, int shape) {
+ debugC(9, kDebugLevelScreen, "Screen_v2::getPtrToShape(%p, %d)", (void *)shpFile, shape);
+ uint16 shapes = READ_LE_UINT16(shpFile);
+
+ if (shapes <= shape)
+ return 0;
+
+ uint32 offset = READ_LE_UINT32(shpFile + (shape << 2) + 2);
+
+ return shpFile + offset + 2;
+}
+
+int Screen_v2::getShapeScaledWidth(const uint8 *shpFile, int scale) {
+ int width = READ_LE_UINT16(shpFile+3);
+ return (width * scale) >> 8;
+}
+
+int Screen_v2::getShapeScaledHeight(const uint8 *shpFile, int scale) {
+ int height = shpFile[2];
+ return (height * scale) >> 8;
+}
+
+uint16 Screen_v2::getShapeSize(const uint8 *shp) {
+ debugC(9, kDebugLevelScreen, "Screen_v2::getShapeSize(%p)", (const void *)shp);
+
+ return READ_LE_UINT16(shp+6);
+}
+
+uint8 *Screen_v2::makeShapeCopy(const uint8 *src, int index) {
+ debugC(9, kDebugLevelScreen, "Screen_v2::makeShapeCopy(%p, %d)", (const void *)src, index);
+
+ const uint8 *shape = getPtrToShape(src, index);
+ int size = getShapeSize(shape);
+
+ uint8 *copy = new uint8[size];
+ assert(copy);
+ memcpy(copy, shape, size);
+
+ return copy;
+}
+
+void Screen_v2::drawShape(uint8 page, const uint8 *shape, int x, int y, int sd, int flags, ...) {
+ if (!shape)
+ return;
+
+ if (*shape & 1)
+ flags |= 0x400;
+
+ va_list args;
+ va_start(args, flags);
+
+ static int drawShapeVar1 = 0;
+ static int drawShapeVar2[] = {
+ 1, 3, 2, 5, 4, 3, 2, 1
+ };
+ static int drawShapeVar3 = 1;
+ static int drawShapeVar4 = 0;
+ static int drawShapeVar5 = 0;
+
+ uint8 *table = 0;
+ int tableLoopCount = 0;
+ int drawLayer = 0;
+ const uint8 *table2 = 0;
+ uint8 *table3 = 0;
+ uint8 *table4 = 0;
+
+ if (flags & 0x8000) {
+ table2 = va_arg(args, uint8*);
+ }
+ if (flags & 0x100) {
+ table = va_arg(args, uint8*);
+ tableLoopCount = va_arg(args, int);
+ if (!tableLoopCount)
+ flags &= 0xFFFFFEFF;
+ }
+ if (flags & 0x1000) {
+ table3 = va_arg(args, uint8*);
+ table4 = va_arg(args, uint8*);
+ }
+ if (flags & 0x200) {
+ drawShapeVar1 += 1;
+ drawShapeVar1 &= 7;
+ drawShapeVar3 = drawShapeVar2[drawShapeVar1];
+ drawShapeVar4 = 0;
+ drawShapeVar5 = 256;
+ }
+ if (flags & 0x4000) {
+ drawShapeVar5 = va_arg(args, int);
+ }
+ if (flags & 0x800) {
+ drawLayer = va_arg(args, int);
+ }
+ int scale_w, scale_h;
+ if (flags & 0x04) {
+ scale_w = va_arg(args, int);
+ scale_h = va_arg(args, int);
+ } else {
+ scale_w = 0x100;
+ scale_h = 0x100;
+ }
+
+ int ppc = (flags >> 8) & 0x3F;
+
+ const uint8 *src = shape;
+ uint16 shapeFlags = READ_LE_UINT16(src); src += 2;
+
+ int shapeHeight = *src++;
+ int scaledShapeHeight = (shapeHeight * scale_h) >> 8;
+ if (scaledShapeHeight == 0) {
+ va_end(args);
+ return;
+ }
+
+ int shapeWidth = READ_LE_UINT16(src); src += 2;
+ int scaledShapeWidth = (shapeWidth * scale_w) >> 8;
+ if (scaledShapeWidth == 0) {
+ va_end(args);
+ return;
+ }
+
+ if (flags & 0x20) {
+ x -= scaledShapeWidth >> 1;
+ y -= scaledShapeHeight >> 1;
+ }
+
+ src += 3;
+
+ uint16 frameSize = READ_LE_UINT16(src); src += 2;
+ int colorTableColors = 0x10;
+
+ if (shapeFlags & 4)
+ colorTableColors = *src++;
+
+ if (!(flags & 0x8000) && (shapeFlags & 1))
+ table2 = src;
+
+ if ((shapeFlags & 1) || (flags & 0x400))
+ src += colorTableColors;
+
+ if (!(shapeFlags & 2)) {
+ decodeFrame4(src, _animBlockPtr, frameSize);
+ src = _animBlockPtr;
+ }
+
+ int shapeSize = shapeWidth * shapeHeight;
+ if (_decodeShapeBufferSize < shapeSize) {
+ delete [] _decodeShapeBuffer;
+ _decodeShapeBuffer = new uint8[shapeSize];
+ _decodeShapeBufferSize = shapeSize;
+ }
+ if (!_decodeShapeBuffer) {
+ _decodeShapeBufferSize = 0;
+ va_end(args);
+ return;
+ }
+ memset(_decodeShapeBuffer, 0, _decodeShapeBufferSize);
+ uint8 *decodedShapeFrame = _decodeShapeBuffer;
+
+ for (int j = 0; j < shapeHeight; ++j) {
+ uint8 *dsbNextLine = decodedShapeFrame + shapeWidth;
+ int count = shapeWidth;
+ while (count > 0) {
+ uint8 code = *src++;
+ if (code != 0) {
+ *decodedShapeFrame++ = code;
+ --count;
+ } else {
+ code = *src++;
+ decodedShapeFrame += code;
+ count -= code;
+ }
+ }
+ decodedShapeFrame = dsbNextLine;
+ }
+
+ uint16 sx1 = getScreenDim(sd)->sx << 3;
+ uint16 sy1 = getScreenDim(sd)->sy;
+ uint16 sx2 = sx1 + (getScreenDim(sd)->w << 3);
+ uint16 sy2 = sy1 + getScreenDim(sd)->h;
+ if (flags & 0x10) {
+ x += sx1;
+ y += sy1;
+ }
+
+ int x1, x2;
+ if (x >= 0) {
+ x1 = 0;
+ if (x + scaledShapeWidth < sx2) {
+ x2 = scaledShapeWidth;
+ } else {
+ x2 = sx2 - x;
+ }
+ } else {
+ x2 = scaledShapeWidth;
+ x1 = -x;
+ x = 0;
+ if (x2 > sx2) {
+ x2 = sx2;
+ }
+ }
+
+ int y1, y2;
+ if (y >= 0) {
+ y1 = 0;
+ if (y + scaledShapeHeight < sy2) {
+ y2 = scaledShapeHeight;
+ } else {
+ y2 = sy2 - y;
+ }
+ } else {
+ y2 = scaledShapeHeight;
+ y1 = -y;
+ y = 0;
+ if (y2 > sy2) {
+ y2 = sy2;
+ }
+ }
+
+ uint8 *dst = getPagePtr(page) + y * 320 + x;
+ uint8 *dstStart = getPagePtr(page);
+
+ int scaleYTable[200];
+ for (y = y1; y < y2; ++y) {
+ scaleYTable[y] = (y << 8) / scale_h;
+ }
+ int scaleXTable[320];
+ for (x = x1; x < x2; ++x) {
+ scaleXTable[x] = (x << 8) / scale_w;
+ }
+
+ const uint8 *shapeBuffer = _decodeShapeBuffer;
+ if (flags & 0x02) {
+ shapeBuffer += shapeWidth * (shapeHeight - 1);
+ }
+ if (flags & 0x01) {
+ shapeBuffer += shapeWidth - 1;
+ }
+
+ for (y = y1; y < y2; ++y) {
+ uint8 *dstNextLine = dst + 320;
+ int j = scaleYTable[y];
+ if (flags & 0x02) {
+ j = -j;
+ }
+ for (x = x1; x < x2; ++x) {
+ int xpos = scaleXTable[x];
+ if (flags & 0x01)
+ xpos = -xpos;
+ uint8 color = shapeBuffer[j * shapeWidth + xpos];
+ if (color != 0) {
+ switch (ppc) {
+ case 0:
+ *dst = color;
+ break;
+
+ case 4:
+ *dst = table2[color];
+ break;
+
+ case 8: {
+ int layer = _shapePages[0][dst - dstStart] & 7;
+ if (drawLayer > layer)
+ color = _shapePages[1][dst - dstStart];
+ *dst = color;
+ } break;
+
+ case 12: {
+ int layer = _shapePages[0][dst - dstStart] & 7;
+ if (drawLayer < layer)
+ color = _shapePages[1][dst - dstStart];
+ else
+ color = table2[color];
+ *dst = color;
+ } break;
+
+ default:
+ warning("unhandled ppc: %d", ppc);
+ break;
+ }
+ }
+ ++dst;
+ }
+ dst = dstNextLine;
+ }
+ va_end(args);
+}
+
+int Screen_v2::getRectSize(int w, int h) {
+ if (w > 320 || h > 200)
+ return 0;
+ return w*h;
+}
+
+int Screen_v2::getLayer(int x, int y) {
+ if (x < 0)
+ x = 0;
+ else if (x >= 320)
+ x = 319;
+ if (y < 0)
+ y = 0;
+ else if (y >= 144)
+ y = 143;
+
+ uint8 pixel = *(getCPagePtr(5) + y * 320 + x);
+ pixel &= 0x7F;
+ pixel >>= 3;
+
+ if (pixel < 1)
+ pixel = 1;
+ else if (pixel > 15)
+ pixel = 15;
+ return pixel;
+}
+
+bool Screen_v2::isMouseVisible() const {
+ return _mouseLockCount == 0;
+}
+
+} // end of namespace Kyra