1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program 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.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 #if defined (__unix__)
21 #include <dlfcn.h> // ELF dl loader
22 #include <sys/stat.h>
23 #endif
24 
25 #include "client.h"
26 #include "qmenu.h"
27 
28 extern cvar_t *vid_ref;
29 extern cvar_t *vid_fullscreen;
30 #if 1
31 extern cvar_t *vid_gamma;
32 #endif
33 cvar_t  *gl_lightmap_saturation;
34 cvar_t  *gl_lightmap_texture_saturation;
35 
36 #if defined (__unix__)
37 static cvar_t *gl_driver;
38 #else
39 static cvar_t *gl_finish;
40 #endif
41 static cvar_t *gl_mode;
42 static cvar_t *gl_texturemode;
43 
44 #if defined (__unix__)
45 /*
46  * ====================================================================
47  * REF stuff ... Used to dynamically load the menu with only
48  * those vid_ref's that are present on this system
49  * ====================================================================
50  */
51 /* this will have to be updated if ref's are added/removed from ref_t */
52 #define NUMBER_OF_REFS 2
53 
54 /* all the refs should be initially set to 0 */
55 static char    *refs[NUMBER_OF_REFS + 1] = {0};
56 
57 /* make all these have illegal values, as they will be redefined */
58 static int	REF_GLX = NUMBER_OF_REFS;
59 static int	REF_SDLGL = NUMBER_OF_REFS;
60 
61 static int	GL_REF_START = NUMBER_OF_REFS;
62 
63 typedef struct {
64 	char	menuname[32];
65 	char	realname[32];
66 	int    *pointer;
67 } ref_t;
68 
69 static const ref_t possible_refs[NUMBER_OF_REFS] =
70 {
71 	{"X11 OpenGL", "gl", &REF_GLX},
72 	{"SDL OpenGL", "sdl", &REF_SDLGL}
73 };
74 
75 /*
76  * ============ VID_CheckRefExists
77  *
78  * Checks to see if the given ref_NAME.so exists. Placed here to avoid
79  * complicating other code if the library .so files ever have their names
80  * changed. ============
81  */
82 qboolean
VID_CheckRefExists(const char * ref)83 VID_CheckRefExists(const char *ref)
84 {
85 	char         fn[MAX_OSPATH];
86 	char        *path;
87 	struct stat  st;
88 
89 #if defined(LIBDIR)
90 	path = LIBDIR;
91 #elif defined(DATADIR)
92 	path = Cvar_Get("basedir", DATADIR, CVAR_NOSET)->string;
93 #else
94 	path = Cvar_Get("basedir", ".", CVAR_NOSET)->string;
95 #endif
96 	Com_sprintf(fn, sizeof(fn), "%s/vid_%s.so", path, ref);
97 
98 	if (stat(fn, &st) == 0)
99 		return true;
100 	else
101 		return false;
102 }
103 #endif
104 
105 /*
106 ====================================================================
107 
108 MENU INTERACTION
109 
110 ====================================================================
111 */
112 
113 #if defined (__unix__)
114 #define OPENGL_MENU   0
115 #endif
116 
117 static menuframework_s	s_opengl_menu;
118 static menuframework_s *s_current_menu;
119 static int		s_current_menu_index;
120 
121 static menulist_s		s_mode_list;
122 #if defined (__unix__)
123 static menulist_s		s_ref_list[2];
124 #else
125 static menulist_s  		s_finish_box;
126 #endif
127 static menuslider_s		s_brightness_slider;
128 static menulist_s  		s_fs_box;
129 static menulist_s  		s_texture_mode;
130 static menuslider_s		s_lightmap_saturation;
131 static menuslider_s		s_lightmap_texture_saturation;
132 static menuaction_s		s_apply_action;
133 
134 #if defined (__unix__)
DriverCallback(void * unused)135 static void DriverCallback( void *unused )
136 {
137 	s_ref_list[!s_current_menu_index].curvalue = s_ref_list[s_current_menu_index].curvalue;
138 	s_current_menu = &s_opengl_menu;
139 	s_current_menu_index = 1;
140 }
141 #endif
142 
BrightnessCallback(void * s)143 static void BrightnessCallback( void *s )
144 {
145 #if 1
146 	float gamma = (0.8 - (s_brightness_slider.curvalue * 0.1 - 0.5)) + 0.5;
147 
148 	Cvar_SetValue( "vid_gamma", gamma );
149 #else
150 	Cvar_SetValue("vid_gamma", s_brightness_slider.curvalue * 0.1);
151 #endif
152 }
153 
ApplyChanges(void * unused)154 static void ApplyChanges( void *unused )
155 {
156 #if defined (__unix__)
157 	int		ref;
158 	/*
159 	 * must use an if here (instead of a switch), since the REF_'s are
160 	 * now variables * and not #DEFINE's (constants)
161 	 */
162 	ref = s_ref_list[s_current_menu_index].curvalue;
163 	if (ref == REF_GLX) {
164 		Cvar_Set("vid_ref", "gl");
165 		Cvar_Get("gl_driver", GL_DRIVER_LIB, CVAR_ARCHIVE);
166 		if (gl_driver->modified)
167 			vid_ref->modified = true;
168 	}
169 	if (ref == REF_SDLGL) {
170 		Cvar_Set("vid_ref", "sdl");
171 		Cvar_Get("gl_driver", GL_DRIVER_LIB, CVAR_ARCHIVE);
172 		if (gl_driver->modified)
173 			vid_ref->modified = true;
174 	}
175 
176 	/*
177 	** make values consistent
178 	*/
179 	s_ref_list[!s_current_menu_index].curvalue = s_ref_list[s_current_menu_index].curvalue;
180 #else
181 	Cvar_SetValue( "gl_finish", s_finish_box.curvalue );
182 #endif
183 	Cvar_SetValue( "vid_fullscreen", s_fs_box.curvalue );
184 	Cvar_SetValue( "gl_mode", s_mode_list.curvalue );
185 
186 	if (s_texture_mode.curvalue == 0)
187 		Cvar_Set("gl_texturemode", "GL_LINEAR_MIPMAP_NEAREST"); //Bilinear
188 	else if (s_texture_mode.curvalue == 1)
189 		Cvar_Set("gl_texturemode", "GL_LINEAR_MIPMAP_LINEAR"); //Trilinear
190 
191 	Cvar_SetValue("gl_lightmap_saturation", s_lightmap_saturation.curvalue * 0.1);
192 	Cvar_SetValue("gl_lightmap_texture_saturation", s_lightmap_texture_saturation.curvalue * 0.1);
193 
194 	M_ForceMenuOff();
195 }
196 
197 /* Knightmare */
TextureMode(void)198 int TextureMode(void)
199 {
200 	char *texmode = Cvar_VariableString("gl_texturemode");
201 
202 	if (!Q_strcasecmp(texmode, "GL_LINEAR_MIPMAP_NEAREST"))
203 		return 0;
204 	else
205 		return 1;
206 }
207 
LightMapSaturation(void * unused)208 static void LightMapSaturation(void *unused)
209 {
210 	Cvar_SetValue("gl_lightmap_saturation",
211 	              s_lightmap_saturation.curvalue / 10);
212 }
213 
LightMapTextureSaturation(void * unused)214 static void LightMapTextureSaturation(void *unused)
215 {
216 	Cvar_SetValue("gl_lightmap_texture_saturation",
217 	              s_lightmap_texture_saturation.curvalue / 10);
218 }
219 
220 /*
221 ** VID_MenuInit
222 */
VID_MenuInit(void)223 void VID_MenuInit( void )
224 {
225 	int	i, y;
226 #if defined (__unix__)
227 	int	counter;
228 #endif
229 
230 	static const char *resolutions[] =
231 	{
232 		"320 x 240 [0]",
233 		"400 x 300 [1]",
234 		"512 x 384 [2]",
235 		"640 x 480 [3]",
236 		"800 x 600 [4]",
237 		"960 x 720 [5]",
238 		"1024 x 768 [6]",
239 		"1152 x 864 [7]",
240 		"1280 x 1024 [8]",
241 		"1600 x 1200 [9]",
242 		"2048 x 1536 [10]",
243 		"640 x 400 [11]",
244 		"800 x 500 [12]",
245 		"1024 x 480 [13]",
246 		"1024 x 640 [14]",
247 		"1152 x 768 [15]",
248 		"1152 x 854 [16]",
249 		"1280 x 800 [17]",
250 		"1280 x 854 [18]",
251 		"1280 x 960 [19]",
252 		"1680 x 1050 [20]",
253 		"1920 x 1200 [21]",
254 		NULL
255 	};
256 	static const char *mip_names[] =
257 	{
258 		"Bilinear ",
259 		"Trilinear",
260 		NULL
261 	};
262 	static const char *yesno_names[] =
263 	{
264 		"No",
265 		"Yes",
266 		NULL
267 	};
268 
269 #if defined (__unix__)
270 	/* make sure these are invalided before showing the menu again */
271 	REF_GLX = NUMBER_OF_REFS;
272 	REF_SDLGL = NUMBER_OF_REFS;
273 
274 
275 	GL_REF_START = NUMBER_OF_REFS;
276 
277 	/* now test to see which ref's are present */
278 	i = counter = 0;
279 	while (i < NUMBER_OF_REFS) {
280 		if (VID_CheckRefExists(possible_refs[i].realname)) {
281 			*(possible_refs[i].pointer) = counter;
282 
283 			/* free any previous string */
284 			if (refs[i])
285 				Q_free(refs[i]);
286 			refs[counter] = strdup(possible_refs[i].menuname);
287 
288 			/*
289 			 * * if we reach the 3rd item in the list, this
290 			 * indicates that a * GL ref has been found; this
291 			 * will change if more software * modes are added to
292 			 * the possible_ref's array
293 			 */
294 			if (i == 3)
295 				GL_REF_START = counter;
296 
297 			counter++;
298 		}
299 		i++;
300 	}
301 	refs[counter] = (char *)0;
302 
303 	if ( !gl_driver )
304 		gl_driver = Cvar_Get( "gl_driver", GL_DRIVER_LIB, CVAR_ARCHIVE );
305 #else
306 	if ( !gl_finish )
307 		gl_finish = Cvar_Get( "gl_finish", "0", CVAR_ARCHIVE );
308 #endif
309 	if ( !gl_mode )
310 		gl_mode = Cvar_Get( "gl_mode", "4", CVAR_ARCHIVE );
311 	if (!gl_texturemode)
312 		gl_texturemode = Cvar_Get("gl_texturemode",
313 		                          "GL_LINEAR_MIPMAP_NEAREST",
314 					  CVAR_ARCHIVE);
315 
316 	if ( !gl_lightmap_saturation )
317 		gl_lightmap_saturation = Cvar_Get( "gl_lightmap_saturation", "1", CVAR_ARCHIVE );
318 
319 	if ( !gl_lightmap_texture_saturation )
320 		gl_lightmap_texture_saturation = Cvar_Get( "gl_lightmap_texture_saturation", "1", CVAR_ARCHIVE );
321 
322 	s_mode_list.curvalue = gl_mode->value;
323 	if (s_mode_list.curvalue < 0)
324 		s_mode_list.curvalue = 4;
325 
326 #if defined (__unix__)
327 	if ( strcmp( vid_ref->string, "sdl" ) == 0 ) {
328 		s_current_menu_index = OPENGL_MENU;
329 		s_ref_list[s_current_menu_index].curvalue = REF_SDLGL;
330 	}
331 	else if ( strcmp( vid_ref->string, "gl" ) == 0 ) {
332 		s_current_menu_index = OPENGL_MENU;
333 		s_ref_list[s_current_menu_index].curvalue = REF_GLX;
334 	}
335 #endif
336 	s_opengl_menu.x = viddef.width * 0.50;
337 	s_opengl_menu.y = 0;
338 	s_opengl_menu.nitems = 0;
339 
340 	for ( i = 0; i < 2; i++ ) {
341 		y = 0;
342 #if defined (__unix__)
343 		s_ref_list[i].generic.type = MTYPE_SPINCONTROL;
344 		s_ref_list[i].generic.name = "VIDEO DRIVER";
345 		s_ref_list[i].generic.x = 0;
346 		s_ref_list[i].generic.y = y;
347 		s_ref_list[i].generic.callback = DriverCallback;
348 		s_ref_list[i].itemnames = (const char **)refs;
349 #endif
350 		s_mode_list.generic.type = MTYPE_SPINCONTROL;
351 		s_mode_list.generic.name = "RESOLUTION";
352 		s_mode_list.generic.x = 0;
353 		s_mode_list.generic.y = y += (MENU_FONT_SIZE+2);
354 		s_mode_list.itemnames = resolutions;
355 		s_mode_list.generic.statusbar =
356 		" ^1^sSet 'gl_mode' to -1 and use 'vid_width'/'vid_height' for custom resolutions.";
357 
358 		s_fs_box.generic.type = MTYPE_SPINCONTROL;
359 		s_fs_box.generic.x	= 0;
360 		s_fs_box.generic.y	= y += (MENU_FONT_SIZE+2);
361 		s_fs_box.generic.name	= "FULLSCREEN";
362 		s_fs_box.itemnames = yesno_names;
363 		s_fs_box.curvalue = vid_fullscreen->value;
364 
365 		s_brightness_slider.generic.type	= MTYPE_SLIDER;
366 		s_brightness_slider.generic.x	= 0;
367 		s_brightness_slider.generic.y	= y += 2*(MENU_FONT_SIZE+2);
368 		s_brightness_slider.generic.name	= "BRIGHTNESS";
369 		s_brightness_slider.generic.callback = BrightnessCallback;
370 #if 1
371 		s_brightness_slider.minvalue = 5;
372 		s_brightness_slider.maxvalue = 13;
373 		s_brightness_slider.curvalue = (1.3 - vid_gamma->value + 0.5) * 10;
374 #else
375 		s_brightness_slider.minvalue = 1;
376 		s_brightness_slider.maxvalue = 8;
377 		s_brightness_slider.curvalue = Cvar_VariableValue("vid_gamma") * 10;
378 #endif
379 		s_texture_mode.generic.type = MTYPE_SPINCONTROL;
380 		s_texture_mode.generic.x = 0;
381 		s_texture_mode.generic.y = y += (MENU_FONT_SIZE+2);
382 		s_texture_mode.generic.name = "TEXTURE MODE";
383 		s_texture_mode.curvalue = TextureMode();
384 		s_texture_mode.itemnames = mip_names;
385 
386 		s_lightmap_saturation.generic.type = MTYPE_SLIDER;
387 		s_lightmap_saturation.generic.x = 0;
388 		s_lightmap_saturation.generic.y = y+=(MENU_FONT_SIZE+2);
389 		s_lightmap_saturation.generic.name = "LIGHT MAP SATURATION";
390 		s_lightmap_saturation.generic.callback = LightMapSaturation;
391 		s_lightmap_saturation.minvalue = 0;
392 		s_lightmap_saturation.maxvalue = 10;
393 		s_lightmap_saturation.curvalue = gl_lightmap_saturation->value * 10;
394 		s_lightmap_saturation.generic.statusbar = "^3Lightmap saturation";
395 
396 		s_lightmap_texture_saturation.generic.type = MTYPE_SLIDER;
397 		s_lightmap_texture_saturation.generic.x = 0;
398 		s_lightmap_texture_saturation.generic.y = y+=(MENU_FONT_SIZE+2);
399 		s_lightmap_texture_saturation.generic.name = "LIGHT MAP TEXTURE SATURATION";
400 		s_lightmap_texture_saturation.generic.callback = LightMapTextureSaturation;
401 		s_lightmap_texture_saturation.minvalue = 0;
402 		s_lightmap_texture_saturation.maxvalue = 10;
403 		s_lightmap_texture_saturation.curvalue = gl_lightmap_texture_saturation->value * 10;
404 		s_lightmap_texture_saturation.generic.statusbar =
405 		"^3Lightmap texture saturation, requires vid_restart.";
406 
407 #if defined _WIN32
408 		s_finish_box.generic.type = MTYPE_SPINCONTROL;
409 		s_finish_box.generic.x	= 0;
410 		s_finish_box.generic.y	= y += (MENU_FONT_SIZE+2);
411 		s_finish_box.generic.name	= "SYNC EVERY FRAME";
412 		s_finish_box.curvalue = gl_finish->value;
413 		s_finish_box.itemnames = yesno_names;
414 #endif
415 
416 		s_apply_action.generic.type = MTYPE_ACTION;
417 		s_apply_action.generic.name = "APPLY";
418 		s_apply_action.generic.x    = 0;
419 		s_apply_action.generic.y    = y += 3*(MENU_FONT_SIZE+2);
420 		s_apply_action.generic.callback = ApplyChanges;
421 	}
422 
423 #if defined (__unix__)
424 	Menu_AddItem( &s_opengl_menu, ( void * ) &s_ref_list[OPENGL_MENU]);
425 #endif
426 	Menu_AddItem( &s_opengl_menu, ( void * ) &s_mode_list);
427 	Menu_AddItem( &s_opengl_menu, ( void * ) &s_fs_box);
428 	Menu_AddItem( &s_opengl_menu, ( void * ) &s_brightness_slider);
429 	Menu_AddItem( &s_opengl_menu, ( void * ) &s_texture_mode);
430 	Menu_AddItem( &s_opengl_menu, ( void * ) &s_lightmap_saturation);
431 	Menu_AddItem( &s_opengl_menu, ( void * ) &s_lightmap_texture_saturation);
432 #if defined _WIN32
433 	Menu_AddItem( &s_opengl_menu, ( void * ) &s_finish_box );
434 #endif
435 	Menu_AddItem( &s_opengl_menu, ( void * ) &s_apply_action);
436 
437 	Menu_Center( &s_opengl_menu );
438 	s_opengl_menu.x -= MENU_FONT_SIZE;
439 }
440 
441 #if defined (__unix__)
442 /*
443  * ================ VID_MenuShutdown ================
444  */
VID_MenuShutdown(void)445 void VID_MenuShutdown(void)
446 {
447 	int		i;
448 
449 	for (i = 0; i < NUMBER_OF_REFS; i++) {
450 		if (refs[i])
451 			Q_free(refs[i]);
452 	}
453 }
454 #endif
455 
456 /*
457 ================
458 VID_MenuDraw
459 ================
460 */
VID_MenuDraw(void)461 void VID_MenuDraw (void)
462 {
463 
464 	s_current_menu = &s_opengl_menu;
465 
466 	/*
467 	** draw the banner
468 	*/
469 	M_Banner("m_banner_video");
470 
471 	/*
472 	** move cursor to a reasonable starting position
473 	*/
474 	Menu_AdjustCursor( s_current_menu, 1 );
475 
476 	/*
477 	** draw the menu
478 	*/
479 	Menu_Draw( s_current_menu );
480 }
481 
482 /*
483 ================
484 VID_MenuKey
485 ================
486 */
VID_MenuKey(int key)487 const char *VID_MenuKey( int key )
488 {
489 
490 	menuframework_s *m = s_current_menu;
491 	static const char *sound = "misc/menu1.wav";
492 
493 	switch ( key ) {
494 		case K_ESCAPE:
495 			M_PopMenu();
496 			return NULL;
497 		case K_UPARROW:
498 			m->cursor--;
499 			Menu_AdjustCursor( m, -1 );
500 			break;
501 		case K_DOWNARROW:
502 			m->cursor++;
503 			Menu_AdjustCursor( m, 1 );
504 			break;
505 		case K_LEFTARROW:
506 			Menu_SlideItem( m, -1 );
507 			break;
508 		case K_RIGHTARROW:
509 			Menu_SlideItem( m, 1 );
510 			break;
511 		case K_ENTER:
512 			if ( !Menu_SelectItem( m ) )
513 				ApplyChanges( NULL );
514 			break;
515 	}
516 
517 	return sound;
518 }
519 
520 
521