ClangFormat: apply to source, most of intern
[blender.git] / intern / ghost / intern / GHOST_DisplayManagerSDL.cpp
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  * Mode switching
16  * Copyright (C) 1997-2001 Id Software, Inc.
17  * Copyright (c) 1993-2011 Tim Riker
18  * Copyright (C) 2012 Alex Fraser
19  */
20
21 /** \file
22  * \ingroup GHOST
23  */
24
25 #include "GHOST_SystemSDL.h"
26 #include "GHOST_DisplayManagerSDL.h"
27
28 #include "GHOST_WindowManager.h"
29
30 GHOST_DisplayManagerSDL::GHOST_DisplayManagerSDL(GHOST_SystemSDL *system)
31     : GHOST_DisplayManager(), m_system(system)
32 {
33   memset(&m_mode, 0, sizeof(m_mode));
34 }
35
36 GHOST_TSuccess GHOST_DisplayManagerSDL::getNumDisplays(GHOST_TUns8 &numDisplays) const
37 {
38   numDisplays = SDL_GetNumVideoDisplays();
39   return GHOST_kSuccess;
40 }
41
42 GHOST_TSuccess GHOST_DisplayManagerSDL::getNumDisplaySettings(GHOST_TUns8 display,
43                                                               GHOST_TInt32 &numSettings) const
44 {
45   GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n");
46
47   numSettings = SDL_GetNumDisplayModes(display - 1);
48
49   return GHOST_kSuccess;
50 }
51
52 static void ghost_mode_from_sdl(GHOST_DisplaySetting &setting, SDL_DisplayMode *mode)
53 {
54   setting.xPixels = mode->w;
55   setting.yPixels = mode->h;
56   setting.bpp = SDL_BYTESPERPIXEL(mode->format) * 8;
57   /* Just guess the frequency :( */
58   setting.frequency = mode->refresh_rate ? mode->refresh_rate : 60;
59 }
60
61 static void ghost_mode_to_sdl(const GHOST_DisplaySetting &setting, SDL_DisplayMode *mode)
62 {
63   mode->w = setting.xPixels;
64   mode->h = setting.yPixels;
65   // setting.bpp = SDL_BYTESPERPIXEL(mode->format) * 8; ???
66   mode->refresh_rate = setting.frequency;
67 }
68
69 GHOST_TSuccess GHOST_DisplayManagerSDL::getDisplaySetting(GHOST_TUns8 display,
70                                                           GHOST_TInt32 index,
71                                                           GHOST_DisplaySetting &setting) const
72 {
73   GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n");
74
75   SDL_DisplayMode mode;
76   SDL_GetDisplayMode(display, index, &mode);
77
78   ghost_mode_from_sdl(setting, &mode);
79
80   return GHOST_kSuccess;
81 }
82
83 GHOST_TSuccess GHOST_DisplayManagerSDL::getCurrentDisplaySetting(
84     GHOST_TUns8 display, GHOST_DisplaySetting &setting) const
85 {
86   SDL_DisplayMode mode;
87   SDL_GetCurrentDisplayMode(display, &mode);
88
89   ghost_mode_from_sdl(setting, &mode);
90
91   return GHOST_kSuccess;
92 }
93
94 GHOST_TSuccess GHOST_DisplayManagerSDL::getCurrentDisplayModeSDL(SDL_DisplayMode &mode) const
95 {
96   mode = m_mode;
97   return GHOST_kSuccess;
98 }
99
100 GHOST_TSuccess GHOST_DisplayManagerSDL::setCurrentDisplaySetting(
101     GHOST_TUns8 display, const GHOST_DisplaySetting &setting)
102 {
103   /*
104    * Mode switching code ported from Quake 2 version 3.21 and bzflag version
105    * 2.4.0:
106    * ftp://ftp.idsoftware.com/idstuff/source/q2source-3.21.zip
107    * See linux/gl_glx.c:GLimp_SetMode
108    * http://wiki.bzflag.org/BZFlag_Source
109    * See src/platform/SDLDisplay.cxx:SDLDisplay and createWindow
110    */
111   SDL_DisplayMode mode;
112   const int num_modes = SDL_GetNumDisplayModes(display);
113   int best_fit, best_dist, dist, x, y;
114
115   best_dist = 9999999;
116   best_fit = -1;
117
118   if (num_modes == 0) {
119     /* Any mode is OK. */
120     ghost_mode_to_sdl(setting, &mode);
121   }
122   else {
123     for (int i = 0; i < num_modes; i++) {
124
125       SDL_GetDisplayMode(display, i, &mode);
126
127       if (setting.xPixels > mode.w || setting.yPixels > mode.h) {
128         continue;
129       }
130
131       x = setting.xPixels - mode.w;
132       y = setting.yPixels - mode.h;
133       dist = (x * x) + (y * y);
134       if (dist < best_dist) {
135         best_dist = dist;
136         best_fit = i;
137       }
138     }
139
140     if (best_fit == -1)
141       return GHOST_kFailure;
142
143     SDL_GetDisplayMode(display, best_fit, &mode);
144   }
145
146   m_mode = mode;
147
148   /* evil, SDL2 needs a window to adjust display modes */
149   GHOST_WindowSDL *win = (GHOST_WindowSDL *)m_system->getWindowManager()->getActiveWindow();
150
151   if (win) {
152     SDL_Window *sdl_win = win->getSDLWindow();
153
154     SDL_SetWindowDisplayMode(sdl_win, &mode);
155     SDL_ShowWindow(sdl_win);
156     SDL_SetWindowFullscreen(sdl_win, SDL_TRUE);
157
158     return GHOST_kSuccess;
159   }
160   else {
161     /* this is a problem for the BGE player :S, perhaps SDL2 will resolve at some point.
162      * we really need SDL_SetDisplayModeForDisplay() to become an API func! - campbell */
163     printf("no windows available, cant fullscreen\n");
164
165     /* do not fail, we will try again later when the window is created - wander */
166     return GHOST_kSuccess;
167   }
168 }