Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

vid_so.c (11181B)


      1 // Main windowed and fullscreen graphics interface module. This module
      2 // is used for both the software and OpenGL rendering versions of the
      3 // Quake refresh engine.
      4 
      5 #define SO_FILE "/etc/quake2.conf"
      6 
      7 #include <errno.h>
      8 #include <assert.h>
      9 #include <dlfcn.h> // ELF dl loader
     10 #include <sys/stat.h>
     11 #include <unistd.h>
     12 
     13 #include "../client/client.h"
     14 
     15 #include "../linux/rw_linux.h"
     16 
     17 // Structure containing functions exported from refresh DLL
     18 refexport_t	re;
     19 
     20 #ifdef REF_HARD_LINKED
     21 refexport_t GetRefAPI (refimport_t rimp);
     22 #endif
     23 
     24 // Console variables that we need to access from this module
     25 cvar_t		*vid_gamma;
     26 cvar_t		*vid_ref;			// Name of Refresh DLL loaded
     27 cvar_t		*vid_xpos;			// X coordinate of window position
     28 cvar_t		*vid_ypos;			// Y coordinate of window position
     29 cvar_t		*vid_fullscreen;
     30 
     31 // Global variables used internally by this module
     32 viddef_t	viddef;				// global video state; used by other modules
     33 void		*reflib_library;		// Handle to refresh DLL 
     34 qboolean	reflib_active = 0;
     35 
     36 #define VID_NUM_MODES ( sizeof( vid_modes ) / sizeof( vid_modes[0] ) )
     37 
     38 /** KEYBOARD **************************************************************/
     39 
     40 void Do_Key_Event(int key, qboolean down);
     41 
     42 void (*KBD_Update_fp)(void);
     43 void (*KBD_Init_fp)(Key_Event_fp_t fp);
     44 void (*KBD_Close_fp)(void);
     45 
     46 /** MOUSE *****************************************************************/
     47 
     48 in_state_t in_state;
     49 
     50 void (*RW_IN_Init_fp)(in_state_t *in_state_p);
     51 void (*RW_IN_Shutdown_fp)(void);
     52 void (*RW_IN_Activate_fp)(qboolean active);
     53 void (*RW_IN_Commands_fp)(void);
     54 void (*RW_IN_Move_fp)(usercmd_t *cmd);
     55 void (*RW_IN_Frame_fp)(void);
     56 
     57 void Real_IN_Init (void);
     58 
     59 /*
     60 ==========================================================================
     61 
     62 DLL GLUE
     63 
     64 ==========================================================================
     65 */
     66 
     67 #define	MAXPRINTMSG	4096
     68 void VID_Printf (int print_level, char *fmt, ...)
     69 {
     70 	va_list		argptr;
     71 	char		msg[MAXPRINTMSG];
     72 	static qboolean	inupdate;
     73 	
     74 	va_start (argptr,fmt);
     75 	vsprintf (msg,fmt,argptr);
     76 	va_end (argptr);
     77 
     78 	if (print_level == PRINT_ALL)
     79 		Com_Printf ("%s", msg);
     80 	else
     81 		Com_DPrintf ("%s", msg);
     82 }
     83 
     84 void VID_Error (int err_level, char *fmt, ...)
     85 {
     86 	va_list		argptr;
     87 	char		msg[MAXPRINTMSG];
     88 	static qboolean	inupdate;
     89 	
     90 	va_start (argptr,fmt);
     91 	vsprintf (msg,fmt,argptr);
     92 	va_end (argptr);
     93 
     94 	Com_Error (err_level,"%s", msg);
     95 }
     96 
     97 //==========================================================================
     98 
     99 /*
    100 ============
    101 VID_Restart_f
    102 
    103 Console command to re-start the video mode and refresh DLL. We do this
    104 simply by setting the modified flag for the vid_ref variable, which will
    105 cause the entire video mode and refresh DLL to be reset on the next frame.
    106 ============
    107 */
    108 void VID_Restart_f (void)
    109 {
    110 	vid_ref->modified = true;
    111 }
    112 
    113 /*
    114 ** VID_GetModeInfo
    115 */
    116 typedef struct vidmode_s
    117 {
    118 	const char *description;
    119 	int         width, height;
    120 	int         mode;
    121 } vidmode_t;
    122 
    123 vidmode_t vid_modes[] =
    124 {
    125 	{ "Mode 0: 320x240",   320, 240,   0 },
    126 	{ "Mode 1: 400x300",   400, 300,   1 },
    127 	{ "Mode 2: 512x384",   512, 384,   2 },
    128 	{ "Mode 3: 640x480",   640, 480,   3 },
    129 	{ "Mode 4: 800x600",   800, 600,   4 },
    130 	{ "Mode 5: 960x720",   960, 720,   5 },
    131 	{ "Mode 6: 1024x768",  1024, 768,  6 },
    132 	{ "Mode 7: 1152x864",  1152, 864,  7 },
    133 	{ "Mode 8: 1280x1024",  1280, 1024, 8 },
    134 	{ "Mode 9: 1600x1200", 1600, 1200, 9 }
    135 };
    136 
    137 qboolean VID_GetModeInfo( int *width, int *height, int mode )
    138 {
    139 	if ( mode < 0 || mode >= VID_NUM_MODES )
    140 		return false;
    141 
    142 	*width  = vid_modes[mode].width;
    143 	*height = vid_modes[mode].height;
    144 
    145 	return true;
    146 }
    147 
    148 /*
    149 ** VID_NewWindow
    150 */
    151 void VID_NewWindow ( int width, int height)
    152 {
    153 	viddef.width  = width;
    154 	viddef.height = height;
    155 }
    156 
    157 void VID_FreeReflib (void)
    158 {
    159 	if (reflib_library) {
    160 		if (KBD_Close_fp)
    161 			KBD_Close_fp();
    162 		if (RW_IN_Shutdown_fp)
    163 			RW_IN_Shutdown_fp();
    164 #ifndef REF_HARD_LINKED
    165 		dlclose(reflib_library);
    166 #endif
    167 	}
    168 
    169 	KBD_Init_fp = NULL;
    170 	KBD_Update_fp = NULL;
    171 	KBD_Close_fp = NULL;
    172 	RW_IN_Init_fp = NULL;
    173 	RW_IN_Shutdown_fp = NULL;
    174 	RW_IN_Activate_fp = NULL;
    175 	RW_IN_Commands_fp = NULL;
    176 	RW_IN_Move_fp = NULL;
    177 	RW_IN_Frame_fp = NULL;
    178 
    179 	memset (&re, 0, sizeof(re));
    180 	reflib_library = NULL;
    181 	reflib_active  = false;
    182 }
    183 
    184 /*
    185 ==============
    186 VID_LoadRefresh
    187 ==============
    188 */
    189 qboolean VID_LoadRefresh( char *name )
    190 {
    191 	refimport_t	ri;
    192 #ifndef REF_HARD_LINKED
    193 	GetRefAPI_t	GetRefAPI;
    194 #endif
    195 	char	fn[MAX_OSPATH];
    196 	struct stat st;
    197 	extern uid_t saved_euid;
    198 	FILE *fp;
    199 	char	*path;
    200 	char	curpath[MAX_OSPATH];
    201 
    202 	if ( reflib_active )
    203 	{
    204 		if (KBD_Close_fp)
    205 			KBD_Close_fp();
    206 		if (RW_IN_Shutdown_fp)
    207 			RW_IN_Shutdown_fp();
    208 		KBD_Close_fp = NULL;
    209 		RW_IN_Shutdown_fp = NULL;
    210 		re.Shutdown();
    211 		VID_FreeReflib ();
    212 	}
    213 
    214 #ifndef REF_HARD_LINKED
    215 	getcwd(curpath, sizeof(curpath));
    216 	
    217 	Com_Printf( "------- Loading %s -------\n", name );
    218 
    219 	// now run through the search paths
    220 	path = NULL;
    221 	while (1)
    222 	{
    223 		path = FS_NextPath (path);
    224 		if (!path)
    225 			return NULL;		// couldn't find one anywhere
    226 		sprintf (fn, "%s/%s/%s", curpath, path, name);
    227 		Com_Printf ("Trying to load library (%s)\n", fn);
    228 
    229 		reflib_library = dlopen( fn, RTLD_NOW );
    230 		if (reflib_library)
    231 		{
    232 			Com_DPrintf ("LoadLibrary (%s)\n",name);
    233 			break;
    234 		}
    235 	}
    236 
    237 #endif
    238 
    239 	ri.Cmd_AddCommand = Cmd_AddCommand;
    240 	ri.Cmd_RemoveCommand = Cmd_RemoveCommand;
    241 	ri.Cmd_Argc = Cmd_Argc;
    242 	ri.Cmd_Argv = Cmd_Argv;
    243 	ri.Cmd_ExecuteText = Cbuf_ExecuteText;
    244 	ri.Con_Printf = VID_Printf;
    245 	ri.Sys_Error = VID_Error;
    246 	ri.FS_LoadFile = FS_LoadFile;
    247 	ri.FS_FreeFile = FS_FreeFile;
    248 	ri.FS_Gamedir = FS_Gamedir;
    249 	ri.Cvar_Get = Cvar_Get;
    250 	ri.Cvar_Set = Cvar_Set;
    251 	ri.Cvar_SetValue = Cvar_SetValue;
    252 	ri.Vid_GetModeInfo = VID_GetModeInfo;
    253 	ri.Vid_MenuInit = VID_MenuInit;
    254 	ri.Vid_NewWindow = VID_NewWindow;
    255 
    256 #ifndef REF_HARD_LINKED
    257 	if ( ( GetRefAPI = (void *) dlsym( reflib_library, "GetRefAPI" ) ) == 0 )
    258 		Com_Error( ERR_FATAL, "dlsym failed on %s", name );
    259 #endif
    260 	re = GetRefAPI( ri );
    261 
    262 	if (re.api_version != API_VERSION)
    263 	{
    264 		VID_FreeReflib ();
    265 		Com_Error (ERR_FATAL, "%s has incompatible api_version", name);
    266 	}
    267 
    268 	/* Init IN (Mouse) */
    269 	in_state.IN_CenterView_fp = IN_CenterView;
    270 	in_state.Key_Event_fp = Do_Key_Event;
    271 	in_state.viewangles = cl.viewangles;
    272 	in_state.in_strafe_state = &in_strafe.state;
    273 
    274 #ifndef REF_HARD_LINKED
    275 	if ((RW_IN_Init_fp = dlsym(reflib_library, "RW_IN_Init")) == NULL ||
    276 		(RW_IN_Shutdown_fp = dlsym(reflib_library, "RW_IN_Shutdown")) == NULL ||
    277 		(RW_IN_Activate_fp = dlsym(reflib_library, "RW_IN_Activate")) == NULL ||
    278 		(RW_IN_Commands_fp = dlsym(reflib_library, "RW_IN_Commands")) == NULL ||
    279 		(RW_IN_Move_fp = dlsym(reflib_library, "RW_IN_Move")) == NULL ||
    280 		(RW_IN_Frame_fp = dlsym(reflib_library, "RW_IN_Frame")) == NULL)
    281 		Sys_Error("No RW_IN functions in REF.\n");
    282 #else
    283 	{
    284 	    void RW_IN_Init(in_state_t *in_state_p);
    285 	    void RW_IN_Shutdown(void);
    286 	    void RW_IN_Commands (void);
    287 	    void RW_IN_Move (usercmd_t *cmd);
    288 	    void RW_IN_Frame (void);
    289 	    void RW_IN_Activate(void);
    290 
    291 	    RW_IN_Init_fp = RW_IN_Init;
    292 	    RW_IN_Shutdown_fp = RW_IN_Shutdown;
    293 	    RW_IN_Activate_fp = RW_IN_Activate;
    294 	    RW_IN_Commands_fp = RW_IN_Commands;
    295 	    RW_IN_Move_fp = RW_IN_Move;
    296 	    RW_IN_Frame_fp = RW_IN_Frame;
    297 	}
    298 #endif
    299 
    300 	if ( re.Init( 0, 0 ) == -1 )
    301 	{
    302 		re.Shutdown();
    303 		VID_FreeReflib ();
    304 		return false;
    305 	}
    306 
    307 	// give up root now
    308 	setreuid(getuid(), getuid());
    309 	setegid(getgid());
    310 
    311 	/* Init KBD */
    312 #ifndef REF_HARD_LINKED
    313 	if ((KBD_Init_fp = dlsym(reflib_library, "KBD_Init")) == NULL ||
    314 		(KBD_Update_fp = dlsym(reflib_library, "KBD_Update")) == NULL ||
    315 		(KBD_Close_fp = dlsym(reflib_library, "KBD_Close")) == NULL)
    316 		Sys_Error("No KBD functions in REF.\n");
    317 #else
    318 	{
    319 		void KBD_Init(void);
    320 		void KBD_Update(void);
    321 		void KBD_Close(void);
    322 
    323 		KBD_Init_fp = KBD_Init;
    324 		KBD_Update_fp = KBD_Update;
    325 		KBD_Close_fp = KBD_Close;
    326 	}
    327 #endif
    328 	KBD_Init_fp(Do_Key_Event);
    329 	Real_IN_Init();
    330 
    331 	Com_Printf( "------------------------------------\n");
    332 	reflib_active = true;
    333 	return true;
    334 }
    335 
    336 /*
    337 ============
    338 VID_CheckChanges
    339 
    340 This function gets called once just before drawing each frame, and it's sole purpose in life
    341 is to check to see if any of the video mode parameters have changed, and if they have to 
    342 update the rendering DLL and/or video mode to match.
    343 ============
    344 */
    345 void VID_CheckChanges (void)
    346 {
    347 	char name[100];
    348 	cvar_t *sw_mode;
    349 
    350 	if ( vid_ref->modified )
    351 	{
    352 		S_StopAllSounds();
    353 	}
    354 
    355 	while (vid_ref->modified)
    356 	{
    357 		/*
    358 		** refresh has changed
    359 		*/
    360 		vid_ref->modified = false;
    361 		vid_fullscreen->modified = true;
    362 		cl.refresh_prepped = false;
    363 		cls.disable_screen = true;
    364 
    365 		sprintf( name, "ref_%s.so", vid_ref->string );
    366 		if ( !VID_LoadRefresh( name ) )
    367 		{
    368 		        if ( strcmp (vid_ref->string, "soft") == 0 ) {
    369 			        Com_Printf("Refresh failed\n");
    370 				sw_mode = Cvar_Get( "sw_mode", "0", 0 );
    371 				if (sw_mode->value != 0) {
    372 				        Com_Printf("Trying mode 0\n");
    373 					Cvar_SetValue("sw_mode", 0);
    374 					if ( !VID_LoadRefresh( name ) )
    375 						Com_Error (ERR_FATAL, "Couldn't fall back to software refresh!");
    376 				} else
    377 					Com_Error (ERR_FATAL, "Couldn't fall back to software refresh!");
    378 			}
    379 
    380 			Cvar_Set( "vid_ref", "soft" );
    381 
    382 			/*
    383 			** drop the console if we fail to load a refresh
    384 			*/
    385 			if ( cls.key_dest != key_console )
    386 			{
    387 				Con_ToggleConsole_f();
    388 			}
    389 		}
    390 		cls.disable_screen = false;
    391 	}
    392 
    393 }
    394 
    395 /*
    396 ============
    397 VID_Init
    398 ============
    399 */
    400 void VID_Init (void)
    401 {
    402 	/* Create the video variables so we know how to start the graphics drivers */
    403         vid_ref = Cvar_Get ("vid_ref", "soft", CVAR_ARCHIVE);
    404 	vid_xpos = Cvar_Get ("vid_xpos", "3", CVAR_ARCHIVE);
    405 	vid_ypos = Cvar_Get ("vid_ypos", "22", CVAR_ARCHIVE);
    406 	vid_fullscreen = Cvar_Get ("vid_fullscreen", "0", CVAR_ARCHIVE);
    407 	vid_gamma = Cvar_Get( "vid_gamma", "1", CVAR_ARCHIVE );
    408 
    409 	/* Add some console commands that we want to handle */
    410 	Cmd_AddCommand ("vid_restart", VID_Restart_f);
    411 
    412 	/* Disable the 3Dfx splash screen */
    413 	putenv("FX_GLIDE_NO_SPLASH=0");
    414 		
    415 	/* Start the graphics mode and load refresh DLL */
    416 	VID_CheckChanges();
    417 }
    418 
    419 /*
    420 ============
    421 VID_Shutdown
    422 ============
    423 */
    424 void VID_Shutdown (void)
    425 {
    426 	if ( reflib_active )
    427 	{
    428 		if (KBD_Close_fp)
    429 			KBD_Close_fp();
    430 		if (RW_IN_Shutdown_fp)
    431 			RW_IN_Shutdown_fp();
    432 		KBD_Close_fp = NULL;
    433 		RW_IN_Shutdown_fp = NULL;
    434 		re.Shutdown ();
    435 		VID_FreeReflib ();
    436 	}
    437 }
    438 
    439 
    440 /*****************************************************************************/
    441 /* INPUT                                                                     */
    442 /*****************************************************************************/
    443 
    444 cvar_t	*in_joystick;
    445 
    446 // This if fake, it's acutally done by the Refresh load
    447 void IN_Init (void)
    448 {
    449 	in_joystick	= Cvar_Get ("in_joystick", "0", CVAR_ARCHIVE);
    450 }
    451 
    452 void Real_IN_Init (void)
    453 {
    454 	if (RW_IN_Init_fp)
    455 		RW_IN_Init_fp(&in_state);
    456 }
    457 
    458 void IN_Shutdown (void)
    459 {
    460 	if (RW_IN_Shutdown_fp)
    461 		RW_IN_Shutdown_fp();
    462 }
    463 
    464 void IN_Commands (void)
    465 {
    466 	if (RW_IN_Commands_fp)
    467 		RW_IN_Commands_fp();
    468 }
    469 
    470 void IN_Move (usercmd_t *cmd)
    471 {
    472 	if (RW_IN_Move_fp)
    473 		RW_IN_Move_fp(cmd);
    474 }
    475 
    476 void IN_Frame (void)
    477 {
    478 	if (RW_IN_Frame_fp)
    479 		RW_IN_Frame_fp();
    480 }
    481 
    482 void IN_Activate (qboolean active)
    483 {
    484 	if (RW_IN_Activate_fp)
    485 		RW_IN_Activate_fp(active);
    486 }
    487 
    488 void Do_Key_Event(int key, qboolean down)
    489 {
    490 	Key_Event(key, down, Sys_Milliseconds());
    491 }
    492