scummvm/sword2/driver/_mouse.cpp

356 lines
8.4 KiB
C++
Raw Normal View History

2003-07-28 01:47:41 +00:00
/* 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$
*/
//=============================================================================
//
// Filename : mouse.c
// Created : 17th September 1996
// By : P.R.Porter
//
// Summary : This module holds the interface to the mouse..
//
// Functions
// ---------
//
// --------------------------------------------------------------------------
//
// _mouseEvent *MouseEvent(void)
//
// The address of a _mouseEvent pointer is passed in. If there is a mouse
// event in the queue, a the value of the mouse event pointer is set to the
// address of the event, otherwise, the mouse event pointer is set to NULL.
//
// --------------------------------------------------------------------------
//
// int32 SetMouseAnim(uint8 *ma, int32 size)
//
// A pointer to a valid mouse animation is passed in, along with the size of
// the header plus sprite data. Remember to check that the function has
// successfully completed, as memory allocation is required.
// Pass NULL in to clear the mouse sprite.
//
// --------------------------------------------------------------------------
//
// int32 SetLuggageAnim(uint8 *ma, int32 size)
//
// A pointer to a valid luggage animation is passed in, along with the size of
// the header plus sprite data. Remember to check that the function has
// successfully completed, as memory allocation is required.
// Pass NULL in to clear the luggage sprite. Luggage sprites are of the same
// format as mouse sprites.
//
// --------------------------------------------------------------------------
//
// int32 AnimateMouse(void)
//
// This function animates the current mouse pointer. If no pointer is
// currently defined, an error code is returned.
//
//=============================================================================
//#include "ddraw.h"
2003-07-28 03:12:49 +00:00
#include "stdafx.h"
2003-07-28 01:47:41 +00:00
#include "driver96.h"
#include "d_draw.h"
#include "render.h"
#include "menu.h"
#include "../sword2.h"
2003-07-28 01:47:41 +00:00
#define MAX_MOUSE_EVENTS 16
#define MOUSEFLASHFRAME 6
// FIXME: Does this struct have to be packed?
2003-07-28 01:47:41 +00:00
typedef struct {
2003-07-28 01:47:41 +00:00
uint8 runTimeComp; // type of runtime compression used for the frame data
uint8 noAnimFrames; // number of frames in the anim
int8 xHotSpot;
int8 yHotSpot;
uint8 mousew;
uint8 mouseh;
} _mouseAnim;
int16 mousex;
int16 mousey;
static uint8 mouseBacklog = 0;
static uint8 mouseLogPos = 0;
static uint8 mouseFrame;
static uint8 *mouseSprite = NULL;
static _mouseAnim *mouseAnim = NULL;
static _mouseAnim *luggageAnim = NULL;
2003-07-28 01:47:41 +00:00
static _mouseEvent mouseLog[MAX_MOUSE_EVENTS];
static int32 *mouseOffsets;
static int32 *luggageOffset;
2003-07-28 01:47:41 +00:00
// FIXME: I have no idea how large the mouse cursor can be. Is this enough?
2003-07-28 01:47:41 +00:00
byte _mouseData[128 * 128];
2003-07-28 01:47:41 +00:00
void ResetRenderEngine(void) {
2003-07-28 01:47:41 +00:00
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;
if (mouseBacklog == MAX_MOUSE_EVENTS-1) // We need to leave the one which is
{ // the current event alone!
return;
}
me = &mouseLog[(mouseBacklog + mouseLogPos) % MAX_MOUSE_EVENTS];
me->buttons = buttons;
mouseBacklog += 1;
}
// 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.
2003-07-28 01:47:41 +00:00
int32 DecompressMouse(uint8 *decomp, uint8 *comp, int width, int height, int pitch, int xOff = 0, int yOff = 0) {
int32 size = width * height;
2003-07-28 01:47:41 +00:00
int32 i = 0;
int x = 0;
int y = 0;
2003-07-28 01:47:41 +00:00
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;
}
2003-07-28 01:47:41 +00:00
i += *comp++;
}
}
return RD_OK;
2003-07-28 01:47:41 +00:00
}
void 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;
2003-07-28 01:47:41 +00:00
}
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
if (mouse_width + deltaX > 80)
deltaX = 80 - mouse_width;
if (mouse_height + deltaY > 80)
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 + (int32)READ_LE_UINT32(luggageOffset), luggageAnim->mousew,
luggageAnim->mouseh, mouse_width, deltaX, deltaY);
if (mouseAnim)
DecompressMouse(_mouseData, mouseSprite, mouseAnim->mousew, mouseAnim->mouseh, mouse_width);
2003-08-28 06:14:46 +00:00
g_system->set_mouse_cursor(_mouseData, mouse_width, mouse_height, hotspot_x, hotspot_y);
2003-07-28 01:47:41 +00:00
}
_mouseEvent *MouseEvent(void)
{
_mouseEvent *me;
if (mouseBacklog)
{
me = &mouseLog[mouseLogPos];
if (++mouseLogPos == MAX_MOUSE_EVENTS)
{
mouseLogPos = 0;
}
mouseBacklog -= 1;
return(me);
}
return(NULL);
}
uint8 CheckForMouseEvents(void) // (James23july97)
{
return (mouseBacklog); // return the number of mouse events waiting
}
int32 AnimateMouse(void) {
uint8 prevMouseFrame = mouseFrame;
2003-07-28 01:47:41 +00:00
if (!mouseAnim)
return RDERR_UNKNOWN;
2003-07-28 01:47:41 +00:00
if (++mouseFrame == mouseAnim->noAnimFrames)
mouseFrame = MOUSEFLASHFRAME;
2003-09-12 18:52:53 +00:00
mouseSprite = (uint8 *) mouseAnim + (int32)READ_LE_UINT32(mouseOffsets + mouseFrame);
if (mouseFrame != prevMouseFrame)
DrawMouse();
2003-07-28 01:47:41 +00:00
return RD_OK;
}
2003-07-28 01:47:41 +00:00
int32 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 = (_mouseAnim *) malloc(size);
if (!mouseAnim)
return RDERR_OUTOFMEMORY;
memcpy((uint8 *) mouseAnim, ma, size);
mouseOffsets = (int32 *) ((uint8 *) mouseAnim + sizeof(_mouseAnim));
AnimateMouse();
DrawMouse();
2003-08-28 06:14:46 +00:00
g_system->show_mouse(true);
} else {
if (luggageAnim)
DrawMouse();
else
2003-08-28 06:14:46 +00:00
g_system->show_mouse(false);
}
return RD_OK;
}
2003-07-28 01:47:41 +00:00
int32 SetLuggageAnim(uint8 *ma, int32 size) {
if (luggageAnim) {
free(luggageAnim);
luggageAnim = NULL;
2003-07-28 01:47:41 +00:00
}
if (ma) {
luggageAnim = (_mouseAnim *) malloc(size);
if (!luggageAnim)
2003-07-28 01:47:41 +00:00
return(RDERR_OUTOFMEMORY);
memcpy((uint8 *) luggageAnim, ma, size);
luggageOffset = (int32 *) ((uint8 *) luggageAnim + sizeof(_mouseAnim));
2003-07-28 01:47:41 +00:00
AnimateMouse();
DrawMouse();
2003-07-28 01:47:41 +00:00
2003-08-28 06:14:46 +00:00
g_system->show_mouse(true);
} else {
if (mouseAnim)
DrawMouse();
else
2003-08-28 06:14:46 +00:00
g_system->show_mouse(false);
}
return RD_OK;
2003-07-28 01:47:41 +00:00
}