1 #include <stdlib.h>
2 #include <string.h>
3 #include <SDL.h>
4 #include "gl_init.h"
5 #include "asc.h"
6 #include "elconfig.h"
7 #include "errors.h"
8 #include "hud.h"
9 #include "init.h"
10 #include "interface.h"
11 #include "paste.h"
12 #include "textures.h"
13 #include "translate.h"
14 #include "sky.h"
15 #include "shader/shader.h"
16 #ifdef	FSAA
17 #include "fsaa/fsaa.h"
18 #endif	/* FSAA */
19 
20 int window_width = 640;
21 int window_height = 480;
22 static float window_highdpi_scale_width = 1.0f;
23 static float window_highdpi_scale_height = 1.0f;
24 
25 SDL_Window *el_gl_window = NULL;
26 static SDL_GLContext el_gl_context = NULL;
27 static SDL_Surface *icon_bmp = NULL;
28 static SDL_version el_gl_linked;
29 static int log_next_window_resize = 0;
30 
31 int bpp = 0;
32 int have_stencil = 1;
33 int video_mode = 0;
34 int video_user_width = 640;
35 int video_user_height = 480;
36 int full_screen = 0;
37 
38 int use_compiled_vertex_array = 0;
39 int use_vertex_buffers = 0;
40 int use_frame_buffer = 0;
41 int use_mipmaps = 0;
42 int use_draw_range_elements = 1;
43 float anisotropic_filter = 1.0f;
44 int disable_gamma_adjust = 0;
45 float gamma_var = 1.00f;
46 float perspective = 0.15f;
47 float near_plane = 0.1f; // don't cut off anything
48 float far_plane = 100.0;   // LOD helper. Cull distant objects. Lower value == higher framerates.
49 float far_reflection_plane = 100.0;   // LOD helper. Cull distant reflected objects. Lower value == higher framerates.
50 int gl_extensions_loaded = 0;
51 
get_window_size(int mode,int * width,int * height)52 static void get_window_size(int mode, int *width, int *height)
53 {
54 	/* Video mode 0 is user defined size (via video_user_width and video_user_height)
55 	 * Video mode 1 and above are defined in the video_modes array where mode 1 is at position 0
56 	 * Therefore we heve to adjust the index by one
57 	 */
58 	int index = mode - 1;
59 
60 	/* Safe fallback
61 	 * If the user select an invalid mode (like a wrong number in the config file) fallback
62 	 * to safe 640x480 mode
63 	 */
64 	if (index < 0 || index >= video_modes_count)
65 		index = 0;
66 
67 	*width = (mode == 0) ?video_user_width :video_modes[index].width;
68 	*height = (mode == 0) ?video_user_height :video_modes[index].height;
69 }
70 
load_window_icon(void)71 static void load_window_icon(void)
72 {
73 	char *icon_name = "icon.bmp";
74 	size_t str_len = strlen(datadir) + strlen(icon_name) + 1;
75 	char *str_buf = malloc(str_len);
76 	safe_strncpy(str_buf, datadir, str_len);
77 	safe_strcat(str_buf, icon_name, str_len);
78 	icon_bmp = SDL_LoadBMP(str_buf);
79 	if (icon_bmp == NULL)
80 		LOG_ERROR("Failed to load window icon: %s\n",str_buf);
81 	else
82 		SDL_SetWindowIcon(el_gl_window, icon_bmp);
83 	free(str_buf);
84 }
85 
init_video(void)86 void init_video(void)
87 {
88 	int target_width = 0, target_height = 0;
89 	int rgb_size[3];
90 	Uint32 flags;
91 
92 	if (!full_screen)
93 		get_window_size(video_mode, &target_width, &target_height);
94 
95 	if (SDL_Init(SDL_INIT_VIDEO) < 0)
96 	{
97 		LOG_ERROR("%s: %s\n", no_sdl_str, SDL_GetError());
98 		fprintf(stderr, "%s: %s\n", no_sdl_str, SDL_GetError());
99 		SDL_Quit();
100 		FATAL_ERROR_WINDOW("Failed to initialise SDL, going to exit.");
101 		exit(1);
102 	}
103 
104 	SDL_GetVersion(&el_gl_linked);
105 
106 	/* Detect the display depth */
107 	if (!bpp)
108 	{
109 		SDL_DisplayMode current;
110 		SDL_GetCurrentDisplayMode(0, &current);
111 		if ( SDL_BITSPERPIXEL(current.format) <= 8 )
112 			bpp = 8;
113 		else if ( SDL_BITSPERPIXEL(current.format) <= 16 )
114 			bpp = 16;
115 		else
116 			bpp = 32;
117 	}
118 
119 	// adjust the video mode depending on the BITSPERPIXEL available
120 	if (video_mode == 0)
121 	{
122 		// do nothing user defined
123 	}
124 	else if (bpp == 16)
125 	{
126 		if (!(video_mode%2))
127 			video_mode -= 1;
128 	}
129 	else
130 	{
131 		if (video_mode%2)
132 			video_mode += 1;
133 	}
134 
135 	/* Initialize the display */
136 	switch (bpp) {
137 	case 8:
138 		rgb_size[0] = 2;
139 		rgb_size[1] = 3;
140 		rgb_size[2] = 3;
141 		break;
142 	case 15:
143 	case 16:
144 		rgb_size[0] = 5;
145 		rgb_size[1] = 5;
146 		rgb_size[2] = 5;
147 		break;
148 	default:
149 		rgb_size[0] = 8;
150 		rgb_size[1] = 8;
151 		rgb_size[2] = 8;
152 		break;
153 	}
154 
155 	// Mac OS X will always use 8-8-8-8 ARGB for 32-bit screens and 5-5-5 RGB for 16-bit screens
156 #ifndef OSX
157 	SDL_GL_SetAttribute( SDL_GL_RED_SIZE, rgb_size[0] );
158 	SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, rgb_size[1] );
159 	SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, rgb_size[2] );
160 #endif
161 
162 	SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 0 );
163 	SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 24 );
164 	SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, 8);
165 	SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
166 
167 	flags = SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE|SDL_WINDOW_ALLOW_HIGHDPI;
168 	if(full_screen)
169 		flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
170 
171 #ifdef	FSAA
172 	if (fsaa > 1)
173 	{
174 		char str[400];
175 		SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
176 		SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, fsaa);
177 		glDisable(GL_MULTISAMPLE);
178 
179 		el_gl_window = SDL_CreateWindow("Eternal Lands", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, target_width, target_height, flags);
180 		if (el_gl_window == NULL)
181 		{
182 			safe_snprintf(str, sizeof(str), "Can't use fsaa mode x%d, disabling it.", fsaa);
183 			LOG_TO_CONSOLE(c_yellow1, str);
184 			LOG_WARNING("%s\n", str);
185 			SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
186 			SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
187 			fsaa = 0;
188 		}
189 	}
190 #endif	/* FSAA */
191 
192 	//try to find a stencil buffer
193 	if (el_gl_window == NULL)
194 	{
195 		el_gl_window = SDL_CreateWindow("Eternal Lands", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, target_width, target_height, flags);
196 		if (el_gl_window == NULL)
197 		{
198 			LOG_TO_CONSOLE(c_red1,no_hardware_stencil_str);
199 			LOG_ERROR("%s\n",no_hardware_stencil_str);
200 			if(bpp!=32)
201 			{
202                    LOG_TO_CONSOLE(c_grey1,suggest_24_or_32_bit);
203                    LOG_ERROR("%s\n",suggest_24_or_32_bit);
204             }
205 			SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,16);
206 			SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE,0);
207 			el_gl_window = SDL_CreateWindow("Eternal Lands", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, target_width, target_height, flags);
208 			if (el_gl_window == NULL)
209 			{
210 				LOG_ERROR("%s: %s\n", fail_opengl_mode, SDL_GetError());
211 				SDL_Quit();
212 				FATAL_ERROR_WINDOW("Failed to create game window, going to exit.");
213 				exit(1);
214 			}
215 			have_stencil=0;
216 		}
217 	}
218 
219 	el_gl_context = SDL_GL_CreateContext(el_gl_window);
220 	if (el_gl_context == NULL)
221 	{
222 		LOG_ERROR("%s: %s\n", "SDL_GL_CreateContext() Failed", SDL_GetError());
223 		SDL_Quit();
224 		FATAL_ERROR_WINDOW("Failed to create game GL context, going to exit.");
225 		exit(1);
226 	}
227 
228 	// check we have a working GL context, we will only fail later if we do not.
229 	{
230 		const GLubyte* test_string = glGetString(GL_VENDOR);
231 		if (test_string == NULL)
232 		{
233 			const char* error_str = "glGetString(GL_VENDOR) failed, going to exit.";
234 			DO_CHECK_GL_ERRORS();
235 			LOG_ERROR("%s: %s\n", error_str, SDL_GetError());
236 			SDL_Quit();
237 			FATAL_ERROR_WINDOW(error_str);
238 			exit(1);
239 		}
240 	}
241 
242 	// set the minimum size for the window, this is too small perhaps but a config option
243 	SDL_SetWindowMinimumSize(el_gl_window, 640,  480);
244 
245 	// read events for a few milliseconds, this will catch window size changes made by the window manger
246 	{
247 		SDL_Event event;
248 		Uint32 start_wait = SDL_GetTicks();
249 		while((SDL_GetTicks() < (start_wait + 100)))
250 		{
251 			SDL_PollEvent(&event);
252 			SDL_Delay(1);
253 		}
254 	}
255 
256 	// get the windos size, these variables are used globaly
257 	update_window_size_and_scale();
258 	// even though no windows have been created, their starting position need to be adjusted
259 	if (!full_screen)
260 		move_windows_proportionally((float)window_width / (float)target_width, (float)window_height / (float)target_height);
261 
262 	// enable V-SYNC, choosing active as a preference
263 	if (SDL_GL_SetSwapInterval(-1) < 0)
264 		SDL_GL_SetSwapInterval(1);
265 
266 	// set the hint that clicks that focus the window, pass through for action too
267 #if SDL_VERSION_ATLEAST(2, 0, 5)
268 	if (SDL_VERSIONNUM(el_gl_linked.major, el_gl_linked.minor, el_gl_linked.patch) >= 2005)
269 		SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
270 #endif
271 
272 	// set the gamma of we are controlling it
273 	if (!disable_gamma_adjust)
274 		SDL_SetWindowBrightness(el_gl_window, gamma_var);
275 
276 	// set the initial window title, though it will change once we are logged in
277 	SDL_SetWindowTitle( el_gl_window, win_principal );
278 
279 	glEnable(GL_DEPTH_TEST);
280 	glDepthFunc(GL_LESS);
281 	//glDepthFunc(GL_LEQUAL);
282 	glEnable(GL_TEXTURE_2D);
283 	glShadeModel(GL_SMOOTH);
284 	glFrontFace(GL_CCW);
285 	glCullFace(GL_BACK);
286 	glEnable(GL_NORMALIZE);
287 	glClearStencil(0);
288 
289 #ifdef ANTI_ALIAS
290 	if (anti_alias) {
291 		glHint(GL_POINT_SMOOTH_HINT,   GL_NICEST);
292 		glHint(GL_LINE_SMOOTH_HINT,    GL_NICEST);
293 		glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
294 		glEnable(GL_POINT_SMOOTH);
295 		glEnable(GL_LINE_SMOOTH);
296 		glEnable(GL_POLYGON_SMOOTH);
297 	} else {
298 		glHint(GL_POINT_SMOOTH_HINT,   GL_FASTEST);
299 		glHint(GL_LINE_SMOOTH_HINT,    GL_FASTEST);
300 		glHint(GL_POLYGON_SMOOTH_HINT, GL_FASTEST);
301 		glDisable(GL_POINT_SMOOTH);
302 		glDisable(GL_LINE_SMOOTH);
303 		glDisable(GL_POLYGON_SMOOTH);
304 	}
305 #endif
306 
307 	last_texture = -1;		//no active texture
308 	video_mode_set = 1;		//now you may set the video mode using the %<foo> in-game
309 
310 #if !defined OSX && !defined WINDOWS
311 	init_x11_copy_paste();
312 #endif
313 
314 	load_window_icon();
315 
316 	check_options();
317 
318 	DO_CHECK_GL_ERRORS();
319 }
320 
321 #ifdef	GL_EXTENSION_CHECK
evaluate_extension(void)322 static void evaluate_extension(void)
323 {
324 	char str[1024];
325 	int has_arb_texture_env_add;
326 	int has_arb_texture_env_crossbar;
327 	int has_arb_texture_rectangle;
328 	int has_arb_fragment_shader_shadow;
329 	int has_ati_fragment_shader;
330 	int has_ati_texture_env_combine3;
331 	int has_nv_texture_env_combine4;
332 	int has_nv_texture_shader;
333 	int has_nv_texture_shader2;
334 	int options;
335 	char* extensions;
336 
337 	extensions = (char*)glGetString(GL_EXTENSIONS);
338 
339 	has_arb_texture_env_add = strstr(extensions, "GL_ARB_texture_env_add") > 0;
340 	has_arb_texture_env_crossbar = strstr(extensions, "GL_ARB_texture_env_crossbar") > 0;
341 	has_arb_texture_rectangle = strstr(extensions, "GL_ARB_texture_rectangle") > 0;
342 	has_arb_fragment_shader_shadow = strstr(extensions, "GL_ARB_fragment_program_shadow") > 0;
343 	has_ati_fragment_shader = strstr(extensions, "GL_ATI_fragment_shader") > 0;
344 	has_ati_texture_env_combine3 = strstr(extensions, "GL_ATI_texture_env_combine3") > 0;
345 	has_nv_texture_env_combine4 = strstr(extensions, "GL_NV_texture_env_combine4") > 0;
346 	has_nv_texture_shader = strstr(extensions, "GL_NV_texture_shader") > 0;
347 	has_nv_texture_shader2 = strstr(extensions, "GL_NV_texture_shader2") > 0;
348 
349 	options = (get_texture_units() >= 2) && has_arb_texture_env_add &&
350 		have_extension(arb_texture_env_combine) && have_extension(arb_vertex_program) &&
351 		have_extension(arb_texture_compression) && have_extension(arb_vertex_buffer_object) &&
352 		have_extension(ext_texture_compression_s3tc);
353 
354 	if (!options)
355 	{
356 		safe_snprintf(str,sizeof(str),"%s%s%s","Your graphic card/driver don't support the minimum",
357 			" requirements for the next EL release. Please upgrade your driver.",
358 			" If this don't help, you need a better graphic card.");
359         LOG_TO_CONSOLE(c_red1, str);
360 		LOG_ERROR("%s\n",str);
361 		return;
362 	}
363 
364 	if (!have_extension(arb_vertex_shader) || (have_extension(arb_fragment_program) &&
365 		!have_extension(arb_fragment_shader)) || (has_ati_fragment_shader &&
366 		!have_extension(arb_fragment_program) && !have_extension(arb_fragment_shader)))
367 	{
368         safe_snprintf(str,sizeof(str),"Please update your graphic card driver!");
369 		LOG_TO_CONSOLE(c_yellow1, str);
370 		LOG_WARNING("%s\n",str);
371 	}
372 
373 	options = ((has_ati_texture_env_combine3 && has_arb_texture_env_crossbar) ||
374 		has_nv_texture_env_combine4) && (get_texture_units() >= 4) &&
375 		have_extension(ext_draw_range_elements) && have_extension(arb_shadow) &&
376 		have_extension(arb_point_parameters) && have_extension(arb_point_sprite);
377 
378 	if (!options)
379 	{
380 		safe_snprintf(str,sizeof(str),"%s%s%s","Your graphic card supports the absolute minimum",
381 			" requirements for the next EL release, but don't expect that you can use",
382 			" all features.");
383         LOG_TO_CONSOLE(c_yellow1, str);
384 		LOG_DEBUG("%s\n",str);
385 
386 	}
387 	else
388 	{
389 		options = (has_ati_fragment_shader || (has_nv_texture_shader &&
390 			has_nv_texture_shader2)) && have_extension(arb_occlusion_query) &&
391 			has_arb_texture_rectangle && have_extension(ext_framebuffer_object);
392 		if (!options)
393 		{
394             safe_snprintf(str,sizeof(str),"%s%s","Your graphic card supports the default ",
395 				"requirements for the next EL release.");
396 			LOG_TO_CONSOLE(c_green2, str);
397 			LOG_DEBUG("%s\n",str);
398 		}
399 		else
400 		{
401 			if (have_extension(arb_fragment_shader) &&
402 				have_extension(arb_shader_objects) &&
403 				have_extension(arb_vertex_shader) &&
404 				have_extension(arb_shading_language_100))
405 			{
406 				safe_snprintf(str,sizeof(str),"%s%s","Your graphic card supports all ",
407 					"features EL will use in the future.");
408                 LOG_TO_CONSOLE(c_blue2, str);
409                 LOG_DEBUG("%s\n",str);
410 			}
411 			else
412 			{
413                 safe_snprintf(str,sizeof(str),"%s%s","Your graphic card supports more than the",
414 				" default requirements for the next EL release.");
415 				LOG_TO_CONSOLE(c_blue2, str);
416                 LOG_DEBUG("%s\n",str);
417 			}
418 		}
419 	}
420 }
421 #endif	//GL_EXTENSION_CHECK
422 
init_gl_extensions(void)423 void init_gl_extensions(void)
424 {
425 	char str[1024];
426 
427 	init_opengl_extensions();
428 
429 	/*	GL_ARB_multitexture			*/
430 	if (have_extension(arb_multitexture))
431 	{
432 		safe_snprintf(str, sizeof(str), gl_ext_found, "GL_ARB_multitexture");
433 		LOG_TO_CONSOLE(c_green2, str);
434 		LOG_DEBUG("%s\n",str);
435 	}
436 	else
437 	{
438 		safe_snprintf(str, sizeof(str), gl_ext_not_found, "GL_ARB_multitexture");
439 		LOG_TO_CONSOLE(c_red1, str);
440 		LOG_DEBUG("%s\n",str);
441 	}
442 	/*	GL_ARB_multitexture			*/
443 
444 	/*	GL_ARB_texture_env_combine		*/
445 	if (have_extension(arb_texture_env_combine))
446 	{
447 		safe_snprintf(str, sizeof(str), gl_ext_found, "GL_ARB_texture_env_combine");
448 		LOG_TO_CONSOLE(c_green2, str);
449 		LOG_DEBUG("%s\n",str);
450 	}
451 	else
452 	{
453 		safe_snprintf(str, sizeof(str), gl_ext_not_found, "GL_ARB_texture_env_combine");
454 		LOG_TO_CONSOLE(c_red1, str);
455 		LOG_DEBUG("%s\n",str);
456 	}
457 	/*	GL_ARB_texture_env_combine		*/
458 
459 	/*	GL_EXT_compiled_vertex_array		*/
460 	if (have_extension(ext_compiled_vertex_array))
461 	{
462 		safe_snprintf(str, sizeof(str), gl_ext_found, "GL_EXT_compiled_vertex_array");
463 		LOG_TO_CONSOLE(c_green2, str);
464 		LOG_DEBUG("%s\n",str);
465 	}
466 	else
467 	{
468 		safe_snprintf(str, sizeof(str), gl_ext_not_found, "GL_EXT_compiled_vertex_array");
469 		LOG_TO_CONSOLE(c_red1, str);
470 		LOG_DEBUG("%s\n",str);
471 	}
472 	/*	GL_EXT_compiled_vertex_array		*/
473 
474 	/*	GL_ARB_point_sprite			*/
475 	if (have_extension(arb_point_sprite))
476 	{
477 		safe_snprintf(str, sizeof(str), gl_ext_found, "GL_ARB_point_sprite");
478 		LOG_TO_CONSOLE(c_green2, str);
479 		LOG_DEBUG("%s\n",str);
480 	}
481 	else
482 	{
483 		safe_snprintf(str, sizeof(str), gl_ext_not_found, "GL_ARB_point_sprite");
484 		LOG_TO_CONSOLE(c_red1, str);
485 		LOG_DEBUG("%s\n",str);
486 	}
487 	/*	GL_ARB_point_sprite		*/
488 
489 	/*	GL_ARB_texture_compression		*/
490 	if (have_extension(arb_texture_compression))
491 	{
492 		safe_snprintf(str, sizeof(str), gl_ext_found, "GL_ARB_texture_compression");
493 		LOG_TO_CONSOLE(c_green2, str);
494 		LOG_DEBUG("%s\n",str);
495 	}
496 	else
497 	{
498 		safe_snprintf(str, sizeof(str), gl_ext_not_found, "GL_ARB_texture_compression");
499 		LOG_TO_CONSOLE(c_red1, str);
500 		LOG_DEBUG("%s\n",str);
501 	}
502 	/*	GL_ARB_texture_compression		*/
503 
504 	/*	GL_EXT_texture_compression_s3tc		*/
505 	if (have_extension(ext_texture_compression_s3tc))
506 	{
507 		safe_snprintf(str, sizeof(str), gl_ext_found, "GL_EXT_texture_compression_s3tc");
508 		LOG_TO_CONSOLE(c_green2, str);
509 		LOG_DEBUG("%s\n",str);
510 	}
511 	else
512 	{
513 		safe_snprintf(str, sizeof(str), gl_ext_not_found, "GL_EXT_texture_compression_s3tc");
514 		LOG_TO_CONSOLE(c_red1, str);
515 		LOG_DEBUG("%s\n",str);
516 	}
517 	/*	GL_EXT_texture_compression_s3tc		*/
518 
519 	/*	GL_SGIS_generate_mipmap			*/
520 	if (have_extension(sgis_generate_mipmap))
521 	{
522 		safe_snprintf(str, sizeof(str), gl_ext_found, "GL_SGIS_generate_mipmap");
523 		LOG_TO_CONSOLE(c_green2, str);
524 		LOG_DEBUG("%s\n",str);
525 	}
526 	else
527 	{
528 		safe_snprintf(str, sizeof(str), gl_ext_not_found, "GL_SGIS_generate_mipmap");
529 		LOG_TO_CONSOLE(c_red1, str);
530 		LOG_DEBUG("%s\n",str);
531 	}
532 	/*	GL_SGIS_generate_mipmap			*/
533 
534 	/*	GL_ARB_shadow				*/
535 	if (have_extension(arb_shadow))
536 	{
537 		safe_snprintf(str, sizeof(str), gl_ext_found, "GL_ARB_shadow");
538 		LOG_TO_CONSOLE(c_green2, str);
539 		LOG_DEBUG("%s\n",str);
540 	}
541 	else
542 	{
543 		safe_snprintf(str, sizeof(str), gl_ext_not_found, "GL_ARB_shadow");
544 		LOG_TO_CONSOLE(c_red1, str);
545 		LOG_DEBUG("%s\n",str);
546 	}
547 	/*	GL_ARB_shadow				*/
548 
549 	/*	GL_ARB_vertex_buffer_object		*/
550 	if (have_extension(arb_vertex_buffer_object))
551 	{
552 		safe_snprintf(str, sizeof(str), gl_ext_found, "GL_ARB_vertex_buffer_object");
553 		LOG_TO_CONSOLE(c_green2, str);
554 		LOG_DEBUG("%s\n",str);
555 	}
556 	else
557 	{
558 		safe_snprintf(str, sizeof(str), gl_ext_not_found, "GL_ARB_vertex_buffer_object");
559 		LOG_TO_CONSOLE(c_red1, str);
560 		LOG_DEBUG("%s\n",str);
561 	}
562 	/*	GL_ARB_vertex_buffer_object		*/
563 
564 	/*	GL_EXT_framebuffer_object		*/
565 	if (have_extension(ext_framebuffer_object))
566 	{
567 		safe_snprintf(str, sizeof(str), gl_ext_found, "GL_EXT_framebuffer_object");
568 		LOG_TO_CONSOLE(c_green2, str);
569 		LOG_DEBUG("%s\n",str);
570 	}
571 	else
572 	{
573 		safe_snprintf(str, sizeof(str), gl_ext_not_found, "GL_EXT_framebuffer_object");
574 		LOG_TO_CONSOLE(c_red1, str);
575 		LOG_DEBUG("%s\n",str);
576 	}
577 	/*	GL_EXT_framebuffer_object		*/
578 
579 	/*	GL_EXT_draw_range_elements		*/
580 	if (have_extension(ext_draw_range_elements))
581 	{
582 		safe_snprintf(str, sizeof(str), gl_ext_found, "GL_EXT_draw_range_elements");
583 		LOG_TO_CONSOLE(c_green2, str);
584 		LOG_DEBUG("%s\n",str);
585 	}
586 	else
587 	{
588 		safe_snprintf(str, sizeof(str), gl_ext_not_found, "GL_EXT_draw_range_elements");
589 		LOG_TO_CONSOLE(c_red1, str);
590 		LOG_DEBUG("%s\n",str);
591 	}
592 	/*	GL_EXT_draw_range_elements		*/
593 
594 	/*	GL_ARB_texture_non_power_of_two		*/
595 	if (have_extension(arb_texture_non_power_of_two))
596 	{
597 		safe_snprintf(str, sizeof(str), gl_ext_found, "GL_ARB_texture_non_power_of_two");
598 		LOG_TO_CONSOLE(c_green2, str);
599 		LOG_DEBUG("%s\n",str);
600 	}
601 	else
602 	{
603 		safe_snprintf(str, sizeof(str), gl_ext_not_found, "GL_ARB_texture_non_power_of_two");
604 		LOG_TO_CONSOLE(c_red1, str);
605 		LOG_DEBUG("%s\n",str);
606 	}
607 	/*	GL_ARB_texture_non_power_of_two		*/
608 
609 	/*	GL_ARB_fragment_program			*/
610 	if (have_extension(arb_fragment_program))
611 	{
612 		safe_snprintf(str, sizeof(str), gl_ext_found, "GL_ARB_fragment_program");
613 		LOG_TO_CONSOLE(c_green2, str);
614 		LOG_DEBUG("%s\n",str);
615 	}
616 	else
617 	{
618 		safe_snprintf(str, sizeof(str), gl_ext_not_found, "GL_ARB_fragment_program");
619 		LOG_TO_CONSOLE(c_red1, str);
620 		LOG_DEBUG("%s\n",str);
621 	}
622 	/*	GL_ARB_fragment_program			*/
623 
624 	/*	GL_ARB_vertex_program			*/
625 	if (have_extension(arb_vertex_program))
626 	{
627 		safe_snprintf(str, sizeof(str), gl_ext_found, "GL_ARB_vertex_program");
628 		LOG_TO_CONSOLE(c_green2, str);
629 		LOG_DEBUG("%s\n",str);
630 	}
631 	else
632 	{
633 		safe_snprintf(str, sizeof(str), gl_ext_not_found, "GL_ARB_vertex_program");
634 		LOG_TO_CONSOLE(c_red1, str);
635 		LOG_DEBUG("%s\n",str);
636 	}
637 	/*	GL_ARB_vertex_program			*/
638 
639 	/*	GL_ARB_fragment_shader			*/
640 	if (have_extension(arb_fragment_shader))
641 	{
642 		safe_snprintf(str, sizeof(str), gl_ext_found, "GL_ARB_fragment_shader");
643 		LOG_TO_CONSOLE(c_green2, str);
644 		LOG_DEBUG("%s\n",str);
645 	}
646 	else
647 	{
648 		safe_snprintf(str, sizeof(str), gl_ext_not_found, "GL_ARB_fragment_shader");
649 		LOG_TO_CONSOLE(c_red1, str);
650 		LOG_DEBUG("%s\n",str);
651 	}
652 	/*	GL_ARB_fragment_shader			*/
653 
654 	/*	GL_ARB_vertex_shader			*/
655 	if (have_extension(arb_vertex_shader))
656 	{
657 		safe_snprintf(str, sizeof(str), gl_ext_found, "GL_ARB_vertex_shader");
658 		LOG_TO_CONSOLE(c_green2, str);
659 		LOG_DEBUG("%s\n",str);
660 	}
661 	else
662 	{
663 		safe_snprintf(str, sizeof(str), gl_ext_not_found, "GL_ARB_vertex_shader");
664 		LOG_TO_CONSOLE(c_red1, str);
665 		LOG_DEBUG("%s\n",str);
666 	}
667 	/*	GL_ARB_vertex_shader			*/
668 
669 	/*	GL_ARB_shader_objects			*/
670 	if (have_extension(arb_shader_objects))
671 	{
672 		safe_snprintf(str, sizeof(str), gl_ext_found, "GL_ARB_shader_objects");
673 		LOG_TO_CONSOLE(c_green2, str);
674 		LOG_DEBUG("%s\n",str);
675 	}
676 	else
677 	{
678 		safe_snprintf(str, sizeof(str), gl_ext_not_found, "GL_ARB_shader_objects");
679 		LOG_TO_CONSOLE(c_red1, str);
680 		LOG_DEBUG("%s\n",str);
681 	}
682 	/*	GL_ARB_shader_objects			*/
683 
684 	/*	GL_ARB_shading_language_100		*/
685 	if (have_extension(arb_shading_language_100))
686 	{
687 		safe_snprintf(str, sizeof(str), gl_ext_found, "GL_ARB_shading_language_100");
688 		LOG_TO_CONSOLE(c_green2, str);
689 		LOG_DEBUG("%s\n",str);
690 	}
691 	else
692 	{
693 		safe_snprintf(str, sizeof(str), gl_ext_not_found, "GL_ARB_shading_language_100");
694 		LOG_TO_CONSOLE(c_red1, str);
695 		LOG_DEBUG("%s\n",str);
696 	}
697 	/*	GL_ARB_shading_language_100		*/
698 
699 	/*	GL_ARB_texture_mirrored_repeat		*/
700 	if (have_extension(arb_texture_mirrored_repeat))
701 	{
702 		safe_snprintf(str, sizeof(str), gl_ext_found_not_used, "GL_ARB_texture_mirrored_repeat");
703 		LOG_TO_CONSOLE(c_green2, str);
704 		LOG_DEBUG("%s\n",str);
705 	}
706 	else
707 	{
708 		safe_snprintf(str, sizeof(str), gl_ext_not_found, "GL_ARB_texture_mirrored_repeat");
709 		LOG_TO_CONSOLE(c_red1, str);
710 		LOG_DEBUG("%s\n",str);
711 	}
712 	/*	GL_ARB_texture_mirrored_repeat		*/
713 
714 	/*	GL_ARB_texture_rectangle		*/
715 	if (have_extension(arb_texture_rectangle))
716 	{
717 		safe_snprintf(str, sizeof(str), gl_ext_found_not_used, "GL_ARB_texture_rectangle");
718 		LOG_TO_CONSOLE(c_green2, str);
719 		LOG_DEBUG("%s\n",str);
720 	}
721 	else
722 	{
723 		safe_snprintf(str, sizeof(str), gl_ext_not_found, "GL_ARB_texture_rectangle");
724 		LOG_TO_CONSOLE(c_red1, str);
725 		LOG_DEBUG("%s\n",str);
726 	}
727 	/*	GL_ARB_texture_rectangle		*/
728 
729 	/*	GL_EXT_fog_coord			*/
730 	if (have_extension(ext_fog_coord))
731 	{
732 		safe_snprintf(str, sizeof(str), gl_ext_found_not_used, "GL_EXT_fog_coord");
733 		LOG_TO_CONSOLE(c_green2, str);
734 		LOG_DEBUG("%s\n",str);
735 	}
736 	else
737 	{
738 		safe_snprintf(str, sizeof(str), gl_ext_not_found, "GL_EXT_fog_coord");
739 		LOG_TO_CONSOLE(c_red1, str);
740 		LOG_DEBUG("%s\n",str);
741 	}
742 	/*	GL_EXT_fog_coord			*/
743 
744 	/*	GL_ATI_texture_compression_3dc		*/
745 	if (have_extension(ati_texture_compression_3dc))
746 	{
747 		safe_snprintf(str, sizeof(str), gl_ext_found, "GL_ATI_texture_compression_3dc");
748 		LOG_TO_CONSOLE(c_green2, str);
749 		LOG_DEBUG("%s\n",str);
750 	}
751 	else
752 	{
753 		safe_snprintf(str, sizeof(str), gl_ext_not_found, "GL_ATI_texture_compression_3dc");
754 		LOG_TO_CONSOLE(c_red1, str);
755 		LOG_DEBUG("%s\n",str);
756 	}
757 	/*	GL_ATI_texture_compression_3dc		*/
758 
759 	/*	GL_EXT_texture_compression_latc		*/
760 	if (have_extension(ext_texture_compression_latc))
761 	{
762 		safe_snprintf(str, sizeof(str), gl_ext_found, "GL_EXT_texture_compression_latc");
763 		LOG_TO_CONSOLE(c_green2, str);
764 		LOG_DEBUG("%s\n",str);
765 	}
766 	else
767 	{
768 		safe_snprintf(str, sizeof(str), gl_ext_not_found, "GL_EXT_texture_compression_latc");
769 		LOG_TO_CONSOLE(c_red1, str);
770 		LOG_DEBUG("%s\n",str);
771 	}
772 	/*	GL_EXT_texture_compression_latc		*/
773 
774 	/*	GL_EXT_texture_filter_anisotropic	*/
775 	if (have_extension(ext_texture_filter_anisotropic))
776 	{
777 		glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropic_filter);
778 		safe_snprintf(str, sizeof(str), gl_ext_found, "GL_EXT_texture_filter_anisotropic");
779 		LOG_TO_CONSOLE(c_green2, str);
780 		LOG_DEBUG("%s\n",str);
781 	}
782 	else
783 	{
784 		anisotropic_filter = 1.0f;
785 		safe_snprintf(str, sizeof(str), gl_ext_not_found, "GL_EXT_texture_filter_anisotropic");
786 		LOG_TO_CONSOLE(c_red1, str);
787 		LOG_DEBUG("%s\n",str);
788 	}
789 	/*	GL_EXT_texture_filter_anisotropic	*/
790 
791 #if	0
792 	// Disabled because of bad drivers
793 	if (have_extension(ext_framebuffer_object))
794 	{
795 		check_fbo_formats();
796 	}
797 #endif
798 	init_shaders();
799 
800 #ifdef	GL_EXTENSION_CHECK
801 	evaluate_extension();
802 #endif	//GL_EXTENSION_CHECK
803 
804 	gl_extensions_loaded = 1;
805 
806 	CHECK_GL_ERRORS();
807 }
808 
resize_root_window(void)809 void resize_root_window(void)
810 {
811 	float window_ratio;
812 	//float hud_x_adjust=0;
813 	//float hud_y_adjust=0;
814 
815 	if (window_height==0)window_height=1;			// Prevent A Divide By Zero
816 
817 	//glViewport(0, hud_y, window_width-hud_x, window_height);	// Reset The Current Viewport
818 	//glViewport(0, 0, window_width-hud_x, -(window_height-hud_y));	// Reset The Current Viewport
819 
820 	glMatrixMode(GL_PROJECTION);					// Select The Projection Matrix
821 	glLoadIdentity();							// Reset The Projection Matrix
822 
823 	window_ratio=(GLfloat)(window_width-hud_x)/(GLfloat)(window_height-hud_y);
824 
825 	//hud_y_adjust=(2.0/window_height)*hud_y;
826 	//hud_x_adjust=(2.0/window_width)*hud_x;
827 	//Setup matrix for the sky. If we don't do this the sky looks unhinged when perspective changes.
828 	glLoadIdentity();
829 	glFrustum(-perspective*window_ratio*near_plane,
830 			   perspective*window_ratio*near_plane,
831 			  -perspective*near_plane,
832 			   perspective*near_plane,
833 			   near_plane, 1000.0);
834 	glGetDoublev(GL_PROJECTION_MATRIX, skybox_view);
835 	glLoadIdentity(); // Reset The Projection Matrix
836 
837 	//new zoom
838 	if (isometric)
839 	{
840 		glOrtho( -1.0*zoom_level*window_ratio, 1.0*zoom_level*window_ratio, -1.0*zoom_level, 1.0*zoom_level, -near_plane*zoom_level, 60.0 );
841 	}
842 	else
843 	{
844 		glFrustum(-perspective*window_ratio*near_plane,
845 				   perspective*window_ratio*near_plane,
846 				  -perspective*near_plane,
847 				   perspective*near_plane,
848 				  near_plane, far_plane);
849 		if (!first_person)
850 		{
851 			glTranslatef(0.0, 0.0, zoom_level*camera_distance);
852 			glTranslatef(0.0, 0.0, -zoom_level/perspective);
853 		}
854 	}
855 
856 	glMatrixMode(GL_MODELVIEW);					// Select The Modelview Matrix
857 	glLoadIdentity();							// Reset The Modelview Matrix
858 	last_texture=-1;	//no active texture
859 }
860 
switch_video(int mode,int full_screen)861 int switch_video(int mode, int full_screen)
862 {
863 	video_mode = mode;
864 	if (full_screen)
865 		SDL_SetWindowFullscreen(el_gl_window, SDL_WINDOW_FULLSCREEN_DESKTOP);
866 	else
867 	{
868 		int target_width, target_height;
869 		get_window_size(mode, &target_width, &target_height);
870 		set_client_window_size(target_width, target_height);
871 	}
872 	return 1;
873 }
874 
875 //	Set the window size as specified without changing the window mode.
set_client_window_size(int width,int height)876 void set_client_window_size(int width, int height)
877 {
878 	// limit the window size to the actual available space
879 #if SDL_VERSION_ATLEAST(2, 0, 5)
880 	{
881 		SDL_Rect rect;
882 		int display_index = SDL_GetWindowDisplayIndex(el_gl_window);
883 		int top, left, bottom, right;
884 		SDL_GetWindowBordersSize(el_gl_window, &top, &left, &bottom, &right);
885 		SDL_GetDisplayUsableBounds(display_index, &rect);
886 		width = (width > (rect.w - left - right)) ?rect.w - left - right :width;
887 		height = (height > (rect.h - top - bottom)) ?rect.h - top - bottom :height;
888 	}
889 #endif
890 
891 	log_next_window_resize = 1;
892 	SDL_RestoreWindow(el_gl_window);
893 	SDL_SetWindowFullscreen(el_gl_window, 0);
894 	SDL_SetWindowSize(el_gl_window, width, height);
895 }
896 
897 //	Get a single value for highhdpi scaling.
get_highdpi_scale(void)898 float get_highdpi_scale(void)
899 {
900 	return (window_highdpi_scale_width > window_highdpi_scale_height) ?window_highdpi_scale_width :window_highdpi_scale_height;
901 }
902 
903 //	Use the calulated values to scale mouse values.
highdpi_scale(int * width,int * height)904 void highdpi_scale(int *width, int *height)
905 {
906 	*width = (int)((0.5 - (*width < 0)) + (float)*width * window_highdpi_scale_width);
907 	*height = (int)((0.5 - (*height < 0)) + (float)*height * window_highdpi_scale_height);
908 }
909 
910 //	For high DPI displays,  SDL_GetWindowSize() reports different values to SDL_GL_GetDrawableSize()
911 //	You need the SDL_GL_GetDrawableSize() to enable use of the full window.
912 //	You need to ration of SDL_GL_GetDrawableSize()/SDL_GetWindowSize() to scale the mouse location.
update_window_size_and_scale(void)913 void update_window_size_and_scale(void)
914 {
915 	float old_width = window_highdpi_scale_width, old_height = window_highdpi_scale_height;
916 	int non_dpi_w, non_dpi_h;
917 	SDL_GetWindowSize(el_gl_window, &non_dpi_w, &non_dpi_h);
918 	SDL_GL_GetDrawableSize(el_gl_window, &window_width, &window_height);
919 	window_highdpi_scale_width = (float)window_width / (float)non_dpi_w;
920 	window_highdpi_scale_height = (float)window_height / (float)non_dpi_h;
921 	if ((old_width != window_highdpi_scale_width) || (old_height != window_highdpi_scale_height))
922 		update_highdpi_auto_scaling();
923 	if (log_next_window_resize)
924 	{
925 		char modestr[100];
926 		char str[100];
927 		safe_snprintf(modestr, sizeof(modestr), "%dx%d", window_width, window_height);
928 		safe_snprintf(str, sizeof(str), window_size_adjusted_str, modestr);
929 		LOG_TO_CONSOLE(c_yellow1, str);
930 		LOG_DEBUG("%s",str);
931 		log_next_window_resize = 0;
932 	}
933 }
934 
toggle_full_screen(void)935 void toggle_full_screen(void)
936 {
937 	full_screen=!full_screen;
938 	switch_video(video_mode, full_screen);
939 }
940 
print_gl_errors(const char * file,int line)941 int print_gl_errors(const char *file, int line)
942 {
943 	GLenum	glErr, anyErr=GL_NO_ERROR;
944 
945 	while ((glErr=glGetError()) != GL_NO_ERROR )
946 	 {
947 		anyErr=glErr;
948 		log_error(file, line, "OpenGL %s", gluErrorString(glErr));
949 	}
950 	return anyErr;
951 }
952 
gl_window_cleanup(void)953 void gl_window_cleanup(void)
954 {
955 	if (el_gl_window != NULL)
956 	{
957 		SDL_DestroyWindow(el_gl_window);
958 		el_gl_window = NULL;
959 	}
960 	if (icon_bmp != NULL)
961 	{
962 		SDL_FreeSurface(icon_bmp);
963 		icon_bmp = NULL;
964 	}
965 }
966