vid_so.c 11 KB

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