Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
VideoMode.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2013 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "precompiled.h"
19 
20 #include "VideoMode.h"
21 
22 #include "graphics/Camera.h"
23 #include "graphics/GameView.h"
24 #include "gui/GUIManager.h"
25 #include "lib/config2.h"
26 #include "lib/ogl.h"
28 #include "lib/sysdep/gfx.h"
29 #include "ps/CConsole.h"
30 #include "ps/CLogger.h"
31 #include "ps/ConfigDB.h"
32 #include "ps/Game.h"
33 #include "ps/GameSetup/Config.h"
34 #include "renderer/Renderer.h"
35 
36 static int DEFAULT_WINDOW_W = 1024;
37 static int DEFAULT_WINDOW_H = 768;
38 
39 static int DEFAULT_FULLSCREEN_W = 1024;
40 static int DEFAULT_FULLSCREEN_H = 768;
41 
43 
45  m_IsFullscreen(false), m_IsInitialised(false), m_Window(NULL),
46  m_PreferredW(0), m_PreferredH(0), m_PreferredBPP(0), m_PreferredFreq(0),
47  m_ConfigW(0), m_ConfigH(0), m_ConfigBPP(0), m_ConfigFullscreen(false), m_ConfigForceS3TCEnable(true),
48  m_WindowedW(DEFAULT_WINDOW_W), m_WindowedH(DEFAULT_WINDOW_H)
49 {
50  // (m_ConfigFullscreen defaults to false, so users don't get stuck if
51  // e.g. half the filesystem is missing and the config files aren't loaded)
52 }
53 
55 {
56  bool windowed = !m_ConfigFullscreen;
57  CFG_GET_VAL("windowed", Bool, windowed);
58  m_ConfigFullscreen = !windowed;
59 
60  CFG_GET_VAL("xres", Int, m_ConfigW);
61  CFG_GET_VAL("yres", Int, m_ConfigH);
62  CFG_GET_VAL("bpp", Int, m_ConfigBPP);
63  CFG_GET_VAL("force_s3tc_enable", Bool, m_ConfigForceS3TCEnable);
64 }
65 
66 bool CVideoMode::SetVideoMode(int w, int h, int bpp, bool fullscreen)
67 {
68 #if SDL_VERSION_ATLEAST(2, 0, 0)
69 
70  Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
71  if (fullscreen)
72  flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
73  else
74  flags |= SDL_WINDOW_RESIZABLE;
75 
76  if (!m_Window)
77  {
78  m_Window = SDL_CreateWindow("0 A.D.", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h, flags);
79  if (!m_Window)
80  {
81  // If fullscreen fails, try windowed mode
82  if (fullscreen)
83  {
84  LOGWARNING(L"Failed to set the video mode to fullscreen for the chosen resolution "
85  L"%dx%d:%d (\"%hs\"), falling back to windowed mode",
86  w, h, bpp, SDL_GetError());
87  // Using default size for the window for now, as the attempted setting
88  // could be as large, or larger than the screen size.
89  return SetVideoMode(DEFAULT_WINDOW_W, DEFAULT_WINDOW_H, bpp, false);
90  }
91  else
92  {
93  LOGERROR(L"SetVideoMode failed in SDL_CreateWindow: %dx%d:%d %d (\"%hs\")",
94  w, h, bpp, fullscreen ? 1 : 0, SDL_GetError());
95  return false;
96  }
97  }
98 
99  if (SDL_SetWindowDisplayMode(m_Window, NULL) < 0)
100  {
101  LOGERROR(L"SetVideoMode failed in SDL_SetWindowDisplayMode: %dx%d:%d %d (\"%hs\")",
102  w, h, bpp, fullscreen ? 1 : 0, SDL_GetError());
103  return false;
104  }
105 
106  SDL_GLContext context = SDL_GL_CreateContext(m_Window);
107  if (!context)
108  {
109  LOGERROR(L"SetVideoMode failed in SDL_GL_CreateContext: %dx%d:%d %d (\"%hs\")",
110  w, h, bpp, fullscreen ? 1 : 0, SDL_GetError());
111  return false;
112  }
113  }
114  else
115  {
116  if (m_IsFullscreen != fullscreen)
117  {
118  if (SDL_SetWindowFullscreen(m_Window, flags) < 0)
119  {
120  LOGERROR(L"SetVideoMode failed in SDL_SetWindowFullscreen: %dx%d:%d %d (\"%hs\")",
121  w, h, bpp, fullscreen ? 1 : 0, SDL_GetError());
122  return false;
123  }
124  }
125 
126  if (!fullscreen)
127  SDL_SetWindowSize(m_Window, w, h);
128  }
129 
130  // Grab the current video settings
131  SDL_GetWindowSize(m_Window, &m_CurrentW, &m_CurrentH);
132  m_CurrentBPP = bpp;
133 
134  if (fullscreen)
135  SDL_SetWindowGrab(m_Window, SDL_TRUE);
136  else
137  SDL_SetWindowGrab(m_Window, SDL_FALSE);
138 
139 #else // SDL 1.2:
140 
141  Uint32 flags = SDL_OPENGL;
142  if (fullscreen)
143  flags |= SDL_FULLSCREEN;
144 #if !OS_MACOSX
145  // TODO: Fix window resizing on OS X, see http://trac.wildfiregames.com/ticket/741
146  else
147  flags |= SDL_RESIZABLE;
148 #endif
149 
150  SDL_Surface* screen = SDL_SetVideoMode(w, h, bpp, flags);
151 
152  if (!screen)
153  {
154  // If fullscreen fails, try windowed mode
155  if (fullscreen)
156  {
157  LOGWARNING(L"Failed to set the video mode to fullscreen for the chosen resolution "
158  L"%dx%d:%d (\"%hs\"), falling back to windowed mode",
159  w, h, bpp, SDL_GetError());
160  // Using default size for the window for now, as the attempted setting
161  // could be as large, or larger than the screen size.
162  return SetVideoMode(DEFAULT_WINDOW_W, DEFAULT_WINDOW_H, bpp, false);
163  }
164  else
165  {
166  LOGERROR(L"SetVideoMode failed: %dx%d:%d %d (\"%hs\")",
167  w, h, bpp, fullscreen ? 1 : 0, SDL_GetError());
168  return false;
169  }
170  }
171 
172  // Grab the current video settings
173  m_CurrentW = screen->w;
174  m_CurrentH = screen->h;
175  m_CurrentBPP = screen->format->BitsPerPixel;
176 
177  if (fullscreen)
179  else
181 #endif
182 
184 
185  g_xres = m_CurrentW;
186  g_yres = m_CurrentH;
187 
188  return true;
189 }
190 
192 {
194 
195  ReadConfig();
196 
197  EnableS3TC();
198 
199  // preferred video mode = current desktop settings
200  // (command line params may override these)
202 
203  int w = m_ConfigW;
204  int h = m_ConfigH;
205 
206  if (m_ConfigFullscreen)
207  {
208  // If fullscreen and no explicit size set, default to the desktop resolution
209  if (w == 0 || h == 0)
210  {
211  w = m_PreferredW;
212  h = m_PreferredH;
213  }
214  }
215 
216  // If no size determined, default to something sensible
217  if (w == 0 || h == 0)
218  {
219  w = DEFAULT_WINDOW_W;
220  h = DEFAULT_WINDOW_H;
221  }
222 
223  if (!m_ConfigFullscreen)
224  {
225  // Limit the window to the screen size (if known)
226  if (m_PreferredW)
227  w = std::min(w, m_PreferredW);
228  if (m_PreferredH)
229  h = std::min(h, m_PreferredH);
230  }
231 
232  int bpp = GetBestBPP();
233 
237 #if !SDL_VERSION_ATLEAST(1, 3, 0)
239 #endif
240 
241 #if CONFIG2_GLES && SDL_VERSION_ATLEAST(1, 3, 0)
242  // Require GLES 2.0
243  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
244  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
245 #endif
246 
247  if (!SetVideoMode(w, h, bpp, m_ConfigFullscreen))
248  {
249  // Fall back to a smaller depth buffer
250  // (The rendering may be ugly but this helps when running in VMware)
252 
253  if (!SetVideoMode(w, h, bpp, m_ConfigFullscreen))
254  return false;
255  }
256 
257 #if SDL_VERSION_ATLEAST(1, 3, 0)
258  SDL_GL_SetSwapInterval(g_VSync ? 1 : 0);
259 #endif
260 
261  // Work around a bug in the proprietary Linux ATI driver (at least versions 8.16.20 and 8.14.13).
262  // The driver appears to register its own atexit hook on context creation.
263  // If this atexit hook is called before SDL_Quit destroys the OpenGL context,
264  // some kind of double-free problem causes a crash and lockup in the driver.
265  // Calling SDL_Quit twice appears to be harmless, though, and avoids the problem
266  // by destroying the context *before* the driver's atexit hook is called.
267  // (Note that atexit hooks are guaranteed to be called in reverse order of their registration.)
268  atexit(SDL_Quit);
269  // End work around.
270 
271  ogl_Init(); // required after each mode change
272  // (TODO: does that mean we need to call this when toggling fullscreen later?)
273 
274 #if SDL_VERSION_ATLEAST(2, 0, 0)
275  u16 ramp[256];
276  SDL_CalculateGammaRamp(g_Gamma, ramp);
277  if (SDL_SetWindowGammaRamp(m_Window, ramp, ramp, ramp) < 0)
278  LOGWARNING(L"SDL_SetGamma failed");
279 #else
280  if (SDL_SetGamma(g_Gamma, g_Gamma, g_Gamma) < 0)
281  LOGWARNING(L"SDL_SetGamma failed");
282 #endif
283 
284  m_IsInitialised = true;
285 
286  if (!m_ConfigFullscreen)
287  {
288  m_WindowedW = w;
289  m_WindowedH = h;
290  }
291 
292  return true;
293 }
294 
296 {
298 
299  ReadConfig();
300 
301  EnableS3TC();
302 
303  m_IsInitialised = true;
304 
305  return true;
306 }
307 
309 {
311 
312  m_IsFullscreen = false;
313  m_IsInitialised = false;
314 }
315 
317 {
318  // On Linux we have to try hard to get S3TC compressed texture support.
319  // If the extension is already provided by default, that's fine.
320  // Otherwise we should enable the 'force_s3tc_enable' environment variable
321  // and (re)initialise the video system, so that Mesa provides the extension
322  // (if the driver at least supports decompression).
323  // (This overrides the force_s3tc_enable specified via driconf files.)
324  // Otherwise we should complain to the user, and stop using compressed textures.
325  //
326  // Setting the environment variable causes Mesa to print an ugly message to stderr
327  // ("ATTENTION: default value of option force_s3tc_enable overridden by environment."),
328  // so it'd be nicer to skip that if S3TC will be supported by default,
329  // but reinitialising video is a pain (and it might do weird things when fullscreen)
330  // so we just unconditionally set it (unless our config file explicitly disables it).
331 
332 #if !(OS_WIN || OS_MACOSX) // (assume Mesa is used for all non-Windows non-Mac platforms)
334  setenv("force_s3tc_enable", "true", 0);
335 #endif
336 }
337 
339 {
341 
342  // Ignore if not windowed
343  if (m_IsFullscreen)
344  return true;
345 
346  // Ignore if the size hasn't changed
347  if (w == m_WindowedW && h == m_WindowedH)
348  return true;
349 
350  int bpp = GetBestBPP();
351 
352  if (!SetVideoMode(w, h, bpp, false))
353  return false;
354 
355  m_WindowedW = w;
356  m_WindowedH = h;
357 
358  UpdateRenderer(w, h);
359 
360  return true;
361 }
362 
364 {
365  // This might get called before initialisation by psDisplayError;
366  // if so then silently fail
367  if (!m_IsInitialised)
368  return false;
369 
370  // Check whether this is actually a change
371  if (fullscreen == m_IsFullscreen)
372  return true;
373 
374  if (!m_IsFullscreen)
375  {
376  // Windowed -> fullscreen:
377 
378  int w = 0, h = 0;
379 
380  // If a fullscreen size was configured, use that; else use the desktop size; else use a default
381  if (m_ConfigFullscreen)
382  {
383  w = m_ConfigW;
384  h = m_ConfigH;
385  }
386  if (w == 0 || h == 0)
387  {
388  w = m_PreferredW;
389  h = m_PreferredH;
390  }
391  if (w == 0 || h == 0)
392  {
395  }
396 
397  int bpp = GetBestBPP();
398 
399  if (!SetVideoMode(w, h, bpp, fullscreen))
400  return false;
401 
403 
404  return true;
405  }
406  else
407  {
408  // Fullscreen -> windowed:
409 
410  // Go back to whatever the previous window size was
411  int w = m_WindowedW, h = m_WindowedH;
412 
413  int bpp = GetBestBPP();
414 
415  if (!SetVideoMode(w, h, bpp, fullscreen))
416  return false;
417 
418  UpdateRenderer(w, h);
419 
420  return true;
421  }
422 }
423 
425 {
426  return SetFullscreen(!m_IsFullscreen);
427 }
428 
430 {
431  if (w < 2) w = 2; // avoid GL errors caused by invalid sizes
432  if (h < 2) h = 2;
433 
434  g_xres = w;
435  g_yres = h;
436 
437  SViewPort vp = { 0, 0, w, h };
438 
440  {
441  g_Renderer.SetViewport(vp);
442  g_Renderer.Resize(w, h);
443  }
444 
445  if (g_GUI)
447 
448  if (g_Console)
450 
451  if (g_Game)
452  g_Game->GetView()->SetViewport(vp);
453 }
454 
456 {
457  if (m_ConfigBPP)
458  return m_ConfigBPP;
459  if (m_PreferredBPP)
460  return m_PreferredBPP;
461  return 32;
462 }
463 
465 {
467  return m_CurrentW;
468 }
469 
471 {
473  return m_CurrentH;
474 }
475 
477 {
479  return m_CurrentBPP;
480 }
481 
483 {
485  return m_PreferredW;
486 }
487 
489 {
491  return m_PreferredH;
492 }
493 
495 {
497  return m_PreferredBPP;
498 }
499 
501 {
503  return m_PreferredFreq;
504 }
505 
507 {
509  return m_Window;
510 }
static bool fullscreen
Definition: wsdl.cpp:61
int m_CurrentH
Definition: VideoMode.h:116
int GetDesktopFreq()
Definition: VideoMode.cpp:500
bool SetVideoMode(int w, int h, int bpp, bool fullscreen)
Definition: VideoMode.cpp:66
int GetDesktopXRes()
Definition: VideoMode.cpp:482
#define LOGERROR
Definition: CLogger.h:35
#define SDL_OPENGL
Definition: wsdl.h:71
int setenv(const char *envname, const char *envval, int overwrite)
rationale: the Windows headers declare many POSIX functions (e.g.
Definition: wposix.cpp:34
SDL_GrabMode SDL_WM_GrabInput(SDL_GrabMode mode)
Definition: wsdl.cpp:1123
static int DEFAULT_WINDOW_H
Definition: VideoMode.cpp:37
int g_xres
Definition: Config.cpp:58
#define CFG_GET_VAL(name, type, destination)
Definition: ConfigDB.h:147
int GetYRes()
Definition: VideoMode.cpp:470
bool ToggleFullscreen()
Switch between fullscreen and windowed mode.
Definition: VideoMode.cpp:424
Uint8 BitsPerPixel
Definition: wsdl.h:77
LIB_API Status GetVideoMode(int *xres, int *yres, int *bpp, int *freq)
(useful for choosing a new video mode)
Definition: android.cpp:47
size_t h
Definition: tex.h:230
CGUIManager * g_GUI
Definition: GUIManager.cpp:32
int SDL_GL_SetAttribute(SDL_GLattr attr, int value)
Definition: wsdl.cpp:286
void SDL_Quit()
Definition: wsdl.cpp:1505
void UpdateResolution()
See CGUI::UpdateResolution; applies to all loaded pages.
Definition: GUIManager.cpp:284
bool m_ConfigFullscreen
Definition: VideoMode.h:103
void SetViewport(const SViewPort &vp)
Definition: GameView.cpp:379
#define g_Renderer
Definition: Renderer.h:61
#define LOGWARNING
Definition: CLogger.h:34
CVideoMode g_VideoMode
Definition: VideoMode.cpp:42
bool ResizeWindow(int w, int h)
Resize the SDL window and associated graphics stuff to the new size.
Definition: VideoMode.cpp:338
int m_ConfigH
Definition: VideoMode.h:101
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
void Shutdown()
Shut down after InitSDL/InitNonSDL, so that they can be used again.
Definition: VideoMode.cpp:308
size_t bpp
Definition: tex.h:231
static int DEFAULT_WINDOW_W
Definition: VideoMode.cpp:36
static int DEFAULT_FULLSCREEN_H
Definition: VideoMode.cpp:40
CConsole * g_Console
Definition: CConsole.cpp:46
SDL_Window * GetWindow()
Definition: VideoMode.cpp:506
int m_PreferredH
Definition: VideoMode.h:95
int m_CurrentBPP
Definition: VideoMode.h:117
int m_ConfigW
Definition: VideoMode.h:100
int g_yres
Definition: Config.cpp:58
int m_WindowedW
Definition: VideoMode.h:108
#define SDL_RESIZABLE
Definition: wsdl.h:73
bool g_VSync
Definition: Config.cpp:59
int m_PreferredW
Definition: VideoMode.h:94
int h
Definition: wsdl.h:83
CGame * g_Game
Globally accessible pointer to the CGame object.
Definition: Game.cpp:56
static void UpdateRenderer(int w, int h)
Update the graphics code to start drawing to the new size.
Definition: VideoMode.cpp:429
SDL_PixelFormat * format
Definition: wsdl.h:82
bool InitNonSDL()
Initialise parts of the video mode, for use in Atlas (which uses wxWidgets instead of SDL for GL)...
Definition: VideoMode.cpp:295
static bool IsInitialised()
Definition: Singleton.h:63
int m_PreferredBPP
Definition: VideoMode.h:96
int m_WindowedH
Definition: VideoMode.h:109
struct SDL_Window SDL_Window
Definition: VideoMode.h:21
int w
Definition: wsdl.h:83
int m_CurrentW
Definition: VideoMode.h:115
int m_ConfigBPP
Definition: VideoMode.h:102
#define u16
Definition: types.h:40
int m_PreferredFreq
Definition: VideoMode.h:97
CGameView * GetView()
Get the pointer to the game view object.
Definition: Game.h:128
size_t w
Definition: tex.h:229
bool m_IsInitialised
Remember whether Init has been called.
Definition: VideoMode.h:89
void ogl_Init()
initialization: import extension function pointers and do feature detect.
Definition: ogl.cpp:473
int GetDesktopYRes()
Definition: VideoMode.cpp:488
int GetDesktopBPP()
Definition: VideoMode.cpp:494
u32 Uint32
Definition: wsdl.h:39
bool SetFullscreen(bool fullscreen)
Switch to fullscreen or windowed mode.
Definition: VideoMode.cpp:363
#define SDL_GetError()
Definition: wsdl.h:334
SDL_Window * m_Window
Definition: VideoMode.h:91
int GetBestBPP()
Definition: VideoMode.cpp:455
static int DEFAULT_FULLSCREEN_W
Definition: VideoMode.cpp:39
int GetXRes()
Definition: VideoMode.cpp:464
bool m_ConfigForceS3TCEnable
Definition: VideoMode.h:104
int GetBPP()
Definition: VideoMode.cpp:476
int SDL_SetGamma(float r, float g, float b)
Definition: wsdl.cpp:180
bool m_IsFullscreen
Definition: VideoMode.h:112
SDL_Surface * SDL_SetVideoMode(int w, int h, int bpp, Uint32 flags)
Definition: wsdl.cpp:372
bool InitSDL()
Initialise the video mode, for use in an SDL-using application.
Definition: VideoMode.cpp:191
void UpdateScreenSize(int w, int h)
Definition: CConsole.cpp:83
size_t flags
see TexFlags and &quot;Format Conversion&quot; in docs.
Definition: tex.h:234
void ReadConfig()
Definition: VideoMode.cpp:54
void EnableS3TC()
Definition: VideoMode.cpp:316
#define SDL_FULLSCREEN
Definition: wsdl.h:72
float g_Gamma
Definition: Config.cpp:54