diff options
Diffstat (limited to 'engines/sword2/mouse.cpp')
-rw-r--r-- | engines/sword2/mouse.cpp | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/engines/sword2/mouse.cpp b/engines/sword2/mouse.cpp index 83a8b1faf2..81419c39e0 100644 --- a/engines/sword2/mouse.cpp +++ b/engines/sword2/mouse.cpp @@ -20,6 +20,8 @@ */ #include "common/stdafx.h" +#include "common/system.h" + #include "sword2/sword2.h" #include "sword2/console.h" #include "sword2/controls.h" @@ -1434,4 +1436,219 @@ void Mouse::unpauseGame() { setLuggage(_realLuggageItem); } +// This is the maximum mouse cursor size in the SDL backend +#define MAX_MOUSE_W 80 +#define MAX_MOUSE_H 80 + +#define MOUSEFLASHFRAME 6 + +void Mouse::decompressMouse(byte *decomp, byte *comp, uint8 frame, int width, int height, int pitch, int xOff, int yOff) { + int32 size = width * height; + int32 i = 0; + int x = 0; + int y = 0; + + comp = comp + READ_LE_UINT32(comp + frame * 4) - MOUSE_ANIM_HEADER_SIZE; + + while (i < size) { + if (*comp > 183) { + decomp[(y + yOff) * pitch + x + xOff] = *comp++; + if (++x >= width) { + x = 0; + y++; + } + i++; + } else { + x += *comp; + while (x >= width) { + y++; + x -= width; + } + i += *comp++; + } + } +} + +void Mouse::drawMouse() { + byte mouseData[MAX_MOUSE_W * MAX_MOUSE_H]; + + if (!_mouseAnim.data && !_luggageAnim.data) + return; + + // When an object is used in the game, the mouse cursor should be a + // combination of a standard mouse cursor and a luggage cursor. + // + // However, judging by the original code luggage cursors can also + // appear on their own. I have no idea which cases though. + + uint16 mouse_width = 0; + uint16 mouse_height = 0; + uint16 hotspot_x = 0; + uint16 hotspot_y = 0; + int deltaX = 0; + int deltaY = 0; + + if (_mouseAnim.data) { + hotspot_x = _mouseAnim.xHotSpot; + hotspot_y = _mouseAnim.yHotSpot; + mouse_width = _mouseAnim.mousew; + mouse_height = _mouseAnim.mouseh; + } + + if (_luggageAnim.data) { + if (!_mouseAnim.data) { + hotspot_x = _luggageAnim.xHotSpot; + hotspot_y = _luggageAnim.yHotSpot; + } + if (_luggageAnim.mousew > mouse_width) + mouse_width = _luggageAnim.mousew; + if (_luggageAnim.mouseh > mouse_height) + mouse_height = _luggageAnim.mouseh; + } + + if (_mouseAnim.data && _luggageAnim.data) { + deltaX = _mouseAnim.xHotSpot - _luggageAnim.xHotSpot; + deltaY = _mouseAnim.yHotSpot - _luggageAnim.yHotSpot; + } + + assert(deltaX >= 0); + assert(deltaY >= 0); + + // HACK for maximum cursor size. (The SDL backend imposes this + // restriction) + + if (mouse_width + deltaX > MAX_MOUSE_W) + deltaX = 80 - mouse_width; + if (mouse_height + deltaY > MAX_MOUSE_H) + deltaY = 80 - mouse_height; + + mouse_width += deltaX; + mouse_height += deltaY; + + if ((uint32)(mouse_width * mouse_height) > sizeof(mouseData)) { + warning("Mouse cursor too large"); + return; + } + + memset(mouseData, 0, mouse_width * mouse_height); + + if (_luggageAnim.data) + decompressMouse(mouseData, _luggageAnim.data, 0, + _luggageAnim.mousew, _luggageAnim.mouseh, + mouse_width, deltaX, deltaY); + + if (_mouseAnim.data) + decompressMouse(mouseData, _mouseAnim.data, _mouseFrame, + _mouseAnim.mousew, _mouseAnim.mouseh, mouse_width); + + _vm->_system->setMouseCursor(mouseData, mouse_width, mouse_height, hotspot_x, hotspot_y, 0); +} + +/** + * Animates the current mouse pointer + */ + +int32 Mouse::animateMouse() { + uint8 prevMouseFrame = _mouseFrame; + + if (!_mouseAnim.data) + return RDERR_UNKNOWN; + + if (++_mouseFrame == _mouseAnim.noAnimFrames) + _mouseFrame = MOUSEFLASHFRAME; + + if (_mouseFrame != prevMouseFrame) + drawMouse(); + + return RD_OK; +} + +/** + * Sets the mouse cursor animation. + * @param ma a pointer to the animation data, or NULL to clear the current one + * @param size the size of the mouse animation data + * @param mouseFlash RDMOUSE_FLASH or RDMOUSE_NOFLASH, depending on whether + * or not there is a lead-in animation + */ + +int32 Mouse::setMouseAnim(byte *ma, int32 size, int32 mouseFlash) { + free(_mouseAnim.data); + _mouseAnim.data = NULL; + + if (ma) { + if (mouseFlash == RDMOUSE_FLASH) + _mouseFrame = 0; + else + _mouseFrame = MOUSEFLASHFRAME; + + Common::MemoryReadStream readS(ma, size); + + _mouseAnim.runTimeComp = readS.readByte(); + _mouseAnim.noAnimFrames = readS.readByte(); + _mouseAnim.xHotSpot = readS.readSByte(); + _mouseAnim.yHotSpot = readS.readSByte(); + _mouseAnim.mousew = readS.readByte(); + _mouseAnim.mouseh = readS.readByte(); + + _mouseAnim.data = (byte *)malloc(size - MOUSE_ANIM_HEADER_SIZE); + if (!_mouseAnim.data) + return RDERR_OUTOFMEMORY; + + readS.read(_mouseAnim.data, size - MOUSE_ANIM_HEADER_SIZE); + + animateMouse(); + drawMouse(); + + _vm->_system->showMouse(true); + } else { + if (_luggageAnim.data) + drawMouse(); + else + _vm->_system->showMouse(false); + } + + return RD_OK; +} + +/** + * Sets the "luggage" animation to accompany the mouse animation. Luggage + * sprites are of the same format as mouse sprites. + * @param ma a pointer to the animation data, or NULL to clear the current one + * @param size the size of the animation data + */ + +int32 Mouse::setLuggageAnim(byte *ma, int32 size) { + free(_luggageAnim.data); + _luggageAnim.data = NULL; + + if (ma) { + Common::MemoryReadStream readS(ma, size); + + _luggageAnim.runTimeComp = readS.readByte(); + _luggageAnim.noAnimFrames = readS.readByte(); + _luggageAnim.xHotSpot = readS.readSByte(); + _luggageAnim.yHotSpot = readS.readSByte(); + _luggageAnim.mousew = readS.readByte(); + _luggageAnim.mouseh = readS.readByte(); + + _luggageAnim.data = (byte *)malloc(size - MOUSE_ANIM_HEADER_SIZE); + if (!_luggageAnim.data) + return RDERR_OUTOFMEMORY; + + readS.read(_luggageAnim.data, size - MOUSE_ANIM_HEADER_SIZE); + + animateMouse(); + drawMouse(); + + _vm->_system->showMouse(true); + } else { + if (_mouseAnim.data) + drawMouse(); + else + _vm->_system->showMouse(false); + } + + return RD_OK; +} + } // End of namespace Sword2 |