|
|
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.