Initial commit
This commit is contained in:
384
engines/sherlock/events.cpp
Normal file
384
engines/sherlock/events.cpp
Normal file
@@ -0,0 +1,384 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/events.h"
|
||||
#include "common/system.h"
|
||||
#include "engines/util.h"
|
||||
#include "graphics/cursorman.h"
|
||||
#include "sherlock/sherlock.h"
|
||||
#include "sherlock/events.h"
|
||||
#include "sherlock/surface.h"
|
||||
#include "sherlock/tattoo/tattoo.h"
|
||||
|
||||
namespace Sherlock {
|
||||
|
||||
enum ButtonFlag { LEFT_BUTTON = 1, RIGHT_BUTTON = 2 };
|
||||
|
||||
Events::Events(SherlockEngine *vm): _vm(vm) {
|
||||
_cursorImages = nullptr;
|
||||
_cursorId = INVALID_CURSOR;
|
||||
_frameCounter = 1;
|
||||
_priorFrameTime = 0;
|
||||
_mouseButtons = 0;
|
||||
_pressed = _released = false;
|
||||
_rightPressed = _rightReleased = false;
|
||||
_oldButtons = _oldRightButton = false;
|
||||
_firstPress = false;
|
||||
_waitCounter = 0;
|
||||
_frameRate = GAME_FRAME_RATE;
|
||||
|
||||
if (_vm->_interactiveFl)
|
||||
loadCursors("rmouse.vgs");
|
||||
}
|
||||
|
||||
Events::~Events() {
|
||||
delete _cursorImages;
|
||||
}
|
||||
|
||||
void Events::loadCursors(const Common::Path &filename) {
|
||||
hideCursor();
|
||||
delete _cursorImages;
|
||||
|
||||
if (!IS_3DO) {
|
||||
// PC
|
||||
_cursorImages = new ImageFile(filename);
|
||||
} else {
|
||||
// 3DO
|
||||
_cursorImages = new ImageFile3DO(filename, kImageFile3DOType_RoomFormat);
|
||||
}
|
||||
_cursorId = INVALID_CURSOR;
|
||||
}
|
||||
|
||||
void Events::setCursor(CursorId cursorId) {
|
||||
if (cursorId == _cursorId || _waitCounter > 0)
|
||||
return;
|
||||
|
||||
int hotspotX, hotspotY;
|
||||
|
||||
if (cursorId == MAGNIFY) {
|
||||
hotspotX = 8;
|
||||
hotspotY = 8;
|
||||
} else {
|
||||
hotspotX = 0;
|
||||
hotspotY = 0;
|
||||
}
|
||||
|
||||
// Set the cursor data
|
||||
Graphics::Surface &s = (*_cursorImages)[cursorId]._frame;
|
||||
|
||||
setCursor(s, hotspotX, hotspotY);
|
||||
|
||||
_cursorId = cursorId;
|
||||
}
|
||||
|
||||
void Events::setCursor(const Graphics::Surface &src, int hotspotX, int hotspotY) {
|
||||
_cursorId = INVALID_CURSOR;
|
||||
_hotspotPos = Common::Point(hotspotX, hotspotY);
|
||||
|
||||
if (!IS_3DO) {
|
||||
// PC 8-bit palettized
|
||||
CursorMan.replaceCursor(src, hotspotX, hotspotY, 0xff);
|
||||
} else if (!_vm->_isScreenDoubled) {
|
||||
CursorMan.replaceCursor(src, hotspotX, hotspotY, 0x0000, false);
|
||||
} else {
|
||||
Graphics::Surface tempSurface;
|
||||
tempSurface.create(2 * src.w, 2 * src.h, src.format);
|
||||
|
||||
for (int y = 0; y < src.h; y++) {
|
||||
const uint16 *srcP = (const uint16 *)src.getBasePtr(0, y);
|
||||
uint16 *destP = (uint16 *)tempSurface.getBasePtr(0, 2 * y);
|
||||
for (int x = 0; x < src.w; ++x, ++srcP, destP += 2) {
|
||||
*destP = *srcP;
|
||||
*(destP + 1) = *srcP;
|
||||
*(destP + 2 * src.w) = *srcP;
|
||||
*(destP + 2 * src.w + 1) = *srcP;
|
||||
}
|
||||
}
|
||||
|
||||
// 3DO RGB565
|
||||
CursorMan.replaceCursor(tempSurface, 2 * hotspotX, 2 * hotspotY, 0x0000, false);
|
||||
|
||||
tempSurface.free();
|
||||
}
|
||||
}
|
||||
|
||||
void Events::setCursor(CursorId cursorId, const Common::Point &cursorPos, const Graphics::Surface &surface) {
|
||||
_cursorId = cursorId;
|
||||
|
||||
// Get the standard cursor frame
|
||||
Graphics::Surface &cursorImg = (*_cursorImages)[cursorId]._frame;
|
||||
|
||||
// If the X pos for the cursor image is -100, this is a special value to indicate
|
||||
// the cursor should be horizontally centered
|
||||
Common::Point cursorPt = cursorPos;
|
||||
if (cursorPos.x == -100)
|
||||
cursorPt.x = (surface.w - cursorImg.w) / 2;
|
||||
|
||||
// Figure total bounds needed for cursor image and passed image
|
||||
Common::Rect bounds(surface.w, surface.h);
|
||||
bounds.extend(Common::Rect(cursorPt.x, cursorPt.y, cursorPt.x + cursorImg.w, cursorPt.y + cursorImg.h));
|
||||
Common::Rect r = bounds;
|
||||
r.moveTo(0, 0);
|
||||
|
||||
// Form a single surface containing both frames
|
||||
Surface s(r.width(), r.height());
|
||||
s.clear(TRANSPARENCY);
|
||||
|
||||
// Draw the passed image
|
||||
Common::Point drawPos;
|
||||
if (cursorPt.x < 0)
|
||||
drawPos.x = -cursorPt.x;
|
||||
if (cursorPt.y < 0)
|
||||
drawPos.y = -cursorPt.y;
|
||||
s.SHblitFrom(surface, Common::Point(drawPos.x, drawPos.y));
|
||||
|
||||
// Draw the cursor image
|
||||
drawPos = Common::Point(MAX(cursorPt.x, (int16)0), MAX(cursorPt.y, (int16)0));
|
||||
s.SHtransBlitFrom(cursorImg, Common::Point(drawPos.x, drawPos.y));
|
||||
|
||||
// Set up hotspot position for cursor, adjusting for cursor image's position within the surface
|
||||
Common::Point hotspot;
|
||||
if (cursorId == MAGNIFY)
|
||||
hotspot = Common::Point(8, 8);
|
||||
hotspot += drawPos;
|
||||
// Set the cursor
|
||||
setCursor(s, hotspot.x, hotspot.y);
|
||||
}
|
||||
|
||||
void Events::animateCursorIfNeeded() {
|
||||
if (_cursorId >= WAIT && _cursorId < (WAIT + 3)) {
|
||||
CursorId newId = (_cursorId == WAIT + 2) ? WAIT : (CursorId)((int)_cursorId + 1);
|
||||
setCursor(newId);
|
||||
}
|
||||
}
|
||||
|
||||
void Events::showCursor() {
|
||||
if (IS_SERRATED_SCALPEL || !static_cast<Tattoo::TattooEngine *>(_vm)->_runningProlog)
|
||||
CursorMan.showMouse(true);
|
||||
}
|
||||
|
||||
void Events::hideCursor() {
|
||||
CursorMan.showMouse(false);
|
||||
}
|
||||
|
||||
CursorId Events::getCursor() const {
|
||||
return _cursorId;
|
||||
}
|
||||
|
||||
bool Events::isCursorVisible() const {
|
||||
return CursorMan.isVisible();
|
||||
}
|
||||
|
||||
void Events::pollEvents() {
|
||||
checkForNextFrameCounter();
|
||||
|
||||
Common::Event event;
|
||||
while (g_system->getEventManager()->pollEvent(event)) {
|
||||
// Handle events
|
||||
switch (event.type) {
|
||||
case Common::EVENT_QUIT:
|
||||
case Common::EVENT_RETURN_TO_LAUNCHER:
|
||||
return;
|
||||
|
||||
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
|
||||
_pendingActions.push(event.customType);
|
||||
return;
|
||||
case Common::EVENT_CUSTOM_ENGINE_ACTION_END:
|
||||
return;
|
||||
case Common::EVENT_KEYDOWN:
|
||||
_pendingKeys.push(event.kbd);
|
||||
return;
|
||||
case Common::EVENT_KEYUP:
|
||||
return;
|
||||
case Common::EVENT_LBUTTONDOWN:
|
||||
_mouseButtons |= LEFT_BUTTON;
|
||||
return;
|
||||
case Common::EVENT_RBUTTONDOWN:
|
||||
_mouseButtons |= RIGHT_BUTTON;
|
||||
return;
|
||||
case Common::EVENT_LBUTTONUP:
|
||||
_mouseButtons &= ~LEFT_BUTTON;
|
||||
return;
|
||||
case Common::EVENT_RBUTTONUP:
|
||||
_mouseButtons &= ~RIGHT_BUTTON;
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_mousePos = g_system->getEventManager()->getMousePos();
|
||||
if (_vm->_isScreenDoubled)
|
||||
_mousePos = Common::Point(_mousePos.x / 2, _mousePos.y / 2);
|
||||
}
|
||||
|
||||
void Events::pollEventsAndWait() {
|
||||
pollEvents();
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
|
||||
void Events::warpMouse(const Common::Point &pt) {
|
||||
Common::Point pos = pt;
|
||||
if (_vm->_isScreenDoubled)
|
||||
pos = Common::Point(pt.x / 2, pt.y);
|
||||
|
||||
_mousePos = pos - _vm->_screen->_currentScroll;
|
||||
g_system->warpMouse(_mousePos.x, _mousePos.y);
|
||||
}
|
||||
|
||||
void Events::warpMouse() {
|
||||
Screen &screen = *_vm->_screen;
|
||||
warpMouse(Common::Point(screen._currentScroll.x + SHERLOCK_SCREEN_WIDTH / 2,
|
||||
screen._currentScroll.y + SHERLOCK_SCREEN_HEIGHT / 2));
|
||||
}
|
||||
|
||||
Common::Point Events::mousePos() const {
|
||||
return _vm->_screen->_currentScroll + _mousePos;
|
||||
}
|
||||
|
||||
void Events::setFrameRate(int newRate) {
|
||||
_frameRate = newRate;
|
||||
}
|
||||
|
||||
void Events::toggleSpeed() {
|
||||
_frameRate = (_frameRate == GAME_FRAME_RATE) ? GAME_FRAME_RATE * 2 : GAME_FRAME_RATE;
|
||||
}
|
||||
|
||||
bool Events::checkForNextFrameCounter() {
|
||||
// Check for next game frame
|
||||
uint32 milli = g_system->getMillis();
|
||||
if ((milli - _priorFrameTime) >= (1000 / _frameRate)) {
|
||||
++_frameCounter;
|
||||
_priorFrameTime = milli;
|
||||
|
||||
// Display the frame
|
||||
_vm->_screen->update();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Common::KeyState Events::getKey() {
|
||||
Common::KeyState keyState = _pendingKeys.pop();
|
||||
|
||||
if (keyState.keycode == Common::KEYCODE_KP_ENTER)
|
||||
keyState.keycode = Common::KEYCODE_RETURN;
|
||||
|
||||
return keyState;
|
||||
}
|
||||
|
||||
Common::CustomEventType Events::getAction() {
|
||||
return _pendingActions.pop();
|
||||
}
|
||||
|
||||
void Events::clearEvents() {
|
||||
_pendingKeys.clear();
|
||||
_pendingActions.clear();
|
||||
_mouseButtons = 0;
|
||||
_pressed = _released = false;
|
||||
_rightPressed = _rightReleased = false;
|
||||
_oldButtons = _oldRightButton = false;
|
||||
_firstPress = false;
|
||||
}
|
||||
|
||||
void Events::clearKeyboard() {
|
||||
_pendingKeys.clear();
|
||||
}
|
||||
|
||||
void Events::clearActions() {
|
||||
_pendingActions.clear();
|
||||
}
|
||||
|
||||
void Events::wait(int numFrames) {
|
||||
uint32 totalMilli = numFrames * 1000 / _frameRate;
|
||||
delay(totalMilli);
|
||||
}
|
||||
|
||||
bool Events::delay(uint32 time, bool interruptable) {
|
||||
// Different handling for really short versus extended times
|
||||
if (time < 10) {
|
||||
// For really short periods, simply delay by the desired amount
|
||||
pollEvents();
|
||||
g_system->delayMillis(time);
|
||||
bool result = !(interruptable && (kbHit() || _pressed || _vm->shouldQuit()));
|
||||
|
||||
if (interruptable)
|
||||
clearEvents();
|
||||
return result;
|
||||
} else {
|
||||
// For long periods go into a loop where we delay by 10ms at a time and then
|
||||
// check for events. This ensures for longer delays that responsiveness is
|
||||
// maintained
|
||||
uint32 delayEnd = g_system->getMillis() + time;
|
||||
|
||||
while (!_vm->shouldQuit() && g_system->getMillis() < delayEnd) {
|
||||
pollEventsAndWait();
|
||||
|
||||
if (interruptable && (kbHit() || _mouseButtons || actionHit())) {
|
||||
clearEvents();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return !_vm->shouldQuit();
|
||||
}
|
||||
}
|
||||
|
||||
void Events::setButtonState() {
|
||||
_firstPress = ((_mouseButtons & 1) && !_pressed) || ((_mouseButtons & 2) && !_rightPressed);
|
||||
|
||||
_released = _rightReleased = false;
|
||||
if (_mouseButtons & LEFT_BUTTON)
|
||||
_pressed = _oldButtons = true;
|
||||
|
||||
if ((_mouseButtons & LEFT_BUTTON) == 0 && _oldButtons) {
|
||||
_pressed = _oldButtons = false;
|
||||
_released = true;
|
||||
}
|
||||
|
||||
if (_mouseButtons & RIGHT_BUTTON)
|
||||
_rightPressed = _oldRightButton = true;
|
||||
|
||||
if ((_mouseButtons & RIGHT_BUTTON) == 0 && _oldRightButton) {
|
||||
_rightPressed = _oldRightButton = false;
|
||||
_rightReleased = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool Events::checkInput() {
|
||||
setButtonState();
|
||||
return kbHit() || actionHit() || _pressed || _released || _rightPressed || _rightReleased;
|
||||
}
|
||||
|
||||
void Events::incWaitCounter() {
|
||||
setCursor(WAIT);
|
||||
++_waitCounter;
|
||||
}
|
||||
|
||||
void Events::decWaitCounter() {
|
||||
assert(_waitCounter > 0);
|
||||
--_waitCounter;
|
||||
}
|
||||
|
||||
} // End of namespace Sherlock
|
||||
Reference in New Issue
Block a user