1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "common/scummsys.h"
24 #include "graphics/cursorman.h"
25 #include "common/events.h"
26 #include "engines/util.h"
27 #include "mads/mads.h"
28 #include "mads/events.h"
29 #include "mads/scene.h"
30 
31 namespace MADS {
32 
EventsManager(MADSEngine * vm)33 EventsManager::EventsManager(MADSEngine *vm) {
34 	_vm = vm;
35 	_cursorSprites = nullptr;
36 	_cursorId = CURSOR_NONE;
37 	_newCursorId = CURSOR_NONE;
38 	_frameCounter = 10;
39 	_priorFrameTime = 0;
40 	_mouseClicked = false;
41 	_mouseReleased = false;
42 	_mouseButtons = 0;
43 	_mouseStatus = 0;
44 	_strokeGoing = 0;
45 	_mouseStatusCopy = 0;
46 	_mouseMoved = false;
47 	_rightMousePressed = false;
48 	_eventTarget = nullptr;
49 }
50 
~EventsManager()51 EventsManager::~EventsManager() {
52 	freeCursors();
53 }
54 
loadCursors(const Common::String & spritesName)55 void EventsManager::loadCursors(const Common::String &spritesName) {
56 	delete _cursorSprites;
57 	_cursorSprites = new SpriteAsset(_vm, spritesName, 0x4000);
58 }
59 
setCursor(CursorType cursorId)60 void EventsManager::setCursor(CursorType cursorId) {
61 	_cursorId = cursorId;
62 	changeCursor();
63 }
64 
setCursor2(CursorType cursorId)65 void EventsManager::setCursor2(CursorType cursorId) {
66 	_cursorId = cursorId;
67 	_newCursorId = cursorId;
68 	changeCursor();
69 }
70 
showCursor()71 void EventsManager::showCursor() {
72 	CursorMan.showMouse(true);
73 }
74 
hideCursor()75 void EventsManager::hideCursor() {
76 	CursorMan.showMouse(false);
77 }
78 
isCursorVisible()79 bool EventsManager::isCursorVisible() {
80 	return CursorMan.isVisible();
81 }
82 
waitCursor()83 void EventsManager::waitCursor() {
84 	CursorType cursorId = (CursorType)MIN(_cursorSprites->getCount(), (int)CURSOR_WAIT);
85 	_newCursorId = cursorId;
86 	if (_cursorId != _newCursorId) {
87 		_cursorId = _newCursorId;
88 		changeCursor();
89 	}
90 }
91 
changeCursor()92 void EventsManager::changeCursor() {
93 	if (_cursorSprites) {
94 		MSprite *cursor = _cursorSprites->getFrame(_cursorId - 1);
95 		assert(cursor->w == cursor->h);
96 		byte transIndex = cursor->getTransparencyIndex();
97 
98 		// Check for hotspot indication pixels along the right-hand and bottom
99 		// row. Put together, these give the cursor's hotspot x,y
100 		int hotspotX = 0, hotspotY = 0;
101 		const byte *cursorData = (const byte *)cursor->getPixels();
102 		for (int idx = 0; idx < cursor->w; ++idx) {
103 			if (cursorData[(cursor->h - 1) * cursor->w + idx] != transIndex)
104 				hotspotX = idx;
105 
106 			if (cursorData[(idx + 1) * cursor->w - 1] != transIndex)
107 				hotspotY = idx;
108 		}
109 
110 		// Reduce the cursor data to remove the last column from each row, since
111 		// the cursor routines don't have a pitch option
112 		byte *destCursor = new byte[(cursor->w - 1) * (cursor->h - 1)];
113 		const byte *srcP = cursorData;
114 		byte *destP = destCursor;
115 
116 		for (int idx = 0; idx < (cursor->h - 1); ++idx) {
117 			Common::copy(srcP, srcP + cursor->w - 1, destP);
118 			srcP += cursor->w;
119 			destP += cursor->w - 1;
120 		}
121 
122 		// Set the raw cursor data to use
123 		CursorMan.replaceCursor(destCursor, cursor->w - 1, cursor->h - 1,
124 			hotspotX, hotspotY, transIndex);
125 		showCursor();
126 		delete[] destCursor;
127 	}
128 }
129 
freeCursors()130 void EventsManager::freeCursors() {
131 	delete _cursorSprites;
132 	_cursorSprites = nullptr;
133 }
134 
pollEvents()135 void EventsManager::pollEvents() {
136 	checkForNextFrameCounter();
137 	_mouseMoved = false;
138 
139 	Common::Event event;
140 	while (g_system->getEventManager()->pollEvent(event)) {
141 		// If an event target is specified, pass the event to it
142 		if (_eventTarget) {
143 			_eventTarget->onEvent(event);
144 			continue;
145 		}
146 
147 		// Handle keypress
148 		switch (event.type) {
149 		case Common::EVENT_QUIT:
150 		case Common::EVENT_RTL:
151 			return;
152 
153 		case Common::EVENT_KEYDOWN:
154 			// Check for debugger
155 			if (event.kbd.keycode == Common::KEYCODE_d && (event.kbd.flags & Common::KBD_CTRL)) {
156 				// Attach to the debugger
157 				_vm->_debugger->attach();
158 				_vm->_debugger->onFrame();
159 			} else {
160 				_pendingKeys.push(event.kbd);
161 			}
162 			return;
163 		case Common::EVENT_KEYUP:
164 			return;
165 		case Common::EVENT_WHEELUP:
166 			_pendingKeys.push(Common::KeyState(Common::KEYCODE_PAGEUP));
167 			return;
168 		case Common::EVENT_WHEELDOWN:
169 			_pendingKeys.push(Common::KeyState(Common::KEYCODE_PAGEDOWN));
170 			return;
171 		case Common::EVENT_LBUTTONDOWN:
172 		case Common::EVENT_RBUTTONDOWN:
173 			_mouseClicked = true;
174 			_mouseButtons = 1;
175 			_mouseMoved = true;
176 			if (event.type == Common::EVENT_RBUTTONDOWN) {
177 				_rightMousePressed = true;
178 				_mouseStatus |= 2;
179 			} else {
180 				_mouseStatus |= 1;
181 			}
182 			return;
183 		case Common::EVENT_LBUTTONUP:
184 		case Common::EVENT_RBUTTONUP:
185 			_mouseClicked = false;
186 			_mouseReleased = true;
187 			_mouseMoved = true;
188 			_rightMousePressed = false;
189 			if (event.type == Common::EVENT_RBUTTONUP) {
190 				_mouseStatus &= ~2;
191 			} else {
192 				_mouseStatus &= ~1;
193 			}
194 			return;
195 		case Common::EVENT_MOUSEMOVE:
196 			_mousePos = event.mouse;
197 			_currentPos = event.mouse;
198 			_mouseMoved = true;
199 			break;
200 		default:
201  			break;
202 		}
203 	}
204 }
205 
checkForNextFrameCounter()206 bool EventsManager::checkForNextFrameCounter() {
207 	// Check for next game frame
208 	uint32 milli = g_system->getMillis();
209 	if ((milli - _priorFrameTime) >= GAME_FRAME_TIME) {
210 		++_frameCounter;
211 		_priorFrameTime = milli;
212 
213 		// Do any palette cycling
214 		_vm->_game->_scene.animatePalette();
215 
216 		// Give time to the debugger
217 		_vm->_debugger->onFrame();
218 
219 		// Display the frame
220 		_vm->_screen->update();
221 
222 		// Signal the ScummVM debugger
223 		_vm->_debugger->onFrame();
224 
225 		return true;
226 	}
227 
228 	return false;
229 }
230 
delay(int cycles)231 void EventsManager::delay(int cycles) {
232 	uint32 totalMilli = cycles * 1000 / GAME_FRAME_RATE;
233 	uint32 delayEnd = g_system->getMillis() + totalMilli;
234 
235 	while (!_vm->shouldQuit() && g_system->getMillis() < delayEnd) {
236 		g_system->delayMillis(10);
237 
238 		pollEvents();
239 	}
240 }
241 
waitForNextFrame()242 void EventsManager::waitForNextFrame() {
243 	_mouseClicked = false;
244 	_mouseReleased = false;
245 	_mouseButtons = 0;
246 
247 	bool mouseClicked = false;
248 	bool mouseReleased = false;
249 	int mouseButtons = 0;
250 
251 	uint32 frameCtr = getFrameCounter();
252 	while (!_vm->shouldQuit() && frameCtr == _frameCounter) {
253 		delay(1);
254 
255 		mouseClicked |= _mouseClicked;
256 		mouseReleased |= _mouseReleased;
257 		mouseButtons |= _mouseButtons;
258 	}
259 
260 	_mouseClicked = mouseClicked;
261 	_mouseReleased = mouseReleased;
262 	_mouseButtons = mouseButtons;
263 	_mouseMoved |= _mouseClicked || _mouseReleased;
264 }
265 
initVars()266 void EventsManager::initVars() {
267 	_mousePos = Common::Point(-1, -1);
268 	_mouseStatusCopy = _mouseStatus;
269 	_strokeGoing = 0;
270 }
271 
clearEvents()272 void EventsManager::clearEvents() {
273 	_pendingKeys.clear();
274 }
275 
276 
277 } // End of namespace MADS
278