ref: c05151aa1b7ac81866cf937c973e7038035dfe53
parent: 005cceb68e49b40e29120a94e9e7138a54f5e65c
author: Konstantinn Bonnet <qu7uux@gmail.com>
date: Fri Feb 27 19:20:40 EST 2015
copy stuff over from linux for plan9
--- /dev/null
+++ b/plan9/cd_linux.c
@@ -1,0 +1,420 @@
+// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All
+// rights reserved.
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+
+#include <linux/cdrom.h>
+
+#include "../client/client.h"
+
+static qboolean cdValid = false;
+static qboolean playing = false;
+static qboolean wasPlaying = false;
+static qboolean initialized = false;
+static qboolean enabled = true;
+static qboolean playLooping = false;
+static float cdvolume;
+static byte remap[100];
+static byte playTrack;
+static byte maxTrack;
+
+static int cdfile = -1;
+
+//static char cd_dev[64] = "/dev/cdrom";
+
+cvar_t *cd_volume;
+cvar_t *cd_nocd;
+cvar_t *cd_dev;
+
+void CDAudio_Pause(void);
+
+static void CDAudio_Eject(void)
+{
+ if (cdfile == -1 || !enabled)
+ return; // no cd init'd
+
+ if ( ioctl(cdfile, CDROMEJECT) == -1 )
+ Com_DPrintf("ioctl cdromeject failed\n");
+}
+
+
+static void CDAudio_CloseDoor(void)
+{
+ if (cdfile == -1 || !enabled)
+ return; // no cd init'd
+
+ if ( ioctl(cdfile, CDROMCLOSETRAY) == -1 )
+ Com_DPrintf("ioctl cdromclosetray failed\n");
+}
+
+static int CDAudio_GetAudioDiskInfo(void)
+{
+ struct cdrom_tochdr tochdr;
+
+ cdValid = false;
+
+ if ( ioctl(cdfile, CDROMREADTOCHDR, &tochdr) == -1 )
+ {
+ Com_DPrintf("ioctl cdromreadtochdr failed\n");
+ return -1;
+ }
+
+ if (tochdr.cdth_trk0 < 1)
+ {
+ Com_DPrintf("CDAudio: no music tracks\n");
+ return -1;
+ }
+
+ cdValid = true;
+ maxTrack = tochdr.cdth_trk1;
+
+ return 0;
+}
+
+
+void CDAudio_Play(int track, qboolean looping)
+{
+ struct cdrom_tocentry entry;
+ struct cdrom_ti ti;
+
+ if (cdfile == -1 || !enabled)
+ return;
+
+ if (!cdValid)
+ {
+ CDAudio_GetAudioDiskInfo();
+ if (!cdValid)
+ return;
+ }
+
+ track = remap[track];
+
+ if (track < 1 || track > maxTrack)
+ {
+ Com_DPrintf("CDAudio: Bad track number %u.\n", track);
+ return;
+ }
+
+ // don't try to play a non-audio track
+ entry.cdte_track = track;
+ entry.cdte_format = CDROM_MSF;
+ if ( ioctl(cdfile, CDROMREADTOCENTRY, &entry) == -1 )
+ {
+ Com_DPrintf("ioctl cdromreadtocentry failed\n");
+ return;
+ }
+ if (entry.cdte_ctrl == CDROM_DATA_TRACK)
+ {
+ Com_Printf("CDAudio: track %i is not audio\n", track);
+ return;
+ }
+
+ if (playing)
+ {
+ if (playTrack == track)
+ return;
+ CDAudio_Stop();
+ }
+
+ ti.cdti_trk0 = track;
+ ti.cdti_trk1 = track;
+ ti.cdti_ind0 = 1;
+ ti.cdti_ind1 = 99;
+
+ if ( ioctl(cdfile, CDROMPLAYTRKIND, &ti) == -1 )
+ {
+ Com_DPrintf("ioctl cdromplaytrkind failed\n");
+ return;
+ }
+
+ if ( ioctl(cdfile, CDROMRESUME) == -1 )
+ Com_DPrintf("ioctl cdromresume failed\n");
+
+ playLooping = looping;
+ playTrack = track;
+ playing = true;
+
+ if (cd_volume->value == 0.0)
+ CDAudio_Pause ();
+}
+
+
+void CDAudio_Stop(void)
+{
+ if (cdfile == -1 || !enabled)
+ return;
+
+ if (!playing)
+ return;
+
+ if ( ioctl(cdfile, CDROMSTOP) == -1 )
+ Com_DPrintf("ioctl cdromstop failed (%d)\n", errno);
+
+ wasPlaying = false;
+ playing = false;
+}
+
+void CDAudio_Pause(void)
+{
+ if (cdfile == -1 || !enabled)
+ return;
+
+ if (!playing)
+ return;
+
+ if ( ioctl(cdfile, CDROMPAUSE) == -1 )
+ Com_DPrintf("ioctl cdrompause failed\n");
+
+ wasPlaying = playing;
+ playing = false;
+}
+
+
+void CDAudio_Resume(void)
+{
+ if (cdfile == -1 || !enabled)
+ return;
+
+ if (!cdValid)
+ return;
+
+ if (!wasPlaying)
+ return;
+
+ if ( ioctl(cdfile, CDROMRESUME) == -1 )
+ Com_DPrintf("ioctl cdromresume failed\n");
+ playing = true;
+}
+
+static void CD_f (void)
+{
+ char *command;
+ int ret;
+ int n;
+
+ if (Cmd_Argc() < 2)
+ return;
+
+ command = Cmd_Argv (1);
+
+ if (Q_strcasecmp(command, "on") == 0)
+ {
+ enabled = true;
+ return;
+ }
+
+ if (Q_strcasecmp(command, "off") == 0)
+ {
+ if (playing)
+ CDAudio_Stop();
+ enabled = false;
+ return;
+ }
+
+ if (Q_strcasecmp(command, "reset") == 0)
+ {
+ enabled = true;
+ if (playing)
+ CDAudio_Stop();
+ for (n = 0; n < 100; n++)
+ remap[n] = n;
+ CDAudio_GetAudioDiskInfo();
+ return;
+ }
+
+ if (Q_strcasecmp(command, "remap") == 0)
+ {
+ ret = Cmd_Argc() - 2;
+ if (ret <= 0)
+ {
+ for (n = 1; n < 100; n++)
+ if (remap[n] != n)
+ Com_Printf(" %u -> %u\n", n, remap[n]);
+ return;
+ }
+ for (n = 1; n <= ret; n++)
+ remap[n] = atoi(Cmd_Argv (n+1));
+ return;
+ }
+
+ if (Q_strcasecmp(command, "close") == 0)
+ {
+ CDAudio_CloseDoor();
+ return;
+ }
+
+ if (!cdValid)
+ {
+ CDAudio_GetAudioDiskInfo();
+ if (!cdValid)
+ {
+ Com_Printf("No CD in player.\n");
+ return;
+ }
+ }
+
+ if (Q_strcasecmp(command, "play") == 0)
+ {
+ CDAudio_Play((byte)atoi(Cmd_Argv (2)), false);
+ return;
+ }
+
+ if (Q_strcasecmp(command, "loop") == 0)
+ {
+ CDAudio_Play((byte)atoi(Cmd_Argv (2)), true);
+ return;
+ }
+
+ if (Q_strcasecmp(command, "stop") == 0)
+ {
+ CDAudio_Stop();
+ return;
+ }
+
+ if (Q_strcasecmp(command, "pause") == 0)
+ {
+ CDAudio_Pause();
+ return;
+ }
+
+ if (Q_strcasecmp(command, "resume") == 0)
+ {
+ CDAudio_Resume();
+ return;
+ }
+
+ if (Q_strcasecmp(command, "eject") == 0)
+ {
+ if (playing)
+ CDAudio_Stop();
+ CDAudio_Eject();
+ cdValid = false;
+ return;
+ }
+
+ if (Q_strcasecmp(command, "info") == 0)
+ {
+ Com_Printf("%u tracks\n", maxTrack);
+ if (playing)
+ Com_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack);
+ else if (wasPlaying)
+ Com_Printf("Paused %s track %u\n", playLooping ? "looping" : "playing", playTrack);
+ Com_Printf("Volume is %f\n", cdvolume);
+ return;
+ }
+}
+
+void CDAudio_Update(void)
+{
+ struct cdrom_subchnl subchnl;
+ static time_t lastchk;
+
+ if (cdfile == -1 || !enabled)
+ return;
+
+ if (cd_volume && cd_volume->value != cdvolume)
+ {
+ if (cdvolume)
+ {
+ Cvar_SetValue ("cd_volume", 0.0);
+ cdvolume = cd_volume->value;
+ CDAudio_Pause ();
+ }
+ else
+ {
+ Cvar_SetValue ("cd_volume", 1.0);
+ cdvolume = cd_volume->value;
+ CDAudio_Resume ();
+ }
+ }
+
+ if (playing && lastchk < time(NULL)) {
+ lastchk = time(NULL) + 2; //two seconds between chks
+ subchnl.cdsc_format = CDROM_MSF;
+ if (ioctl(cdfile, CDROMSUBCHNL, &subchnl) == -1 ) {
+ Com_DPrintf("ioctl cdromsubchnl failed\n");
+ playing = false;
+ return;
+ }
+ if (subchnl.cdsc_audiostatus != CDROM_AUDIO_PLAY &&
+ subchnl.cdsc_audiostatus != CDROM_AUDIO_PAUSED) {
+ playing = false;
+ if (playLooping)
+ CDAudio_Play(playTrack, true);
+ }
+ }
+}
+
+int CDAudio_Init(void)
+{
+ int i;
+ cvar_t *cv;
+ extern uid_t saved_euid;
+
+ cv = Cvar_Get ("nocdaudio", "0", CVAR_NOSET);
+ if (cv->value)
+ return -1;
+
+ cd_nocd = Cvar_Get ("cd_nocd", "0", CVAR_ARCHIVE );
+ if ( cd_nocd->value)
+ return -1;
+
+ cd_volume = Cvar_Get ("cd_volume", "1", CVAR_ARCHIVE);
+
+ cd_dev = Cvar_Get("cd_dev", "/dev/cdrom", CVAR_ARCHIVE);
+
+ seteuid(saved_euid);
+
+ cdfile = open(cd_dev->string, O_RDONLY);
+
+ seteuid(getuid());
+
+ if (cdfile == -1) {
+ Com_Printf("CDAudio_Init: open of \"%s\" failed (%i)\n", cd_dev->string, errno);
+ cdfile = -1;
+ return -1;
+ }
+
+ for (i = 0; i < 100; i++)
+ remap[i] = i;
+ initialized = true;
+ enabled = true;
+
+ if (CDAudio_GetAudioDiskInfo())
+ {
+ Com_Printf("CDAudio_Init: No CD in player.\n");
+ cdValid = false;
+ }
+
+ Cmd_AddCommand ("cd", CD_f);
+
+ Com_Printf("CD Audio Initialized\n");
+
+ return 0;
+}
+
+void CDAudio_Activate (qboolean active)
+{
+ if (active)
+ CDAudio_Resume ();
+ else
+ CDAudio_Pause ();
+}
+
+void CDAudio_Shutdown(void)
+{
+ if (!initialized)
+ return;
+ CDAudio_Stop();
+ close(cdfile);
+ cdfile = -1;
+}
--- /dev/null
+++ b/plan9/glob.c
@@ -1,0 +1,164 @@
+
+#include <stdio.h>
+#include "../linux/glob.h"
+
+/* Like glob_match, but match PATTERN against any final segment of TEXT. */
+static int glob_match_after_star(char *pattern, char *text)
+{
+ register char *p = pattern, *t = text;
+ register char c, c1;
+
+ while ((c = *p++) == '?' || c == '*')
+ if (c == '?' && *t++ == '\0')
+ return 0;
+
+ if (c == '\0')
+ return 1;
+
+ if (c == '\\')
+ c1 = *p;
+ else
+ c1 = c;
+
+ while (1) {
+ if ((c == '[' || *t == c1) && glob_match(p - 1, t))
+ return 1;
+ if (*t++ == '\0')
+ return 0;
+ }
+}
+
+/* Return nonzero if PATTERN has any special globbing chars in it. */
+static int glob_pattern_p(char *pattern)
+{
+ register char *p = pattern;
+ register char c;
+ int open = 0;
+
+ while ((c = *p++) != '\0')
+ switch (c) {
+ case '?':
+ case '*':
+ return 1;
+
+ case '[': /* Only accept an open brace if there is a close */
+ open++; /* brace to match it. Bracket expressions must be */
+ continue; /* complete, according to Posix.2 */
+ case ']':
+ if (open)
+ return 1;
+ continue;
+
+ case '\\':
+ if (*p++ == '\0')
+ return 0;
+ }
+
+ return 0;
+}
+
+/* Match the pattern PATTERN against the string TEXT;
+ return 1 if it matches, 0 otherwise.
+
+ A match means the entire string TEXT is used up in matching.
+
+ In the pattern string, `*' matches any sequence of characters,
+ `?' matches any character, [SET] matches any character in the specified set,
+ [!SET] matches any character not in the specified set.
+
+ A set is composed of characters or ranges; a range looks like
+ character hyphen character (as in 0-9 or A-Z).
+ [0-9a-zA-Z_] is the set of characters allowed in C identifiers.
+ Any other character in the pattern must be matched exactly.
+
+ To suppress the special syntactic significance of any of `[]*?!-\',
+ and match the character exactly, precede it with a `\'.
+*/
+
+int glob_match(char *pattern, char *text)
+{
+ register char *p = pattern, *t = text;
+ register char c;
+
+ while ((c = *p++) != '\0')
+ switch (c) {
+ case '?':
+ if (*t == '\0')
+ return 0;
+ else
+ ++t;
+ break;
+
+ case '\\':
+ if (*p++ != *t++)
+ return 0;
+ break;
+
+ case '*':
+ return glob_match_after_star(p, t);
+
+ case '[':
+ {
+ register char c1 = *t++;
+ int invert;
+
+ if (!c1)
+ return (0);
+
+ invert = ((*p == '!') || (*p == '^'));
+ if (invert)
+ p++;
+
+ c = *p++;
+ while (1) {
+ register char cstart = c, cend = c;
+
+ if (c == '\\') {
+ cstart = *p++;
+ cend = cstart;
+ }
+ if (c == '\0')
+ return 0;
+
+ c = *p++;
+ if (c == '-' && *p != ']') {
+ cend = *p++;
+ if (cend == '\\')
+ cend = *p++;
+ if (cend == '\0')
+ return 0;
+ c = *p++;
+ }
+ if (c1 >= cstart && c1 <= cend)
+ goto match;
+ if (c == ']')
+ break;
+ }
+ if (!invert)
+ return 0;
+ break;
+
+ match:
+ /* Skip the rest of the [...] construct that already matched. */
+ while (c != ']') {
+ if (c == '\0')
+ return 0;
+ c = *p++;
+ if (c == '\0')
+ return 0;
+ else if (c == '\\')
+ ++p;
+ }
+ if (invert)
+ return 0;
+ break;
+ }
+
+ default:
+ if (c != *t++)
+ return 0;
+ }
+
+ return *t == '\0';
+}
+
--- /dev/null
+++ b/plan9/glob.h
@@ -1,0 +1,1 @@
+int glob_match(char *pattern, char *text);
--- /dev/null
+++ b/plan9/in_linux.c
@@ -1,0 +1,29 @@
+// in_null.c -- for systems without a mouse
+
+#include "../client/client.h"
+
+cvar_t *in_mouse;
+cvar_t *in_joystick;
+
+void IN_Init (void)
+{
+ in_mouse = Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE);
+ in_joystick = Cvar_Get ("in_joystick", "0", CVAR_ARCHIVE);
+}
+
+void IN_Shutdown (void)
+{
+}
+
+void IN_Commands (void)
+{
+}
+
+void IN_Move (usercmd_t *cmd)
+{
+}
+
+void IN_Activate (qboolean active)
+{
+}
+
--- /dev/null
+++ b/plan9/mkfile
@@ -1,0 +1,299 @@
+</$objtype/mkfile
+
+BIN=.
+TARG=qk2
+
+CLDIR=../client
+SVDIR=../server
+SRDIR=../ref_soft
+CMDIR=../qcommon
+P9DIR=.
+GMDIR=../game
+CTFDIR=../ctf
+XADIR=../xatrix
+
+CLOFILES=\
+ $CLDIR/cl_cin.$O\
+ $CLDIR/cl_ents.$O\
+ $CLDIR/cl_fx.$O\
+ $CLDIR/cl_newfx.$O\
+ $CLDIR/cl_input.$O\
+ $CLDIR/cl_inv.$O\
+ $CLDIR/cl_main.$O\
+ $CLDIR/cl_parse.$O\
+ $CLDIR/cl_pred.$O\
+ $CLDIR/cl_tent.$O\
+ $CLDIR/cl_scrn.$O\
+ $CLDIR/cl_view.$O\
+ $CLDIR/console.$O\
+ $CLDIR/keys.$O\
+ $CLDIR/menu.$O\
+ $CLDIR/snd_dma.$O\
+ $CLDIR/snd_mem.$O\
+ $CLDIR/snd_mix.$O\
+ $CLDIR/qmenu.$O\
+ $GMDIR/m_flash.$O\
+ $CMDIR/cmd.$O\
+ $CMDIR/cmodel.$O\
+ $CMDIR/common.$O\
+ $CMDIR/crc.$O\
+ $CMDIR/cvar.$O\
+ $CMDIR/files.$O\
+ $CMDIR/md4.$O\
+ $CMDIR/net_chan.$O\
+ $GMDIR/q_shared.$O\
+ $CMDIR/pmove.$O\
+ $SVDIR/sv_ccmds.$O\
+ $SVDIR/sv_ents.$O\
+ $SVDIR/sv_game.$O\
+ $SVDIR/sv_init.$O\
+ $SVDIR/sv_main.$O\
+ $SVDIR/sv_send.$O\
+ $SVDIR/sv_user.$O\
+ $SVDIR/sv_world.$O\
+ $P9DIR/cd_linux.$O\
+ $P9DIR/q_shlinux.$O\
+ $P9DIR/vid_menu.$O\
+ $P9DIR/vid_so.$O\
+ $P9DIR/snd_linux.$O\
+ $P9DIR/sys_linux.$O\
+ $P9DIR/glob.$O\
+ $P9DIR/net_udp.$O\
+
+CLHFILES=\
+ $CLDIR/adivtab.h\
+ $CLDIR/anorms.h\
+ $CLDIR/asm_i386.h\
+ $CLDIR/block16.h\
+ $CLDIR/block8.h\
+ $CLDIR/cdaudio.h\
+ $CLDIR/client.h\
+ $CLDIR/console.h\
+ $CLDIR/input.h\
+ $CLDIR/keys.h\
+ $CLDIR/qmenu.h\
+ $CLDIR/ref.h\
+ $CLDIR/screen.h\
+ $CLDIR/snd_loc.h\
+ $CLDIR/sound.h\
+ $CLDIR/vid.h\
+
+# g_chase.c -> ChasePrev, ChaseNext, .. undefined symbols -> dlopen fails
+ #$GMDIR/g_chase.$O\
+GMOFILES=\
+ $GMDIR/g_ai.$O\
+ $GMDIR/p_client.$O\
+ $GMDIR/g_cmds.$O\
+ $GMDIR/g_svcmds.$O\
+ $GMDIR/g_combat.$O\
+ $GMDIR/g_func.$O\
+ $GMDIR/g_items.$O\
+ $GMDIR/g_main.$O\
+ $GMDIR/g_misc.$O\
+ $GMDIR/g_monster.$O\
+ $GMDIR/g_phys.$O\
+ $GMDIR/g_save.$O\
+ $GMDIR/g_spawn.$O\
+ $GMDIR/g_target.$O\
+ $GMDIR/g_trigger.$O\
+ $GMDIR/g_turret.$O\
+ $GMDIR/g_utils.$O\
+ $GMDIR/g_weapon.$O\
+ $GMDIR/m_actor.$O\
+ $GMDIR/m_berserk.$O\
+ $GMDIR/m_boss2.$O\
+ $GMDIR/m_boss3.$O\
+ $GMDIR/m_boss31.$O\
+ $GMDIR/m_boss32.$O\
+ $GMDIR/m_brain.$O\
+ $GMDIR/m_chick.$O\
+ $GMDIR/m_flipper.$O\
+ $GMDIR/m_float.$O\
+ $GMDIR/m_flyer.$O\
+ $GMDIR/m_gladiator.$O\
+ $GMDIR/m_gunner.$O\
+ $GMDIR/m_hover.$O\
+ $GMDIR/m_infantry.$O\
+ $GMDIR/m_insane.$O\
+ $GMDIR/m_medic.$O\
+ $GMDIR/m_move.$O\
+ $GMDIR/m_mutant.$O\
+ $GMDIR/m_parasite.$O\
+ $GMDIR/m_soldier.$O\
+ $GMDIR/m_supertank.$O\
+ $GMDIR/m_tank.$O\
+ $GMDIR/p_hud.$O\
+ $GMDIR/p_trail.$O\
+ $GMDIR/p_view.$O\
+ $GMDIR/p_weapon.$O\
+ $GMDIR/q_shared.$O\
+ $GMDIR/m_flash.$O\
+
+GMHFILES=\
+ $GMDIR/g_local.h\
+ $GMDIR/game.h\
+ $GMDIR/m_actor.h\
+ $GMDIR/m_berserk.h\
+ $GMDIR/m_boss2.h\
+ $GMDIR/m_boss31.h\
+ $GMDIR/m_boss32.h\
+ $GMDIR/m_brain.h\
+ $GMDIR/m_chick.h\
+ $GMDIR/m_flipper.h\
+ $GMDIR/m_float.h\
+ $GMDIR/m_flyer.h\
+ $GMDIR/m_gladiator.h\
+ $GMDIR/m_gunner.h\
+ $GMDIR/m_hover.h\
+ $GMDIR/m_infantry.h\
+ $GMDIR/m_insane.h\
+ $GMDIR/m_medic.h\
+ $GMDIR/m_mutant.h\
+ $GMDIR/m_parasite.h\
+ $GMDIR/m_player.h\
+ $GMDIR/m_rider.h\
+ $GMDIR/m_soldier.h\
+ $GMDIR/m_supertank.h\
+ $GMDIR/m_tank.h\
+ $GMDIR/q_shared.h\
+
+CTFOFILES=\
+ $CTFDIR/g_ai.$O\
+ $CTFDIR/g_chase.$O\
+ $CTFDIR/g_cmds.$O\
+ $CTFDIR/g_combat.$O\
+ $CTFDIR/g_ctf.$O\
+ $CTFDIR/g_func.$O\
+ $CTFDIR/g_items.$O\
+ $CTFDIR/g_main.$O\
+ $CTFDIR/g_misc.$O\
+ $CTFDIR/g_monster.$O\
+ $CTFDIR/g_phys.$O\
+ $CTFDIR/g_save.$O\
+ $CTFDIR/g_spawn.$O\
+ $CTFDIR/g_svcmds.$O\
+ $CTFDIR/g_target.$O\
+ $CTFDIR/g_trigger.$O\
+ $CTFDIR/g_utils.$O\
+ $CTFDIR/g_weapon.$O\
+ $CTFDIR/m_move.$O\
+ $CTFDIR/p_client.$O\
+ $CTFDIR/p_hud.$O\
+ $CTFDIR/p_menu.$O\
+ $CTFDIR/p_trail.$O\
+ $CTFDIR/p_view.$O\
+ $CTFDIR/p_weapon.$O\
+ $CTFDIR/q_shared.$O\
+
+CTFHFILES=\
+ $CTFDIR/g_ctf.h\
+ $CTFDIR/g_local.h\
+ $CTFDIR/game.h\
+ $CTFDIR/m_player.h\
+ $CTFDIR/p_menu.h\
+ $CTFDIR/q_shared.h\
+
+XAOFILES=\
+ $XADIR/g_ai.$O\
+ $XADIR/g_cmds.$O\
+ $XADIR/g_combat.$O\
+ $XADIR/g_func.$O\
+ $XADIR/g_items.$O\
+ $XADIR/g_main.$O\
+ $XADIR/g_misc.$O\
+ $XADIR/g_monster.$O\
+ $XADIR/g_phys.$O\
+ $XADIR/g_save.$O\
+ $XADIR/g_spawn.$O\
+ $XADIR/g_svcmds.$O\
+ $XADIR/g_target.$O\
+ $XADIR/g_trigger.$O\
+ $XADIR/g_turret.$O\
+ $XADIR/g_utils.$O\
+ $XADIR/g_weapon.$O\
+ $XADIR/m_actor.$O\
+ $XADIR/m_berserk.$O\
+ $XADIR/m_boss2.$O\
+ $XADIR/m_boss3.$O\
+ $XADIR/m_boss31.$O\
+ $XADIR/m_boss32.$O\
+ $XADIR/m_boss5.$O\
+ $XADIR/m_brain.$O\
+ $XADIR/m_chick.$O\
+ $XADIR/m_fixbot.$O\
+ $XADIR/m_flash.$O\
+ $XADIR/m_flipper.$O\
+ $XADIR/m_float.$O\
+ $XADIR/m_flyer.$O\
+ $XADIR/m_gekk.$O\
+ $XADIR/m_gladb.$O\
+ $XADIR/m_gladiator.$O\
+ $XADIR/m_gunner.$O\
+ $XADIR/m_hover.$O\
+ $XADIR/m_infantry.$O\
+ $XADIR/m_insane.$O\
+ $XADIR/m_medic.$O\
+ $XADIR/m_move.$O\
+ $XADIR/m_mutant.$O\
+ $XADIR/m_parasite.$O\
+ $XADIR/m_soldier.$O\
+ $XADIR/m_supertank.$O\
+ $XADIR/m_tank.$O\
+ $XADIR/p_client.$O\
+ $XADIR/p_hud.$O\
+ $XADIR/p_trail.$O\
+ $XADIR/p_view.$O\
+ $XADIR/p_weapon.$O\
+ $XADIR/q_shared.$O\
+
+# FIXME
+XAHFILES=
+
+SROFILES=\
+ $SRDIR/r_aclip.$O\
+ $SRDIR/r_alias.$O\
+ $SRDIR/r_bsp.$O\
+ $SRDIR/r_draw.$O\
+ $SRDIR/r_edge.$O\
+ $SRDIR/r_image.$O\
+ $SRDIR/r_light.$O\
+ $SRDIR/r_main.$O\
+ $SRDIR/r_misc.$O\
+ $SRDIR/r_model.$O\
+ $SRDIR/r_part.$O\
+ $SRDIR/r_poly.$O\
+ $SRDIR/r_polyse.$O\
+ $SRDIR/r_rast.$O\
+ $SRDIR/r_scan.$O\
+ $SRDIR/r_sprite.$O\
+ $SRDIR/r_surf.$O\
+ $GMDIR/q_shared.$O\
+ $P9DIR/q_shlinux.$O\
+ $P9DIR/glob.$O\
+ $P9DIR/rw_x11.$O\
+
+SRHFILES=\
+ $SRDIR/adivtab.h\
+ $SRDIR/anorms.h\
+ $SRDIR/asm_draw.h\
+ $SRDIR/d_ifacea.h\
+ $SRDIR/r_local.h\
+ $SRDIR/r_model.h\
+ $SRDIR/rand1k.h\
+
+CMHFILES=\
+ $CMDIR/crc.h\
+ $CMDIR/qcommon.h\
+ $CMDIR/qfiles.h\
+
+# only build and link needed modules for main game
+# *ofiles: ofiles needed for each module
+# *hfiles: hfiles in each module directory...
+OFILES= $CLOFILES $GMOFILES $SROFILES
+HFILES= $CLHFILES $GMHFILES $SRHFILES $CMHFILES
+
+</sys/src/cmd/mkone
+
+# FIXME
+clean:
+ rm -f $CLOFILES $GMOFILES $SROFILES $CTFOFILES $XAOFILES
--- /dev/null
+++ b/plan9/net_udp.c
@@ -1,0 +1,537 @@
+// net_wins.c
+
+#include "../qcommon/qcommon.h"
+
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+#include <errno.h>
+
+#ifdef NeXT
+#include <libc.h>
+#endif
+
+netadr_t net_local_adr;
+
+#define LOOPBACK 0x7f000001
+
+#define MAX_LOOPBACK 4
+
+typedef struct
+{
+ byte data[MAX_MSGLEN];
+ int datalen;
+} loopmsg_t;
+
+typedef struct
+{
+ loopmsg_t msgs[MAX_LOOPBACK];
+ int get, send;
+} loopback_t;
+
+loopback_t loopbacks[2];
+int ip_sockets[2];
+int ipx_sockets[2];
+
+int NET_Socket (char *net_interface, int port);
+char *NET_ErrorString (void);
+
+//=============================================================================
+
+void NetadrToSockadr (netadr_t *a, struct sockaddr_in *s)
+{
+ memset (s, 0, sizeof(*s));
+
+ if (a->type == NA_BROADCAST)
+ {
+ s->sin_family = AF_INET;
+
+ s->sin_port = a->port;
+ *(int *)&s->sin_addr = -1;
+ }
+ else if (a->type == NA_IP)
+ {
+ s->sin_family = AF_INET;
+
+ *(int *)&s->sin_addr = *(int *)&a->ip;
+ s->sin_port = a->port;
+ }
+}
+
+void SockadrToNetadr (struct sockaddr_in *s, netadr_t *a)
+{
+ *(int *)&a->ip = *(int *)&s->sin_addr;
+ a->port = s->sin_port;
+ a->type = NA_IP;
+}
+
+
+qboolean NET_CompareAdr (netadr_t a, netadr_t b)
+{
+ if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3] && a.port == b.port)
+ return true;
+ return false;
+}
+
+/*
+===================
+NET_CompareBaseAdr
+
+Compares without the port
+===================
+*/
+qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b)
+{
+ if (a.type != b.type)
+ return false;
+
+ if (a.type == NA_LOOPBACK)
+ return true;
+
+ if (a.type == NA_IP)
+ {
+ if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3])
+ return true;
+ return false;
+ }
+
+ if (a.type == NA_IPX)
+ {
+ if ((memcmp(a.ipx, b.ipx, 10) == 0))
+ return true;
+ return false;
+ }
+}
+
+char *NET_AdrToString (netadr_t a)
+{
+ static char s[64];
+
+ Com_sprintf (s, sizeof(s), "%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], ntohs(a.port));
+
+ return s;
+}
+
+char *NET_BaseAdrToString (netadr_t a)
+{
+ static char s[64];
+
+ Com_sprintf (s, sizeof(s), "%i.%i.%i.%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3]);
+
+ return s;
+}
+
+/*
+=============
+NET_StringToAdr
+
+localhost
+idnewt
+idnewt:28000
+192.246.40.70
+192.246.40.70:28000
+=============
+*/
+qboolean NET_StringToSockaddr (char *s, struct sockaddr *sadr)
+{
+ struct hostent *h;
+ char *colon;
+ char copy[128];
+
+ memset (sadr, 0, sizeof(*sadr));
+ ((struct sockaddr_in *)sadr)->sin_family = AF_INET;
+
+ ((struct sockaddr_in *)sadr)->sin_port = 0;
+
+ strcpy (copy, s);
+ // strip off a trailing :port if present
+ for (colon = copy ; *colon ; colon++)
+ if (*colon == ':')
+ {
+ *colon = 0;
+ ((struct sockaddr_in *)sadr)->sin_port = htons((short)atoi(colon+1));
+ }
+
+ if (copy[0] >= '0' && copy[0] <= '9')
+ {
+ *(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr(copy);
+ }
+ else
+ {
+ if (! (h = gethostbyname(copy)) )
+ return 0;
+ *(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0];
+ }
+
+ return true;
+}
+
+/*
+=============
+NET_StringToAdr
+
+localhost
+idnewt
+idnewt:28000
+192.246.40.70
+192.246.40.70:28000
+=============
+*/
+qboolean NET_StringToAdr (char *s, netadr_t *a)
+{
+ struct sockaddr_in sadr;
+
+ if (!strcmp (s, "localhost"))
+ {
+ memset (a, 0, sizeof(*a));
+ a->type = NA_LOOPBACK;
+ return true;
+ }
+
+ if (!NET_StringToSockaddr (s, (struct sockaddr *)&sadr))
+ return false;
+
+ SockadrToNetadr (&sadr, a);
+
+ return true;
+}
+
+
+qboolean NET_IsLocalAddress (netadr_t adr)
+{
+ return NET_CompareAdr (adr, net_local_adr);
+}
+
+/*
+=============================================================================
+
+LOOPBACK BUFFERS FOR LOCAL PLAYER
+
+=============================================================================
+*/
+
+qboolean NET_GetLoopPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message)
+{
+ int i;
+ loopback_t *loop;
+
+ loop = &loopbacks[sock];
+
+ if (loop->send - loop->get > MAX_LOOPBACK)
+ loop->get = loop->send - MAX_LOOPBACK;
+
+ if (loop->get >= loop->send)
+ return false;
+
+ i = loop->get & (MAX_LOOPBACK-1);
+ loop->get++;
+
+ memcpy (net_message->data, loop->msgs[i].data, loop->msgs[i].datalen);
+ net_message->cursize = loop->msgs[i].datalen;
+ *net_from = net_local_adr;
+ return true;
+
+}
+
+
+void NET_SendLoopPacket (netsrc_t sock, int length, void *data, netadr_t to)
+{
+ int i;
+ loopback_t *loop;
+
+ loop = &loopbacks[sock^1];
+
+ i = loop->send & (MAX_LOOPBACK-1);
+ loop->send++;
+
+ memcpy (loop->msgs[i].data, data, length);
+ loop->msgs[i].datalen = length;
+}
+
+//=============================================================================
+
+qboolean NET_GetPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message)
+{
+ int ret;
+ struct sockaddr_in from;
+ int fromlen;
+ int net_socket;
+ int protocol;
+ int err;
+
+ if (NET_GetLoopPacket (sock, net_from, net_message))
+ return true;
+
+ for (protocol = 0 ; protocol < 2 ; protocol++)
+ {
+ if (protocol == 0)
+ net_socket = ip_sockets[sock];
+ else
+ net_socket = ipx_sockets[sock];
+
+ if (!net_socket)
+ continue;
+
+ fromlen = sizeof(from);
+ ret = recvfrom (net_socket, net_message->data, net_message->maxsize
+ , 0, (struct sockaddr *)&from, &fromlen);
+ if (ret == -1)
+ {
+ err = errno;
+
+ if (err == EWOULDBLOCK || err == ECONNREFUSED)
+ continue;
+ Com_Printf ("NET_GetPacket: %s", NET_ErrorString());
+ continue;
+ }
+
+ if (ret == net_message->maxsize)
+ {
+ Com_Printf ("Oversize packet from %s\n", NET_AdrToString (*net_from));
+ continue;
+ }
+
+ net_message->cursize = ret;
+ SockadrToNetadr (&from, net_from);
+ return true;
+ }
+
+ return false;
+}
+
+//=============================================================================
+
+void NET_SendPacket (netsrc_t sock, int length, void *data, netadr_t to)
+{
+ int ret;
+ struct sockaddr_in addr;
+ int net_socket;
+
+ if ( to.type == NA_LOOPBACK )
+ {
+ NET_SendLoopPacket (sock, length, data, to);
+ return;
+ }
+
+ if (to.type == NA_BROADCAST)
+ {
+ net_socket = ip_sockets[sock];
+ if (!net_socket)
+ return;
+ }
+ else if (to.type == NA_IP)
+ {
+ net_socket = ip_sockets[sock];
+ if (!net_socket)
+ return;
+ }
+ else if (to.type == NA_IPX)
+ {
+ net_socket = ipx_sockets[sock];
+ if (!net_socket)
+ return;
+ }
+ else if (to.type == NA_BROADCAST_IPX)
+ {
+ net_socket = ipx_sockets[sock];
+ if (!net_socket)
+ return;
+ }
+ else
+ Com_Error (ERR_FATAL, "NET_SendPacket: bad address type");
+
+ NetadrToSockadr (&to, &addr);
+
+ ret = sendto (net_socket, data, length, 0, (struct sockaddr *)&addr, sizeof(addr) );
+ if (ret == -1)
+ {
+ Com_Printf ("NET_SendPacket ERROR: %i\n", NET_ErrorString());
+ }
+}
+
+
+//=============================================================================
+
+
+
+
+/*
+====================
+NET_OpenIP
+====================
+*/
+void NET_OpenIP (void)
+{
+ cvar_t *port, *ip;
+
+ port = Cvar_Get ("port", va("%i", PORT_SERVER), CVAR_NOSET);
+ ip = Cvar_Get ("ip", "localhost", CVAR_NOSET);
+
+ if (!ip_sockets[NS_SERVER])
+ ip_sockets[NS_SERVER] = NET_Socket (ip->string, port->value);
+ if (!ip_sockets[NS_CLIENT])
+ ip_sockets[NS_CLIENT] = NET_Socket (ip->string, PORT_ANY);
+}
+
+/*
+====================
+NET_OpenIPX
+====================
+*/
+void NET_OpenIPX (void)
+{
+}
+
+
+/*
+====================
+NET_Config
+
+A single player game will only use the loopback code
+====================
+*/
+void NET_Config (qboolean multiplayer)
+{
+ int i;
+
+ if (!multiplayer)
+ { // shut down any existing sockets
+ for (i=0 ; i<2 ; i++)
+ {
+ if (ip_sockets[i])
+ {
+ close (ip_sockets[i]);
+ ip_sockets[i] = 0;
+ }
+ if (ipx_sockets[i])
+ {
+ close (ipx_sockets[i]);
+ ipx_sockets[i] = 0;
+ }
+ }
+ }
+ else
+ { // open sockets
+ NET_OpenIP ();
+ NET_OpenIPX ();
+ }
+}
+
+
+//===================================================================
+
+
+/*
+====================
+NET_Init
+====================
+*/
+void NET_Init (void)
+{
+}
+
+
+/*
+====================
+NET_Socket
+====================
+*/
+int NET_Socket (char *net_interface, int port)
+{
+ int newsocket;
+ struct sockaddr_in address;
+ qboolean _true = true;
+ int i = 1;
+
+ if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
+ {
+ Com_Printf ("ERROR: UDP_OpenSocket: socket:", NET_ErrorString());
+ return 0;
+ }
+
+ // make it non-blocking
+ if (ioctl (newsocket, FIONBIO, &_true) == -1)
+ {
+ Com_Printf ("ERROR: UDP_OpenSocket: ioctl FIONBIO:%s\n", NET_ErrorString());
+ return 0;
+ }
+
+ // make it broadcast capable
+ if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == -1)
+ {
+ Com_Printf ("ERROR: UDP_OpenSocket: setsockopt SO_BROADCAST:%s\n", NET_ErrorString());
+ return 0;
+ }
+
+ if (!net_interface || !net_interface[0] || !stricmp(net_interface, "localhost"))
+ address.sin_addr.s_addr = INADDR_ANY;
+ else
+ NET_StringToSockaddr (net_interface, (struct sockaddr *)&address);
+
+ if (port == PORT_ANY)
+ address.sin_port = 0;
+ else
+ address.sin_port = htons((short)port);
+
+ address.sin_family = AF_INET;
+
+ if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
+ {
+ Com_Printf ("ERROR: UDP_OpenSocket: bind: %s\n", NET_ErrorString());
+ close (newsocket);
+ return 0;
+ }
+
+ return newsocket;
+}
+
+
+/*
+====================
+NET_Shutdown
+====================
+*/
+void NET_Shutdown (void)
+{
+ NET_Config (false); // close sockets
+}
+
+
+/*
+====================
+NET_ErrorString
+====================
+*/
+char *NET_ErrorString (void)
+{
+ int code;
+
+ code = errno;
+ return strerror (code);
+}
+
+// sleeps msec or until net socket is ready
+void NET_Sleep(int msec)
+{
+ struct timeval timeout;
+ fd_set fdset;
+ extern cvar_t *dedicated;
+ extern qboolean stdin_active;
+
+ if (!ip_sockets[NS_SERVER] || (dedicated && !dedicated->value))
+ return; // we're not a server, just run full speed
+
+ FD_ZERO(&fdset);
+ if (stdin_active)
+ FD_SET(0, &fdset); // stdin is processed too
+ FD_SET(ip_sockets[NS_SERVER], &fdset); // network socket
+ timeout.tv_sec = msec/1000;
+ timeout.tv_usec = (msec%1000)*1000;
+ select(ip_sockets[NS_SERVER]+1, &fdset, NULL, NULL, &timeout);
+}
+
--- /dev/null
+++ b/plan9/q_shlinux.c
@@ -1,0 +1,205 @@
+#include <sys/types.h>
+#include <errno.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include "../linux/glob.h"
+
+#include "../qcommon/qcommon.h"
+
+//===============================================================================
+
+byte *membase;
+int maxhunksize;
+int curhunksize;
+
+void *Hunk_Begin (int maxsize)
+{
+ // reserve a huge chunk of memory, but don't commit any yet
+ maxhunksize = maxsize + sizeof(int);
+ curhunksize = 0;
+ membase = mmap(0, maxhunksize, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+ if (membase == NULL || membase == (byte *)-1)
+ Sys_Error("unable to virtual allocate %d bytes", maxsize);
+
+ *((int *)membase) = curhunksize;
+
+ return membase + sizeof(int);
+}
+
+void *Hunk_Alloc (int size)
+{
+ byte *buf;
+
+ // round to cacheline
+ size = (size+31)&~31;
+ if (curhunksize + size > maxhunksize)
+ Sys_Error("Hunk_Alloc overflow");
+ buf = membase + sizeof(int) + curhunksize;
+ curhunksize += size;
+ return buf;
+}
+
+int Hunk_End (void)
+{
+ byte *n;
+
+ n = mremap(membase, maxhunksize, curhunksize + sizeof(int), 0);
+ if (n != membase)
+ Sys_Error("Hunk_End: Could not remap virtual block (%d)", errno);
+ *((int *)membase) = curhunksize + sizeof(int);
+
+ return curhunksize;
+}
+
+void Hunk_Free (void *base)
+{
+ byte *m;
+
+ if (base) {
+ m = ((byte *)base) - sizeof(int);
+ if (munmap(m, *((int *)m)))
+ Sys_Error("Hunk_Free: munmap failed (%d)", errno);
+ }
+}
+
+//===============================================================================
+
+
+/*
+================
+Sys_Milliseconds
+================
+*/
+int curtime;
+int Sys_Milliseconds (void)
+{
+ struct timeval tp;
+ struct timezone tzp;
+ static int secbase;
+
+ gettimeofday(&tp, &tzp);
+
+ if (!secbase)
+ {
+ secbase = tp.tv_sec;
+ return tp.tv_usec/1000;
+ }
+
+ curtime = (tp.tv_sec - secbase)*1000 + tp.tv_usec/1000;
+
+ return curtime;
+}
+
+void Sys_Mkdir (char *path)
+{
+ mkdir (path, 0777);
+}
+
+char *strlwr (char *s)
+{
+ while (*s) {
+ *s = tolower(*s);
+ s++;
+ }
+}
+
+//============================================
+
+static char findbase[MAX_OSPATH];
+static char findpath[MAX_OSPATH];
+static char findpattern[MAX_OSPATH];
+static DIR *fdir;
+
+static qboolean CompareAttributes(char *path, char *name,
+ unsigned musthave, unsigned canthave )
+{
+ struct stat st;
+ char fn[MAX_OSPATH];
+
+// . and .. never match
+ if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
+ return false;
+
+ sprintf(fn, "%s/%s", path, name);
+ if (stat(fn, &st) == -1)
+ return false; // shouldn't happen
+
+ if ( ( st.st_mode & S_IFDIR ) && ( canthave & SFF_SUBDIR ) )
+ return false;
+
+ if ( ( musthave & SFF_SUBDIR ) && !( st.st_mode & S_IFDIR ) )
+ return false;
+
+ return true;
+}
+
+char *Sys_FindFirst (char *path, unsigned musthave, unsigned canhave)
+{
+ struct dirent *d;
+ char *p;
+
+ if (fdir)
+ Sys_Error ("Sys_BeginFind without close");
+
+// COM_FilePath (path, findbase);
+ strcpy(findbase, path);
+
+ if ((p = strrchr(findbase, '/')) != NULL) {
+ *p = 0;
+ strcpy(findpattern, p + 1);
+ } else
+ strcpy(findpattern, "*");
+
+ if (strcmp(findpattern, "*.*") == 0)
+ strcpy(findpattern, "*");
+
+ if ((fdir = opendir(findbase)) == NULL)
+ return NULL;
+ while ((d = readdir(fdir)) != NULL) {
+ if (!*findpattern || glob_match(findpattern, d->d_name)) {
+// if (*findpattern)
+// printf("%s matched %s\n", findpattern, d->d_name);
+ if (CompareAttributes(findbase, d->d_name, musthave, canhave)) {
+ sprintf (findpath, "%s/%s", findbase, d->d_name);
+ return findpath;
+ }
+ }
+ }
+ return NULL;
+}
+
+char *Sys_FindNext (unsigned musthave, unsigned canhave)
+{
+ struct dirent *d;
+
+ if (fdir == NULL)
+ return NULL;
+ while ((d = readdir(fdir)) != NULL) {
+ if (!*findpattern || glob_match(findpattern, d->d_name)) {
+// if (*findpattern)
+// printf("%s matched %s\n", findpattern, d->d_name);
+ if (CompareAttributes(findbase, d->d_name, musthave, canhave)) {
+ sprintf (findpath, "%s/%s", findbase, d->d_name);
+ return findpath;
+ }
+ }
+ }
+ return NULL;
+}
+
+void Sys_FindClose (void)
+{
+ if (fdir != NULL)
+ closedir(fdir);
+ fdir = NULL;
+}
+
+
+//============================================
+
--- /dev/null
+++ b/plan9/rw_linux.h
@@ -1,0 +1,16 @@
+
+
+typedef void (*Key_Event_fp_t)(int key, qboolean down);
+
+extern void (*KBD_Update_fp)(void);
+extern void (*KBD_Init_fp)(Key_Event_fp_t fp);
+extern void (*KBD_Close_fp)(void);
+
+typedef struct in_state {
+ // Pointers to functions back in client, set by vid_so
+ void (*IN_CenterView_fp)(void);
+ Key_Event_fp_t Key_Event_fp;
+ vec_t *viewangles;
+ int *in_strafe_state;
+} in_state_t;
+
--- /dev/null
+++ b/plan9/rw_x11.c
@@ -1,0 +1,1093 @@
+/*
+** RW_X11.C
+**
+** This file contains ALL Linux specific stuff having to do with the
+** software refresh. When a port is being made the following functions
+** must be implemented by the port:
+**
+** SWimp_EndFrame
+** SWimp_Init
+** SWimp_InitGraphics
+** SWimp_SetPalette
+** SWimp_Shutdown
+** SWimp_SwitchFullscreen
+*/
+
+#include <ctype.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/keysym.h>
+#include <X11/extensions/XShm.h>
+
+#include "../ref_soft/r_local.h"
+#include "../client/keys.h"
+#include "../linux/rw_linux.h"
+
+/*****************************************************************************/
+
+static qboolean doShm;
+static Display *x_disp;
+static Colormap x_cmap;
+static Window x_win;
+static GC x_gc;
+static Visual *x_vis;
+static XVisualInfo *x_visinfo;
+//static XImage *x_image;
+
+#define STD_EVENT_MASK (StructureNotifyMask | KeyPressMask \
+ | KeyReleaseMask | ExposureMask | PointerMotionMask | \
+ ButtonPressMask | ButtonReleaseMask)
+
+static int x_shmeventtype;
+//static XShmSegmentInfo x_shminfo;
+
+static qboolean oktodraw = false;
+static qboolean X11_active = false;
+
+int XShmQueryExtension(Display *);
+int XShmGetEventBase(Display *);
+
+int current_framebuffer;
+static XImage *x_framebuffer[2] = { 0, 0 };
+static XShmSegmentInfo x_shminfo[2];
+
+struct
+{
+ int key;
+ int down;
+} keyq[64];
+int keyq_head=0;
+int keyq_tail=0;
+
+int config_notify=0;
+int config_notify_width;
+int config_notify_height;
+
+typedef unsigned short PIXEL;
+
+// Console variables that we need to access from this module
+
+/*****************************************************************************/
+/* MOUSE */
+/*****************************************************************************/
+
+// this is inside the renderer shared lib, so these are called from vid_so
+
+static qboolean mouse_avail;
+static int mouse_buttonstate;
+static int mouse_oldbuttonstate;
+static int mouse_x, mouse_y;
+static int old_mouse_x, old_mouse_y;
+static int mx, my;
+static float old_windowed_mouse;
+static int p_mouse_x, p_mouse_y;
+
+static cvar_t *_windowed_mouse;
+static cvar_t *m_filter;
+static cvar_t *in_mouse;
+
+static qboolean mlooking;
+
+// state struct passed in Init
+static in_state_t *in_state;
+
+static cvar_t *sensitivity;
+static cvar_t *lookstrafe;
+static cvar_t *m_side;
+static cvar_t *m_yaw;
+static cvar_t *m_pitch;
+static cvar_t *m_forward;
+static cvar_t *freelook;
+
+static void Force_CenterView_f (void)
+{
+ in_state->viewangles[PITCH] = 0;
+}
+
+static void RW_IN_MLookDown (void)
+{
+ mlooking = true;
+}
+
+static void RW_IN_MLookUp (void)
+{
+ mlooking = false;
+ in_state->IN_CenterView_fp ();
+}
+
+void RW_IN_Init(in_state_t *in_state_p)
+{
+ int mtype;
+ int i;
+
+ in_state = in_state_p;
+
+ // mouse variables
+ _windowed_mouse = ri.Cvar_Get ("_windowed_mouse", "0", CVAR_ARCHIVE);
+ m_filter = ri.Cvar_Get ("m_filter", "0", 0);
+ in_mouse = ri.Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE);
+ freelook = ri.Cvar_Get( "freelook", "0", 0 );
+ lookstrafe = ri.Cvar_Get ("lookstrafe", "0", 0);
+ sensitivity = ri.Cvar_Get ("sensitivity", "3", 0);
+ m_pitch = ri.Cvar_Get ("m_pitch", "0.022", 0);
+ m_yaw = ri.Cvar_Get ("m_yaw", "0.022", 0);
+ m_forward = ri.Cvar_Get ("m_forward", "1", 0);
+ m_side = ri.Cvar_Get ("m_side", "0.8", 0);
+
+ ri.Cmd_AddCommand ("+mlook", RW_IN_MLookDown);
+ ri.Cmd_AddCommand ("-mlook", RW_IN_MLookUp);
+
+ ri.Cmd_AddCommand ("force_centerview", Force_CenterView_f);
+
+ mouse_x = mouse_y = 0.0;
+ mouse_avail = true;
+}
+
+void RW_IN_Shutdown(void)
+{
+ mouse_avail = false;
+}
+
+/*
+===========
+IN_Commands
+===========
+*/
+void RW_IN_Commands (void)
+{
+ int i;
+
+ if (!mouse_avail)
+ return;
+
+ for (i=0 ; i<3 ; i++) {
+ if ( (mouse_buttonstate & (1<<i)) && !(mouse_oldbuttonstate & (1<<i)) )
+ in_state->Key_Event_fp (K_MOUSE1 + i, true);
+
+ if ( !(mouse_buttonstate & (1<<i)) && (mouse_oldbuttonstate & (1<<i)) )
+ in_state->Key_Event_fp (K_MOUSE1 + i, false);
+ }
+ mouse_oldbuttonstate = mouse_buttonstate;
+}
+
+/*
+===========
+IN_Move
+===========
+*/
+void RW_IN_Move (usercmd_t *cmd)
+{
+ if (!mouse_avail)
+ return;
+
+ if (m_filter->value)
+ {
+ mouse_x = (mx + old_mouse_x) * 0.5;
+ mouse_y = (my + old_mouse_y) * 0.5;
+ } else {
+ mouse_x = mx;
+ mouse_y = my;
+ }
+
+ old_mouse_x = mx;
+ old_mouse_y = my;
+
+ if (!mouse_x && !mouse_y)
+ return;
+
+ mouse_x *= sensitivity->value;
+ mouse_y *= sensitivity->value;
+
+// add mouse X/Y movement to cmd
+ if ( (*in_state->in_strafe_state & 1) ||
+ (lookstrafe->value && mlooking ))
+ cmd->sidemove += m_side->value * mouse_x;
+ else
+ in_state->viewangles[YAW] -= m_yaw->value * mouse_x;
+
+ if ( (mlooking || freelook->value) &&
+ !(*in_state->in_strafe_state & 1))
+ {
+ in_state->viewangles[PITCH] += m_pitch->value * mouse_y;
+ }
+ else
+ {
+ cmd->forwardmove -= m_forward->value * mouse_y;
+ }
+ mx = my = 0;
+}
+
+void RW_IN_Frame (void)
+{
+}
+
+void RW_IN_Activate(void)
+{
+}
+
+/*****************************************************************************/
+
+static PIXEL st2d_8to16table[256];
+static int shiftmask_fl=0;
+static long r_shift,g_shift,b_shift;
+static unsigned long r_mask,g_mask,b_mask;
+
+void shiftmask_init()
+{
+ unsigned int x;
+ r_mask=x_vis->red_mask;
+ g_mask=x_vis->green_mask;
+ b_mask=x_vis->blue_mask;
+ for(r_shift=-8,x=1;x<r_mask;x=x<<1)r_shift++;
+ for(g_shift=-8,x=1;x<g_mask;x=x<<1)g_shift++;
+ for(b_shift=-8,x=1;x<b_mask;x=x<<1)b_shift++;
+ shiftmask_fl=1;
+}
+
+PIXEL xlib_rgb(int r,int g,int b)
+{
+ PIXEL p;
+ if(shiftmask_fl==0) shiftmask_init();
+ p=0;
+
+ if(r_shift>0) {
+ p=(r<<(r_shift))&r_mask;
+ } else if(r_shift<0) {
+ p=(r>>(-r_shift))&r_mask;
+ } else p|=(r&r_mask);
+
+ if(g_shift>0) {
+ p|=(g<<(g_shift))&g_mask;
+ } else if(g_shift<0) {
+ p|=(g>>(-g_shift))&g_mask;
+ } else p|=(g&g_mask);
+
+ if(b_shift>0) {
+ p|=(b<<(b_shift))&b_mask;
+ } else if(b_shift<0) {
+ p|=(b>>(-b_shift))&b_mask;
+ } else p|=(b&b_mask);
+
+ return p;
+}
+
+void st2_fixup( XImage *framebuf, int x, int y, int width, int height)
+{
+ int xi,yi;
+ unsigned char *src;
+ PIXEL *dest;
+
+ if( (x<0)||(y<0) )return;
+
+ for (yi = y; yi < (y+height); yi++) {
+ src = &framebuf->data [yi * framebuf->bytes_per_line];
+ dest = (PIXEL*)src;
+ for(xi = (x+width-1); xi >= x; xi -= 8) {
+ dest[xi ] = st2d_8to16table[src[xi ]];
+ dest[xi-1] = st2d_8to16table[src[xi-1]];
+ dest[xi-2] = st2d_8to16table[src[xi-2]];
+ dest[xi-3] = st2d_8to16table[src[xi-3]];
+ dest[xi-4] = st2d_8to16table[src[xi-4]];
+ dest[xi-5] = st2d_8to16table[src[xi-5]];
+ dest[xi-6] = st2d_8to16table[src[xi-6]];
+ dest[xi-7] = st2d_8to16table[src[xi-7]];
+ }
+ }
+}
+
+// ========================================================================
+// makes a null cursor
+// ========================================================================
+
+static Cursor CreateNullCursor(Display *display, Window root)
+{
+ Pixmap cursormask;
+ XGCValues xgc;
+ GC gc;
+ XColor dummycolour;
+ Cursor cursor;
+
+ cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
+ xgc.function = GXclear;
+ gc = XCreateGC(display, cursormask, GCFunction, &xgc);
+ XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
+ dummycolour.pixel = 0;
+ dummycolour.red = 0;
+ dummycolour.flags = 04;
+ cursor = XCreatePixmapCursor(display, cursormask, cursormask,
+ &dummycolour,&dummycolour, 0,0);
+ XFreePixmap(display,cursormask);
+ XFreeGC(display,gc);
+ return cursor;
+}
+
+void ResetFrameBuffer(void)
+{
+ int mem;
+ int pwidth;
+
+ if (x_framebuffer[0])
+ {
+ free(x_framebuffer[0]->data);
+ free(x_framebuffer[0]);
+ }
+
+// alloc an extra line in case we want to wrap, and allocate the z-buffer
+ pwidth = x_visinfo->depth / 8;
+ if (pwidth == 3) pwidth = 4;
+ mem = ((vid.width*pwidth+7)&~7) * vid.height;
+
+ x_framebuffer[0] = XCreateImage( x_disp,
+ x_vis,
+ x_visinfo->depth,
+ ZPixmap,
+ 0,
+ malloc(mem),
+ vid.width, vid.height,
+ 32,
+ 0);
+
+ if (!x_framebuffer[0])
+ Sys_Error("VID: XCreateImage failed\n");
+
+ vid.buffer = (byte*) (x_framebuffer[0]);
+}
+
+void ResetSharedFrameBuffers(void)
+{
+ int size;
+ int key;
+ int minsize = getpagesize();
+ int frm;
+
+ for (frm=0 ; frm<2 ; frm++)
+ {
+ // free up old frame buffer memory
+ if (x_framebuffer[frm])
+ {
+ XShmDetach(x_disp, &x_shminfo[frm]);
+ free(x_framebuffer[frm]);
+ shmdt(x_shminfo[frm].shmaddr);
+ }
+
+ // create the image
+ x_framebuffer[frm] = XShmCreateImage( x_disp,
+ x_vis,
+ x_visinfo->depth,
+ ZPixmap,
+ 0,
+ &x_shminfo[frm],
+ vid.width,
+ vid.height );
+
+ // grab shared memory
+
+ size = x_framebuffer[frm]->bytes_per_line
+ * x_framebuffer[frm]->height;
+ if (size < minsize)
+ Sys_Error("VID: Window must use at least %d bytes\n", minsize);
+
+ key = random();
+ x_shminfo[frm].shmid = shmget((key_t)key, size, IPC_CREAT|0777);
+ if (x_shminfo[frm].shmid==-1)
+ Sys_Error("VID: Could not get any shared memory\n");
+
+ // attach to the shared memory segment
+ x_shminfo[frm].shmaddr =
+ (void *) shmat(x_shminfo[frm].shmid, 0, 0);
+
+ ri.Con_Printf(PRINT_ALL,
+ "MITSHM shared memory (id=%d, addr=0x%lx)\n",
+ x_shminfo[frm].shmid,
+ (long) x_shminfo[frm].shmaddr);
+
+ x_framebuffer[frm]->data = x_shminfo[frm].shmaddr;
+
+ // get the X server to attach to it
+
+ if (!XShmAttach(x_disp, &x_shminfo[frm]))
+ Sys_Error("VID: XShmAttach() failed\n");
+ XSync(x_disp, 0);
+ shmctl(x_shminfo[frm].shmid, IPC_RMID, 0);
+ }
+
+}
+
+// ========================================================================
+// Tragic death handler
+// ========================================================================
+
+void TragicDeath(int signal_num)
+{
+ XAutoRepeatOn(x_disp);
+ XCloseDisplay(x_disp);
+ Sys_Error("This death brought to you by the number %d\n", signal_num);
+}
+
+int XLateKey(XKeyEvent *ev)
+{
+
+ int key;
+ char buf[64];
+ KeySym keysym;
+
+ key = 0;
+
+ XLookupString(ev, buf, sizeof buf, &keysym, 0);
+
+ switch(keysym)
+ {
+ case XK_KP_Page_Up: key = K_KP_PGUP; break;
+ case XK_Page_Up: key = K_PGUP; break;
+
+ case XK_KP_Page_Down: key = K_KP_PGDN; break;
+ case XK_Page_Down: key = K_PGDN; break;
+
+ case XK_KP_Home: key = K_KP_HOME; break;
+ case XK_Home: key = K_HOME; break;
+
+ case XK_KP_End: key = K_KP_END; break;
+ case XK_End: key = K_END; break;
+
+ case XK_KP_Left: key = K_KP_LEFTARROW; break;
+ case XK_Left: key = K_LEFTARROW; break;
+
+ case XK_KP_Right: key = K_KP_RIGHTARROW; break;
+ case XK_Right: key = K_RIGHTARROW; break;
+
+ case XK_KP_Down: key = K_KP_DOWNARROW; break;
+ case XK_Down: key = K_DOWNARROW; break;
+
+ case XK_KP_Up: key = K_KP_UPARROW; break;
+ case XK_Up: key = K_UPARROW; break;
+
+ case XK_Escape: key = K_ESCAPE; break;
+
+ case XK_KP_Enter: key = K_KP_ENTER; break;
+ case XK_Return: key = K_ENTER; break;
+
+ case XK_Tab: key = K_TAB; break;
+
+ case XK_F1: key = K_F1; break;
+
+ case XK_F2: key = K_F2; break;
+
+ case XK_F3: key = K_F3; break;
+
+ case XK_F4: key = K_F4; break;
+
+ case XK_F5: key = K_F5; break;
+
+ case XK_F6: key = K_F6; break;
+
+ case XK_F7: key = K_F7; break;
+
+ case XK_F8: key = K_F8; break;
+
+ case XK_F9: key = K_F9; break;
+
+ case XK_F10: key = K_F10; break;
+
+ case XK_F11: key = K_F11; break;
+
+ case XK_F12: key = K_F12; break;
+
+ case XK_BackSpace: key = K_BACKSPACE; break;
+
+ case XK_KP_Delete: key = K_KP_DEL; break;
+ case XK_Delete: key = K_DEL; break;
+
+ case XK_Pause: key = K_PAUSE; break;
+
+ case XK_Shift_L:
+ case XK_Shift_R: key = K_SHIFT; break;
+
+ case XK_Execute:
+ case XK_Control_L:
+ case XK_Control_R: key = K_CTRL; break;
+
+ case XK_Alt_L:
+ case XK_Meta_L:
+ case XK_Alt_R:
+ case XK_Meta_R: key = K_ALT; break;
+
+ case XK_KP_Begin: key = K_KP_5; break;
+
+ case XK_Insert:key = K_INS; break;
+ case XK_KP_Insert: key = K_KP_INS; break;
+
+ case XK_KP_Multiply: key = '*'; break;
+ case XK_KP_Add: key = K_KP_PLUS; break;
+ case XK_KP_Subtract: key = K_KP_MINUS; break;
+ case XK_KP_Divide: key = K_KP_SLASH; break;
+
+#if 0
+ case 0x021: key = '1';break;/* [!] */
+ case 0x040: key = '2';break;/* [@] */
+ case 0x023: key = '3';break;/* [#] */
+ case 0x024: key = '4';break;/* [$] */
+ case 0x025: key = '5';break;/* [%] */
+ case 0x05e: key = '6';break;/* [^] */
+ case 0x026: key = '7';break;/* [&] */
+ case 0x02a: key = '8';break;/* [*] */
+ case 0x028: key = '9';;break;/* [(] */
+ case 0x029: key = '0';break;/* [)] */
+ case 0x05f: key = '-';break;/* [_] */
+ case 0x02b: key = '=';break;/* [+] */
+ case 0x07c: key = '\'';break;/* [|] */
+ case 0x07d: key = '[';break;/* [}] */
+ case 0x07b: key = ']';break;/* [{] */
+ case 0x022: key = '\'';break;/* ["] */
+ case 0x03a: key = ';';break;/* [:] */
+ case 0x03f: key = '/';break;/* [?] */
+ case 0x03e: key = '.';break;/* [>] */
+ case 0x03c: key = ',';break;/* [<] */
+#endif
+
+ default:
+ key = *(unsigned char*)buf;
+ if (key >= 'A' && key <= 'Z')
+ key = key - 'A' + 'a';
+ break;
+ }
+
+ return key;
+}
+
+void GetEvent(void)
+{
+ XEvent x_event;
+ int b;
+
+ XNextEvent(x_disp, &x_event);
+ switch(x_event.type) {
+ case KeyPress:
+ keyq[keyq_head].key = XLateKey(&x_event.xkey);
+ keyq[keyq_head].down = true;
+ keyq_head = (keyq_head + 1) & 63;
+ break;
+ case KeyRelease:
+ keyq[keyq_head].key = XLateKey(&x_event.xkey);
+ keyq[keyq_head].down = false;
+ keyq_head = (keyq_head + 1) & 63;
+ break;
+
+ case MotionNotify:
+ if (_windowed_mouse->value) {
+ mx += ((int)x_event.xmotion.x - (int)(vid.width/2));
+ my += ((int)x_event.xmotion.y - (int)(vid.height/2));
+
+ /* move the mouse to the window center again */
+ XSelectInput(x_disp,x_win, STD_EVENT_MASK & ~PointerMotionMask);
+ XWarpPointer(x_disp,None,x_win,0,0,0,0,
+ (vid.width/2),(vid.height/2));
+ XSelectInput(x_disp,x_win, STD_EVENT_MASK);
+ } else {
+ mx = ((int)x_event.xmotion.x - (int)p_mouse_x);
+ my = ((int)x_event.xmotion.y - (int)p_mouse_y);
+ p_mouse_x=x_event.xmotion.x;
+ p_mouse_y=x_event.xmotion.y;
+ }
+ break;
+
+ case ButtonPress:
+ b=-1;
+ if (x_event.xbutton.button == 1)
+ b = 0;
+ else if (x_event.xbutton.button == 2)
+ b = 2;
+ else if (x_event.xbutton.button == 3)
+ b = 1;
+ if (b>=0)
+ mouse_buttonstate |= 1<<b;
+ break;
+
+ case ButtonRelease:
+ b=-1;
+ if (x_event.xbutton.button == 1)
+ b = 0;
+ else if (x_event.xbutton.button == 2)
+ b = 2;
+ else if (x_event.xbutton.button == 3)
+ b = 1;
+ if (b>=0)
+ mouse_buttonstate &= ~(1<<b);
+ break;
+
+ case ConfigureNotify:
+ config_notify_width = x_event.xconfigure.width;
+ config_notify_height = x_event.xconfigure.height;
+ config_notify = 1;
+ break;
+
+ default:
+ if (doShm && x_event.type == x_shmeventtype)
+ oktodraw = true;
+ }
+
+ if (old_windowed_mouse != _windowed_mouse->value) {
+ old_windowed_mouse = _windowed_mouse->value;
+
+ if (!_windowed_mouse->value) {
+ /* ungrab the pointer */
+ XUngrabPointer(x_disp,CurrentTime);
+ } else {
+ /* grab the pointer */
+ XGrabPointer(x_disp,x_win,True,0,GrabModeAsync,
+ GrabModeAsync,x_win,None,CurrentTime);
+ }
+ }
+}
+
+/*****************************************************************************/
+
+/*
+** SWimp_Init
+**
+** This routine is responsible for initializing the implementation
+** specific stuff in a software rendering subsystem.
+*/
+int SWimp_Init( void *hInstance, void *wndProc )
+{
+// open the display
+ x_disp = XOpenDisplay(0);
+ if (!x_disp)
+ {
+ if (getenv("DISPLAY"))
+ Sys_Error("VID: Could not open display [%s]\n",
+ getenv("DISPLAY"));
+ else
+ Sys_Error("VID: Could not open local display\n");
+ }
+
+// catch signals so i can turn on auto-repeat
+
+ {
+ struct sigaction sa;
+ sigaction(SIGINT, 0, &sa);
+ sa.sa_handler = TragicDeath;
+ sigaction(SIGINT, &sa, 0);
+ sigaction(SIGTERM, &sa, 0);
+ }
+
+ return true;
+}
+
+/*
+** SWimp_InitGraphics
+**
+** This initializes the software refresh's implementation specific
+** graphics subsystem. In the case of Windows it creates DIB or
+** DDRAW surfaces.
+**
+** The necessary width and height parameters are grabbed from
+** vid.width and vid.height.
+*/
+static qboolean SWimp_InitGraphics( qboolean fullscreen )
+{
+ int pnum, i;
+ XVisualInfo template;
+ int num_visuals;
+ int template_mask;
+
+ srandom(getpid());
+
+ // free resources in use
+ SWimp_Shutdown ();
+
+ // let the sound and input subsystems know about the new window
+ ri.Vid_NewWindow (vid.width, vid.height);
+
+ XAutoRepeatOff(x_disp);
+
+// for debugging only
+ XSynchronize(x_disp, True);
+
+// check for command-line window size
+ template_mask = 0;
+
+#if 0
+// specify a visual id
+ if ((pnum=COM_CheckParm("-visualid")))
+ {
+ if (pnum >= com_argc-1)
+ Sys_Error("VID: -visualid <id#>\n");
+ template.visualid = Q_atoi(com_argv[pnum+1]);
+ template_mask = VisualIDMask;
+ }
+
+// If not specified, use default visual
+ else
+#endif
+ {
+ int screen;
+ screen = XDefaultScreen(x_disp);
+ template.visualid =
+ XVisualIDFromVisual(XDefaultVisual(x_disp, screen));
+ template_mask = VisualIDMask;
+ }
+
+// pick a visual- warn if more than one was available
+ x_visinfo = XGetVisualInfo(x_disp, template_mask, &template, &num_visuals);
+ if (num_visuals > 1)
+ {
+ printf("Found more than one visual id at depth %d:\n", template.depth);
+ for (i=0 ; i<num_visuals ; i++)
+ printf(" -visualid %d\n", (int)(x_visinfo[i].visualid));
+ }
+ else if (num_visuals == 0)
+ {
+ if (template_mask == VisualIDMask)
+ Sys_Error("VID: Bad visual id %d\n", template.visualid);
+ else
+ Sys_Error("VID: No visuals at depth %d\n", template.depth);
+ }
+
+#if 0
+ if (verbose)
+ {
+ printf("Using visualid %d:\n", (int)(x_visinfo->visualid));
+ printf(" screen %d\n", x_visinfo->screen);
+ printf(" red_mask 0x%x\n", (int)(x_visinfo->red_mask));
+ printf(" green_mask 0x%x\n", (int)(x_visinfo->green_mask));
+ printf(" blue_mask 0x%x\n", (int)(x_visinfo->blue_mask));
+ printf(" colormap_size %d\n", x_visinfo->colormap_size);
+ printf(" bits_per_rgb %d\n", x_visinfo->bits_per_rgb);
+ }
+#endif
+
+ x_vis = x_visinfo->visual;
+
+// setup attributes for main window
+ {
+ int attribmask = CWEventMask | CWColormap | CWBorderPixel;
+ XSetWindowAttributes attribs;
+ Colormap tmpcmap;
+
+ tmpcmap = XCreateColormap(x_disp, XRootWindow(x_disp,
+ x_visinfo->screen), x_vis, AllocNone);
+
+ attribs.event_mask = STD_EVENT_MASK;
+ attribs.border_pixel = 0;
+ attribs.colormap = tmpcmap;
+
+// create the main window
+ x_win = XCreateWindow( x_disp,
+ XRootWindow(x_disp, x_visinfo->screen),
+ 0, 0, // x, y
+ vid.width, vid.height,
+ 0, // borderwidth
+ x_visinfo->depth,
+ InputOutput,
+ x_vis,
+ attribmask,
+ &attribs );
+ XStoreName(x_disp, x_win, "Quake II");
+
+ if (x_visinfo->class != TrueColor)
+ XFreeColormap(x_disp, tmpcmap);
+ }
+
+ if (x_visinfo->depth == 8)
+ {
+ // create and upload the palette
+ if (x_visinfo->class == PseudoColor)
+ {
+ x_cmap = XCreateColormap(x_disp, x_win, x_vis, AllocAll);
+ XSetWindowColormap(x_disp, x_win, x_cmap);
+ }
+
+ }
+
+// inviso cursor
+ XDefineCursor(x_disp, x_win, CreateNullCursor(x_disp, x_win));
+
+// create the GC
+ {
+ XGCValues xgcvalues;
+ int valuemask = GCGraphicsExposures;
+ xgcvalues.graphics_exposures = False;
+ x_gc = XCreateGC(x_disp, x_win, valuemask, &xgcvalues );
+ }
+
+// map the window
+ XMapWindow(x_disp, x_win);
+
+// wait for first exposure event
+ {
+ XEvent event;
+ do
+ {
+ XNextEvent(x_disp, &event);
+ if (event.type == Expose && !event.xexpose.count)
+ oktodraw = true;
+ } while (!oktodraw);
+ }
+// now safe to draw
+
+// even if MITSHM is available, make sure it's a local connection
+ if (XShmQueryExtension(x_disp))
+ {
+ char *displayname;
+ doShm = true;
+ displayname = (char *) getenv("DISPLAY");
+ if (displayname)
+ {
+ char *d = displayname;
+ while (*d && (*d != ':')) d++;
+ if (*d) *d = 0;
+ if (!(!strcasecmp(displayname, "unix") || !*displayname))
+ doShm = false;
+ }
+ }
+
+ if (doShm)
+ {
+ x_shmeventtype = XShmGetEventBase(x_disp) + ShmCompletion;
+ ResetSharedFrameBuffers();
+ }
+ else
+ ResetFrameBuffer();
+
+ current_framebuffer = 0;
+ vid.rowbytes = x_framebuffer[0]->bytes_per_line;
+ vid.buffer = x_framebuffer[0]->data;
+
+// XSynchronize(x_disp, False);
+
+ X11_active = true;
+
+ return true;
+}
+
+/*
+** SWimp_EndFrame
+**
+** This does an implementation specific copy from the backbuffer to the
+** front buffer. In the Win32 case it uses BitBlt or BltFast depending
+** on whether we're using DIB sections/GDI or DDRAW.
+*/
+void SWimp_EndFrame (void)
+{
+// if the window changes dimension, skip this frame
+#if 0
+ if (config_notify)
+ {
+ fprintf(stderr, "config notify\n");
+ config_notify = 0;
+ vid.width = config_notify_width & ~7;
+ vid.height = config_notify_height;
+ if (doShm)
+ ResetSharedFrameBuffers();
+ else
+ ResetFrameBuffer();
+ vid.rowbytes = x_framebuffer[0]->bytes_per_line;
+ vid.buffer = x_framebuffer[current_framebuffer]->data;
+ vid.recalc_refdef = 1; // force a surface cache flush
+ Con_CheckResize();
+ Con_Clear_f();
+ return;
+ }
+#endif
+
+ if (doShm)
+ {
+
+ if (x_visinfo->depth != 8)
+ st2_fixup( x_framebuffer[current_framebuffer],
+ 0, 0, vid.width, vid.height);
+ if (!XShmPutImage(x_disp, x_win, x_gc,
+ x_framebuffer[current_framebuffer], 0, 0,
+ 0, 0, vid.width, vid.height, True))
+ Sys_Error("VID_Update: XShmPutImage failed\n");
+ oktodraw = false;
+ while (!oktodraw)
+ GetEvent();
+ current_framebuffer = !current_framebuffer;
+ vid.buffer = x_framebuffer[current_framebuffer]->data;
+ XSync(x_disp, False);
+ }
+ else
+ {
+ if (x_visinfo->depth != 8)
+ st2_fixup( x_framebuffer[current_framebuffer],
+ 0, 0, vid.width, vid.height);
+ XPutImage(x_disp, x_win, x_gc, x_framebuffer[0],
+ 0, 0, 0, 0, vid.width, vid.height);
+ XSync(x_disp, False);
+ }
+}
+
+/*
+** SWimp_SetMode
+*/
+rserr_t SWimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen )
+{
+ rserr_t retval = rserr_ok;
+
+ ri.Con_Printf (PRINT_ALL, "setting mode %d:", mode );
+
+ if ( !ri.Vid_GetModeInfo( pwidth, pheight, mode ) )
+ {
+ ri.Con_Printf( PRINT_ALL, " invalid mode\n" );
+ return rserr_invalid_mode;
+ }
+
+ ri.Con_Printf( PRINT_ALL, " %d %d\n", *pwidth, *pheight);
+
+ if ( !SWimp_InitGraphics( false ) ) {
+ // failed to set a valid mode in windowed mode
+ return rserr_invalid_mode;
+ }
+
+ R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
+
+ return retval;
+}
+
+/*
+** SWimp_SetPalette
+**
+** System specific palette setting routine. A NULL palette means
+** to use the existing palette. The palette is expected to be in
+** a padded 4-byte xRGB format.
+*/
+void SWimp_SetPalette( const unsigned char *palette )
+{
+ int i;
+ XColor colors[256];
+
+ if (!X11_active)
+ return;
+
+ if ( !palette )
+ palette = ( const unsigned char * ) sw_state.currentpalette;
+
+ for(i=0;i<256;i++)
+ st2d_8to16table[i]= xlib_rgb(palette[i*4],
+ palette[i*4+1],palette[i*4+2]);
+
+ if (x_visinfo->class == PseudoColor && x_visinfo->depth == 8)
+ {
+ for (i=0 ; i<256 ; i++)
+ {
+ colors[i].pixel = i;
+ colors[i].flags = DoRed|DoGreen|DoBlue;
+ colors[i].red = palette[i*4] * 257;
+ colors[i].green = palette[i*4+1] * 257;
+ colors[i].blue = palette[i*4+2] * 257;
+ }
+ XStoreColors(x_disp, x_cmap, colors, 256);
+ }
+}
+
+/*
+** SWimp_Shutdown
+**
+** System specific graphics subsystem shutdown routine. Destroys
+** DIBs or DDRAW surfaces as appropriate.
+*/
+void SWimp_Shutdown( void )
+{
+ int i;
+
+ if (!X11_active)
+ return;
+
+ if (doShm) {
+ for (i = 0; i < 2; i++)
+ if (x_framebuffer[i]) {
+ XShmDetach(x_disp, &x_shminfo[i]);
+ free(x_framebuffer[i]);
+ shmdt(x_shminfo[i].shmaddr);
+ x_framebuffer[i] = NULL;
+ }
+ } else if (x_framebuffer[0]) {
+ free(x_framebuffer[0]->data);
+ free(x_framebuffer[0]);
+ x_framebuffer[0] = NULL;
+ }
+
+ XDestroyWindow( x_disp, x_win );
+
+ XAutoRepeatOn(x_disp);
+// XCloseDisplay(x_disp);
+
+ X11_active = false;
+}
+
+/*
+** SWimp_AppActivate
+*/
+void SWimp_AppActivate( qboolean active )
+{
+}
+
+//===============================================================================
+
+/*
+================
+Sys_MakeCodeWriteable
+================
+*/
+void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
+{
+
+ int r;
+ unsigned long addr;
+ int psize = getpagesize();
+
+ addr = (startaddr & ~(psize-1)) - psize;
+
+// fprintf(stderr, "writable code %lx(%lx)-%lx, length=%lx\n", startaddr,
+// addr, startaddr+length, length);
+
+ r = mprotect((char*)addr, length + startaddr - addr + psize, 7);
+
+ if (r < 0)
+ Sys_Error("Protection change failed\n");
+
+}
+
+/*****************************************************************************/
+/* KEYBOARD */
+/*****************************************************************************/
+
+Key_Event_fp_t Key_Event_fp;
+
+void KBD_Init(Key_Event_fp_t fp)
+{
+ Key_Event_fp = fp;
+}
+
+void KBD_Update(void)
+{
+// get events from x server
+ if (x_disp)
+ {
+ while (XPending(x_disp))
+ GetEvent();
+ while (keyq_head != keyq_tail)
+ {
+ Key_Event_fp(keyq[keyq_tail].key, keyq[keyq_tail].down);
+ keyq_tail = (keyq_tail + 1) & 63;
+ }
+ }
+}
+
+void KBD_Close(void)
+{
+}
+
+
--- /dev/null
+++ b/plan9/snd_linux.c
@@ -1,0 +1,266 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/shm.h>
+#include <sys/wait.h>
+#include <linux/soundcard.h>
+#include <stdio.h>
+
+#include "../client/client.h"
+#include "../client/snd_loc.h"
+
+int audio_fd;
+int snd_inited;
+
+cvar_t *sndbits;
+cvar_t *sndspeed;
+cvar_t *sndchannels;
+cvar_t *snddevice;
+
+static int tryrates[] = { 11025, 22051, 44100, 8000 };
+
+qboolean SNDDMA_Init(void)
+{
+
+ int rc;
+ int fmt;
+ int tmp;
+ int i;
+ char *s;
+ struct audio_buf_info info;
+ int caps;
+ extern uid_t saved_euid;
+
+ if (snd_inited)
+ return;
+
+ if (!snddevice) {
+ sndbits = Cvar_Get("sndbits", "16", CVAR_ARCHIVE);
+ sndspeed = Cvar_Get("sndspeed", "0", CVAR_ARCHIVE);
+ sndchannels = Cvar_Get("sndchannels", "2", CVAR_ARCHIVE);
+ snddevice = Cvar_Get("snddevice", "/dev/dsp", CVAR_ARCHIVE);
+ }
+
+// open /dev/dsp, confirm capability to mmap, and get size of dma buffer
+
+ if (!audio_fd) {
+ seteuid(saved_euid);
+
+ audio_fd = open(snddevice->string, O_RDWR);
+
+ seteuid(getuid());
+
+ if (audio_fd < 0)
+ {
+ perror(snddevice->string);
+ Com_Printf("Could not open %s\n", snddevice->string);
+ return 0;
+ }
+ }
+
+ rc = ioctl(audio_fd, SNDCTL_DSP_RESET, 0);
+ if (rc < 0)
+ {
+ perror(snddevice->string);
+ Com_Printf("Could not reset %s\n", snddevice->string);
+ close(audio_fd);
+ return 0;
+ }
+
+ if (ioctl(audio_fd, SNDCTL_DSP_GETCAPS, &caps)==-1)
+ {
+ perror(snddevice->string);
+ Com_Printf("Sound driver too old\n");
+ close(audio_fd);
+ return 0;
+ }
+
+ if (!(caps & DSP_CAP_TRIGGER) || !(caps & DSP_CAP_MMAP))
+ {
+ Com_Printf("Sorry but your soundcard can't do this\n");
+ close(audio_fd);
+ return 0;
+ }
+
+ if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info)==-1)
+ {
+ perror("GETOSPACE");
+ Com_Printf("Um, can't do GETOSPACE?\n");
+ close(audio_fd);
+ return 0;
+ }
+
+// set sample bits & speed
+
+ dma.samplebits = (int)sndbits->value;
+ if (dma.samplebits != 16 && dma.samplebits != 8)
+ {
+ ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &fmt);
+ if (fmt & AFMT_S16_LE) dma.samplebits = 16;
+ else if (fmt & AFMT_U8) dma.samplebits = 8;
+ }
+
+ dma.speed = (int)sndspeed->value;
+ if (!dma.speed) {
+ for (i=0 ; i<sizeof(tryrates)/4 ; i++)
+ if (!ioctl(audio_fd, SNDCTL_DSP_SPEED, &tryrates[i])) break;
+ dma.speed = tryrates[i];
+ }
+
+ dma.channels = (int)sndchannels->value;
+ if (dma.channels < 1 || dma.channels > 2)
+ dma.channels = 2;
+
+ dma.samples = info.fragstotal * info.fragsize / (dma.samplebits/8);
+ dma.submission_chunk = 1;
+
+// memory map the dma buffer
+
+ if (!dma.buffer)
+ dma.buffer = (unsigned char *) mmap(NULL, info.fragstotal
+ * info.fragsize, PROT_WRITE, MAP_FILE|MAP_SHARED, audio_fd, 0);
+ if (!dma.buffer)
+ {
+ perror(snddevice->string);
+ Com_Printf("Could not mmap %s\n", snddevice->string);
+ close(audio_fd);
+ return 0;
+ }
+
+ tmp = 0;
+ if (dma.channels == 2)
+ tmp = 1;
+ rc = ioctl(audio_fd, SNDCTL_DSP_STEREO, &tmp);
+ if (rc < 0)
+ {
+ perror(snddevice->string);
+ Com_Printf("Could not set %s to stereo=%d", snddevice->string, dma.channels);
+ close(audio_fd);
+ return 0;
+ }
+ if (tmp)
+ dma.channels = 2;
+ else
+ dma.channels = 1;
+
+ rc = ioctl(audio_fd, SNDCTL_DSP_SPEED, &dma.speed);
+ if (rc < 0)
+ {
+ perror(snddevice->string);
+ Com_Printf("Could not set %s speed to %d", snddevice->string, dma.speed);
+ close(audio_fd);
+ return 0;
+ }
+
+ if (dma.samplebits == 16)
+ {
+ rc = AFMT_S16_LE;
+ rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc);
+ if (rc < 0)
+ {
+ perror(snddevice->string);
+ Com_Printf("Could not support 16-bit data. Try 8-bit.\n");
+ close(audio_fd);
+ return 0;
+ }
+ }
+ else if (dma.samplebits == 8)
+ {
+ rc = AFMT_U8;
+ rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc);
+ if (rc < 0)
+ {
+ perror(snddevice->string);
+ Com_Printf("Could not support 8-bit data.\n");
+ close(audio_fd);
+ return 0;
+ }
+ }
+ else
+ {
+ perror(snddevice->string);
+ Com_Printf("%d-bit sound not supported.", dma.samplebits);
+ close(audio_fd);
+ return 0;
+ }
+
+// toggle the trigger & start her up
+
+ tmp = 0;
+ rc = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp);
+ if (rc < 0)
+ {
+ perror(snddevice->string);
+ Com_Printf("Could not toggle.\n");
+ close(audio_fd);
+ return 0;
+ }
+ tmp = PCM_ENABLE_OUTPUT;
+ rc = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp);
+ if (rc < 0)
+ {
+ perror(snddevice->string);
+ Com_Printf("Could not toggle.\n");
+ close(audio_fd);
+ return 0;
+ }
+
+ dma.samplepos = 0;
+
+ snd_inited = 1;
+ return 1;
+
+}
+
+int SNDDMA_GetDMAPos(void)
+{
+
+ struct count_info count;
+
+ if (!snd_inited) return 0;
+
+ if (ioctl(audio_fd, SNDCTL_DSP_GETOPTR, &count)==-1)
+ {
+ perror(snddevice->string);
+ Com_Printf("Uh, sound dead.\n");
+ close(audio_fd);
+ snd_inited = 0;
+ return 0;
+ }
+// dma.samplepos = (count.bytes / (dma.samplebits / 8)) & (dma.samples-1);
+// fprintf(stderr, "%d \r", count.ptr);
+ dma.samplepos = count.ptr / (dma.samplebits / 8);
+
+ return dma.samplepos;
+
+}
+
+void SNDDMA_Shutdown(void)
+{
+#if 0
+ if (snd_inited)
+ {
+ close(audio_fd);
+ snd_inited = 0;
+ }
+#endif
+}
+
+/*
+==============
+SNDDMA_Submit
+
+Send sound to device if buffer isn't really the dma buffer
+===============
+*/
+void SNDDMA_Submit(void)
+{
+}
+
+void SNDDMA_BeginPainting (void)
+{
+}
+
--- /dev/null
+++ b/plan9/sys_linux.c
@@ -1,0 +1,381 @@
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <mntent.h>
+
+#include <dlfcn.h>
+
+#include "../qcommon/qcommon.h"
+
+#include "../linux/rw_linux.h"
+
+cvar_t *nostdout;
+
+unsigned sys_frame_time;
+
+uid_t saved_euid;
+qboolean stdin_active = true;
+
+// =======================================================================
+// General routines
+// =======================================================================
+
+void Sys_ConsoleOutput (char *string)
+{
+ if (nostdout && nostdout->value)
+ return;
+
+ fputs(string, stdout);
+}
+
+void Sys_Printf (char *fmt, ...)
+{
+ va_list argptr;
+ char text[1024];
+ unsigned char *p;
+
+ va_start (argptr,fmt);
+ vsprintf (text,fmt,argptr);
+ va_end (argptr);
+
+ if (strlen(text) > sizeof(text))
+ Sys_Error("memory overwrite in Sys_Printf");
+
+ if (nostdout && nostdout->value)
+ return;
+
+ for (p = (unsigned char *)text; *p; p++) {
+ *p &= 0x7f;
+ if ((*p > 128 || *p < 32) && *p != 10 && *p != 13 && *p != 9)
+ printf("[%02x]", *p);
+ else
+ putc(*p, stdout);
+ }
+}
+
+void Sys_Quit (void)
+{
+ CL_Shutdown ();
+ Qcommon_Shutdown ();
+ fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
+ _exit(0);
+}
+
+void Sys_Init(void)
+{
+#if id386
+// Sys_SetFPCW();
+#endif
+}
+
+void Sys_Error (char *error, ...)
+{
+ va_list argptr;
+ char string[1024];
+
+// change stdin to non blocking
+ fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
+
+ CL_Shutdown ();
+ Qcommon_Shutdown ();
+
+ va_start (argptr,error);
+ vsprintf (string,error,argptr);
+ va_end (argptr);
+ fprintf(stderr, "Error: %s\n", string);
+
+ _exit (1);
+
+}
+
+void Sys_Warn (char *warning, ...)
+{
+ va_list argptr;
+ char string[1024];
+
+ va_start (argptr,warning);
+ vsprintf (string,warning,argptr);
+ va_end (argptr);
+ fprintf(stderr, "Warning: %s", string);
+}
+
+/*
+============
+Sys_FileTime
+
+returns -1 if not present
+============
+*/
+int Sys_FileTime (char *path)
+{
+ struct stat buf;
+
+ if (stat (path,&buf) == -1)
+ return -1;
+
+ return buf.st_mtime;
+}
+
+void floating_point_exception_handler(int whatever)
+{
+// Sys_Warn("floating point exception\n");
+ signal(SIGFPE, floating_point_exception_handler);
+}
+
+char *Sys_ConsoleInput(void)
+{
+ static char text[256];
+ int len;
+ fd_set fdset;
+ struct timeval timeout;
+
+ if (!dedicated || !dedicated->value)
+ return NULL;
+
+ if (!stdin_active)
+ return NULL;
+
+ FD_ZERO(&fdset);
+ FD_SET(0, &fdset); // stdin
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ if (select (1, &fdset, NULL, NULL, &timeout) == -1 || !FD_ISSET(0, &fdset))
+ return NULL;
+
+ len = read (0, text, sizeof(text));
+ if (len == 0) { // eof!
+ stdin_active = false;
+ return NULL;
+ }
+
+ if (len < 1)
+ return NULL;
+ text[len-1] = 0; // rip off the /n and terminate
+
+ return text;
+}
+
+/*****************************************************************************/
+
+static void *game_library;
+
+/*
+=================
+Sys_UnloadGame
+=================
+*/
+void Sys_UnloadGame (void)
+{
+ if (game_library)
+ dlclose (game_library);
+ game_library = NULL;
+}
+
+/*
+=================
+Sys_GetGameAPI
+
+Loads the game dll
+=================
+*/
+void *Sys_GetGameAPI (void *parms)
+{
+ void *(*GetGameAPI) (void *);
+
+ char name[MAX_OSPATH];
+ char curpath[MAX_OSPATH];
+ char *path;
+#ifdef __i386__
+ const char *gamename = "gamei386.so";
+#elif defined __alpha__
+ const char *gamename = "gameaxp.so";
+#else
+#error Unknown arch
+#endif
+
+ setreuid(getuid(), getuid());
+ setegid(getgid());
+
+ if (game_library)
+ Com_Error (ERR_FATAL, "Sys_GetGameAPI without Sys_UnloadingGame");
+
+ getcwd(curpath, sizeof(curpath));
+
+ Com_Printf("------- Loading %s -------", gamename);
+
+ // now run through the search paths
+ path = NULL;
+ while (1)
+ {
+ path = FS_NextPath (path);
+ if (!path)
+ return NULL; // couldn't find one anywhere
+ sprintf (name, "%s/%s/%s", curpath, path, gamename);
+ game_library = dlopen (name, RTLD_NOW );
+ if (game_library)
+ {
+ Com_DPrintf ("LoadLibrary (%s)\n",name);
+ break;
+ }
+ else
+ printf("dlerror: %s\n", dlerror());
+ }
+
+ GetGameAPI = (void *)dlsym (game_library, "GetGameAPI");
+ if (!GetGameAPI)
+ {
+ Sys_UnloadGame ();
+ return NULL;
+ }
+
+ return GetGameAPI (parms);
+}
+
+/*****************************************************************************/
+
+void Sys_AppActivate (void)
+{
+}
+
+void Sys_SendKeyEvents (void)
+{
+#ifndef DEDICATED_ONLY
+ if (KBD_Update_fp)
+ KBD_Update_fp();
+#endif
+
+ // grab frame time
+ sys_frame_time = Sys_Milliseconds();
+}
+
+/*****************************************************************************/
+
+char *Sys_GetClipboardData(void)
+{
+ return NULL;
+}
+
+int main (int argc, char **argv)
+{
+ int time, oldtime, newtime;
+
+ // go back to real user for config loads
+ saved_euid = geteuid();
+ seteuid(getuid());
+
+ Qcommon_Init(argc, argv);
+
+ fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
+
+ nostdout = Cvar_Get("nostdout", "0", 0);
+ if (!nostdout->value) {
+ fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
+// printf ("Linux Quake -- Version %0.3f\n", LINUX_VERSION);
+ }
+
+ oldtime = Sys_Milliseconds ();
+ while (1)
+ {
+// find time spent rendering last frame
+ do {
+ newtime = Sys_Milliseconds ();
+ time = newtime - oldtime;
+ } while (time < 1);
+ Qcommon_Frame (time);
+ oldtime = newtime;
+ }
+
+}
+
+void Sys_CopyProtect(void)
+{
+ FILE *mnt;
+ struct mntent *ent;
+ char path[MAX_OSPATH];
+ struct stat st;
+ qboolean found_cd = false;
+
+ static qboolean checked = false;
+
+ if (checked)
+ return;
+
+ if ((mnt = setmntent("/etc/mtab", "r")) == NULL)
+ Com_Error(ERR_FATAL, "Can't read mount table to determine mounted cd location.");
+
+ while ((ent = getmntent(mnt)) != NULL) {
+ if (strcmp(ent->mnt_type, "iso9660") == 0) {
+ // found a cd file system
+ found_cd = true;
+ sprintf(path, "%s/%s", ent->mnt_dir, "install/data/quake2.exe");
+ if (stat(path, &st) == 0) {
+ // found it
+ checked = true;
+ endmntent(mnt);
+ return;
+ }
+ sprintf(path, "%s/%s", ent->mnt_dir, "Install/Data/quake2.exe");
+ if (stat(path, &st) == 0) {
+ // found it
+ checked = true;
+ endmntent(mnt);
+ return;
+ }
+ sprintf(path, "%s/%s", ent->mnt_dir, "quake2.exe");
+ if (stat(path, &st) == 0) {
+ // found it
+ checked = true;
+ endmntent(mnt);
+ return;
+ }
+ }
+ }
+ endmntent(mnt);
+
+ if (found_cd)
+ Com_Error (ERR_FATAL, "Could not find a Quake2 CD in your CD drive.");
+ Com_Error (ERR_FATAL, "Unable to find a mounted iso9660 file system.\n"
+ "You must mount the Quake2 CD in a cdrom drive in order to play.");
+}
+
+#if 0
+/*
+================
+Sys_MakeCodeWriteable
+================
+*/
+void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
+{
+
+ int r;
+ unsigned long addr;
+ int psize = getpagesize();
+
+ addr = (startaddr & ~(psize-1)) - psize;
+
+// fprintf(stderr, "writable code %lx(%lx)-%lx, length=%lx\n", startaddr,
+// addr, startaddr+length, length);
+
+ r = mprotect((char*)addr, length + startaddr - addr + psize, 7);
+
+ if (r < 0)
+ Sys_Error("Protection change failed\n");
+
+}
+
+#endif
--- /dev/null
+++ b/plan9/vid_menu.c
@@ -1,0 +1,437 @@
+#include "../client/client.h"
+#include "../client/qmenu.h"
+
+#define REF_SOFT 0
+#define REF_SOFTX11 1
+#define REF_OPENGL 2
+
+extern cvar_t *vid_ref;
+extern cvar_t *vid_fullscreen;
+extern cvar_t *vid_gamma;
+extern cvar_t *scr_viewsize;
+
+static cvar_t *gl_mode;
+static cvar_t *gl_driver;
+static cvar_t *gl_picmip;
+static cvar_t *gl_ext_palettedtexture;
+
+static cvar_t *sw_mode;
+static cvar_t *sw_stipplealpha;
+
+static cvar_t *_windowed_mouse;
+
+extern void M_ForceMenuOff( void );
+
+/*
+====================================================================
+
+MENU INTERACTION
+
+====================================================================
+*/
+#define SOFTWARE_MENU 0
+#define OPENGL_MENU 1
+
+static menuframework_s s_software_menu;
+static menuframework_s s_opengl_menu;
+static menuframework_s *s_current_menu;
+static int s_current_menu_index;
+
+static menulist_s s_mode_list[2];
+static menulist_s s_ref_list[2];
+static menuslider_s s_tq_slider;
+static menuslider_s s_screensize_slider[2];
+static menuslider_s s_brightness_slider[2];
+static menulist_s s_fs_box[2];
+static menulist_s s_stipple_box;
+static menulist_s s_paletted_texture_box;
+static menulist_s s_windowed_mouse;
+static menuaction_s s_apply_action[2];
+static menuaction_s s_defaults_action[2];
+
+static void DriverCallback( void *unused )
+{
+ s_ref_list[!s_current_menu_index].curvalue = s_ref_list[s_current_menu_index].curvalue;
+
+ if ( s_ref_list[s_current_menu_index].curvalue < 2 )
+ {
+ s_current_menu = &s_software_menu;
+ s_current_menu_index = 0;
+ }
+ else
+ {
+ s_current_menu = &s_opengl_menu;
+ s_current_menu_index = 1;
+ }
+
+}
+
+static void ScreenSizeCallback( void *s )
+{
+ menuslider_s *slider = ( menuslider_s * ) s;
+
+ Cvar_SetValue( "viewsize", slider->curvalue * 10 );
+}
+
+static void BrightnessCallback( void *s )
+{
+ menuslider_s *slider = ( menuslider_s * ) s;
+
+ if ( s_current_menu_index == 0)
+ s_brightness_slider[1].curvalue = s_brightness_slider[0].curvalue;
+ else
+ s_brightness_slider[0].curvalue = s_brightness_slider[1].curvalue;
+
+ if ( stricmp( vid_ref->string, "soft" ) == 0 ||
+ stricmp( vid_ref->string, "softx" ) == 0 )
+ {
+ float gamma = ( 0.8 - ( slider->curvalue/10.0 - 0.5 ) ) + 0.5;
+
+ Cvar_SetValue( "vid_gamma", gamma );
+ }
+}
+
+static void ResetDefaults( void *unused )
+{
+ VID_MenuInit();
+}
+
+static void ApplyChanges( void *unused )
+{
+ float gamma;
+
+ /*
+ ** make values consistent
+ */
+ s_fs_box[!s_current_menu_index].curvalue = s_fs_box[s_current_menu_index].curvalue;
+ s_brightness_slider[!s_current_menu_index].curvalue = s_brightness_slider[s_current_menu_index].curvalue;
+ s_ref_list[!s_current_menu_index].curvalue = s_ref_list[s_current_menu_index].curvalue;
+
+ /*
+ ** invert sense so greater = brighter, and scale to a range of 0.5 to 1.3
+ */
+ gamma = ( 0.8 - ( s_brightness_slider[s_current_menu_index].curvalue/10.0 - 0.5 ) ) + 0.5;
+
+ Cvar_SetValue( "vid_gamma", gamma );
+ Cvar_SetValue( "sw_stipplealpha", s_stipple_box.curvalue );
+ Cvar_SetValue( "gl_picmip", 3 - s_tq_slider.curvalue );
+ Cvar_SetValue( "vid_fullscreen", s_fs_box[s_current_menu_index].curvalue );
+ Cvar_SetValue( "gl_ext_palettedtexture", s_paletted_texture_box.curvalue );
+ Cvar_SetValue( "sw_mode", s_mode_list[SOFTWARE_MENU].curvalue );
+ Cvar_SetValue( "gl_mode", s_mode_list[OPENGL_MENU].curvalue );
+ Cvar_SetValue( "_windowed_mouse", s_windowed_mouse.curvalue);
+
+ switch ( s_ref_list[s_current_menu_index].curvalue )
+ {
+ case REF_SOFT:
+ Cvar_Set( "vid_ref", "soft" );
+ break;
+ case REF_SOFTX11:
+ Cvar_Set( "vid_ref", "softx" );
+ break;
+ case REF_OPENGL:
+ Cvar_Set( "vid_ref", "gl" );
+ Cvar_Set( "gl_driver", "opengl32" );
+ break;
+ }
+
+#if 0
+ /*
+ ** update appropriate stuff if we're running OpenGL and gamma
+ ** has been modified
+ */
+ if ( stricmp( vid_ref->string, "gl" ) == 0 )
+ {
+ if ( vid_gamma->modified )
+ {
+ vid_ref->modified = true;
+ if ( stricmp( gl_driver->string, "3dfxgl" ) == 0 )
+ {
+ char envbuffer[1024];
+ float g;
+
+ vid_ref->modified = true;
+
+ g = 2.00 * ( 0.8 - ( vid_gamma->value - 0.5 ) ) + 1.0F;
+ Com_sprintf( envbuffer, sizeof(envbuffer), "SST_GAMMA=%f", g );
+ putenv( envbuffer );
+
+ vid_gamma->modified = false;
+ }
+ }
+ }
+#endif
+
+ M_ForceMenuOff();
+}
+
+/*
+** VID_MenuInit
+*/
+void VID_MenuInit( void )
+{
+ static const char *resolutions[] =
+ {
+ "[320 240 ]",
+ "[400 300 ]",
+ "[512 384 ]",
+ "[640 480 ]",
+ "[800 600 ]",
+ "[960 720 ]",
+ "[1024 768 ]",
+ "[1152 864 ]",
+ "[1280 1024]",
+ "[1600 1200]",
+ 0
+ };
+ static const char *refs[] =
+ {
+ "[software ]",
+ "[software X11 ]",
+ "[default OpenGL]",
+ 0
+ };
+ static const char *yesno_names[] =
+ {
+ "no",
+ "yes",
+ 0
+ };
+ int i;
+
+ if ( !gl_driver )
+ gl_driver = Cvar_Get( "gl_driver", "opengl32", 0 );
+ if ( !gl_picmip )
+ gl_picmip = Cvar_Get( "gl_picmip", "0", 0 );
+ if ( !gl_mode )
+ gl_mode = Cvar_Get( "gl_mode", "3", 0 );
+ if ( !sw_mode )
+ sw_mode = Cvar_Get( "sw_mode", "0", 0 );
+ if ( !gl_ext_palettedtexture )
+ gl_ext_palettedtexture = Cvar_Get( "gl_ext_palettedtexture", "1", CVAR_ARCHIVE );
+
+ if ( !sw_stipplealpha )
+ sw_stipplealpha = Cvar_Get( "sw_stipplealpha", "0", CVAR_ARCHIVE );
+
+ if ( !_windowed_mouse)
+ _windowed_mouse = Cvar_Get( "_windowed_mouse", "0", CVAR_ARCHIVE );
+
+ s_mode_list[SOFTWARE_MENU].curvalue = sw_mode->value;
+ s_mode_list[OPENGL_MENU].curvalue = gl_mode->value;
+
+ if ( !scr_viewsize )
+ scr_viewsize = Cvar_Get ("viewsize", "100", CVAR_ARCHIVE);
+
+ s_screensize_slider[SOFTWARE_MENU].curvalue = scr_viewsize->value/10;
+ s_screensize_slider[OPENGL_MENU].curvalue = scr_viewsize->value/10;
+
+ if ( strcmp( vid_ref->string, "soft" ) == 0)
+ {
+ s_current_menu_index = SOFTWARE_MENU;
+ s_ref_list[0].curvalue = s_ref_list[1].curvalue = REF_SOFT;
+ }
+ else if (strcmp( vid_ref->string, "softx" ) == 0 )
+ {
+ s_current_menu_index = SOFTWARE_MENU;
+ s_ref_list[0].curvalue = s_ref_list[1].curvalue = REF_SOFTX11;
+ }
+ else if ( strcmp( vid_ref->string, "gl" ) == 0 )
+ {
+ s_current_menu_index = OPENGL_MENU;
+ s_ref_list[s_current_menu_index].curvalue = REF_OPENGL;
+#if 0
+ if ( strcmp( gl_driver->string, "3dfxgl" ) == 0 )
+ s_ref_list[s_current_menu_index].curvalue = REF_3DFX;
+ else if ( strcmp( gl_driver->string, "pvrgl" ) == 0 )
+ s_ref_list[s_current_menu_index].curvalue = REF_POWERVR;
+ else if ( strcmp( gl_driver->string, "opengl32" ) == 0 )
+ s_ref_list[s_current_menu_index].curvalue = REF_OPENGL;
+ else
+ s_ref_list[s_current_menu_index].curvalue = REF_VERITE;
+#endif
+ }
+
+ s_software_menu.x = viddef.width * 0.50;
+ s_software_menu.nitems = 0;
+ s_opengl_menu.x = viddef.width * 0.50;
+ s_opengl_menu.nitems = 0;
+
+ for ( i = 0; i < 2; i++ )
+ {
+ s_ref_list[i].generic.type = MTYPE_SPINCONTROL;
+ s_ref_list[i].generic.name = "driver";
+ s_ref_list[i].generic.x = 0;
+ s_ref_list[i].generic.y = 0;
+ s_ref_list[i].generic.callback = DriverCallback;
+ s_ref_list[i].itemnames = refs;
+
+ s_mode_list[i].generic.type = MTYPE_SPINCONTROL;
+ s_mode_list[i].generic.name = "video mode";
+ s_mode_list[i].generic.x = 0;
+ s_mode_list[i].generic.y = 10;
+ s_mode_list[i].itemnames = resolutions;
+
+ s_screensize_slider[i].generic.type = MTYPE_SLIDER;
+ s_screensize_slider[i].generic.x = 0;
+ s_screensize_slider[i].generic.y = 20;
+ s_screensize_slider[i].generic.name = "screen size";
+ s_screensize_slider[i].minvalue = 3;
+ s_screensize_slider[i].maxvalue = 12;
+ s_screensize_slider[i].generic.callback = ScreenSizeCallback;
+
+ s_brightness_slider[i].generic.type = MTYPE_SLIDER;
+ s_brightness_slider[i].generic.x = 0;
+ s_brightness_slider[i].generic.y = 30;
+ s_brightness_slider[i].generic.name = "brightness";
+ s_brightness_slider[i].generic.callback = BrightnessCallback;
+ s_brightness_slider[i].minvalue = 5;
+ s_brightness_slider[i].maxvalue = 13;
+ s_brightness_slider[i].curvalue = ( 1.3 - vid_gamma->value + 0.5 ) * 10;
+
+ s_fs_box[i].generic.type = MTYPE_SPINCONTROL;
+ s_fs_box[i].generic.x = 0;
+ s_fs_box[i].generic.y = 40;
+ s_fs_box[i].generic.name = "fullscreen";
+ s_fs_box[i].itemnames = yesno_names;
+ s_fs_box[i].curvalue = vid_fullscreen->value;
+
+ s_defaults_action[i].generic.type = MTYPE_ACTION;
+ s_defaults_action[i].generic.name = "reset to default";
+ s_defaults_action[i].generic.x = 0;
+ s_defaults_action[i].generic.y = 90;
+ s_defaults_action[i].generic.callback = ResetDefaults;
+
+ s_apply_action[i].generic.type = MTYPE_ACTION;
+ s_apply_action[i].generic.name = "apply";
+ s_apply_action[i].generic.x = 0;
+ s_apply_action[i].generic.y = 100;
+ s_apply_action[i].generic.callback = ApplyChanges;
+ }
+
+ s_stipple_box.generic.type = MTYPE_SPINCONTROL;
+ s_stipple_box.generic.x = 0;
+ s_stipple_box.generic.y = 60;
+ s_stipple_box.generic.name = "stipple alpha";
+ s_stipple_box.curvalue = sw_stipplealpha->value;
+ s_stipple_box.itemnames = yesno_names;
+
+ s_windowed_mouse.generic.type = MTYPE_SPINCONTROL;
+ s_windowed_mouse.generic.x = 0;
+ s_windowed_mouse.generic.y = 72;
+ s_windowed_mouse.generic.name = "windowed mouse";
+ s_windowed_mouse.curvalue = _windowed_mouse->value;
+ s_windowed_mouse.itemnames = yesno_names;
+
+ s_tq_slider.generic.type = MTYPE_SLIDER;
+ s_tq_slider.generic.x = 0;
+ s_tq_slider.generic.y = 60;
+ s_tq_slider.generic.name = "texture quality";
+ s_tq_slider.minvalue = 0;
+ s_tq_slider.maxvalue = 3;
+ s_tq_slider.curvalue = 3-gl_picmip->value;
+
+ s_paletted_texture_box.generic.type = MTYPE_SPINCONTROL;
+ s_paletted_texture_box.generic.x = 0;
+ s_paletted_texture_box.generic.y = 70;
+ s_paletted_texture_box.generic.name = "8-bit textures";
+ s_paletted_texture_box.itemnames = yesno_names;
+ s_paletted_texture_box.curvalue = gl_ext_palettedtexture->value;
+
+ Menu_AddItem( &s_software_menu, ( void * ) &s_ref_list[SOFTWARE_MENU] );
+ Menu_AddItem( &s_software_menu, ( void * ) &s_mode_list[SOFTWARE_MENU] );
+ Menu_AddItem( &s_software_menu, ( void * ) &s_screensize_slider[SOFTWARE_MENU] );
+ Menu_AddItem( &s_software_menu, ( void * ) &s_brightness_slider[SOFTWARE_MENU] );
+ Menu_AddItem( &s_software_menu, ( void * ) &s_fs_box[SOFTWARE_MENU] );
+ Menu_AddItem( &s_software_menu, ( void * ) &s_stipple_box );
+ Menu_AddItem( &s_software_menu, ( void * ) &s_windowed_mouse );
+
+ Menu_AddItem( &s_opengl_menu, ( void * ) &s_ref_list[OPENGL_MENU] );
+ Menu_AddItem( &s_opengl_menu, ( void * ) &s_mode_list[OPENGL_MENU] );
+ Menu_AddItem( &s_opengl_menu, ( void * ) &s_screensize_slider[OPENGL_MENU] );
+ Menu_AddItem( &s_opengl_menu, ( void * ) &s_brightness_slider[OPENGL_MENU] );
+ Menu_AddItem( &s_opengl_menu, ( void * ) &s_fs_box[OPENGL_MENU] );
+ Menu_AddItem( &s_opengl_menu, ( void * ) &s_tq_slider );
+ Menu_AddItem( &s_opengl_menu, ( void * ) &s_paletted_texture_box );
+
+ Menu_AddItem( &s_software_menu, ( void * ) &s_defaults_action[SOFTWARE_MENU] );
+ Menu_AddItem( &s_software_menu, ( void * ) &s_apply_action[SOFTWARE_MENU] );
+ Menu_AddItem( &s_opengl_menu, ( void * ) &s_defaults_action[OPENGL_MENU] );
+ Menu_AddItem( &s_opengl_menu, ( void * ) &s_apply_action[OPENGL_MENU] );
+
+ Menu_Center( &s_software_menu );
+ Menu_Center( &s_opengl_menu );
+ s_opengl_menu.x -= 8;
+ s_software_menu.x -= 8;
+}
+
+/*
+================
+VID_MenuDraw
+================
+*/
+void VID_MenuDraw (void)
+{
+ int w, h;
+
+ if ( s_current_menu_index == 0 )
+ s_current_menu = &s_software_menu;
+ else
+ s_current_menu = &s_opengl_menu;
+
+ /*
+ ** draw the banner
+ */
+ re.DrawGetPicSize( &w, &h, "m_banner_video" );
+ re.DrawPic( viddef.width / 2 - w / 2, viddef.height /2 - 110, "m_banner_video" );
+
+ /*
+ ** move cursor to a reasonable starting position
+ */
+ Menu_AdjustCursor( s_current_menu, 1 );
+
+ /*
+ ** draw the menu
+ */
+ Menu_Draw( s_current_menu );
+}
+
+/*
+================
+VID_MenuKey
+================
+*/
+const char *VID_MenuKey( int key )
+{
+ extern void M_PopMenu( void );
+
+ menuframework_s *m = s_current_menu;
+ static const char *sound = "misc/menu1.wav";
+
+ switch ( key )
+ {
+ case K_ESCAPE:
+ M_PopMenu();
+ return NULL;
+ case K_UPARROW:
+ m->cursor--;
+ Menu_AdjustCursor( m, -1 );
+ break;
+ case K_DOWNARROW:
+ m->cursor++;
+ Menu_AdjustCursor( m, 1 );
+ break;
+ case K_LEFTARROW:
+ Menu_SlideItem( m, -1 );
+ break;
+ case K_RIGHTARROW:
+ Menu_SlideItem( m, 1 );
+ break;
+ case K_ENTER:
+ Menu_SelectItem( m );
+ break;
+ }
+
+ return sound;
+}
+
+
--- /dev/null
+++ b/plan9/vid_so.c
@@ -1,0 +1,489 @@
+// Main windowed and fullscreen graphics interface module. This module
+// is used for both the software and OpenGL rendering versions of the
+// Quake refresh engine.
+
+#define SO_FILE "/etc/quake2.conf"
+
+#include <assert.h>
+#include <dlfcn.h> // ELF dl loader
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "../client/client.h"
+
+#include "../linux/rw_linux.h"
+
+// Structure containing functions exported from refresh DLL
+refexport_t re;
+
+// Console variables that we need to access from this module
+cvar_t *vid_gamma;
+cvar_t *vid_ref; // Name of Refresh DLL loaded
+cvar_t *vid_xpos; // X coordinate of window position
+cvar_t *vid_ypos; // Y coordinate of window position
+cvar_t *vid_fullscreen;
+
+// Global variables used internally by this module
+viddef_t viddef; // global video state; used by other modules
+void *reflib_library; // Handle to refresh DLL
+qboolean reflib_active = 0;
+
+#define VID_NUM_MODES ( sizeof( vid_modes ) / sizeof( vid_modes[0] ) )
+
+/** KEYBOARD **************************************************************/
+
+void Do_Key_Event(int key, qboolean down);
+
+void (*KBD_Update_fp)(void);
+void (*KBD_Init_fp)(Key_Event_fp_t fp);
+void (*KBD_Close_fp)(void);
+
+/** MOUSE *****************************************************************/
+
+in_state_t in_state;
+
+void (*RW_IN_Init_fp)(in_state_t *in_state_p);
+void (*RW_IN_Shutdown_fp)(void);
+void (*RW_IN_Activate_fp)(qboolean active);
+void (*RW_IN_Commands_fp)(void);
+void (*RW_IN_Move_fp)(usercmd_t *cmd);
+void (*RW_IN_Frame_fp)(void);
+
+void Real_IN_Init (void);
+
+/*
+==========================================================================
+
+DLL GLUE
+
+==========================================================================
+*/
+
+#define MAXPRINTMSG 4096
+void VID_Printf (int print_level, char *fmt, ...)
+{
+ va_list argptr;
+ char msg[MAXPRINTMSG];
+ static qboolean inupdate;
+
+ va_start (argptr,fmt);
+ vsprintf (msg,fmt,argptr);
+ va_end (argptr);
+
+ if (print_level == PRINT_ALL)
+ Com_Printf ("%s", msg);
+ else
+ Com_DPrintf ("%s", msg);
+}
+
+void VID_Error (int err_level, char *fmt, ...)
+{
+ va_list argptr;
+ char msg[MAXPRINTMSG];
+ static qboolean inupdate;
+
+ va_start (argptr,fmt);
+ vsprintf (msg,fmt,argptr);
+ va_end (argptr);
+
+ Com_Error (err_level,"%s", msg);
+}
+
+//==========================================================================
+
+/*
+============
+VID_Restart_f
+
+Console command to re-start the video mode and refresh DLL. We do this
+simply by setting the modified flag for the vid_ref variable, which will
+cause the entire video mode and refresh DLL to be reset on the next frame.
+============
+*/
+void VID_Restart_f (void)
+{
+ vid_ref->modified = true;
+}
+
+/*
+** VID_GetModeInfo
+*/
+typedef struct vidmode_s
+{
+ const char *description;
+ int width, height;
+ int mode;
+} vidmode_t;
+
+vidmode_t vid_modes[] =
+{
+ { "Mode 0: 320x240", 320, 240, 0 },
+ { "Mode 1: 400x300", 400, 300, 1 },
+ { "Mode 2: 512x384", 512, 384, 2 },
+ { "Mode 3: 640x480", 640, 480, 3 },
+ { "Mode 4: 800x600", 800, 600, 4 },
+ { "Mode 5: 960x720", 960, 720, 5 },
+ { "Mode 6: 1024x768", 1024, 768, 6 },
+ { "Mode 7: 1152x864", 1152, 864, 7 },
+ { "Mode 8: 1280x1024", 1280, 1024, 8 },
+ { "Mode 9: 1600x1200", 1600, 1200, 9 }
+};
+
+qboolean VID_GetModeInfo( int *width, int *height, int mode )
+{
+ if ( mode < 0 || mode >= VID_NUM_MODES )
+ return false;
+
+ *width = vid_modes[mode].width;
+ *height = vid_modes[mode].height;
+
+ return true;
+}
+
+/*
+** VID_NewWindow
+*/
+void VID_NewWindow ( int width, int height)
+{
+ viddef.width = width;
+ viddef.height = height;
+}
+
+void VID_FreeReflib (void)
+{
+ if (reflib_library) {
+ if (KBD_Close_fp)
+ KBD_Close_fp();
+ if (RW_IN_Shutdown_fp)
+ RW_IN_Shutdown_fp();
+ dlclose(reflib_library);
+ }
+
+ KBD_Init_fp = NULL;
+ KBD_Update_fp = NULL;
+ KBD_Close_fp = NULL;
+ RW_IN_Init_fp = NULL;
+ RW_IN_Shutdown_fp = NULL;
+ RW_IN_Activate_fp = NULL;
+ RW_IN_Commands_fp = NULL;
+ RW_IN_Move_fp = NULL;
+ RW_IN_Frame_fp = NULL;
+
+ memset (&re, 0, sizeof(re));
+ reflib_library = NULL;
+ reflib_active = false;
+}
+
+/*
+==============
+VID_LoadRefresh
+==============
+*/
+qboolean VID_LoadRefresh( char *name )
+{
+ refimport_t ri;
+ GetRefAPI_t GetRefAPI;
+ char fn[MAX_OSPATH];
+ struct stat st;
+ extern uid_t saved_euid;
+ FILE *fp;
+
+ if ( reflib_active )
+ {
+ if (KBD_Close_fp)
+ KBD_Close_fp();
+ if (RW_IN_Shutdown_fp)
+ RW_IN_Shutdown_fp();
+ KBD_Close_fp = NULL;
+ RW_IN_Shutdown_fp = NULL;
+ re.Shutdown();
+ VID_FreeReflib ();
+ }
+
+ Com_Printf( "------- Loading %s -------\n", name );
+
+ //regain root
+ seteuid(saved_euid);
+
+ if ((fp = fopen(SO_FILE, "r")) == NULL) {
+ Com_Printf( "LoadLibrary(\"%s\") failed: can't open " SO_FILE " (required for location of ref libraries)\n", name);
+ return false;
+ }
+ fgets(fn, sizeof(fn), fp);
+ fclose(fp);
+ if (*fn && fn[strlen(fn) - 1] == '\n')
+ fn[strlen(fn) - 1] = 0;
+
+ strcat(fn, "/");
+ strcat(fn, name);
+
+ // permission checking
+ if (strstr(fn, "softx") == NULL) { // softx doesn't require root
+ if (stat(fn, &st) == -1) {
+ Com_Printf( "LoadLibrary(\"%s\") failed: %s\n", name, strerror(errno));
+ return false;
+ }
+ if (st.st_uid != 0) {
+ Com_Printf( "LoadLibrary(\"%s\") failed: ref is not owned by root\n", name);
+ return false;
+ }
+#if 0
+ if ((st.st_mode & 0777) & ~0700) {
+ Com_Printf( "LoadLibrary(\"%s\") failed: invalid permissions, must be 700 for security considerations\n", name);
+ return false;
+ }
+#endif
+ } else {
+ // softx requires we give up root now
+ setreuid(getuid(), getuid());
+ setegid(getgid());
+ }
+
+ if ( ( reflib_library = dlopen( fn, RTLD_NOW ) ) == 0 )
+ {
+ Com_Printf( "LoadLibrary(\"%s\") failed: %s\n", name , dlerror());
+ return false;
+ }
+
+ ri.Cmd_AddCommand = Cmd_AddCommand;
+ ri.Cmd_RemoveCommand = Cmd_RemoveCommand;
+ ri.Cmd_Argc = Cmd_Argc;
+ ri.Cmd_Argv = Cmd_Argv;
+ ri.Cmd_ExecuteText = Cbuf_ExecuteText;
+ ri.Con_Printf = VID_Printf;
+ ri.Sys_Error = VID_Error;
+ ri.FS_LoadFile = FS_LoadFile;
+ ri.FS_FreeFile = FS_FreeFile;
+ ri.FS_Gamedir = FS_Gamedir;
+ ri.Cvar_Get = Cvar_Get;
+ ri.Cvar_Set = Cvar_Set;
+ ri.Cvar_SetValue = Cvar_SetValue;
+ ri.Vid_GetModeInfo = VID_GetModeInfo;
+ ri.Vid_MenuInit = VID_MenuInit;
+ ri.Vid_NewWindow = VID_NewWindow;
+
+ if ( ( GetRefAPI = (void *) dlsym( reflib_library, "GetRefAPI" ) ) == 0 )
+ Com_Error( ERR_FATAL, "dlsym failed on %s", name );
+
+ re = GetRefAPI( ri );
+
+ if (re.api_version != API_VERSION)
+ {
+ VID_FreeReflib ();
+ Com_Error (ERR_FATAL, "%s has incompatible api_version", name);
+ }
+
+ /* Init IN (Mouse) */
+ in_state.IN_CenterView_fp = IN_CenterView;
+ in_state.Key_Event_fp = Do_Key_Event;
+ in_state.viewangles = cl.viewangles;
+ in_state.in_strafe_state = &in_strafe.state;
+
+ if ((RW_IN_Init_fp = dlsym(reflib_library, "RW_IN_Init")) == NULL ||
+ (RW_IN_Shutdown_fp = dlsym(reflib_library, "RW_IN_Shutdown")) == NULL ||
+ (RW_IN_Activate_fp = dlsym(reflib_library, "RW_IN_Activate")) == NULL ||
+ (RW_IN_Commands_fp = dlsym(reflib_library, "RW_IN_Commands")) == NULL ||
+ (RW_IN_Move_fp = dlsym(reflib_library, "RW_IN_Move")) == NULL ||
+ (RW_IN_Frame_fp = dlsym(reflib_library, "RW_IN_Frame")) == NULL)
+ Sys_Error("No RW_IN functions in REF.\n");
+
+ Real_IN_Init();
+
+ if ( re.Init( 0, 0 ) == -1 )
+ {
+ re.Shutdown();
+ VID_FreeReflib ();
+ return false;
+ }
+
+ /* Init KBD */
+#if 1
+ if ((KBD_Init_fp = dlsym(reflib_library, "KBD_Init")) == NULL ||
+ (KBD_Update_fp = dlsym(reflib_library, "KBD_Update")) == NULL ||
+ (KBD_Close_fp = dlsym(reflib_library, "KBD_Close")) == NULL)
+ Sys_Error("No KBD functions in REF.\n");
+#else
+ {
+ void KBD_Init(void);
+ void KBD_Update(void);
+ void KBD_Close(void);
+
+ KBD_Init_fp = KBD_Init;
+ KBD_Update_fp = KBD_Update;
+ KBD_Close_fp = KBD_Close;
+ }
+#endif
+ KBD_Init_fp(Do_Key_Event);
+
+ // give up root now
+ setreuid(getuid(), getuid());
+ setegid(getgid());
+
+ Com_Printf( "------------------------------------\n");
+ reflib_active = true;
+ return true;
+}
+
+/*
+============
+VID_CheckChanges
+
+This function gets called once just before drawing each frame, and it's sole purpose in life
+is to check to see if any of the video mode parameters have changed, and if they have to
+update the rendering DLL and/or video mode to match.
+============
+*/
+void VID_CheckChanges (void)
+{
+ char name[100];
+ cvar_t *sw_mode;
+
+ if ( vid_ref->modified )
+ {
+ S_StopAllSounds();
+ }
+
+ while (vid_ref->modified)
+ {
+ /*
+ ** refresh has changed
+ */
+ vid_ref->modified = false;
+ vid_fullscreen->modified = true;
+ cl.refresh_prepped = false;
+ cls.disable_screen = true;
+
+ sprintf( name, "ref_%s.so", vid_ref->string );
+ if ( !VID_LoadRefresh( name ) )
+ {
+ if ( strcmp (vid_ref->string, "soft") == 0 ||
+ strcmp (vid_ref->string, "softx") == 0 ) {
+Com_Printf("Refresh failed\n");
+ sw_mode = Cvar_Get( "sw_mode", "0", 0 );
+ if (sw_mode->value != 0) {
+Com_Printf("Trying mode 0\n");
+ Cvar_SetValue("sw_mode", 0);
+ if ( !VID_LoadRefresh( name ) )
+ Com_Error (ERR_FATAL, "Couldn't fall back to software refresh!");
+ } else
+ Com_Error (ERR_FATAL, "Couldn't fall back to software refresh!");
+ }
+
+ Cvar_Set( "vid_ref", "soft" );
+
+ /*
+ ** drop the console if we fail to load a refresh
+ */
+ if ( cls.key_dest != key_console )
+ {
+ Con_ToggleConsole_f();
+ }
+ }
+ cls.disable_screen = false;
+ }
+
+}
+
+/*
+============
+VID_Init
+============
+*/
+void VID_Init (void)
+{
+ /* Create the video variables so we know how to start the graphics drivers */
+ // if DISPLAY is defined, try X
+ if (getenv("DISPLAY"))
+ vid_ref = Cvar_Get ("vid_ref", "softx", CVAR_ARCHIVE);
+ else
+ vid_ref = Cvar_Get ("vid_ref", "soft", CVAR_ARCHIVE);
+ vid_xpos = Cvar_Get ("vid_xpos", "3", CVAR_ARCHIVE);
+ vid_ypos = Cvar_Get ("vid_ypos", "22", CVAR_ARCHIVE);
+ vid_fullscreen = Cvar_Get ("vid_fullscreen", "0", CVAR_ARCHIVE);
+ vid_gamma = Cvar_Get( "vid_gamma", "1", CVAR_ARCHIVE );
+
+ /* Add some console commands that we want to handle */
+ Cmd_AddCommand ("vid_restart", VID_Restart_f);
+
+ /* Disable the 3Dfx splash screen */
+ putenv("FX_GLIDE_NO_SPLASH=0");
+
+ /* Start the graphics mode and load refresh DLL */
+ VID_CheckChanges();
+}
+
+/*
+============
+VID_Shutdown
+============
+*/
+void VID_Shutdown (void)
+{
+ if ( reflib_active )
+ {
+ if (KBD_Close_fp)
+ KBD_Close_fp();
+ if (RW_IN_Shutdown_fp)
+ RW_IN_Shutdown_fp();
+ KBD_Close_fp = NULL;
+ RW_IN_Shutdown_fp = NULL;
+ re.Shutdown ();
+ VID_FreeReflib ();
+ }
+}
+
+
+/*****************************************************************************/
+/* INPUT */
+/*****************************************************************************/
+
+cvar_t *in_joystick;
+
+// This if fake, it's acutally done by the Refresh load
+void IN_Init (void)
+{
+ in_joystick = Cvar_Get ("in_joystick", "0", CVAR_ARCHIVE);
+}
+
+void Real_IN_Init (void)
+{
+ if (RW_IN_Init_fp)
+ RW_IN_Init_fp(&in_state);
+}
+
+void IN_Shutdown (void)
+{
+ if (RW_IN_Shutdown_fp)
+ RW_IN_Shutdown_fp();
+}
+
+void IN_Commands (void)
+{
+ if (RW_IN_Commands_fp)
+ RW_IN_Commands_fp();
+}
+
+void IN_Move (usercmd_t *cmd)
+{
+ if (RW_IN_Move_fp)
+ RW_IN_Move_fp(cmd);
+}
+
+void IN_Frame (void)
+{
+ if (RW_IN_Frame_fp)
+ RW_IN_Frame_fp();
+}
+
+void IN_Activate (qboolean active)
+{
+ if (RW_IN_Activate_fp)
+ RW_IN_Activate_fp(active);
+}
+
+void Do_Key_Event(int key, qboolean down)
+{
+ Key_Event(key, down, Sys_Milliseconds());
+}
+