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