aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/graphics/cursor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/graphics/cursor.cpp')
-rw-r--r--engines/sci/graphics/cursor.cpp227
1 files changed, 227 insertions, 0 deletions
diff --git a/engines/sci/graphics/cursor.cpp b/engines/sci/graphics/cursor.cpp
new file mode 100644
index 0000000000..4682fd42a6
--- /dev/null
+++ b/engines/sci/graphics/cursor.cpp
@@ -0,0 +1,227 @@
+/* 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 "graphics/cursorman.h"
+#include "common/util.h"
+#include "common/events.h"
+
+#include "sci/sci.h"
+#include "sci/engine/state.h"
+#include "sci/graphics/palette.h"
+#include "sci/graphics/screen.h"
+#include "sci/graphics/view.h"
+#include "sci/graphics/cursor.h"
+
+namespace Sci {
+
+Cursor::Cursor(ResourceManager *resMan, SciPalette *palette, Screen *screen)
+ : _resMan(resMan), _palette(palette), _screen(screen) {
+
+ _upscaledHires = _screen->getUpscaledHires();
+ // center mouse cursor
+ setPosition(Common::Point(_screen->_displayWidth / 2, _screen->_displayHeight / 2));
+ setMoveZone(Common::Rect(0, 0, _screen->_displayWidth, _screen->_displayHeight));
+
+ _isVisible = true;
+}
+
+Cursor::~Cursor() {
+ purgeCache();
+}
+
+void Cursor::show() {
+ CursorMan.showMouse(true);
+ _isVisible = true;
+}
+
+void Cursor::hide() {
+ CursorMan.showMouse(false);
+ _isVisible = false;
+}
+
+bool Cursor::isVisible() {
+ return _isVisible;
+}
+
+void Cursor::purgeCache() {
+ for (CursorCache::iterator iter = _cachedCursors.begin(); iter != _cachedCursors.end(); ++iter) {
+ delete iter->_value;
+ iter->_value = 0;
+ }
+
+ _cachedCursors.clear();
+}
+
+void Cursor::setShape(GuiResourceId resourceId) {
+ Resource *resource;
+ byte *resourceData;
+ Common::Point hotspot = Common::Point(0, 0);
+ byte colorMapping[4];
+ int16 x, y;
+ byte color;
+ int16 maskA, maskB;
+ byte *pOut;
+ byte *rawBitmap = new byte[SCI_CURSOR_SCI0_HEIGHTWIDTH * SCI_CURSOR_SCI0_HEIGHTWIDTH];
+
+ if (resourceId == -1) {
+ // no resourceId given, so we actually hide the cursor
+ hide();
+ delete[] rawBitmap;
+ return;
+ }
+
+ // Load cursor resource...
+ resource = _resMan->findResource(ResourceId(kResourceTypeCursor, resourceId), false);
+ if (!resource)
+ error("cursor resource %d not found", resourceId);
+ if (resource->size != SCI_CURSOR_SCI0_RESOURCESIZE)
+ error("cursor resource %d has invalid size", resourceId);
+
+ resourceData = resource->data;
+ // hotspot is specified for SCI1 cursors
+ hotspot.x = READ_LE_UINT16(resourceData);
+ hotspot.y = READ_LE_UINT16(resourceData + 2);
+ // bit 0 of resourceData[3] is set on <SCI1 games, which means center hotspot
+ if ((hotspot.x == 0) && (hotspot.y == 256))
+ hotspot.x = hotspot.y = SCI_CURSOR_SCI0_HEIGHTWIDTH / 2;
+
+ // Now find out what colors we are supposed to use
+ colorMapping[0] = 0; // Black is hardcoded
+ colorMapping[1] = _screen->_colorWhite; // White is also hardcoded
+ colorMapping[2] = SCI_CURSOR_SCI0_TRANSPARENCYCOLOR;
+ colorMapping[3] = _palette->matchColor(&_palette->_sysPalette, 170, 170, 170); // Grey
+
+ // Seek to actual data
+ resourceData += 4;
+
+ pOut = rawBitmap;
+ for (y = 0; y < SCI_CURSOR_SCI0_HEIGHTWIDTH; y++) {
+ maskA = READ_LE_UINT16(resourceData + (y << 1));
+ maskB = READ_LE_UINT16(resourceData + 32 + (y << 1));
+
+ for (x = 0; x < SCI_CURSOR_SCI0_HEIGHTWIDTH; x++) {
+ color = (((maskA << x) & 0x8000) | (((maskB << x) >> 1) & 0x4000)) >> 14;
+ *pOut++ = colorMapping[color];
+ }
+ }
+
+ CursorMan.replaceCursor(rawBitmap, SCI_CURSOR_SCI0_HEIGHTWIDTH, SCI_CURSOR_SCI0_HEIGHTWIDTH, hotspot.x, hotspot.y, SCI_CURSOR_SCI0_TRANSPARENCYCOLOR);
+ CursorMan.showMouse(true);
+
+ delete[] rawBitmap;
+}
+
+void Cursor::setView(GuiResourceId viewNum, int loopNum, int celNum, Common::Point *hotspot) {
+ if (_cachedCursors.size() >= MAX_CACHED_CURSORS)
+ purgeCache();
+
+ if (!_cachedCursors.contains(viewNum))
+ _cachedCursors[viewNum] = new View(_resMan, _screen, _palette, viewNum);
+
+ View *cursorView = _cachedCursors[viewNum];
+
+ CelInfo *celInfo = cursorView->getCelInfo(loopNum, celNum);
+ int16 width = celInfo->width;
+ int16 height = celInfo->height;
+ byte clearKey = celInfo->clearKey;
+ Common::Point *cursorHotspot = hotspot;
+ if (!cursorHotspot)
+ // Compute hotspot from xoffset/yoffset
+ cursorHotspot = new Common::Point((celInfo->width >> 1) - celInfo->displaceX, celInfo->height - celInfo->displaceY - 1);
+
+ // Eco Quest 1 uses a 1x1 transparent cursor to hide the cursor from the user. Some scalers don't seem to support this
+ if (width < 2 || height < 2) {
+ hide();
+ delete cursorHotspot;
+ return;
+ }
+
+ byte *cursorBitmap = cursorView->getBitmap(loopNum, celNum);
+
+ if (_upscaledHires) {
+ // Scale cursor by 2x
+ width *= 2;
+ height *= 2;
+ cursorHotspot->x *= 2;
+ cursorHotspot->y *= 2;
+ cursorBitmap = new byte[width * height];
+ _screen->scale2x(celInfo->rawBitmap, cursorBitmap, celInfo->width, celInfo->height);
+ }
+
+ CursorMan.replaceCursor(cursorBitmap, width, height, cursorHotspot->x, cursorHotspot->y, clearKey);
+
+ if (_upscaledHires)
+ delete[] cursorBitmap;
+
+ show();
+
+ delete cursorHotspot;
+}
+
+void Cursor::setPosition(Common::Point pos) {
+ if (!_upscaledHires) {
+ g_system->warpMouse(pos.x, pos.y);
+ } else {
+ g_system->warpMouse(pos.x * 2, pos.y * 2);
+ }
+}
+
+Common::Point Cursor::getPosition() {
+ Common::Point mousePos = g_system->getEventManager()->getMousePos();
+
+ if (_upscaledHires) {
+ mousePos.x /= 2;
+ mousePos.y /= 2;
+ }
+
+ return mousePos;
+}
+
+void Cursor::refreshPosition() {
+ bool clipped = false;
+ Common::Point mousePoint = getPosition();
+
+ if (mousePoint.x < _moveZone.left) {
+ mousePoint.x = _moveZone.left;
+ clipped = true;
+ } else if (mousePoint.x >= _moveZone.right) {
+ mousePoint.x = _moveZone.right - 1;
+ clipped = true;
+ }
+
+ if (mousePoint.y < _moveZone.top) {
+ mousePoint.y = _moveZone.top;
+ clipped = true;
+ } else if (mousePoint.y >= _moveZone.bottom) {
+ mousePoint.y = _moveZone.bottom - 1;
+ clipped = true;
+ }
+
+ // FIXME: Do this only when mouse is grabbed?
+ if (clipped)
+ setPosition(mousePoint);
+}
+
+} // End of namespace Sci