/* Copyright (C) 1994-2003 Revolution Software Ltd * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * $Header$ */ #include "stdafx.h" #include "sword2/driver/driver96.h" #include "sword2/driver/d_draw.h" #include "sword2/driver/render.h" #include "sword2/driver/menu.h" #include "sword2/sword2.h" namespace Sword2 { #define MAX_MOUSE_EVENTS 16 #define MOUSEFLASHFRAME 6 static uint8 mouseBacklog = 0; static uint8 mouseLogPos = 0; static _mouseEvent mouseLog[MAX_MOUSE_EVENTS]; void Display::resetRenderEngine(void) { _parallaxScrollX = 0; _parallaxScrollY = 0; _scrollX = 0; _scrollY = 0; } // -------------------------------------------------------------------------- // Logs the mouse button event passed in buttons. The button events are // defined as RD_LEFTBUTTONDOWN, RD_LEFTBUTTONUP, RD_RIGHTBUTTONDOWN and // RD_RIGHTBUTTONUP. // -------------------------------------------------------------------------- void LogMouseEvent(uint16 buttons) { _mouseEvent *me; // We need to leave the one, which is the current event, alone! if (mouseBacklog == MAX_MOUSE_EVENTS - 1) return; me = &mouseLog[(mouseBacklog + mouseLogPos) % MAX_MOUSE_EVENTS]; me->buttons = buttons; mouseBacklog++; } // FIXME: The original code used 0 for transparency, while our backend uses // 0xFF. That means that parts of the mouse cursor that weren't meant to be // transparent may be now. void Display::decompressMouse(uint8 *decomp, uint8 *comp, int width, int height, int pitch, int xOff, int yOff) { int32 size = width * height; int32 i = 0; int x = 0; int y = 0; 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 Display::drawMouse(void) { if (!_mouseAnim && !_luggageAnim) 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) { hotspot_x = _mouseAnim->xHotSpot; hotspot_y = _mouseAnim->yHotSpot; mouse_width = _mouseAnim->mousew; mouse_height = _mouseAnim->mouseh; } if (_luggageAnim) { if (!_mouseAnim) { 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 && _luggageAnim) { 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, 0xFF, mouse_width * mouse_height); if (_luggageAnim) decompressMouse(_mouseData, (uint8 *) _luggageAnim + READ_LE_UINT32(_luggageOffset), _luggageAnim->mousew, _luggageAnim->mouseh, mouse_width, deltaX, deltaY); if (_mouseAnim) decompressMouse(_mouseData, _mouseSprite, _mouseAnim->mousew, _mouseAnim->mouseh, mouse_width); g_system->set_mouse_cursor(_mouseData, mouse_width, mouse_height, hotspot_x, hotspot_y); } /** * Get the next pending mouse event. * @return a pointer to the mouse event, or NULL of there is none */ _mouseEvent *MouseEvent(void) { _mouseEvent *me; if (mouseBacklog) { me = &mouseLog[mouseLogPos]; if (++mouseLogPos == MAX_MOUSE_EVENTS) mouseLogPos = 0; mouseBacklog--; return me; } return NULL; } uint8 CheckForMouseEvents(void) { return mouseBacklog; // return the number of mouse events waiting } /** * Animates the current mouse pointer */ int32 Display::animateMouse(void) { uint8 prevMouseFrame = _mouseFrame; if (!_mouseAnim) return RDERR_UNKNOWN; if (++_mouseFrame == _mouseAnim->noAnimFrames) _mouseFrame = MOUSEFLASHFRAME; _mouseSprite = (uint8 *) _mouseAnim + READ_LE_UINT32(_mouseOffsets + _mouseFrame); 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 Display::setMouseAnim(uint8 *ma, int32 size, int32 mouseFlash) { if (_mouseAnim) { free(_mouseAnim); _mouseAnim = NULL; } if (ma) { if (mouseFlash == RDMOUSE_FLASH) _mouseFrame = 0; else _mouseFrame = MOUSEFLASHFRAME; _mouseAnim = (struct _mouseAnim *) malloc(size); if (!_mouseAnim) return RDERR_OUTOFMEMORY; memcpy((uint8 *) _mouseAnim, ma, size); _mouseOffsets = (int32 *) ((uint8 *) _mouseAnim + sizeof(struct _mouseAnim)); animateMouse(); drawMouse(); g_system->show_mouse(true); } else { if (_luggageAnim) drawMouse(); else g_system->show_mouse(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 Display::setLuggageAnim(uint8 *ma, int32 size) { if (_luggageAnim) { free(_luggageAnim); _luggageAnim = NULL; } if (ma) { _luggageAnim = (struct _mouseAnim *) malloc(size); if (!_luggageAnim) return RDERR_OUTOFMEMORY; memcpy((uint8 *) _luggageAnim, ma, size); _luggageOffset = (int32 *) ((uint8 *) _luggageAnim + sizeof(struct _mouseAnim)); animateMouse(); drawMouse(); g_system->show_mouse(true); } else { if (_mouseAnim) drawMouse(); else g_system->show_mouse(false); } return RD_OK; } } // End of namespace Sword2