xoreos  0.0.5
windowman.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos 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 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos 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 xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 #include <cstring>
26 
27 #include <boost/bind.hpp>
28 
29 #include "src/common/error.h"
30 #include "src/common/configman.h"
31 #include "src/common/threads.h"
32 #include "src/common/util.h"
33 
35 #include "src/events/requests.h"
36 
37 #include "src/graphics/windowman.h"
38 #include "src/graphics/icon.h"
39 
40 #include "src/version/version.h"
41 
43 
44 namespace Graphics {
45 
47  _fullScreen = false;
48 
49  _fsaaMax = 0;
50 
51  _gamma = 1.0f;
52 
54 
55  _window = 0;
56  _glContext = 0;
57 
58  _width = 800;
59  _height = 600;
60 
62 }
63 
65 }
66 
69 
70  const uint32 sdlInitFlags = SDL_INIT_TIMER | SDL_INIT_VIDEO | SDL_INIT_JOYSTICK;
71  if (SDL_Init(sdlInitFlags) < 0)
72  throw Common::Exception("Failed to initialize SDL: %s", SDL_GetError());
73 
74  _width = ConfigMan.getInt ("width" , _width);
75  _height = ConfigMan.getInt ("height" , _height);
76  _fullScreen = ConfigMan.getBool("fullscreen", false);
77 
78  probeFSAA();
79 
80  // Set the gamma correction to what the config specifies
81  if (ConfigMan.hasKey("gamma"))
82  _gamma = ConfigMan.getDouble("gamma", 1.0);
83 }
84 
86  SDL_Quit();
87 }
88 
89 bool WindowManager::initRender(RenderType type, bool useDebug, int fsaa) {
90  uint32 flags = windowFlags();
91 
92  deinitWindow();
93 
94  SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
95  SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
96  SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
97  SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
98  SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
99 
100  SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, (fsaa > 0) ? 1 : 0);
101  SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, fsaa);
102 
103  int majorVersion = type == kOpenGL32Compat ? 3 : 2;
104  int minorVersion = type == kOpenGL32Compat ? 2 : 1;
105  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, majorVersion);
106  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minorVersion);
107  SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, type);
108 
109  // Create a debug context?
110  SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, useDebug ? SDL_GL_CONTEXT_DEBUG_FLAG : 0);
111 
112  initWindow(flags);
113 
114  _glContext = SDL_GL_CreateContext(_window);
115  if (!_glContext) {
116  warning("Could not create OpenGL %i.%i context: %s", majorVersion, minorVersion, SDL_GetError());
117  return false;
118  }
119 
120  /* It is possible, that OSX operating systems create an opengl 3.x/4.x core context even if a
121  * 2.1 core context is requested. This condition checks, that if we create a 2.1 core context
122  * that the returned context is actually a 2.1 core context, and if not return false. */
123  if (type == kOpenGL21Core) {
124  Common::UString version(reinterpret_cast<const char *>(glGetString(GL_VERSION)));
125 
126  if (!version.beginsWith("2.1")) {
127  return false;
128  }
129  }
130 
131  status("OpenGL context successfully created:");
132  SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &majorVersion);
133  SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minorVersion);
134  int currentFsaa;
135  SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &currentFsaa);
136  status("OpenGL version: %i.%i", majorVersion, minorVersion);
137  status("FSAA level : %ix", currentFsaa);
138 
139  return true;
140 }
141 
143  return _fullScreen;
144 }
145 
146 void WindowManager::setFullScreen(bool fullScreen) {
147  if (_fullScreen == fullScreen)
148  // Nothing to do
149  return;
150 
151  // Force calling it from the main thread
152  if (!Common::isMainThread()) {
153  Events::MainThreadFunctor<void> functor(boost::bind(&WindowManager::setFullScreen, this, fullScreen));
154 
155  return RequestMan.callInMainThread(functor);
156  }
157 
158  // Now try to change modes
159  int result;
160  if (fullScreen)
161  result = SDL_SetWindowFullscreen(_window, SDL_WINDOW_FULLSCREEN);
162  else
163  result = SDL_SetWindowFullscreen(_window, 0);
164 
165  // There's no reason how this could possibly fail, but ok...
166  if (result < 0)
167  throw Common::Exception("Unable to set %s mode: %s", (fullScreen ? "fullscreen" : "windowed"), SDL_GetError());
168 
169  // The windowed size might not have been adjusted by changes in fullscreen mode
170  // We cannot count on SDL_GetWindowSize to return the correct window size
171  if (!fullScreen) {
172  int width, height;
173  SDL_GetWindowSize(_window, &width, &height);
174  SDL_SetWindowSize(_window, _width, _height);
175  NotificationMan.resized(width, height, _width, _height);
176  }
177 
178  _fullScreen = fullScreen;
179 }
180 
183 }
184 
186  return _width;
187 }
188 
190  return _height;
191 }
192 
193 void WindowManager::setWindowSize(int width, int height) {
194  if (_width == width && _height == height)
195  // Nothing to do
196  return;
197 
198  // Force calling it from the main thread
199  if (!Common::isMainThread()) {
200  Events::MainThreadFunctor<void> functor(boost::bind(&WindowManager::setWindowSize, this, width, height));
201 
202  return RequestMan.callInMainThread(functor);
203  }
204 
205  // Now try to change modes
206  int result = 0;
207  if (!_fullScreen) {
208  SDL_SetWindowSize(_window, width, height);
209  } else {
210  SDL_DisplayMode displayMode;
211  result = SDL_GetWindowDisplayMode(_window, &displayMode);
212  if (result >= 0) {
213  displayMode.w = width;
214  displayMode.h = height;
215  result = SDL_SetWindowDisplayMode(_window, &displayMode);
216  }
217  }
218 
219  if (result < 0)
220  throw Common::Exception("Unable to set window size to %ix%i: %s", width, height, SDL_GetError());
221 
222  int oldWidth = _width;
223  int oldHight = _height;
224  _width = width;
225  _height = height;
226 
227  NotificationMan.resized(oldWidth, oldHight, _width, _height);
228 }
229 
230 std::vector<DisplayMode> WindowManager::getDisplayModes() {
231  const int numDisplays = SDL_GetNumVideoDisplays();
232 
233  std::vector<DisplayMode> modes;
234  for (int i = 0; i < numDisplays; ++i) {
235  const int numModes = SDL_GetNumDisplayModes(i);
236 
237  for (int j = 0; j < numModes; ++j) {
238  DisplayMode mode;
239  SDL_GetDisplayMode(i, j, &mode);
240  modes.push_back(mode);
241  }
242  }
243 
244  return modes;
245 }
246 
248  int displayIndex = SDL_GetWindowDisplayIndex(_window);
249  SDL_DisplayMode maxWidth;
250  // The display mode are sorted by, in this order, greater bpp, largest width, largest height and higher refresh rate.
251  SDL_GetDisplayMode(displayIndex, 0, &maxWidth);
252 
253  return maxWidth.w;
254 }
255 
257  int displayIndex = SDL_GetWindowDisplayIndex(_window);
258  SDL_DisplayMode maxHeight;
259  // The display mode are sorted by, in this order, greater bpp, largest width, largest height and higher refresh rate.
260  SDL_GetDisplayMode(displayIndex, 0, &maxHeight);
261 
262  return maxHeight.h;
263 }
264 
266  return _fsaaMax;
267 }
268 
270  if (_window)
271  return SDL_GetWindowFlags(_window);
272 
273  uint32 flags = SDL_WINDOW_OPENGL;
274  if (_fullScreen)
275  flags |= SDL_WINDOW_FULLSCREEN;
276  return flags;
277 }
278 
280  int x = ConfigMan.getInt("x", SDL_WINDOWPOS_UNDEFINED);
281  int y = ConfigMan.getInt("y", SDL_WINDOWPOS_UNDEFINED);
282 
283  _window = SDL_CreateWindow(_windowTitle.c_str(), x, y, getWindowWidth(), getWindowHeight(), flags);
284  if (!_window)
285  throw Common::Exception("Failed creating the window: %s", SDL_GetError());
286 
288 
289  setGamma(_gamma);
290 }
291 
293  if (_glContext) {
294  SDL_GL_DeleteContext(_glContext);
295  }
296  if (_window) {
297  SDL_DestroyWindow(_window);
298  }
299 }
300 
302  // Find the max supported FSAA level
303  for (int i = 32; i >= 2; i >>= 1) {
304  SDL_GL_SetAttribute(SDL_GL_RED_SIZE , 8);
305  SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE , 8);
306  SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE , 8);
307  SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE , 8);
308  SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
309 
310  SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
311  SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, i);
312 
313  SDL_Window *testScreen = SDL_CreateWindow("nrst", 0, 0, 1, 1, SDL_WINDOW_OPENGL);
314  if (testScreen) {
315  SDL_GLContext context = SDL_GL_CreateContext(testScreen);
316  if (context) {
317  SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &_fsaaMax);
318  status("Found Max FSAA: %ix", _fsaaMax);
319 
320  SDL_GL_DeleteContext(context);
321  SDL_DestroyWindow(testScreen);
322 
323  return;
324  } else {
325  SDL_DestroyWindow(testScreen);
326  }
327  }
328  }
329 }
330 
332  _windowTitle = title;
333  if (_windowTitle.empty())
335 
336  SDL_SetWindowTitle(_window, _windowTitle.c_str());
337 }
338 
339 float WindowManager::getGamma() const {
340  return _gamma;
341 }
342 
343 void WindowManager::setGamma(float gamma) {
344  if (_gamma == gamma)
345  // Nothing to do
346  return;
347 
348  // Force calling it from the main thread
349  if (!Common::isMainThread()) {
350  Events::MainThreadFunctor<void> functor(boost::bind(&WindowManager::setGamma, this, gamma));
351 
352  return RequestMan.callInMainThread(functor);
353  }
354 
355  uint16 gammaRamp[256];
356  SDL_CalculateGammaRamp(gamma, gammaRamp);
357 
358  int result = SDL_SetWindowGammaRamp(_window, gammaRamp, gammaRamp, gammaRamp);
359  if (result < 0)
360  error("Failed to set gamma to %f: %s", gamma, SDL_GetError());
361  else
362  _gamma = gamma;
363 }
364 
366  SDL_WarpMouseInWindow(_window, x, y);
367 }
368 
370  // Switch cursor on/off
372 }
373 
375  SDL_GL_SwapWindow(_window);
376 }
377 
380  return;
381 
383 
385  SDL_ShowCursor(SDL_ENABLE);
387  SDL_ShowCursor(SDL_DISABLE);
388 
390 }
391 
393  SDL_SetWindowGrab(_window, (SDL_bool) !SDL_GetWindowGrab(_window));
394 }
395 
396 void WindowManager::showCursor(bool show) {
398 
400 }
401 
402 } // End of namespace Graphics
int getWindowHeight() const
Return the current window height.
Definition: windowman.cpp:189
void showCursor(bool show)
Show/Hide the cursor.
Definition: windowman.cpp:396
Inter-thread request events.
Make the render window display our icon.
void setWindowIcon(SDL_Window &window)
Definition: icon.cpp:350
Common::UString _windowTitle
The current window title.
Definition: windowman.h:117
A class holding an UTF-8 string.
Definition: ustring.h:48
int _width
The game&#39;s window width.
Definition: windowman.h:112
Template specialization for a MainThreadFunctor returning void.
Definition: types.h:323
The global config manager.
bool beginsWith(const UString &with) const
Definition: ustring.cpp:295
bool isMainThread()
Returns true if called from the main thread, false otherwise.
Definition: threads.cpp:54
int getSystemHeight() const
Return the system&#39;s screen height.
Definition: windowman.cpp:256
void deinit()
Deinitialize the window manager.
Definition: windowman.cpp:85
SDL_Window * _window
The OpenGL hardware surface.
Definition: windowman.h:119
int getSystemWidth() const
Return the system&#39;s screen width.
Definition: windowman.cpp:247
#define NotificationMan
Shortcut for accessing the notification manager.
Definition: notifications.h:75
int _fsaaMax
Max supported FSAA level.
Definition: windowman.h:110
The global window manager.
The graphics manager.
Definition: windowman.h:39
void setWindowSize(int width, int height)
Set the window size.
Definition: windowman.cpp:193
bool initRender(RenderType type, bool useDebug, int fsaa)
Setup the Render Context on the window.
Definition: windowman.cpp:89
void init()
Initialize the window manager.
Definition: windowman.cpp:67
The notification manager, handling all notifications.
Basic exceptions to throw.
Threading system helpers.
Common::Mutex _cursorMutex
A mutex locked for the cursor.
Definition: windowman.h:122
const char * c_str() const
Return the (utf8 encoded) string data.
Definition: ustring.cpp:249
CursorState _cursorState
What to do with the cursor.
Definition: windowman.h:123
float getGamma() const
Get the overall gamma correction.
Definition: windowman.cpp:339
uint16_t uint16
Definition: types.h:202
#define ConfigMan
Shortcut for accessing the config manager.
Definition: configman.h:176
Utility templates and functions.
int getWindowWidth() const
Return the current window width.
Definition: windowman.cpp:185
Basic xoreos version information.
#define DECLARE_SINGLETON(T)
Note that you need to use this macro from the global namespace.
Definition: singleton.h:122
int getMaxFSAA() const
Return the max supported FSAA level.
Definition: windowman.cpp:265
int _height
The game&#39;s window height.
Definition: windowman.h:113
const char * getProjectNameVersion()
Definition: version.cpp:92
void setWindowTitle(const Common::UString &title="")
Set the window&#39;s title.
Definition: windowman.cpp:331
void initWindow(uint32 flags)
Definition: windowman.cpp:279
bool empty() const
Is the string empty?
Definition: ustring.cpp:245
StackException Exception
Definition: error.h:59
bool isFullScreen() const
Are we currently in full screen mode?
Definition: windowman.cpp:142
void warning(const char *s,...)
Definition: util.cpp:33
Convenience class that locks a mutex on creation and unlocks it on destruction.
Definition: mutex.h:71
SDL_GLContext _glContext
Definition: windowman.h:120
void setFullScreen(bool fullScreen)
Set full screen/windowed mode.
Definition: windowman.cpp:146
void enforceMainThread()
Throws an Exception if called from a non-main thread.
Definition: threads.cpp:60
bool _fullScreen
Are we currently in fullscreen mode?
Definition: windowman.h:108
uint32_t uint32
Definition: types.h:204
void status(const char *s,...)
Definition: util.cpp:52
SDL_DisplayMode DisplayMode
Definition: windowman.h:36
#define RequestMan
Shortcut for accessing the request manager.
Definition: requests.h:127
void toggleMouseGrab()
Toggle mouse grab.
Definition: windowman.cpp:392
void toggleFullScreen()
Toggle between full screen and windowed mode.
Definition: windowman.cpp:181
float _gamma
The current gamma correction value.
Definition: windowman.h:115
std::vector< DisplayMode > getDisplayModes()
Get all possible display modes.
Definition: windowman.cpp:230
void NORETURN_PRE error(const char *s,...)
Definition: util.cpp:86
void setCursorPosition(int x, int y)
Set position to the cursor.
Definition: windowman.cpp:365
void setGamma(float gamma)
Set the overall gamma correction.
Definition: windowman.cpp:343