vid_so.c 11 KB

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