1 /**
2  * @file
3  * @brief This file contains SDL specific stuff having to do with the OpenGL refresh
4  */
5 
6 /*
7 Copyright (C) 1997-2001 Id Software, Inc.
8 
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 
18 See the GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23 
24 */
25 
26 #include "r_local.h"
27 #include "r_main.h"
28 #include "r_sdl.h"
29 #include "../../ports/system.h"
30 #include "../client.h"
31 
32 r_sdl_config_t r_sdl_config;
33 
R_SetSDLIcon(void)34 static void R_SetSDLIcon (void)
35 {
36 #ifndef _WIN32
37 #include "../../ports/linux/ufoicon.xbm"
38 	SDL_Surface* icon = SDL_CreateRGBSurface(SDL_SWSURFACE, ufoicon_width, ufoicon_height, 8, 0, 0, 0, 0);
39 	if (icon == nullptr)
40 		return;
41 #if SDL_VERSION_ATLEAST(2,0,0)
42 	SDL_SetColorKey(icon, SDL_TRUE, 0);
43 #else
44 	SDL_SetColorKey(icon, SDL_SRCCOLORKEY, 0);
45 
46 	SDL_Color color;
47 	color.r = color.g = color.b = 255;
48 	SDL_SetColors(icon, &color, 0, 1); /* just in case */
49 
50 	color.r = color.b = 0;
51 	color.g = 16;
52 	SDL_SetColors(icon, &color, 1, 1);
53 #endif
54 
55 	Uint8 *ptr = (Uint8 *)icon->pixels;
56 	for (unsigned int i = 0; i < sizeof(ufoicon_bits); i++) {
57 		for (unsigned int mask = 1; mask != 0x100; mask <<= 1) {
58 			*ptr = (ufoicon_bits[i] & mask) ? 1 : 0;
59 			ptr++;
60 		}
61 	}
62 
63 #if SDL_VERSION_ATLEAST(2,0,0)
64 	SDL_SetWindowIcon(cls.window, icon);
65 #else
66 	SDL_WM_SetIcon(icon, nullptr);
67 #endif
68 	SDL_FreeSurface(icon);
69 #endif
70 }
71 
Rimp_Init(void)72 bool Rimp_Init (void)
73 {
74 	SDL_version version;
75 	int attrValue;
76 
77 	Com_Printf("\n------- video initialization -------\n");
78 
79 	OBJZERO(r_sdl_config);
80 
81 	if (r_driver->string[0] != '\0') {
82 		Com_Printf("using driver: %s\n", r_driver->string);
83 		SDL_GL_LoadLibrary(r_driver->string);
84 	}
85 
86 	Sys_Setenv("SDL_VIDEO_CENTERED", "1");
87 	Sys_Setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "0");
88 
89 	if (SDL_WasInit(SDL_INIT_VIDEO) == 0) {
90 		if (SDL_Init(SDL_INIT_VIDEO) < 0)
91 			Com_Error(ERR_FATAL, "Video SDL_Init failed: %s", SDL_GetError());
92 	}
93 
94 	SDL_VERSION(&version)
95 	Com_Printf("SDL version: %i.%i.%i\n", version.major, version.minor, version.patch);
96 
97 #if SDL_VERSION_ATLEAST(2,0,0)
98 	int screen = 0;
99 	const int modes = SDL_GetNumDisplayModes(screen);
100 	if (modes > 0) {
101 		r_sdl_config.modes = Mem_AllocTypeN(rect_t, modes);
102 		for (int i = 0; i < modes; i++) {
103 			SDL_DisplayMode displayMode;
104 			SDL_GetDisplayMode(screen, i, &displayMode);
105 			r_sdl_config.modes[i][0] = displayMode.w;
106 			r_sdl_config.modes[i][1] = displayMode.h;
107 		}
108 	}
109 #else
110 	const SDL_VideoInfo* info = SDL_GetVideoInfo();
111 	if (info != nullptr) {
112 		SDL_VideoInfo videoInfo;
113 		SDL_PixelFormat pixelFormat;
114 		SDL_Rect **modes;
115 		Com_Printf("I: desktop depth: %ibpp\n", info->vfmt->BitsPerPixel);
116 		r_config.videoMemory = info->video_mem;
117 		Com_Printf("I: video memory: %i\n", r_config.videoMemory);
118 		memcpy(&pixelFormat, info->vfmt, sizeof(pixelFormat));
119 		memcpy(&videoInfo, info, sizeof(videoInfo));
120 		videoInfo.vfmt = &pixelFormat;
121 		modes = SDL_ListModes(videoInfo.vfmt, SDL_OPENGL | SDL_FULLSCREEN);
122 		if (modes) {
123 			if (modes == (SDL_Rect **)-1) {
124 				Com_Printf("I: Available resolutions: any resolution is supported\n");
125 				r_sdl_config.modes = nullptr;
126 			} else {
127 				for (r_sdl_config.numModes = 0; modes[r_sdl_config.numModes]; r_sdl_config.numModes++) {}
128 
129 				r_sdl_config.modes = Mem_AllocTypeN(rect_t, r_sdl_config.numModes);
130 				for (int i = 0; i < r_sdl_config.numModes; i++) {
131 					r_sdl_config.modes[i][0] = modes[i]->w;
132 					r_sdl_config.modes[i][1] = modes[i]->h;
133 				}
134 			}
135 		} else {
136 			Com_Printf("I: Could not get list of available resolutions\n");
137 		}
138 	}
139 	char videoDriverName[MAX_VAR] = "";
140 	SDL_VideoDriverName(videoDriverName, sizeof(videoDriverName));
141 	Com_Printf("I: video driver: %s\n", videoDriverName);
142 #endif
143 	if (r_sdl_config.numModes > 0) {
144 		char buf[4096] = "";
145 		Q_strcat(buf, sizeof(buf), "I: Available resolutions:");
146 		for (int i = 0; i < r_sdl_config.numModes; i++) {
147 			Q_strcat(buf, sizeof(buf), " %ix%i", r_sdl_config.modes[i][0], r_sdl_config.modes[i][1]);
148 		}
149 		Com_Printf("%s (%i)\n", buf, r_sdl_config.numModes);
150 	}
151 
152 	if (!R_SetMode())
153 		Com_Error(ERR_FATAL, "Video subsystem failed to initialize");
154 
155 #if !SDL_VERSION_ATLEAST(2,0,0)
156 	SDL_WM_SetCaption(GAME_TITLE, GAME_TITLE_LONG);
157 
158 	/* we need this in the renderer because if we issue an vid_restart we have
159 	 * to set these values again, too */
160 	SDL_EnableUNICODE(SDL_ENABLE);
161 	SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
162 #endif
163 
164 	R_SetSDLIcon();
165 
166 	if (!SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &attrValue))
167 		Com_Printf("I: got %d bits of stencil\n", attrValue);
168 	if (!SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &attrValue))
169 		Com_Printf("I: got %d bits of depth buffer\n", attrValue);
170 	if (!SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &attrValue))
171 		Com_Printf("I: got double buffer\n");
172 	if (!SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &attrValue))
173 		Com_Printf("I: got %d bits for red\n", attrValue);
174 	if (!SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &attrValue))
175 		Com_Printf("I: got %d bits for green\n", attrValue);
176 	if (!SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &attrValue))
177 		Com_Printf("I: got %d bits for blue\n", attrValue);
178 	if (!SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &attrValue))
179 		Com_Printf("I: got %d bits for alpha\n", attrValue);
180 	if (!SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &attrValue))
181 		Com_Printf("I: got multisample %s\n", attrValue != 0 ? "enabled" : "disabled");
182 	if (!SDL_GL_GetAttribute(SDL_GL_MULTISAMPLEBUFFERS, &attrValue))
183 		Com_Printf("I: got %d multisample buffers\n", attrValue);
184 
185 	return true;
186 }
187 
188 /**
189  * @brief Init the SDL window
190  */
R_InitGraphics(const viddefContext_t * context)191 bool R_InitGraphics (const viddefContext_t* context)
192 {
193 	uint32_t flags;
194 	int i;
195 
196 	SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
197 	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
198 	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
199 
200 	if (context->multisample > 0) {
201 		Com_Printf("I: set multisample buffers to %i\n", context->multisample);
202 		SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
203 		SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, context->multisample);
204 	} else {
205 		Com_Printf("I: disable multisample buffers\n");
206 		SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
207 		SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
208 	}
209 
210 #if SDL_VERSION_ATLEAST(2,0,0)
211 	/* valid values are between -1 and 1 */
212 	i = std::min(1, std::max(-1, context->swapinterval));
213 	Com_Printf("I: set swap control to %i\n", i);
214 	SDL_GL_SetSwapInterval(i);
215 	flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
216 
217 	if (context->fullscreen)
218 		flags |= SDL_WINDOW_FULLSCREEN | SDL_WINDOW_BORDERLESS;
219 
220 	const int videoDrivers = SDL_GetNumVideoDrivers();
221 	for (int i = 0; i < videoDrivers; ++i) {
222 		Com_Printf("available driver: %s\n", SDL_GetVideoDriver(i));
223 	}
224 
225 	SDL_DisplayMode displayMode;
226 	SDL_GetDesktopDisplayMode(0, &displayMode);
227 	const char* name = SDL_GetPixelFormatName(displayMode.format);
228 	Com_Printf("current desktop mode: %dx%d@%dHz (%s)\n",
229 			displayMode.w, displayMode.h, displayMode.refresh_rate, name);
230 
231 	SDL_VideoInit(nullptr);
232 	SDL_SetModState(KMOD_NONE);
233 	SDL_StopTextInput();
234 
235 	Com_Printf("driver: %s\n", SDL_GetCurrentVideoDriver());
236 	const int displays = SDL_GetNumVideoDisplays();
237 	Com_Printf("found %i display(s)\n", displays);
238 	int width = context->width;
239 	int height = context->height;
240 	if (context->fullscreen && displays > 1) {
241 		width = displayMode.w;
242 		height = displayMode.h;
243 		Com_Printf("use fake fullscreen for the first display: %i:%i\n", width, height);
244 	}
245 
246 	cls.window = SDL_CreateWindow(GAME_TITLE_LONG, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, flags);
247 	if (!cls.window) {
248 		const char* error = SDL_GetError();
249 		Com_Printf("SDL SDL_CreateWindow failed: %s\n", error);
250 		SDL_ClearError();
251 		return -1;
252 	}
253 
254 	cls.context = SDL_GL_CreateContext(cls.window);
255 #else
256 	/* valid values are between 0 and 2 */
257 	i = std::min(2, std::max(0, context->swapinterval));
258 	Com_Printf("I: set swap control to %i\n", i);
259 	SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, i);
260 	flags = SDL_OPENGL;
261 	if (context->fullscreen)
262 		flags |= SDL_FULLSCREEN;
263 	/*flags |= SDL_NOFRAME;*/
264 
265 	SDL_Surface* screen = SDL_SetVideoMode(context->width, context->height, 0, flags);
266 	if (!screen) {
267 		const char* error = SDL_GetError();
268 		Com_Printf("SDL SetVideoMode failed: %s\n", error);
269 		SDL_ClearError();
270 		return false;
271 	}
272 #endif
273 
274 	SDL_ShowCursor(SDL_DISABLE);
275 
276 	return true;
277 }
278 
Rimp_Shutdown(void)279 void Rimp_Shutdown (void)
280 {
281 #if SDL_VERSION_ATLEAST(2,0,0)
282 	SDL_DestroyWindow(cls.window);
283 	SDL_GL_DeleteContext(cls.context);
284 #endif
285 	/* SDL on Android does not support multiple video init/deinit yet, however calling SDL_SetVideoMode() multiple times works */
286 #ifndef ANDROID
287 	SDL_ShowCursor(SDL_ENABLE);
288 
289 	if (SDL_WasInit(SDL_INIT_EVERYTHING) == SDL_INIT_VIDEO)
290 		SDL_Quit();
291 	else
292 		SDL_QuitSubSystem(SDL_INIT_VIDEO);
293 #endif
294 }
295