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