1 /* ResidualVM - A 3D game interpreter
2 *
3 * ResidualVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the AUTHORS
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/events.h"
24 #include "common/stream.h"
25 #include "common/system.h"
26
27 #include "engines/stark/services/userinterface.h"
28
29 #include "engines/stark/gfx/driver.h"
30
31 #include "engines/stark/services/gameinterface.h"
32 #include "engines/stark/services/global.h"
33 #include "engines/stark/services/services.h"
34 #include "engines/stark/services/staticprovider.h"
35
36 #include "engines/stark/ui/actionmenu.h"
37 #include "engines/stark/ui/cursor.h"
38 #include "engines/stark/ui/dialogpanel.h"
39 #include "engines/stark/ui/fmvplayer.h"
40 #include "engines/stark/ui/gamewindow.h"
41 #include "engines/stark/ui/inventorywindow.h"
42 #include "engines/stark/ui/topmenu.h"
43
44 namespace Stark {
45
UserInterface(Gfx::Driver * gfx)46 UserInterface::UserInterface(Gfx::Driver *gfx) :
47 _gfx(gfx),
48 _cursor(nullptr),
49 _topMenu(nullptr),
50 _dialogPanel(nullptr),
51 _inventoryWindow(nullptr),
52 _exitGame(false),
53 _fmvPlayer(nullptr),
54 _actionMenu(nullptr),
55 _gameWindow(nullptr),
56 _interactive(true),
57 _interactionAttemptDenied(false),
58 _currentScreen(kScreenGame),
59 _gameWindowThumbnail(nullptr) {
60 }
61
~UserInterface()62 UserInterface::~UserInterface() {
63 freeGameScreenThumbnail();
64
65 delete _gameWindow;
66 delete _actionMenu;
67 delete _topMenu;
68 delete _dialogPanel;
69 delete _inventoryWindow;
70 delete _fmvPlayer;
71 delete _cursor;
72 }
73
init()74 void UserInterface::init() {
75 // Game screen windows
76 _cursor = new Cursor(_gfx);
77 _topMenu = new TopMenu(_gfx, _cursor);
78 _dialogPanel = new DialogPanel(_gfx, _cursor);
79 _actionMenu = new ActionMenu(_gfx, _cursor);
80 _inventoryWindow = new InventoryWindow(_gfx, _cursor, _actionMenu);
81 _actionMenu->setInventory(_inventoryWindow);
82 _gameWindow = new GameWindow(_gfx, _cursor, _actionMenu, _inventoryWindow);
83
84 _gameScreenWindows.push_back(_actionMenu);
85 _gameScreenWindows.push_back(_inventoryWindow);
86 _gameScreenWindows.push_back(_gameWindow);
87 _gameScreenWindows.push_back(_topMenu);
88 _gameScreenWindows.push_back(_dialogPanel);
89
90 // FMV Screen window
91 _fmvPlayer = new FMVPlayer(_gfx, _cursor);
92 }
93
update()94 void UserInterface::update() {
95 StarkStaticProvider->onGameLoop();
96
97 // Check for UI mouse overs
98 dispatchEvent(&Window::handleMouseMove);
99 }
100
handleMouseMove(const Common::Point & pos)101 void UserInterface::handleMouseMove(const Common::Point &pos) {
102 _cursor->setMousePosition(pos);
103 }
104
handleClick()105 void UserInterface::handleClick() {
106 dispatchEvent(&Window::handleClick);
107 }
108
handleRightClick()109 void UserInterface::handleRightClick() {
110 dispatchEvent(&Window::handleRightClick);
111 }
112
handleDoubleClick()113 void UserInterface::handleDoubleClick() {
114 dispatchEvent(&Window::handleDoubleClick);
115 }
116
dispatchEvent(WindowHandler handler)117 void UserInterface::dispatchEvent(WindowHandler handler) {
118 switch (_currentScreen) {
119 case kScreenGame:
120 for (uint i = 0; i < _gameScreenWindows.size(); i++) {
121 if (_gameScreenWindows[i]->isMouseInside()) {
122 (*_gameScreenWindows[i].*handler)();
123 return;
124 }
125 }
126 break;
127 case kScreenFMV:
128 if (_fmvPlayer->isMouseInside()) {
129 (*_fmvPlayer.*handler)();
130 return;
131 }
132 break;
133 default: // Nothing goes here
134 break;
135 }
136 }
137
inventoryOpen(bool open)138 void UserInterface::inventoryOpen(bool open) {
139 // Make the inventory update its contents.
140 if (open) {
141 _inventoryWindow->open();
142 } else {
143 _inventoryWindow->close();
144 }
145 }
146
getSelectedInventoryItem() const147 int16 UserInterface::getSelectedInventoryItem() const {
148 if (_inventoryWindow) {
149 return _inventoryWindow->getSelectedInventoryItem();
150 } else {
151 return -1;
152 }
153 }
154
selectInventoryItem(int16 itemIndex)155 void UserInterface::selectInventoryItem(int16 itemIndex) {
156 _inventoryWindow->setSelectedInventoryItem(itemIndex);
157 }
158
requestFMVPlayback(const Common::String & name)159 void UserInterface::requestFMVPlayback(const Common::String &name) {
160 // TODO: Save the current screen so that it can be restored when the playback ends
161 changeScreen(kScreenFMV);
162
163 _fmvPlayer->play(name);
164 }
165
onFMVStopped()166 void UserInterface::onFMVStopped() {
167 // TODO: Restore the previous screen
168 changeScreen(kScreenGame);
169 }
170
changeScreen(Screen screen)171 void UserInterface::changeScreen(Screen screen) {
172 _currentScreen = screen;
173 }
174
isInGameScreen() const175 bool UserInterface::isInGameScreen() const {
176 return _currentScreen == kScreenGame;
177 }
178
isInventoryOpen() const179 bool UserInterface::isInventoryOpen() const {
180 return _inventoryWindow->isVisible();
181 }
182
skipFMV()183 bool UserInterface::skipFMV() {
184 if (_currentScreen == kScreenFMV) {
185 _fmvPlayer->stop();
186 return true;
187 }
188 return false;
189 }
190
render()191 void UserInterface::render() {
192 switch (_currentScreen) {
193 case kScreenGame:
194 for (int i = _gameScreenWindows.size() - 1; i >= 0; i--) {
195 _gameScreenWindows[i]->render();
196 }
197 break;
198 case kScreenFMV:
199 _fmvPlayer->render();
200 break;
201 default: // Nothing goes here
202 break;
203 }
204
205 // The cursor depends on the UI being done.
206 _cursor->render();
207 }
208
isInteractive() const209 bool UserInterface::isInteractive() const {
210 return _interactive;
211 }
212
setInteractive(bool interactive)213 void UserInterface::setInteractive(bool interactive) {
214 if (interactive && !_interactive) {
215 StarkGlobal->setNormalSpeed();
216 } else if (!interactive && _interactive) {
217 _interactionAttemptDenied = false;
218 }
219
220 _interactive = interactive;
221 }
222
markInteractionDenied()223 void UserInterface::markInteractionDenied() {
224 if (!_interactive) {
225 _interactionAttemptDenied = true;
226 }
227 }
228
wasInteractionDenied() const229 bool UserInterface::wasInteractionDenied() const {
230 return !_interactive && _interactionAttemptDenied;
231 }
232
clearLocationDependentState()233 void UserInterface::clearLocationDependentState() {
234 _dialogPanel->reset();
235 _gameWindow->reset();
236 _inventoryWindow->reset();
237 }
238
optionsOpen()239 void UserInterface::optionsOpen() {
240 // TODO: Open the TLJ menu instead of the ResidualVM one
241 Common::Event event;
242 event.type = Common::EVENT_MAINMENU;
243 g_system->getEventManager()->pushEvent(event);
244 }
245
saveGameScreenThumbnail()246 void UserInterface::saveGameScreenThumbnail() {
247 freeGameScreenThumbnail();
248
249 Graphics::Surface *big = _gameWindow->getScreenshot();
250 assert(big->format.bytesPerPixel == 4);
251
252 _gameWindowThumbnail = new Graphics::Surface();
253 _gameWindowThumbnail->create(kThumbnailWidth, kThumbnailHeight, big->format);
254
255 uint32 *dst = (uint32 *)_gameWindowThumbnail->getPixels();
256 for (uint i = 0; i < _gameWindowThumbnail->h; i++) {
257 for (uint j = 0; j < _gameWindowThumbnail->w; j++) {
258 uint32 srcX = big->w * j / _gameWindowThumbnail->w;
259 uint32 srcY = big->h * i / _gameWindowThumbnail->h;
260 uint32 *src = (uint32 *)big->getBasePtr(srcX, srcY);
261
262 // Copy RGBA pixel
263 *dst++ = *src;
264 }
265 }
266
267 big->free();
268 delete big;
269 }
270
freeGameScreenThumbnail()271 void UserInterface::freeGameScreenThumbnail() {
272 if (_gameWindowThumbnail) {
273 _gameWindowThumbnail->free();
274 delete _gameWindowThumbnail;
275 _gameWindowThumbnail = nullptr;
276 }
277 }
278
getGameWindowThumbnail() const279 const Graphics::Surface *UserInterface::getGameWindowThumbnail() const {
280 return _gameWindowThumbnail;
281 }
282
onScreenChanged()283 void UserInterface::onScreenChanged() {
284 _dialogPanel->onScreenChanged();
285 }
286
287 } // End of namespace Stark
288
289