aboutsummaryrefslogtreecommitdiff
path: root/engines/scumm/cursor.cpp
diff options
context:
space:
mode:
authorMax Horn2006-02-11 22:45:04 +0000
committerMax Horn2006-02-11 22:45:04 +0000
commit26ee630756ebdd7c96bccede0881a8c8b98e8f2b (patch)
tree26e378d5cf990a2b81c2c96e9e683a7f333b62e8 /engines/scumm/cursor.cpp
parent2a9a0d4211b1ea5723f1409d91cb95de8984429e (diff)
downloadscummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.gz
scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.bz2
scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.zip
Moved engines to the new engines/ directory
svn-id: r20582
Diffstat (limited to 'engines/scumm/cursor.cpp')
-rw-r--r--engines/scumm/cursor.cpp520
1 files changed, 520 insertions, 0 deletions
diff --git a/engines/scumm/cursor.cpp b/engines/scumm/cursor.cpp
new file mode 100644
index 0000000000..6fee33e79b
--- /dev/null
+++ b/engines/scumm/cursor.cpp
@@ -0,0 +1,520 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-2006 The ScummVM project
+ *
+ * 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/system.h"
+#include "common/util.h"
+#include "scumm/bomp.h"
+#include "scumm/charset.h"
+#include "scumm/intern.h"
+#include "scumm/intern_he.h"
+#include "scumm/object.h"
+#include "scumm/resource_v7he.h"
+#include "scumm/saveload.h"
+#include "scumm/scumm.h"
+
+namespace Scumm {
+
+/*
+ * Mouse cursor cycle colors (for the default crosshair).
+ */
+static const byte default_v1_cursor_colors[4] = {
+ 1, 1, 12, 11
+};
+
+static const byte default_cursor_colors[4] = {
+ 15, 15, 7, 8
+};
+
+
+static const uint16 default_cursor_images[4][16] = {
+ /* cross-hair */
+ { 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0000, 0x7e3f,
+ 0x0000, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0000 },
+ /* hourglass */
+ { 0x0000, 0x7ffe, 0x6006, 0x300c, 0x1818, 0x0c30, 0x0660, 0x03c0,
+ 0x0660, 0x0c30, 0x1998, 0x33cc, 0x67e6, 0x7ffe, 0x0000, 0x0000 },
+ /* arrow */
+ { 0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x7f00,
+ 0x7f80, 0x78c0, 0x7c00, 0x4600, 0x0600, 0x0300, 0x0300, 0x0180 },
+ /* hand */
+ { 0x1e00, 0x1200, 0x1200, 0x1200, 0x1200, 0x13ff, 0x1249, 0x1249,
+ 0xf249, 0x9001, 0x9001, 0x9001, 0x8001, 0x8001, 0x8001, 0xffff },
+};
+
+static const byte default_cursor_hotspots[10] = {
+ 8, 7, 8, 7, 1, 1, 5, 0,
+ 8, 7, //zak256
+};
+
+static const uint16 default_he_cursor[64] = {
+ 0x0000, 0x0000, 0x3800, 0x0000, 0x7e00, 0x0000, 0x5f80, 0x0000,
+ 0x5fe0, 0x0000, 0x2ff8, 0x0000, 0x27fe, 0x0000, 0x17ff, 0x8000,
+ 0x13ff, 0xe000, 0x09ff, 0xf000, 0x09ff, 0xf800, 0x04ff, 0xf800,
+ 0x047f, 0xf000, 0x027f, 0xe000, 0x023f, 0xf000, 0x011f, 0xf800,
+ 0x0111, 0xfc00, 0x0080, 0xfc00, 0x0084, 0x0c00, 0x004a, 0x0800,
+ 0x0031, 0x1000, 0x0000, 0xe000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+};
+
+static const byte default_v6_cursor[] = {
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x00,0x0F,0x00, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x00,0x0F,0x00, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x00,0x0F,0x00, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x00,0x0F,0x00, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x00,0x0F,0x00, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x0F,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xFF,
+ 0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, 0x0F,0x0F,0x0F, 0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0xFF,
+ 0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x0F,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x00,0x0F,0x00, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x00,0x0F,0x00, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x00,0x0F,0x00, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x00,0x0F,0x00, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x00,0x0F,0x00, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+};
+
+ScummEngine_v5::ScummEngine_v5(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16], int substResFileNameIndex)
+ : ScummEngine(detector, syst, gs, md5sum, substResFileNameIndex) {
+
+ for (int i = 0; i < 4; i++) {
+ memcpy(_cursorImages[i], default_cursor_images[i], 32);
+ }
+ memcpy(_cursorHotspots, default_cursor_hotspots, 8);
+}
+
+
+void ScummEngine::setupCursor() {
+ _cursor.animate = 1;
+}
+
+void ScummEngine_v5::animateCursor() {
+ if (_cursor.animate) {
+ if (!(_cursor.animateIndex & 0x1)) {
+ setBuiltinCursor((_cursor.animateIndex >> 1) & 3);
+ }
+ _cursor.animateIndex++;
+ }
+}
+
+void ScummEngine_v6::setCursorHotspot(int x, int y) {
+ _cursor.hotspotX = x;
+ _cursor.hotspotY = y;
+}
+
+void ScummEngine_v6::setCursorTransparency(int a) {
+ int i, size;
+
+ size = _cursor.width * _cursor.height;
+
+ for (i = 0; i < size; i++)
+ if (_grabbedCursor[i] == (byte)a)
+ _grabbedCursor[i] = 0xFF;
+
+ updateCursor();
+}
+
+void ScummEngine::updateCursor() {
+ const int transColor = (_heversion >= 80) ? 5 : 255;
+ _system->setMouseCursor(_grabbedCursor, _cursor.width, _cursor.height,
+ _cursor.hotspotX, _cursor.hotspotY,
+ (_platform == Common::kPlatformNES ? _grabbedCursor[63] : transColor),
+ (_heversion == 70 ? 2 : 1));
+}
+
+void ScummEngine_v6::grabCursor(int x, int y, int w, int h) {
+ VirtScreen *vs = findVirtScreen(y);
+
+ if (vs == NULL) {
+ debug(0, "grabCursor: invalid Y %d", y);
+ return;
+ }
+
+ setCursorFromBuffer((byte *)vs->pixels + (y - vs->topline) * vs->pitch + x, w, h, vs->pitch);
+}
+
+void ScummEngine_v6::setDefaultCursor() {
+ setCursorHotspot(7, 6);
+ setCursorFromBuffer(default_v6_cursor, 16, 13, 16);
+}
+
+void ScummEngine::setCursorFromBuffer(const byte *ptr, int width, int height, int pitch) {
+ uint size;
+ byte *dst;
+
+ size = width * height;
+ if (size > sizeof(_grabbedCursor))
+ error("grabCursor: grabbed cursor too big");
+
+ _cursor.width = width;
+ _cursor.height = height;
+ _cursor.animate = 0;
+
+ dst = _grabbedCursor;
+ for (; height; height--) {
+ memcpy(dst, ptr, width);
+ dst += width;
+ ptr += pitch;
+ }
+
+ updateCursor();
+}
+
+#ifndef DISABLE_HE
+void ScummEngine_v70he::setCursorFromImg(uint img, uint room, uint imgindex) {
+ _resExtractor->setCursor(img);
+}
+
+void ScummEngine_v90he::setDefaultCursor() {
+ const uint16 *src;
+ int i, j;
+ static byte palette[] = { 0xff, 0xff, 0xff, 0,
+ 0, 0, 0, 0};
+
+ memset(_grabbedCursor, 5, sizeof(_grabbedCursor));
+
+ _cursor.hotspotX = _cursor.hotspotY = 2;
+ src = default_he_cursor;
+
+ _cursor.width = 32;
+ _cursor.height = 32;
+
+ for (i = 0; i < 32; i++) {
+ for (j = 0; j < 32; j++) {
+ if (*src & (1 << (15 - (j % 16))))
+ _grabbedCursor[32 * i + j] = 0xfe;
+ if (j == 15)
+ src++;
+ }
+ src++;
+ }
+
+ // Since white color position is not guaranteed
+ // we setup our own palette if supported by backend
+ if (_system->hasFeature(OSystem::kFeatureCursorHasPalette))
+ _system->setCursorPalette(palette, 0xfe, 2);
+
+ updateCursor();
+}
+#endif
+
+void ScummEngine_v6::setCursorFromImg(uint img, uint room, uint imgindex) {
+ int w, h;
+ const byte *dataptr, *bomp;
+ uint32 size;
+ FindObjectInRoom foir;
+ const ImageHeader *imhd;
+
+ if (room == (uint) - 1)
+ room = getObjectRoom(img);
+
+ findObjectInRoom(&foir, foCodeHeader | foImageHeader | foCheckAlreadyLoaded, img, room);
+ imhd = (const ImageHeader *)findResourceData(MKID('IMHD'), foir.obim);
+
+ if (_version == 8) {
+ setCursorHotspot(READ_LE_UINT32(&imhd->v8.hotspot[0].x),
+ READ_LE_UINT32(&imhd->v8.hotspot[0].y));
+ w = READ_LE_UINT32(&imhd->v8.width) / 8;
+ h = READ_LE_UINT32(&imhd->v8.height) / 8;
+ } else if (_version == 7) {
+ setCursorHotspot(READ_LE_UINT16(&imhd->v7.hotspot[0].x),
+ READ_LE_UINT16(&imhd->v7.hotspot[0].y));
+ w = READ_LE_UINT16(&imhd->v7.width) / 8;
+ h = READ_LE_UINT16(&imhd->v7.height) / 8;
+ } else {
+ if (_heversion == 0) {
+ setCursorHotspot(READ_LE_UINT16(&imhd->old.hotspot[0].x),
+ READ_LE_UINT16(&imhd->old.hotspot[0].y));
+ }
+ w = READ_LE_UINT16(&foir.cdhd->v6.w) / 8;
+ h = READ_LE_UINT16(&foir.cdhd->v6.h) / 8;
+ }
+
+ dataptr = getObjectImage(foir.obim, imgindex);
+ assert(dataptr);
+ if (_version == 8) {
+ bomp = dataptr;
+ } else {
+ size = READ_BE_UINT32(dataptr + 4);
+ if (size > sizeof(_grabbedCursor))
+ error("setCursorFromImg: Cursor image too large");
+
+ bomp = findResource(MKID('BOMP'), dataptr);
+ }
+
+ if (bomp != NULL)
+ useBompCursor(bomp, w, h);
+ else
+ useIm01Cursor(dataptr, w, h);
+}
+
+void ScummEngine_v6::useIm01Cursor(const byte *im, int w, int h) {
+ VirtScreen *vs = &virtscr[0];
+ byte *buf, *dst;
+ const byte *src;
+ int i;
+
+ w *= 8;
+ h *= 8;
+
+ // Backup the screen content
+ dst = buf = (byte *)malloc(w * h);
+ src = vs->getPixels(0, 0);
+
+ for (i = 0; i < h; i++) {
+ memcpy(dst, src, w);
+ dst += w;
+ src += vs->pitch;
+ }
+
+ // Do some drawing
+ drawBox(0, 0, w - 1, h - 1, 0xFF);
+
+ vs->hasTwoBuffers = false;
+ gdi.disableZBuffer();
+ gdi.drawBitmap(im, vs, _screenStartStrip, 0, w, h, 0, w / 8, 0);
+ vs->hasTwoBuffers = true;
+ gdi.enableZBuffer();
+
+ // Grab the data we just drew and setup the cursor with it
+ setCursorFromBuffer(vs->getPixels(0, 0), w, h, vs->pitch);
+
+ // Restore the screen content
+ src = buf;
+ dst = vs->getPixels(0, 0);
+
+ for (i = 0; i < h; i++) {
+ memcpy(dst, src, w);
+ dst += vs->pitch;
+ src += w;
+ }
+
+ free(buf);
+}
+
+void ScummEngine_v6::useBompCursor(const byte *im, int width, int height) {
+ uint size;
+
+ width *= 8;
+ height *= 8;
+
+ size = width * height;
+ if (size > sizeof(_grabbedCursor))
+ error("useBompCursor: cursor too big (%d)", size);
+
+ _cursor.width = width;
+ _cursor.height = height;
+ _cursor.animate = 0;
+
+ // Skip the header
+ if (_version == 8) {
+ im += 16;
+ } else {
+ im += 18;
+ }
+ decompressBomp(_grabbedCursor, im, width, height);
+
+ updateCursor();
+}
+
+void ScummEngine_v5::redefineBuiltinCursorFromChar(int index, int chr) {
+ // Cursor image in both Looms are based on images from charset.
+ if (_gameId != GID_LOOM) {
+ // FIXME: Actually: is this opcode ever called by a non-Loom game?
+ // Which V3-V5 game besides Loom makes use of custom cursors, ever?
+ error("V3--V5 SO_CURSOR_IMAGE(%d,%d) called - tell Fingolfin where you saw this!", index, chr);
+ }
+
+ assert(index >= 0 && index < 4);
+
+// const int oldID = _charset->getCurID();
+
+ if (_version == 3) {
+ _charset->setCurID(0);
+ } else if (_version >= 4) {
+ _charset->setCurID(1);
+ }
+
+ Graphics::Surface s;
+ byte buf[16*17];
+ memset(buf, 123, 16*17);
+ s.pixels = buf;
+ s.w = _charset->getCharWidth(chr);
+ s.h = _charset->getFontHeight();
+ s.pitch = s.w;
+ // s.h = 17 for FM-TOWNS Loom Japanese. Fixes bug #1166917
+ assert(s.w <= 16 && s.h <= 17);
+ s.bytesPerPixel = 1;
+
+ _charset->drawChar(chr, s, 0, 0);
+
+ uint16 *ptr = _cursorImages[index];
+ memset(ptr, 0, 17 * sizeof(uint16));
+ for (int h = 0; h < s.h; h++) {
+ for (int w = 0; w < s.w; w++) {
+ if (buf[s.pitch * h + w] != 123)
+ *ptr |= 1 << (15 - w);
+ }
+ ptr++;
+ }
+
+// _charset->setCurID(oldID);
+}
+
+void ScummEngine_v5::redefineBuiltinCursorHotspot(int index, int x, int y) {
+ // Cursor image in both Looms are based on images from charset.
+ if (_gameId != GID_LOOM) {
+ // FIXME: Actually: is this opcode ever called by a non-Loom game?
+ // Which V3-V5 game besides Loom makes use of custom cursors, ever?
+ error("V3--V5 SO_CURSOR_HOTSPOT(%d,%d,%d) called - tell Fingolfin where you saw this!", index, x, y);
+ }
+
+ assert(index >= 0 && index < 4);
+
+ _cursorHotspots[index * 2] = x;
+ _cursorHotspots[index * 2 + 1] = y;
+}
+
+void ScummEngine_v5::setBuiltinCursor(int idx) {
+ int i, j;
+ byte color;
+
+ memset(_grabbedCursor, 0xFF, sizeof(_grabbedCursor));
+
+ if (_version == 1)
+ color = default_v1_cursor_colors[idx];
+ else
+ color = default_cursor_colors[idx];
+
+ if (_platform == Common::kPlatformNES) {
+ _cursor.width = 8;
+ _cursor.height = 8;
+ _cursor.hotspotX = 0;
+ _cursor.hotspotY = 0;
+
+ byte *dst = _grabbedCursor;
+ byte *src = &_NESPatTable[0][0xfa * 16];
+ byte *palette = _NESPalette[1];
+
+ for (i = 0; i < 8; i++) {
+ byte c0 = src[i];
+ byte c1 = src[i + 8];
+ for (j = 0; j < 8; j++)
+ *dst++ = palette[((c0 >> (7 - j)) & 1) | (((c1 >> (7 - j)) & 1) << 1) | ((idx == 3) ? 4 : 0)];
+ }
+
+ } else if (_version <= 2 && _platform == Common::kPlatformAmiga) {
+ _cursor.width = 15;
+ _cursor.height = 15;
+ _cursor.hotspotX = 7;
+ _cursor.hotspotY = 7;
+
+ byte *hotspot = _grabbedCursor + _cursor.hotspotY * _cursor.width + _cursor.hotspotX;
+
+ // Crosshair, symmetric
+ // TODO: Instead of setting this up via code, we should simply extend
+ // default_cursor_images to contain this shape.
+ for (i = 0; i < 5; i++) {
+ *(hotspot - 3 - i) = color;
+ *(hotspot + 3 + i) = color;
+ *(hotspot - _cursor.width * (3 + i)) = color;
+ *(hotspot + _cursor.width * (3 + i)) = color;
+ }
+
+ // Arrow heads, diagonal lines
+ for (i = 1; i <= 2; i++) {
+ *(hotspot - _cursor.width * i - (3 + i)) = color;
+ *(hotspot + _cursor.width * i - (3 + i)) = color;
+ *(hotspot - _cursor.width * i + (3 + i)) = color;
+ *(hotspot + _cursor.width * i + (3 + i)) = color;
+ *(hotspot - _cursor.width * (3 + i) - i) = color;
+ *(hotspot + _cursor.width * (3 + i) - i) = color;
+ *(hotspot - _cursor.width * (3 + i) + i) = color;
+ *(hotspot + _cursor.width * (3 + i) + i) = color;
+ }
+ } else if (_version <= 2) {
+ _cursor.width = 23;
+ _cursor.height = 21;
+ _cursor.hotspotX = 11;
+ _cursor.hotspotY = 10;
+
+ byte *hotspot = _grabbedCursor + _cursor.hotspotY * _cursor.width + _cursor.hotspotX;
+
+ // Crosshair, slightly assymetric
+ // TODO: Instead of setting this up via code, we should simply extend
+ // default_cursor_images to contain this shape.
+
+ for (i = 0; i < 7; i++) {
+ *(hotspot - 5 - i) = color;
+ *(hotspot + 5 + i) = color;
+ }
+
+ for (i = 0; i < 8; i++) {
+ *(hotspot - _cursor.width * (3 + i)) = color;
+ *(hotspot + _cursor.width * (3 + i)) = color;
+ }
+
+ // Arrow heads, diagonal lines
+
+ for (i = 1; i <= 3; i++) {
+ *(hotspot - _cursor.width * i - 5 - i) = color;
+ *(hotspot + _cursor.width * i - 5 - i) = color;
+ *(hotspot - _cursor.width * i + 5 + i) = color;
+ *(hotspot + _cursor.width * i + 5 + i) = color;
+ *(hotspot - _cursor.width * (i + 3) - i) = color;
+ *(hotspot - _cursor.width * (i + 3) + i) = color;
+ *(hotspot + _cursor.width * (i + 3) - i) = color;
+ *(hotspot + _cursor.width * (i + 3) + i) = color;
+ }
+
+ // Final touches
+
+ *(hotspot - _cursor.width - 7) = color;
+ *(hotspot - _cursor.width + 7) = color;
+ *(hotspot + _cursor.width - 7) = color;
+ *(hotspot + _cursor.width + 7) = color;
+ *(hotspot - (_cursor.width * 5) - 1) = color;
+ *(hotspot - (_cursor.width * 5) + 1) = color;
+ *(hotspot + (_cursor.width * 5) - 1) = color;
+ *(hotspot + (_cursor.width * 5) + 1) = color;
+ } else {
+ const uint16 *src;
+
+ _cursor.hotspotX = _cursorHotspots[2 * _currentCursor];
+ _cursor.hotspotY = _cursorHotspots[2 * _currentCursor + 1];
+ src = _cursorImages[_currentCursor];
+
+ _cursor.width = 16;
+ _cursor.height = 16;
+
+ for (i = 0; i < 16; i++) {
+ for (j = 0; j < 16; j++) {
+ if (src[i] & (1 << j))
+ _grabbedCursor[16 * i + 15 - j] = color;
+ }
+ }
+ }
+
+ updateCursor();
+}
+
+} // End of namespace Scumm