shithub: qk2

Download patch

ref: 9e8fb5bd060cfe44303744978ceab8ab23ee5ae6
parent: 92b27541349fc0d3d6f3bf5a548592fac8d384dc
author: Konstantinn Bonnet <qu7uux@gmail.com>
date: Mon Apr 20 18:58:59 EDT 2015

less stupid names for plan9/*.c

--- a/mkfile
+++ b/mkfile
@@ -43,15 +43,15 @@
 	qcommon/md4.$O\
 	qcommon/net_chan.$O\
 	qcommon/pmove.$O\
-	plan9/cd_9.$O\
-	plan9/in_9.$O\
-	plan9/net_udp.$O\
-	plan9/q_sh9.$O\
-	plan9/rw_9.$O\
-	plan9/snd_9.$O\
-	plan9/sys_9.$O\
-	plan9/vid_menu.$O\
-	plan9/vid_so.$O\
+	plan9/cd.$O\
+	plan9/in.$O\
+	plan9/menu.$O\
+	plan9/misc.$O\
+	plan9/snd.$O\
+	plan9/so.$O\
+	plan9/sys.$O\
+	plan9/udp.$O\
+	plan9/vid.$O\
 	ref/r_aclip.$O\
 	ref/r_alias.$O\
 	ref/r_bsp.$O\
--- /dev/null
+++ b/plan9/cd.c
@@ -1,0 +1,414 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "../q_shared.h"
+
+qboolean cdValid = false;
+qboolean playing = false;
+qboolean wasPlaying = false;
+qboolean initialized = false;
+qboolean enabled = true;
+qboolean playLooping = false;
+float cdvolume;
+byte remap[100];
+byte playTrack;
+byte maxTrack;
+int cdfile = -1;
+
+cvar_t	*cd_volume;
+cvar_t *cd_nocd;
+cvar_t *cd_dev;
+
+
+void CDAudio_Eject(void)
+{
+	if (cdfile == -1 || !enabled)
+		return;
+
+	Com_DPrintf("CDAudio_Eject: PORTME\n");
+	/*
+	if ( ioctl(cdfile, CDROMEJECT) == -1 ) 
+		Com_DPrintf("ioctl cdromeject failed\n");
+	*/
+}
+
+void CDAudio_CloseDoor(void)
+{
+	if (cdfile == -1 || !enabled)
+		return;
+
+	Com_DPrintf("CDAudio_CloseDoor: PORTME\n");
+	/*
+	if ( ioctl(cdfile, CDROMCLOSETRAY) == -1 ) 
+		Com_DPrintf("ioctl cdromclosetray failed\n");
+	*/
+}
+
+int CDAudio_GetAudioDiskInfo(void)
+{
+	cdValid = false;
+	Com_DPrintf("CDAudio_GetAudioDiskInfo: PORTME\n");
+	return -1;
+
+	/*
+	struct cdrom_tochdr tochdr;
+
+	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_Pause(void)
+{
+	if (cdfile == -1 || !enabled)
+		return;
+	if (!playing)
+		return;
+
+	Com_DPrintf("CDAudio_GetAudioDiskInfo: PORTME\n");
+
+	/*
+	if ( ioctl(cdfile, CDROMPAUSE) == -1 ) 
+		Com_DPrintf("ioctl cdrompause failed\n");
+
+	wasPlaying = playing;
+	playing = false;
+	*/
+}
+
+void CDAudio_Play(int track, qboolean looping)
+{
+	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;
+	}
+
+	USED(looping);
+	Com_DPrintf("CDAudio_Play: PORTME\n");
+
+	/*
+	struct cdrom_tocentry entry;
+	struct cdrom_ti ti;
+
+	// 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;
+
+	Com_DPrintf("CDAudio_Stop: PORTME\n");
+
+	/*
+	if ( ioctl(cdfile, CDROMSTOP) == -1 )
+		Com_DPrintf("ioctl cdromstop failed (%d)\n", errno);
+
+	wasPlaying = false;
+	playing = false;
+	*/
+}
+
+void CDAudio_Resume(void)
+{
+	if (cdfile == -1 || !enabled)
+		return;
+	if (!cdValid)
+		return;
+	if (!wasPlaying)
+		return;
+
+	Com_DPrintf("CDAudio_Stop: PORTME\n");
+
+	/*
+	if ( ioctl(cdfile, CDROMRESUME) == -1 ) 
+		Com_DPrintf("ioctl cdromresume failed\n");
+	playing = true;
+	*/
+}
+
+static void CD_f (void)
+{
+	char	*command;
+	int n, ret;
+
+	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)
+{
+	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 ();
+		}
+	}
+
+	Com_DPrintf("CDAudio_Stop: PORTME\n");
+
+	/*
+	struct cdrom_subchnl subchnl;
+	static time_t lastchk;
+
+	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;
+
+	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);
+
+	if((cdfile = open(cd_dev->string, OREAD)) < 0){
+		fprint(2, "CDAudio_Init: %r\n");
+		Com_Printf("CDAudio_Init: failed to open \"%s\"\n", cd_dev->string);
+		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;
+}
--- a/plan9/cd_9.c
+++ /dev/null
@@ -1,414 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-qboolean cdValid = false;
-qboolean playing = false;
-qboolean wasPlaying = false;
-qboolean initialized = false;
-qboolean enabled = true;
-qboolean playLooping = false;
-float cdvolume;
-byte remap[100];
-byte playTrack;
-byte maxTrack;
-int cdfile = -1;
-
-cvar_t	*cd_volume;
-cvar_t *cd_nocd;
-cvar_t *cd_dev;
-
-
-void CDAudio_Eject(void)
-{
-	if (cdfile == -1 || !enabled)
-		return;
-
-	Com_DPrintf("CDAudio_Eject: PORTME\n");
-	/*
-	if ( ioctl(cdfile, CDROMEJECT) == -1 ) 
-		Com_DPrintf("ioctl cdromeject failed\n");
-	*/
-}
-
-void CDAudio_CloseDoor(void)
-{
-	if (cdfile == -1 || !enabled)
-		return;
-
-	Com_DPrintf("CDAudio_CloseDoor: PORTME\n");
-	/*
-	if ( ioctl(cdfile, CDROMCLOSETRAY) == -1 ) 
-		Com_DPrintf("ioctl cdromclosetray failed\n");
-	*/
-}
-
-int CDAudio_GetAudioDiskInfo(void)
-{
-	cdValid = false;
-	Com_DPrintf("CDAudio_GetAudioDiskInfo: PORTME\n");
-	return -1;
-
-	/*
-	struct cdrom_tochdr tochdr;
-
-	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_Pause(void)
-{
-	if (cdfile == -1 || !enabled)
-		return;
-	if (!playing)
-		return;
-
-	Com_DPrintf("CDAudio_GetAudioDiskInfo: PORTME\n");
-
-	/*
-	if ( ioctl(cdfile, CDROMPAUSE) == -1 ) 
-		Com_DPrintf("ioctl cdrompause failed\n");
-
-	wasPlaying = playing;
-	playing = false;
-	*/
-}
-
-void CDAudio_Play(int track, qboolean looping)
-{
-	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;
-	}
-
-	USED(looping);
-	Com_DPrintf("CDAudio_Play: PORTME\n");
-
-	/*
-	struct cdrom_tocentry entry;
-	struct cdrom_ti ti;
-
-	// 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;
-
-	Com_DPrintf("CDAudio_Stop: PORTME\n");
-
-	/*
-	if ( ioctl(cdfile, CDROMSTOP) == -1 )
-		Com_DPrintf("ioctl cdromstop failed (%d)\n", errno);
-
-	wasPlaying = false;
-	playing = false;
-	*/
-}
-
-void CDAudio_Resume(void)
-{
-	if (cdfile == -1 || !enabled)
-		return;
-	if (!cdValid)
-		return;
-	if (!wasPlaying)
-		return;
-
-	Com_DPrintf("CDAudio_Stop: PORTME\n");
-
-	/*
-	if ( ioctl(cdfile, CDROMRESUME) == -1 ) 
-		Com_DPrintf("ioctl cdromresume failed\n");
-	playing = true;
-	*/
-}
-
-static void CD_f (void)
-{
-	char	*command;
-	int n, ret;
-
-	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)
-{
-	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 ();
-		}
-	}
-
-	Com_DPrintf("CDAudio_Stop: PORTME\n");
-
-	/*
-	struct cdrom_subchnl subchnl;
-	static time_t lastchk;
-
-	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;
-
-	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);
-
-	if((cdfile = open(cd_dev->string, OREAD)) < 0){
-		fprint(2, "CDAudio_Init: %r\n");
-		Com_Printf("CDAudio_Init: failed to open \"%s\"\n", cd_dev->string);
-		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/in.c
@@ -1,0 +1,352 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include <draw.h>
+#include <thread.h>
+#include <mouse.h>
+#include <keyboard.h>
+#include "../q_shared.h"
+
+cvar_t	*in_mouse;
+cvar_t	*in_joystick;
+cvar_t	*m_filter;
+cvar_t	*m_windowed;
+cvar_t	*sensitivity;
+cvar_t	*lookstrafe;
+cvar_t	*m_side;
+cvar_t	*m_yaw;
+cvar_t	*m_pitch;
+cvar_t	*m_forward;
+cvar_t	*freelook;
+
+qboolean mouseon;
+qboolean mlooking;
+int dx, dy;
+int oldmwin;
+
+typedef struct Kev Kev;
+struct Kev{
+	int key;
+	int down;
+};
+enum{
+	Nbuf	= 64,
+	ITHGRP	= 2
+};
+Channel *kchan;
+Channel *mchan;
+
+/* rw_9.c */
+extern int resized;
+extern Point center;
+extern refimport_t ri;
+
+void IN_Grabm(int on)
+{
+	static char nocurs[2*4+2*2*16];
+	static int fd = -1;
+
+	if(mouseon == on)
+		return;
+	if(mouseon = on && m_windowed->value){
+		if((fd = open("/dev/cursor", ORDWR|OCEXEC)) < 0){
+			sysfatal("IN_Grabm:open: %r\n");
+			return;
+		}
+		write(fd, nocurs, sizeof nocurs);
+	}else if(fd >= 0){
+		close(fd);
+		fd = -1;
+	}
+}
+
+void IN_Commands (void)
+{
+	/* joystick stuff */
+}
+
+void btnev (int btn, ulong msec)
+{
+	static int oldb;
+	int i, b;
+
+	for(i = 0; i < 3; i++){
+		b = 1<<i;
+		if(btn & b && ~oldb & b)
+			Key_Event(K_MOUSE1+i, true, msec);
+		else if(~btn & b && oldb & b)
+			Key_Event(K_MOUSE1+i, false, msec);
+	}
+	oldb = btn;
+	/* mwheelup and mwheeldn buttons are never held down */
+	for(i = 3; i < 5; i++){
+		b = 1<<i;
+		if(btn & b){
+			Key_Event(K_MOUSE1+i, true, msec);
+			Key_Event(K_MOUSE1+i, false, msec);
+		}
+	}
+}
+
+void KBD_Update (void)
+{
+	int r;
+	Kev ev;
+	Mouse m;
+
+	if(oldmwin != m_windowed->value){
+		oldmwin = m_windowed->value;
+		IN_Grabm(m_windowed->value);
+	}
+	while((r = nbrecv(kchan, &ev)) > 0)
+		Key_Event(ev.key, ev.down, Sys_Milliseconds());
+	if(r < 0)
+		sysfatal("KBD_Update:nbrecv: %r\n");
+	while((r = nbrecv(mchan, &m)) > 0){
+		dx += m.xy.x;
+		dy += m.xy.y;
+		btnev(m.buttons, m.msec);
+	}
+	if(r < 0)
+		sysfatal("KBD_Update:nbrecv: %r\n");
+}
+
+void IN_Move (usercmd_t *cmd)
+{
+	static int mx, my, oldmx, oldmy;
+
+	if(!mouseon)
+		return;
+
+	if(m_filter->value){
+		mx = (dx + oldmx) * 0.5;
+		my = (dy + oldmy) * 0.5;
+	}else{
+		mx = dx;
+		my = dy;
+	}
+	oldmx = dx;
+	oldmy = dy;
+	dx = dy = 0;
+	if(!mx && !my)
+		return;
+	mx *= sensitivity->value;
+	my *= sensitivity->value;
+
+	/* add mouse x/y movement to cmd */
+	if(in_strafe.state & 1 || lookstrafe->value && mlooking)
+		cmd->sidemove += m_side->value * mx;
+	else
+		cl.viewangles[YAW] -= m_yaw->value * mx;
+	if((mlooking || freelook->value) && ~in_strafe.state & 1)
+		cl.viewangles[PITCH] += m_pitch->value * my;
+	else
+		cmd->forwardmove -= m_forward->value * my;
+}
+
+/* called on focus/unfocus in win32 */
+void IN_Activate (qboolean)
+{
+}
+
+/* called every frame even if not generating commands */
+void IN_Frame (void)
+{
+}
+
+void IN_ForceCenterView (void)
+{
+	cl.viewangles[PITCH] = 0;
+}
+
+void IN_MLookDown (void)
+{
+	mlooking = true;
+}
+
+void IN_MLookUp (void)
+{
+	mlooking = false;
+	IN_CenterView();
+}
+
+int runetokey (Rune r)
+{
+	int k = 0;
+
+	switch(r){
+	case Kpgup:	k = K_PGUP; break;
+	case Kpgdown:	k = K_PGDN; break;
+	case Khome:	k = K_HOME; break;
+	case Kend:	k = K_END; break;
+	case Kleft:	k = K_LEFTARROW; break;
+	case Kright:	k = K_RIGHTARROW; break;
+	case Kdown:	k = K_DOWNARROW; break;
+	case Kup:	k = K_UPARROW; break;
+	case Kesc:	k = K_ESCAPE; break;
+	case '\n':	k = K_ENTER; break;
+	case '\t':	k = K_TAB; break;
+	case KF|1:	k = K_F1; break;
+	case KF|2:	k = K_F2; break;
+	case KF|3:	k = K_F3; break;
+	case KF|4:	k = K_F4; break;
+	case KF|5:	k = K_F5; break;
+	case KF|6:	k = K_F6; break;
+	case KF|7:	k = K_F7; break;
+	case KF|8:	k = K_F8; break;
+	case KF|9:	k = K_F9; break;
+	case KF|10:	k = K_F10; break;
+	case KF|11:	k = K_F11; break;
+	case KF|12:	k = K_F12; break;
+	case Kbs:	k = K_BACKSPACE; break;
+	case Kdel:	k = K_DEL; break;
+	case Kbreak:	k = K_PAUSE; break;
+	case Kshift:	k = K_SHIFT; break;
+	case Kctl:	k = K_CTRL; break;
+	case Kalt:
+	case Kaltgr:	k = K_ALT; break;
+	case Kins:	k = K_INS; break;
+	default:
+		if(r < 0x80)
+			k = r;
+	};
+	return k;
+}
+
+void kproc (void *)
+{
+	int n, k, fd;
+	char buf[128], kdown[128] = {0}, *s;
+	Rune r;
+	Kev ev;
+
+	if(threadsetgrp(ITHGRP) < 0)
+		sysfatal("kproc:threadsetgrp: %r");
+	if((fd = open("/dev/kbd", OREAD)) < 0)
+		sysfatal("open /dev/kbd: %r");
+
+	while((n = read(fd, buf, sizeof buf)) > 0){
+		buf[n-1] = 0;
+		switch(*buf){
+		case 'c':
+		default:
+			continue;
+		case 'k':
+			s = buf+1;
+			while(*s){
+				s += chartorune(&r, s);
+				if(utfrune(kdown+1, r) == nil){
+					if(k = runetokey(r)){
+						ev.key = k;
+						ev.down = true;
+						if(send(kchan, &ev) < 0)
+							sysfatal("kproc:nbsend: %r\n");
+					}
+				}
+			}
+			break;
+		case 'K':
+			s = kdown+1;
+			while(*s){
+				s += chartorune(&r, s);
+				if(utfrune(buf+1, r) == nil){
+					if(k = runetokey(r)){
+						ev.key = k;
+						ev.down = false;
+						if(send(kchan, &ev) < 0)
+							sysfatal("mproc:nbsend: %r\n");
+					}
+				}
+			}
+			break;
+		}
+		strcpy(kdown, buf);
+	}
+	fprint(2, "kproc: %r\n");
+	close(fd);
+}
+
+void mproc (void *)
+{
+	int n, nerr = 0, fd;
+	char buf[1+5*12];
+	Mouse m;
+
+	if(threadsetgrp(ITHGRP) < 0)
+		sysfatal("mproc:threadsetgrp: %r");
+	if((fd = open("/dev/mouse", ORDWR)) < 0)
+		sysfatal("open /dev/mouse: %r");
+
+	for(;;){
+		if((n = read(fd, buf, sizeof buf)) != 1+4*12){
+			fprint(2, "mproc:read: bad count %d not 49: %r\n", n);
+			if(n < 0 || ++nerr > 10)
+				break;
+			continue;
+		}
+		nerr = 0;
+		switch(*buf){
+		case 'r':
+			resized = 1;
+			/* fall through */
+		case 'm':
+			if(!mouseon)
+				break;
+
+			m.xy.x = atoi(buf+1+0*12) - center.x;
+			m.xy.y = atoi(buf+1+1*12) - center.y;
+			if(m.xy.x != 0 || m.xy.y != 0)
+				fprint(fd, "m%d %d", center.x, center.y);
+			m.buttons = atoi(buf+1+2*12);
+			m.msec = atoi(buf+1+3*12);
+			if(nbsend(mchan, &m) < 0)
+				sysfatal("mproc:nbsend: %r\n");
+			break;
+		}
+	}
+	fprint(2, "mproc: %r\n");
+	IN_Grabm(0);
+	close(fd);
+}
+
+void IN_Shutdown (void)
+{
+	IN_Grabm(0);
+	threadkillgrp(ITHGRP);
+	if(kchan != nil){
+		chanfree(kchan);
+		kchan = nil;
+	}
+	if(mchan != nil){
+		chanfree(mchan);
+		mchan = nil;
+	}
+}
+
+void IN_Init (void)
+{
+	in_mouse = ri.Cvar_Get("in_mouse", "1", CVAR_ARCHIVE);
+	in_joystick = ri.Cvar_Get("in_joystick", "0", CVAR_ARCHIVE);
+	m_windowed = ri.Cvar_Get("m_windowed", "0", CVAR_ARCHIVE);
+	m_filter = ri.Cvar_Get("m_filter", "0", 0);
+	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", IN_MLookDown);
+	ri.Cmd_AddCommand("-mlook", IN_MLookUp);
+	ri.Cmd_AddCommand("force_centerview", IN_ForceCenterView);
+
+	if((kchan = chancreate(sizeof(Kev), Nbuf)) == nil)
+		sysfatal("chancreate kchan: %r");
+	if(proccreate(kproc, nil, 8192) < 0)
+		sysfatal("proccreate kproc: %r");
+	if((mchan = chancreate(sizeof(Mouse), Nbuf)) == nil)
+		sysfatal("chancreate kchan: %r");
+	if(proccreate(mproc, nil, 8192) < 0)
+		sysfatal("proccreate mproc: %r");
+}
--- a/plan9/in_9.c
+++ /dev/null
@@ -1,352 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include <draw.h>
-#include <thread.h>
-#include <mouse.h>
-#include <keyboard.h>
-#include "../q_shared.h"
-
-cvar_t	*in_mouse;
-cvar_t	*in_joystick;
-cvar_t	*m_filter;
-cvar_t	*m_windowed;
-cvar_t	*sensitivity;
-cvar_t	*lookstrafe;
-cvar_t	*m_side;
-cvar_t	*m_yaw;
-cvar_t	*m_pitch;
-cvar_t	*m_forward;
-cvar_t	*freelook;
-
-qboolean mouseon;
-qboolean mlooking;
-int dx, dy;
-int oldmwin;
-
-typedef struct Kev Kev;
-struct Kev{
-	int key;
-	int down;
-};
-enum{
-	Nbuf	= 64,
-	ITHGRP	= 2
-};
-Channel *kchan;
-Channel *mchan;
-
-/* rw_9.c */
-extern int resized;
-extern Point center;
-extern refimport_t ri;
-
-void IN_Grabm(int on)
-{
-	static char nocurs[2*4+2*2*16];
-	static int fd = -1;
-
-	if(mouseon == on)
-		return;
-	if(mouseon = on && m_windowed->value){
-		if((fd = open("/dev/cursor", ORDWR|OCEXEC)) < 0){
-			sysfatal("IN_Grabm:open: %r\n");
-			return;
-		}
-		write(fd, nocurs, sizeof nocurs);
-	}else if(fd >= 0){
-		close(fd);
-		fd = -1;
-	}
-}
-
-void IN_Commands (void)
-{
-	/* joystick stuff */
-}
-
-void btnev (int btn, ulong msec)
-{
-	static int oldb;
-	int i, b;
-
-	for(i = 0; i < 3; i++){
-		b = 1<<i;
-		if(btn & b && ~oldb & b)
-			Key_Event(K_MOUSE1+i, true, msec);
-		else if(~btn & b && oldb & b)
-			Key_Event(K_MOUSE1+i, false, msec);
-	}
-	oldb = btn;
-	/* mwheelup and mwheeldn buttons are never held down */
-	for(i = 3; i < 5; i++){
-		b = 1<<i;
-		if(btn & b){
-			Key_Event(K_MOUSE1+i, true, msec);
-			Key_Event(K_MOUSE1+i, false, msec);
-		}
-	}
-}
-
-void KBD_Update (void)
-{
-	int r;
-	Kev ev;
-	Mouse m;
-
-	if(oldmwin != m_windowed->value){
-		oldmwin = m_windowed->value;
-		IN_Grabm(m_windowed->value);
-	}
-	while((r = nbrecv(kchan, &ev)) > 0)
-		Key_Event(ev.key, ev.down, Sys_Milliseconds());
-	if(r < 0)
-		sysfatal("KBD_Update:nbrecv: %r\n");
-	while((r = nbrecv(mchan, &m)) > 0){
-		dx += m.xy.x;
-		dy += m.xy.y;
-		btnev(m.buttons, m.msec);
-	}
-	if(r < 0)
-		sysfatal("KBD_Update:nbrecv: %r\n");
-}
-
-void IN_Move (usercmd_t *cmd)
-{
-	static int mx, my, oldmx, oldmy;
-
-	if(!mouseon)
-		return;
-
-	if(m_filter->value){
-		mx = (dx + oldmx) * 0.5;
-		my = (dy + oldmy) * 0.5;
-	}else{
-		mx = dx;
-		my = dy;
-	}
-	oldmx = dx;
-	oldmy = dy;
-	dx = dy = 0;
-	if(!mx && !my)
-		return;
-	mx *= sensitivity->value;
-	my *= sensitivity->value;
-
-	/* add mouse x/y movement to cmd */
-	if(in_strafe.state & 1 || lookstrafe->value && mlooking)
-		cmd->sidemove += m_side->value * mx;
-	else
-		cl.viewangles[YAW] -= m_yaw->value * mx;
-	if((mlooking || freelook->value) && ~in_strafe.state & 1)
-		cl.viewangles[PITCH] += m_pitch->value * my;
-	else
-		cmd->forwardmove -= m_forward->value * my;
-}
-
-/* called on focus/unfocus in win32 */
-void IN_Activate (qboolean)
-{
-}
-
-/* called every frame even if not generating commands */
-void IN_Frame (void)
-{
-}
-
-void IN_ForceCenterView (void)
-{
-	cl.viewangles[PITCH] = 0;
-}
-
-void IN_MLookDown (void)
-{
-	mlooking = true;
-}
-
-void IN_MLookUp (void)
-{
-	mlooking = false;
-	IN_CenterView();
-}
-
-int runetokey (Rune r)
-{
-	int k = 0;
-
-	switch(r){
-	case Kpgup:	k = K_PGUP; break;
-	case Kpgdown:	k = K_PGDN; break;
-	case Khome:	k = K_HOME; break;
-	case Kend:	k = K_END; break;
-	case Kleft:	k = K_LEFTARROW; break;
-	case Kright:	k = K_RIGHTARROW; break;
-	case Kdown:	k = K_DOWNARROW; break;
-	case Kup:	k = K_UPARROW; break;
-	case Kesc:	k = K_ESCAPE; break;
-	case '\n':	k = K_ENTER; break;
-	case '\t':	k = K_TAB; break;
-	case KF|1:	k = K_F1; break;
-	case KF|2:	k = K_F2; break;
-	case KF|3:	k = K_F3; break;
-	case KF|4:	k = K_F4; break;
-	case KF|5:	k = K_F5; break;
-	case KF|6:	k = K_F6; break;
-	case KF|7:	k = K_F7; break;
-	case KF|8:	k = K_F8; break;
-	case KF|9:	k = K_F9; break;
-	case KF|10:	k = K_F10; break;
-	case KF|11:	k = K_F11; break;
-	case KF|12:	k = K_F12; break;
-	case Kbs:	k = K_BACKSPACE; break;
-	case Kdel:	k = K_DEL; break;
-	case Kbreak:	k = K_PAUSE; break;
-	case Kshift:	k = K_SHIFT; break;
-	case Kctl:	k = K_CTRL; break;
-	case Kalt:
-	case Kaltgr:	k = K_ALT; break;
-	case Kins:	k = K_INS; break;
-	default:
-		if(r < 0x80)
-			k = r;
-	};
-	return k;
-}
-
-void kproc (void *)
-{
-	int n, k, fd;
-	char buf[128], kdown[128] = {0}, *s;
-	Rune r;
-	Kev ev;
-
-	if(threadsetgrp(ITHGRP) < 0)
-		sysfatal("kproc:threadsetgrp: %r");
-	if((fd = open("/dev/kbd", OREAD)) < 0)
-		sysfatal("open /dev/kbd: %r");
-
-	while((n = read(fd, buf, sizeof buf)) > 0){
-		buf[n-1] = 0;
-		switch(*buf){
-		case 'c':
-		default:
-			continue;
-		case 'k':
-			s = buf+1;
-			while(*s){
-				s += chartorune(&r, s);
-				if(utfrune(kdown+1, r) == nil){
-					if(k = runetokey(r)){
-						ev.key = k;
-						ev.down = true;
-						if(send(kchan, &ev) < 0)
-							sysfatal("kproc:nbsend: %r\n");
-					}
-				}
-			}
-			break;
-		case 'K':
-			s = kdown+1;
-			while(*s){
-				s += chartorune(&r, s);
-				if(utfrune(buf+1, r) == nil){
-					if(k = runetokey(r)){
-						ev.key = k;
-						ev.down = false;
-						if(send(kchan, &ev) < 0)
-							sysfatal("mproc:nbsend: %r\n");
-					}
-				}
-			}
-			break;
-		}
-		strcpy(kdown, buf);
-	}
-	fprint(2, "kproc: %r\n");
-	close(fd);
-}
-
-void mproc (void *)
-{
-	int n, nerr = 0, fd;
-	char buf[1+5*12];
-	Mouse m;
-
-	if(threadsetgrp(ITHGRP) < 0)
-		sysfatal("mproc:threadsetgrp: %r");
-	if((fd = open("/dev/mouse", ORDWR)) < 0)
-		sysfatal("open /dev/mouse: %r");
-
-	for(;;){
-		if((n = read(fd, buf, sizeof buf)) != 1+4*12){
-			fprint(2, "mproc:read: bad count %d not 49: %r\n", n);
-			if(n < 0 || ++nerr > 10)
-				break;
-			continue;
-		}
-		nerr = 0;
-		switch(*buf){
-		case 'r':
-			resized = 1;
-			/* fall through */
-		case 'm':
-			if(!mouseon)
-				break;
-
-			m.xy.x = atoi(buf+1+0*12) - center.x;
-			m.xy.y = atoi(buf+1+1*12) - center.y;
-			if(m.xy.x != 0 || m.xy.y != 0)
-				fprint(fd, "m%d %d", center.x, center.y);
-			m.buttons = atoi(buf+1+2*12);
-			m.msec = atoi(buf+1+3*12);
-			if(nbsend(mchan, &m) < 0)
-				sysfatal("mproc:nbsend: %r\n");
-			break;
-		}
-	}
-	fprint(2, "mproc: %r\n");
-	IN_Grabm(0);
-	close(fd);
-}
-
-void IN_Shutdown (void)
-{
-	IN_Grabm(0);
-	threadkillgrp(ITHGRP);
-	if(kchan != nil){
-		chanfree(kchan);
-		kchan = nil;
-	}
-	if(mchan != nil){
-		chanfree(mchan);
-		mchan = nil;
-	}
-}
-
-void IN_Init (void)
-{
-	in_mouse = ri.Cvar_Get("in_mouse", "1", CVAR_ARCHIVE);
-	in_joystick = ri.Cvar_Get("in_joystick", "0", CVAR_ARCHIVE);
-	m_windowed = ri.Cvar_Get("m_windowed", "0", CVAR_ARCHIVE);
-	m_filter = ri.Cvar_Get("m_filter", "0", 0);
-	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", IN_MLookDown);
-	ri.Cmd_AddCommand("-mlook", IN_MLookUp);
-	ri.Cmd_AddCommand("force_centerview", IN_ForceCenterView);
-
-	if((kchan = chancreate(sizeof(Kev), Nbuf)) == nil)
-		sysfatal("chancreate kchan: %r");
-	if(proccreate(kproc, nil, 8192) < 0)
-		sysfatal("proccreate kproc: %r");
-	if((mchan = chancreate(sizeof(Mouse), Nbuf)) == nil)
-		sysfatal("chancreate kchan: %r");
-	if(proccreate(mproc, nil, 8192) < 0)
-		sysfatal("proccreate mproc: %r");
-}
--- /dev/null
+++ b/plan9/menu.c
@@ -1,0 +1,137 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "../q_shared.h"
+
+extern cvar_t *vid_fullscreen;
+extern cvar_t *vid_gamma;
+extern cvar_t *scr_viewsize;
+
+extern void M_PopMenu(void);
+
+menuframework_s	vmenu;
+menuslider_s	ssizeslide;
+menuslider_s	gammaslide;
+menulist_s	fullscrbox;
+menuaction_s	applyaction;
+menuaction_s	defaultsaction;
+
+
+void vmssize (void *s)
+{
+	Cvar_SetValue("viewsize", ((menuslider_s *)s)->curvalue * 10);
+}
+
+void vmgamma (void *s)
+{
+	// invert sense so greater = brighter, and scale to a range of 0.5 to 1.3
+	Cvar_SetValue("vid_gamma", 0.8 - (((menuslider_s *)s)->curvalue/10.0 - 0.5) + 0.5);
+}
+
+void vmreset (void *)
+{
+	VID_MenuInit();
+}
+
+void vmapply (void *)
+{
+	Cvar_SetValue("vid_gamma", 0.8 - (gammaslide.curvalue/10.0 - 0.5) + 0.5);
+	Cvar_SetValue("vid_fullscreen", fullscrbox.curvalue);
+	M_ForceMenuOff();
+}
+
+void VID_MenuInit (void)
+{
+	static char *yesno[] = {"no", "yes", nil};
+
+	if(!scr_viewsize)
+		scr_viewsize = Cvar_Get("viewsize", "100", CVAR_ARCHIVE);
+	ssizeslide.curvalue = scr_viewsize->value/10;
+
+	vmenu.x = vid.width * 0.50;
+	vmenu.nitems = 0;
+
+	ssizeslide.generic.type = MTYPE_SLIDER;
+	ssizeslide.generic.x = 0;
+	ssizeslide.generic.y = 20;
+	ssizeslide.generic.name = "screen size";
+	ssizeslide.minvalue = 3;
+	ssizeslide.maxvalue = 12;
+	ssizeslide.generic.callback = vmssize;
+
+	gammaslide.generic.type = MTYPE_SLIDER;
+	gammaslide.generic.x = 0;
+	gammaslide.generic.y = 30;
+	gammaslide.generic.name = "gamma";
+	gammaslide.generic.callback = vmgamma;
+	gammaslide.minvalue = 5;
+	gammaslide.maxvalue = 13;
+	gammaslide.curvalue = (1.3 - vid_gamma->value + 0.5) * 10;
+
+	fullscrbox.generic.type = MTYPE_SPINCONTROL;
+	fullscrbox.generic.x = 0;
+	fullscrbox.generic.y = 40;
+	fullscrbox.generic.name = "fullscreen";
+	fullscrbox.itemnames = yesno;
+	fullscrbox.curvalue = vid_fullscreen->value;
+
+	defaultsaction.generic.type = MTYPE_ACTION;
+	defaultsaction.generic.name = "reset to default";
+	defaultsaction.generic.x = 0;
+	defaultsaction.generic.y = 90;
+	defaultsaction.generic.callback = vmreset;
+
+	applyaction.generic.type = MTYPE_ACTION;
+	applyaction.generic.name = "apply";
+	applyaction.generic.x = 0;
+	applyaction.generic.y = 100;
+	applyaction.generic.callback = vmapply;
+
+	Menu_AddItem(&vmenu, (void *)&ssizeslide);
+	Menu_AddItem(&vmenu, (void *)&gammaslide);
+	Menu_AddItem(&vmenu, (void *)&fullscrbox);
+	Menu_AddItem(&vmenu, (void *)&defaultsaction);
+	Menu_AddItem(&vmenu, (void *)&applyaction);
+
+	Menu_Center(&vmenu);
+	vmenu.x -= 8;
+}
+
+void VID_MenuDraw (void)
+{
+	int w, h;
+
+	re.DrawGetPicSize(&w, &h, "m_banner_video");
+	re.DrawPic(vid.width/2 - w/2, vid.height/2 - 110, "m_banner_video");
+	Menu_AdjustCursor(&vmenu, 1);	// starting position
+	Menu_Draw(&vmenu);
+}
+
+char *VID_MenuKey (int key)
+{
+	static char *sound = "misc/menu1.wav";
+
+	switch(key){
+	case K_ESCAPE:
+		M_PopMenu();
+		return NULL;
+	case K_UPARROW:
+		vmenu.cursor--;
+		Menu_AdjustCursor(&vmenu, -1);
+		break;
+	case K_DOWNARROW:
+		vmenu.cursor++;
+		Menu_AdjustCursor(&vmenu, 1);
+		break;
+	case K_LEFTARROW:
+		Menu_SlideItem(&vmenu, -1);
+		break;
+	case K_RIGHTARROW:
+		Menu_SlideItem(&vmenu, 1);
+		break;
+	case K_ENTER:
+		Menu_SelectItem(&vmenu);
+		break;
+	}
+	return sound;
+}
--- /dev/null
+++ b/plan9/misc.c
@@ -1,0 +1,307 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "../q_shared.h"
+
+byte *membase;
+int maxhunksize;
+int curhunksize;
+int curtime;
+char findbase[MAX_OSPATH], findpath[MAX_OSPATH], findpattern[MAX_OSPATH];
+long dirn, di;
+Dir *dirs;
+
+int	glob_match(char *, char *);
+
+
+/* Like glob_match, but match PATTERN against any final segment of TEXT.  */
+int glob_match_after_star(char *pattern, char *text)
+{
+	char *p = pattern, *t = text;
+	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.  */
+int glob_pattern_p(char *pattern)
+{
+	char *p = pattern;
+	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)
+{
+	char *p = pattern, *t = text;
+	char c, c1, cstart, cend;
+	int invert;
+
+	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 '[':
+			{
+				c1 = *t++;
+
+				if (!c1)
+					return (0);
+
+				invert = ((*p == '!') || (*p == '^'));
+				if (invert)
+					p++;
+
+				c = *p++;
+				while (1) {
+					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;
+		}
+
+	/* if the pattern is empty, Sys_FindNext looks at the current file anyway */
+	return *t == '\0';
+}
+
+void *Hunk_Begin (int maxsize)
+{
+	// reserve a huge chunk of memory, but don't commit any yet
+	maxhunksize = maxsize;
+	curhunksize = 0;
+	if((membase = mallocz(maxhunksize, 1)) == nil)
+		sysfatal("Hunk_Begin:malloc %d: %r", maxhunksize);
+	return membase;
+}
+
+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 + curhunksize;
+	curhunksize += size;
+	return buf;
+}
+
+int Hunk_End (void)
+{
+	if(realloc(membase, curhunksize) != membase)
+		sysfatal("Hunk_End:realloc: %r");
+	return curhunksize;
+}
+
+void Hunk_Free (void *base)
+{
+	if(base != nil)
+		free(base);
+}
+
+int Sys_Milliseconds (void)
+{
+	static long msbase;
+
+	if(msbase == 0)
+		msbase = time(nil)*1000;
+	curtime = nsec()/1000000 - msbase;
+	return curtime;
+}
+
+void Sys_Mkdir (char *path)
+{
+	int d;
+
+	if((d = create(path, OREAD, DMDIR|0777)) < 0)
+		fprint(2, "Sys_Mkdir:create: %r\n");
+	else
+		close(d);
+}
+
+qboolean CompareAttributes (ulong m, uint musthave, uint canthave)
+{
+	if(m & DMDIR && canthave & SFF_SUBDIR)
+		return false;
+	if(musthave & SFF_SUBDIR && ~m & DMDIR)
+		return false;
+	return true;
+}
+
+char *Sys_FindFirst (char *path, uint musthave, uint canhave)
+{
+	char *p;
+	int fd;
+
+	if(dirs != nil)
+		Sys_Error("Sys_BeginFind without close");
+
+	strncpy(findbase, path, sizeof findbase-1);
+	if((p = strrchr(findbase, '/')) != nil){
+		*p = 0;
+		strncpy(findpattern, p+1, sizeof findpattern-1);
+	}else
+		strcpy(findpattern, "*");
+	if(strcmp(findpattern, "*.*") == 0)
+		strcpy(findpattern, "*");
+	if(*findpattern == '\0'){
+		Com_Printf("Sys_BeginFind: empty pattern\n");
+		return nil;
+	}
+
+	if((fd = open(findbase, OREAD)) < 0){
+		fprint(2, "Sys_BeginFind:open: %r\n");
+		return nil;
+	}
+	dirn = dirreadall(fd, &dirs);
+	close(fd);
+	if(dirn == 0)
+		return nil;
+	if(dirn < 0){
+		fprint(2, "Sys_BeginFind:dirread: %r\n");
+		return nil;
+	}
+
+	di = 0;
+	return Sys_FindNext (musthave, canhave);
+}
+
+char *Sys_FindNext (uint musthave, uint canhave)
+{
+	int i;
+
+	if(dirs == nil)
+		Sys_Error("Sys_FindNext without open\n");
+
+	while(di < dirn){
+		i = di++;
+		if(glob_match(findpattern, dirs[i].name)){
+			if(CompareAttributes(dirs[i].mode, musthave, canhave)){
+				snprintf(findpath, sizeof findpath, "%s/%s", findbase, dirs[i].name);
+				return findpath;
+			}
+		}
+	}
+	return nil;
+}
+
+void Sys_FindClose (void)
+{
+	if(dirs != nil){
+		free(dirs);
+		dirs = nil;
+	}
+}
--- a/plan9/net_udp.c
+++ /dev/null
@@ -1,523 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include <thread.h>
-#include <bio.h>
-#include <ndb.h>
-#include <ip.h>
-#include "../q_shared.h"
-
-/* FIXME: this shit SUCKS, and ipv4 only because of other code */
-
-cvar_t	*svport;	/* server port and copy of string value */
-char	srv[6];
-cvar_t	*clport;	/* "client" port and copy */
-char	clsrv[6];
-
-typedef struct Loopmsg Loopmsg;
-typedef struct Loopback Loopback;
-typedef struct Conmsg Conmsg;
-typedef struct Conlist Conlist;
-
-enum{
-	MAX_LOOPBACK	= 4,
-	HDRSZ		= 16+16+16+2+2,	/* sizeof Udphdr w/o padding */
-	BUFSZ		= MAX_MSGLEN,
-	NBUF		= 64,
-	DTHGRP		= 1,
-	CLPORT		= 27909
-};
-struct Loopmsg{
-	byte	data[MAX_MSGLEN];
-	int	datalen;
-};
-struct Loopback{
-	Loopmsg	msgs[MAX_LOOPBACK];
-	int	get;
-	int	send;
-};
-Loopback	loopbacks[2];
-
-struct Conlist{
-	Conlist *p;
-	uchar	u[IPaddrlen+2];
-	char	addr[IPaddrlen*2+8+6];	/* ipv6 + separators + port in decimal */
-	int	dfd;
-	Udphdr	h;
-	int	src;	/* q2 assumes broadcast replies are received on NS_CLIENT */
-};
-Conlist *cnroot;
-
-struct Conmsg{
-	Conlist *p;
-	int	n;
-	uchar	buf[BUFSZ];
-};
-Channel *udpchan;
-Channel *clchan;
-
-netadr_t laddr;		/* 0.0.0.0:0 */
-int cfd = -1, ufd = -1, clfd = -1, cldfd = -1;
-QLock cnlock;
-
-
-qboolean NET_CompareAdr (netadr_t a, netadr_t b)
-{
-	return (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);
-}
-
-/* compares without the port */
-qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b)
-{
-	if(a.type != b.type)
-		return false;
-	switch(a.type){
-	case NA_LOOPBACK:
-		return true;
-	case NA_IP:
-		return (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3]);
-	case NA_IPX:
-		return !memcmp(a.ipx, b.ipx, 10);
-	default:
-		return false;
-	}
-}
-
-char *NET_AdrToString (netadr_t a)
-{
-	static char s[256];
-
-	seprint(s, s+sizeof s, "%ud.%ud.%ud.%ud:%hud", a.ip[0], a.ip[1], a.ip[2], a.ip[3], BigShort(a.port));
-	return s;
-}
-
-char *NET_BaseAdrToString (netadr_t a)
-{
-	static char s[256];
-
-	seprint(s, s+sizeof s, "%ud.%ud.%ud.%ud", 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_StringToAdr (char *addr, netadr_t *a)		/* assumes IPv4 */
-{
-	int i;
-	char s[256], *p, *pp;
-	Ndb *db;
-	Ndbtuple *nt;
-
-	if(!strcmp(addr, "localhost")){
-		memset(a, 0, sizeof *a);
-		a->type = NA_LOOPBACK;
-		return true;
-	}
-
-	strncpy(s, addr, sizeof s);
-	s[sizeof(s)-1] = 0;
-
-	if((p = strrchr(s, ':')) != nil){
-		*p++ = '\0';
-		a->port = BigShort(atoi(p));
-	}
-
-	if((db = ndbopen(nil)) == nil){
-		fprint(2, "NET_StringToAdr:ndbopen: %r\n");
-		return false;
-	}
-	if((nt = ndbgetipaddr(db, s)) == nil){
-		ndbclose(db);
-		fprint(2, "NET_StringToAdr:ndbgetipaddr: %r\n");
-		return false;
-	}
-	strncpy(s, nt->val, sizeof(s)-1);	/* just look at first value found */
-	ndbfree(nt);
-	ndbclose(db);
-
-	for(i = 0, pp = s; i < IPv4addrlen; i++){
-		if((p = strchr(pp, '.')) != nil)
-			*p++ = '\0';
-		a->ip[i] = atoi(pp);
-		pp = p;
-	}
-	a->type = NA_IP;
-	return true;
-}
-
-qboolean NET_IsLocalAddress (netadr_t adr)
-{
-	return NET_CompareAdr(adr, laddr);
-}
-
-qboolean looprecv (netsrc_t sock, netadr_t *net_from, sizebuf_t *d)
-{
-	int i;
-	Loopback *l;
-
-	l = &loopbacks[sock];
-	if(l->send - l->get > MAX_LOOPBACK)
-		l->get = l->send - MAX_LOOPBACK;
-	if(l->get >= l->send)
-		return false;
-	i = l->get & (MAX_LOOPBACK-1);
-	l->get++;
-
-	memcpy(d->data, l->msgs[i].data, l->msgs[i].datalen);
-	d->cursize = l->msgs[i].datalen;
-	*net_from = laddr;
-	return true;
-}
-
-void loopsend (netsrc_t sock, int length, void *data, netadr_t /*to*/)
-{
-	Loopback *l;
-	int i;
-
-	l = &loopbacks[sock^1];
-	i = l->send & (MAX_LOOPBACK-1);
-	l->send++;
-	memcpy(l->msgs[i].data, data, length);
-	l->msgs[i].datalen = length;
-}
-
-void cninit (void)
-{
-	if(cnroot != nil)
-		return;
-	if((cnroot = malloc(sizeof *cnroot)) == nil)
-		sysfatal("cninit:malloc: %r");
-	cnroot->p = cnroot;
-	memset(cnroot->u, 0, sizeof cnroot->u);
-	memset(cnroot->addr, 0, sizeof cnroot->addr);
-	cnroot->dfd = -1;
-}
-
-Conlist *cnins (int fd, char *addr, uchar *u, Udphdr *h, int src)
-{
-	Conlist *p, *l;
-
-	l = cnroot;
-	if((p = malloc(sizeof *p)) == nil)
-		sysfatal("cnins:malloc: %r");
-
-	strncpy(p->addr, addr, sizeof p->addr);
-	memcpy(p->u, u, sizeof p->u);
-	p->dfd = fd;
-	if(h != nil)
-		memcpy(&p->h, h, sizeof p->h);
-	p->src = src;
-	p->p = l->p;
-	l->p = p;
-	return p;
-}
-
-Conlist *cnfind (char *raddr)
-{
-	Conlist *p = cnroot->p;
-
-	while(p != cnroot){
-		if(!strncmp(p->addr, raddr, strlen(p->addr)))
-			return p;
-		p = p->p;
-	}
-	return nil;
-}
-
-void cndel (Conlist *p)
-{
-	Conlist *l = cnroot;
-
-	while(l->p != p){
-		l = l->p;
-		if(l == cnroot)
-			sysfatal("cndel: bad unlink: cnroot 0x%p node 0x%p\n", cnroot, p);
-	}
-	l->p = p->p;
-	if(p->dfd != ufd && p->dfd != cldfd && p->dfd != -1)
-		close(p->dfd);
-	free(p);
-}
-
-void cnnuke (void)
-{
-	Conlist *p, *l = cnroot;
-
-	if(cnroot == nil)
-		return;
-	do{
-		p = l;
-		l = l->p;
-		if(p->dfd != -1)
-			close(p->dfd);
-		free(p);
-	}while(l != cnroot);
-	cnroot = nil;
-}
-
-void dproc (void *me)
-{
-	int n, fd;
-	Conmsg m;
-	Conlist *p;
-	Channel *c;
-
-	if(threadsetgrp(DTHGRP) < 0)
-		sysfatal("dproc:threadsetgrp: %r");
-
-	m.p = p = me;
-	c = p->src == NS_CLIENT ? clchan : udpchan;
-	fd = p->dfd;
-
-	for(;;){
-		if((n = read(fd, m.buf, sizeof m.buf)) <= 0)
-			break;
-		m.n = n;
-		if(send(c, &m) < 0)
-			sysfatal("uproc:send: %r\n");
-	}
-	fprint(2, "dproc %d: %r\n", threadpid(threadid()));
-	cndel(me);
-}
-
-void uproc (void *c)
-{
-	int n, fd;
-	uchar udpbuf[BUFSZ+HDRSZ], u[IPaddrlen+2];
-	char a[IPaddrlen*2+8+6];
-	Udphdr h;
-	Conmsg m;
-	Conlist *p;
-
-	if(threadsetgrp(DTHGRP) < 0)
-		sysfatal("uproc:threadsetgrp: %r");
-
-	fd = ufd;
-	if(c == clchan)
-		fd = cldfd;
-	for(;;){
-		if((n = read(fd, udpbuf, sizeof udpbuf)) <= 0)
-			sysfatal("uproc:read: %r\n");
-		memcpy(&h, udpbuf, HDRSZ);
-
-		memcpy(u, h.raddr, IPaddrlen);
-		memcpy(u+IPaddrlen, h.rport, 2);
-		snprint(a, sizeof a, "%ud.%ud.%ud.%ud:%hud", u[12], u[13], u[14], u[15], u[16]<<8 | u[17]);
-		qlock(&cnlock);
-		if((p = cnfind(a)) == nil)
-			p = cnins(fd, a, u, &h, 0);
-		qunlock(&cnlock);
-		m.p = p;
-
-		if(n - HDRSZ < 0){	/* FIXME */
-			m.n = n;
-			memcpy(m.buf, udpbuf, m.n);
-		}else{
-			m.n = n - HDRSZ;
-			memcpy(m.buf, udpbuf+HDRSZ, m.n);
-		}
-		if(send(c, &m) < 0)
-			sysfatal("uproc:send: %r\n");
-	}
-}
-
-qboolean NET_GetPacket (netsrc_t src, netadr_t *from, sizebuf_t *d)
-{
-	int n;
-	Conmsg m;
-
-	if(looprecv(src, from, d))
-		return true;
-	if(cfd == -1)
-		return false;
-
-	if((n = nbrecv(src == NS_SERVER ? udpchan : clchan, &m)) < 0)
-		sysfatal("NET_GetPacket:nbrecv: %r");
-	if(n == 0)
-		return false;
-
-	memcpy(from->ip, m.p->u+12, 4);
-	from->port = m.p->u[17] << 8 | m.p->u[16];
-	if(m.n == d->maxsize){
-		Com_Printf("Oversize packet from %s\n", NET_AdrToString(*from));
-		return false;
-	}
-	from->type = NA_IP;
-	d->cursize = m.n;
-	memcpy(d->data, m.buf, m.n);
-	return true;
-}
-
-void NET_SendPacket (netsrc_t src, int length, void *data, netadr_t to)
-{
-	int fd;
-	char *addr, *s, *lport;
-	uchar b[BUFSZ+HDRSZ], u[IPaddrlen+2];
-	Conlist *p;
-
-	switch(to.type){
-	case NA_LOOPBACK:
-		loopsend(src, length, data, to);
-		break;
-	case NA_BROADCAST_IPX:
-	case NA_IPX:
-		break;
-	case NA_BROADCAST:
-		memset(to.ip, 0xff, 4);
-		addr = NET_AdrToString(to);	/* port is PORT_SERVER */
-		s = strrchr(addr, ':');
-		*s++ = '\0';
-		if((fd = dial(netmkaddr(addr, "udp", s), clsrv, nil, nil)) < 0)
-			sysfatal("NET_SendPacket:dial bcast: %r");
-		if(write(fd, data, length) != length)
-			sysfatal("NET_SendPacket:write bcast: %r");
-		close(fd);
-		break;
-	case NA_IP:
-		if(cfd == -1)
-			break;
-
-		addr = NET_AdrToString(to);
-		qlock(&cnlock);
-		p = cnfind(addr);
-		qunlock(&cnlock);
-		if(p != nil){
-			fd = p->dfd;
-			if(fd == ufd || fd == cldfd){
-				memcpy(b, &p->h, HDRSZ);
-				memcpy(b+HDRSZ, data, length);
-				write(fd, b, length+HDRSZ);
-				break;
-			}
-		}else{
-			lport = strrchr(addr, ':');
-			*lport++ = '\0';
-			s = netmkaddr(addr, "udp", lport);
-			if((fd = dial(s, srv, nil, nil)) < 0)
-				sysfatal("NET_SendPacket:dial: %r");
-
-			memcpy(u, v4prefix, sizeof v4prefix);
-			memcpy(u+IPv4off, to.ip, IPv4addrlen);
-			u[16] = to.port;
-			u[17] = to.port >> 8;
-			*(lport-1) = ':';
-			qlock(&cnlock);
-			p = cnins(fd, addr, u, nil, src);
-			qunlock(&cnlock);
-
-			if(proccreate(dproc, p, 8196) < 0)
-				sysfatal("NET_SendPacket:proccreate: %r");
-		}
-		if(write(fd, data, length) != length)
-			sysfatal("NET_SendPacket:write: %r");
-		break;
-	default:
-		Com_Error(ERR_FATAL, "NET_SendPacket: bad address type");
-	}
-}
-
-/* sleeps msec or until data is read from dfd */
-void NET_Sleep (int msec)
-{
-	if(cfd == -1 || dedicated != nil && !dedicated->value)
-		return; // we're not a server, just run full speed
-
-	/* FIXME */
-	print("NET_Sleep %d: PORTME\n", msec);
-}
-
-int openname (char *port, int *dfd, Channel **c)
-{
-	int fd;
-	char data[64], adir[40];
-
-	if((fd = announce(netmkaddr("*", "udp", port), adir)) < 0)
-		sysfatal("openname:announce udp!*!%s: %r", port);
-	if(fprint(fd, "headers") < 0)
-		sysfatal("openname: failed to set header mode: %r");
-	snprint(data, sizeof data, "%s/data", adir);
-	if((*dfd = open(data, ORDWR)) < 0)
-		sysfatal("openname:open %r");
-	if((*c = chancreate(sizeof(Conmsg), NBUF)) == nil)
-		sysfatal("openname:chancreate: %r");
-	if(proccreate(uproc, *c, 8196) < 0)
-		sysfatal("openname:proccreate: %r");
-	return fd;
-}
-
-void openudp (void)
-{
-	if(cfd != -1)
-		return;
-
-	/* svport value can be changed at any time */
-	if(svport->value == PORT_ANY || svport->value > 32767)
-		/* FIXME */
-		strncpy(srv, "*", sizeof(srv)-1);
-	else
-		strncpy(srv, svport->string, sizeof(srv)-1);
-	cfd = openname(srv, &ufd, &udpchan);
-
-	/* broadcast kluge */
-	if(clport->value == PORT_ANY || clport->value > 32767)
-		strncpy(clsrv, "*", sizeof(clsrv)-1);
-	else
-		strncpy(clsrv, clport->string, sizeof(clsrv)-1);
-	clfd = openname(clsrv, &cldfd, &clchan);
-}
-
-/* a single player game will only use the loopback code */
-void NET_Config (qboolean multiplayer)
-{
-	if(!multiplayer){	/* shut down existing udp connections */
-		threadkillgrp(DTHGRP);
-		cnnuke();
-		if(udpchan != nil){
-			chanfree(udpchan);
-			udpchan = nil;
-		}
-		if(clchan != nil){
-			chanfree(clchan);
-			clchan = nil;
-		}
-		if(cfd != -1){
-			close(cfd);
-			cfd = -1;
-		}
-		if(clfd != -1){
-			close(clfd);
-			clfd = -1;
-		}
-		if(ufd != -1){
-			close(ufd);
-			ufd = -1;
-		}
-		if(cldfd != -1){
-			close(cldfd);
-			cldfd = -1;
-		}
-	}else{			/* announce open line and get cfd for it */
-		cninit();
-		openudp();
-	}
-}
-
-void NET_Shutdown (void)
-{
-	NET_Config(false);
-}
-
-void NET_Init (void)
-{
-	svport = Cvar_Get("port", va("%d", PORT_SERVER), CVAR_NOSET);
-	clport = Cvar_Get("clport", va("%hud", CLPORT), CVAR_NOSET);
-}
--- a/plan9/q_sh9.c
+++ /dev/null
@@ -1,307 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-byte *membase;
-int maxhunksize;
-int curhunksize;
-int curtime;
-char findbase[MAX_OSPATH], findpath[MAX_OSPATH], findpattern[MAX_OSPATH];
-long dirn, di;
-Dir *dirs;
-
-int	glob_match(char *, char *);
-
-
-/* Like glob_match, but match PATTERN against any final segment of TEXT.  */
-int glob_match_after_star(char *pattern, char *text)
-{
-	char *p = pattern, *t = text;
-	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.  */
-int glob_pattern_p(char *pattern)
-{
-	char *p = pattern;
-	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)
-{
-	char *p = pattern, *t = text;
-	char c, c1, cstart, cend;
-	int invert;
-
-	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 '[':
-			{
-				c1 = *t++;
-
-				if (!c1)
-					return (0);
-
-				invert = ((*p == '!') || (*p == '^'));
-				if (invert)
-					p++;
-
-				c = *p++;
-				while (1) {
-					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;
-		}
-
-	/* if the pattern is empty, Sys_FindNext looks at the current file anyway */
-	return *t == '\0';
-}
-
-void *Hunk_Begin (int maxsize)
-{
-	// reserve a huge chunk of memory, but don't commit any yet
-	maxhunksize = maxsize;
-	curhunksize = 0;
-	if((membase = mallocz(maxhunksize, 1)) == nil)
-		sysfatal("Hunk_Begin:malloc %d: %r", maxhunksize);
-	return membase;
-}
-
-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 + curhunksize;
-	curhunksize += size;
-	return buf;
-}
-
-int Hunk_End (void)
-{
-	if(realloc(membase, curhunksize) != membase)
-		sysfatal("Hunk_End:realloc: %r");
-	return curhunksize;
-}
-
-void Hunk_Free (void *base)
-{
-	if(base != nil)
-		free(base);
-}
-
-int Sys_Milliseconds (void)
-{
-	static long msbase;
-
-	if(msbase == 0)
-		msbase = time(nil)*1000;
-	curtime = nsec()/1000000 - msbase;
-	return curtime;
-}
-
-void Sys_Mkdir (char *path)
-{
-	int d;
-
-	if((d = create(path, OREAD, DMDIR|0777)) < 0)
-		fprint(2, "Sys_mkdir:create: %r\n");
-	else
-		close(d);
-}
-
-qboolean CompareAttributes (ulong m, uint musthave, uint canthave)
-{
-	if(m & DMDIR && canthave & SFF_SUBDIR)
-		return false;
-	if(musthave & SFF_SUBDIR && ~m & DMDIR)
-		return false;
-	return true;
-}
-
-char *Sys_FindFirst (char *path, uint musthave, uint canhave)
-{
-	char *p;
-	int fd;
-
-	if(dirs != nil)
-		Sys_Error("Sys_BeginFind without close");
-
-	strncpy(findbase, path, sizeof findbase-1);
-	if((p = strrchr(findbase, '/')) != nil){
-		*p = 0;
-		strncpy(findpattern, p+1, sizeof findpattern-1);
-	}else
-		strcpy(findpattern, "*");
-	if(strcmp(findpattern, "*.*") == 0)
-		strcpy(findpattern, "*");
-	if(*findpattern == '\0'){
-		Com_Printf("Sys_BeginFind: empty pattern\n");
-		return nil;
-	}
-
-	if((fd = open(findbase, OREAD)) < 0){
-		fprint(2, "Sys_BeginFind:open: %r\n");
-		return nil;
-	}
-	dirn = dirreadall(fd, &dirs);
-	close(fd);
-	if(dirn == 0)
-		return nil;
-	if(dirn < 0){
-		fprint(2, "Sys_BeginFind:dirread: %r\n");
-		return nil;
-	}
-
-	di = 0;
-	return Sys_FindNext (musthave, canhave);
-}
-
-char *Sys_FindNext (uint musthave, uint canhave)
-{
-	int i;
-
-	if(dirs == nil)
-		Sys_Error("Sys_FindNext without open\n");
-
-	while(di < dirn){
-		i = di++;
-		if(glob_match(findpattern, dirs[i].name)){
-			if(CompareAttributes(dirs[i].mode, musthave, canhave)){
-				snprintf(findpath, sizeof findpath, "%s/%s", findbase, dirs[i].name);
-				return findpath;
-			}
-		}
-	}
-	return nil;
-}
-
-void Sys_FindClose (void)
-{
-	if(dirs != nil){
-		free(dirs);
-		dirs = nil;
-	}
-}
--- a/plan9/rw_9.c
+++ /dev/null
@@ -1,173 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <stdio.h>
-#include <ctype.h>
-#include "../q_shared.h"
-
-qboolean rwon;
-uchar *framebuf;
-Image *fbim;
-int resized;
-Point center;
-
-typedef ulong PIXEL;
-PIXEL st2d_8to24table[256];
-int shiftmask_fl;
-int r_shift, g_shift, b_shift;
-uint r_mask, g_mask, b_mask;
-
-
-void shiftmask_init (void)
-{
-	uint x;
-
-	r_mask = 0xff0000;
-	g_mask = 0xff00;
-	b_mask = 0xff;
-	for(r_shift = -8, x = 1; x < r_mask; x <<= 1)
-		r_shift++;
-	for(g_shift = -8, x = 1; x < g_mask; x <<= 1)
-		g_shift++;
-	for(b_shift = -8, x = 1; x < b_mask; x <<= 1)
-		b_shift++;
-	shiftmask_fl = 1;
-}
-
-PIXEL rgb24 (int r, int g, int b)
-{
-	PIXEL p = 0;
-
-	if(shiftmask_fl == 0)
-		shiftmask_init();
-
-	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 st3_fixup (void)
-{
-	int x, y;
-	uchar *src;
-	PIXEL *dest;
-
-	for(y = 0; y < vid.height; y++){
-		src = &framebuf[y*vid.rowbytes];
-		dest = (PIXEL*)src;
-
-		/* vid.width % 8 not always 0
-		for(x = vid.width-1; x >= 0; x -= 8) {
-			dest[x  ] = st2d_8to24table[src[x  ]];
-			dest[x-1] = st2d_8to24table[src[x-1]];
-			dest[x-2] = st2d_8to24table[src[x-2]];
-			dest[x-3] = st2d_8to24table[src[x-3]];
-			dest[x-4] = st2d_8to24table[src[x-4]];
-			dest[x-5] = st2d_8to24table[src[x-5]];
-			dest[x-6] = st2d_8to24table[src[x-6]];
-			dest[x-7] = st2d_8to24table[src[x-7]];
-		}
-		*/
-
-		for(x = vid.width-1; x >= 0; x--)
-			dest[x] = st2d_8to24table[src[x]];
-	}
-}
-
-void resetfb (void)
-{
-	vid.width = Dx(screen->r);
-	vid.height = Dy(screen->r);
-	if(framebuf != nil){
-		free(framebuf);
-		framebuf = nil;
-	}
-	if(fbim != nil){
-		freeimage(fbim);
-		fbim = nil;
-	}
-	if((framebuf = malloc(sizeof *framebuf * vid.width * vid.height * screen->depth/8)) == nil)
-		sysfatal("resetfb:malloc: %r");
-	if((fbim = allocimage(display, Rect(0, 0, vid.width, vid.height), screen->chan, 1, DNofill)) == nil)
-		sysfatal("resetfb: %r");
-	vid.buffer = framebuf;
-	vid.rowbytes = vid.width * screen->depth/8;
-	center = addpt(screen->r.min, Pt(vid.width/2, vid.height/2));
-	sw_mode->modified = true;	/* make ref_soft refresh its shit */
-}
-
-int SWimp_Init (void */*hInstance*/, void */*wndProc*/)
-{
-	srand(getpid());
-
-	if(initdraw(nil, nil, "quake2") < 0)
-		sysfatal("VID_Init:initdraw: %r\n");
-	resetfb();
-	rwon = true;
-	return true;
-}
-
-/* copy backbuffer to front buffer */
-void SWimp_EndFrame (void)
-{
-	if(resized){		/* skip frame if window resizes */
-		resized = 0;
-		if(getwindow(display, Refnone) < 0)
-			sysfatal("SWimp_EndFrame:getwindow: %r\n");
-		resetfb();
-		return;
-	}
-	st3_fixup();
-	loadimage(fbim, fbim->r, framebuf, vid.height * vid.rowbytes);
-	draw(screen, screen->r, fbim, nil, ZP);
-	flushimage(display, 1);
-}
-
-rserr_t SWimp_SetMode (int */*pwidth*/, int */*pheight*/, int /*mode*/, qboolean /*fullscreen*/)
-{
-	return rserr_ok;
-}
-
-/* nil palette == use existing; palette is expected to be in padded 4-byte xRGB format */
-void SWimp_SetPalette (uchar *palette)
-{
-	int i;
-
-	if(!rwon)
-		return;
-	if(!palette)
-        	palette = (uchar *)sw_state.currentpalette;
-	for(i = 0; i < 256; i++)
-		st2d_8to24table[i] = rgb24(palette[i*4], palette[i*4+1], palette[i*4+2]);
-}
-
-void SWimp_Shutdown (void)
-{
-	if(!rwon)
-		return;
-	if(framebuf != nil)
-		free(framebuf);
-	if(fbim != nil)
-		freeimage(fbim);
-	rwon = false;
-}
-
-void SWimp_AppActivate (qboolean /*active*/)
-{
-}
--- /dev/null
+++ b/plan9/snd.c
@@ -1,0 +1,121 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include <thread.h>
+#include "../q_shared.h"
+
+int sndon;
+
+enum{
+	Nbuf	= 32
+};
+int audio_fd;
+int wpos;
+int stid = -1;
+Channel *schan;
+
+cvar_t *sndbits;
+cvar_t *sndspeed;
+cvar_t *sndchannels;
+cvar_t *snddevice;
+
+
+void sproc (void *)
+{
+	int n;
+
+	for(;;){
+		if(recv(schan, nil) < 0){
+			fprint(2, "sproc:recv %r\n");
+			break;
+		}
+		if((n = write(audio_fd, dma.buffer, dma.samplebits/8 * dma.samples)) < 0){
+			fprint(2, "sproc:write %r\n");
+			break;
+		}
+		wpos += n;
+	}
+	stid = -1;
+}
+
+qboolean SNDDMA_Init(void)
+{
+	if(sndon)
+		return false;
+
+	if(COM_CheckParm("-nosound"))
+		return false;
+
+	if(!snddevice){
+		sndbits = Cvar_Get("sndbits", "16", CVAR_ARCHIVE);
+		sndspeed = Cvar_Get("sndspeed", "44100", CVAR_ARCHIVE);
+		sndchannels = Cvar_Get("sndchannels", "2", CVAR_ARCHIVE);
+		snddevice = Cvar_Get("snddevice", "/dev/audio", CVAR_ARCHIVE);
+	}
+
+	if((audio_fd = open(snddevice->string, OWRITE)) < 0){
+		fprint(2, "SNDDMA_Init:open %r\n");
+		return false;
+	}
+
+	dma.samplebits = (int)sndbits->value;
+	if(dma.samplebits != 16 && dma.samplebits != 8)
+		dma.samplebits = 16;
+	dma.speed = (int)sndspeed->value;
+	if(dma.speed != 44100)
+		dma.speed = 44100;
+	dma.channels = (int)sndchannels->value;
+	if(dma.channels < 1 || dma.channels > 2)
+		dma.channels = 2;
+	dma.samples = 8192;
+	dma.submission_chunk = 1;
+	if((dma.buffer = mallocz(dma.samplebits/8 * dma.samples, 1)) == nil)
+		sysfatal("SNDDMA_Init:mallocz: %r\n");
+	dma.samplepos = 0;
+	sndon = 1;
+
+	schan = chancreate(sizeof(int), Nbuf);
+	if((stid = proccreate(sproc, nil, 8192)) < 0){
+		stid = -1;
+		SNDDMA_Shutdown();
+		sysfatal("SNDDMA_Init:proccreate: %r\n");
+	}
+	return true;
+}
+
+int SNDDMA_GetDMAPos(void)
+{
+	if(!sndon)
+		return 0;
+	dma.samplepos = wpos / (dma.samplebits/8);
+	return dma.samplepos;
+}
+
+void SNDDMA_Shutdown(void)
+{
+	if(!sndon)
+		return;
+	if(stid != -1){
+		threadkill(stid);
+		stid = -1;
+	}
+	if(schan != nil){
+		chanfree(schan);
+		schan = nil;
+	}
+	free(dma.buffer);
+	close(audio_fd);
+	sndon = 0;
+}
+
+void SNDDMA_Submit(void)
+{
+	if(nbsend(schan, nil) < 0){
+		fprint(2, "SNDDMA_Submit:nbsend: %r\n");
+		SNDDMA_Shutdown();
+	}
+}
+
+void SNDDMA_BeginPainting (void)
+{
+}
--- a/plan9/snd_9.c
+++ /dev/null
@@ -1,121 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include <thread.h>
-#include "../q_shared.h"
-
-int sndon;
-
-enum{
-	Nbuf	= 32
-};
-int audio_fd;
-int wpos;
-int stid = -1;
-Channel *schan;
-
-cvar_t *sndbits;
-cvar_t *sndspeed;
-cvar_t *sndchannels;
-cvar_t *snddevice;
-
-
-void sproc (void *)
-{
-	int n;
-
-	for(;;){
-		if(recv(schan, nil) < 0){
-			fprint(2, "sproc:recv %r\n");
-			break;
-		}
-		if((n = write(audio_fd, dma.buffer, dma.samplebits/8 * dma.samples)) < 0){
-			fprint(2, "sproc:write %r\n");
-			break;
-		}
-		wpos += n;
-	}
-	stid = -1;
-}
-
-qboolean SNDDMA_Init(void)
-{
-	if(sndon)
-		return false;
-
-	if(COM_CheckParm("-nosound"))
-		return false;
-
-	if(!snddevice){
-		sndbits = Cvar_Get("sndbits", "16", CVAR_ARCHIVE);
-		sndspeed = Cvar_Get("sndspeed", "44100", CVAR_ARCHIVE);
-		sndchannels = Cvar_Get("sndchannels", "2", CVAR_ARCHIVE);
-		snddevice = Cvar_Get("snddevice", "/dev/audio", CVAR_ARCHIVE);
-	}
-
-	if((audio_fd = open(snddevice->string, OWRITE)) < 0){
-		fprint(2, "SNDDMA_Init:open %r\n");
-		return false;
-	}
-
-	dma.samplebits = (int)sndbits->value;
-	if(dma.samplebits != 16 && dma.samplebits != 8)
-		dma.samplebits = 16;
-	dma.speed = (int)sndspeed->value;
-	if(dma.speed != 44100)
-		dma.speed = 44100;
-	dma.channels = (int)sndchannels->value;
-	if(dma.channels < 1 || dma.channels > 2)
-		dma.channels = 2;
-	dma.samples = 8192;
-	dma.submission_chunk = 1;
-	if((dma.buffer = mallocz(dma.samplebits/8 * dma.samples, 1)) == nil)
-		sysfatal("SNDDMA_Init:mallocz: %r\n");
-	dma.samplepos = 0;
-	sndon = 1;
-
-	schan = chancreate(sizeof(int), Nbuf);
-	if((stid = proccreate(sproc, nil, 8192)) < 0){
-		stid = -1;
-		SNDDMA_Shutdown();
-		sysfatal("SNDDMA_Init:proccreate: %r\n");
-	}
-	return true;
-}
-
-int SNDDMA_GetDMAPos(void)
-{
-	if(!sndon)
-		return 0;
-	dma.samplepos = wpos / (dma.samplebits/8);
-	return dma.samplepos;
-}
-
-void SNDDMA_Shutdown(void)
-{
-	if(!sndon)
-		return;
-	if(stid != -1){
-		threadkill(stid);
-		stid = -1;
-	}
-	if(schan != nil){
-		chanfree(schan);
-		schan = nil;
-	}
-	free(dma.buffer);
-	close(audio_fd);
-	sndon = 0;
-}
-
-void SNDDMA_Submit(void)
-{
-	if(nbsend(schan, nil) < 0){
-		fprint(2, "SNDDMA_Submit:nbsend: %r\n");
-		SNDDMA_Shutdown();
-	}
-}
-
-void SNDDMA_BeginPainting (void)
-{
-}
--- /dev/null
+++ b/plan9/so.c
@@ -1,0 +1,77 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "../q_shared.h"
+
+refexport_t	GetRefAPI(refimport_t);
+
+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;
+refexport_t re;			/* exported functions from refresh DLL */
+
+
+void VID_Printf (int print_level, char *fmt, ...)
+{
+	va_list argptr;
+	char msg[4096];
+	
+	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[4096];
+	
+	va_start(argptr, fmt);
+	vsprintf(msg, fmt, argptr);
+	va_end(argptr);
+	Com_Error(err_level, "%s", msg);
+}
+
+void VID_CheckChanges (void)
+{
+}
+
+void VID_Shutdown (void)
+{
+	re.Shutdown();
+}
+
+void VID_Init (void)
+{
+	refimport_t ri;
+
+	vid_ref = Cvar_Get("vid_ref", "libdraw", 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);
+
+	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_MenuInit = VID_MenuInit;
+
+	re = GetRefAPI(ri);
+	re.Init(nil, nil);
+}
--- /dev/null
+++ b/plan9/sys.c
@@ -1,0 +1,132 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <thread.h>
+#include "../q_shared.h"
+
+mainstacksize = 512*1024;	/* FIXME */
+
+uint sys_frame_time;
+qboolean stdin_active = true;
+
+void KBD_Update(void);
+
+
+/* prints to "debugging console" */
+void Sys_ConsoleOutput (char *string)
+{
+	write(1, string, strlen(string));
+}
+
+void Sys_Quit (void)
+{
+	CL_Shutdown();
+	Qcommon_Shutdown();
+	threadexitsall(nil);
+}
+
+void Sys_Init(void)
+{
+	//Sys_SetFPCW();
+}
+
+void Sys_Error (char *error, ...)
+{ 
+	char buf[1024], *out;
+	va_list arg;
+
+	CL_Shutdown();
+	Qcommon_Shutdown();
+
+	va_start(arg, error);
+	out = vseprint(buf, buf+sizeof(buf), error, arg);
+	va_end(arg);
+	write(2, buf, out-buf);
+	print("\n");
+	sysfatal("ending.");
+}
+
+int Sys_FileTime (char *path)
+{
+	uchar sb[1024];
+
+	if(stat(path, sb, sizeof sb) < 0){
+		fprint(2, "Sys_FileTime:stat: %r\n");
+		return -1;
+	}
+	return *((int *)(sb+25));
+}
+
+char *Sys_ConsoleInput(void)
+{
+	static char text[256];
+	int n;
+
+	if(!dedicated || !dedicated->value || !stdin_active)
+		return nil;
+
+	if((n = read(0, text, sizeof(text))) < 0)
+		return nil;
+	if(n == 0){
+		stdin_active = false;
+		return nil;
+	}
+	text[n-1] = '\0';	/* rip off \n */
+	return text;
+}
+
+void Sys_UnloadGame (void)
+{
+}
+
+void Sys_AppActivate (void)
+{
+}
+
+void Sys_SendKeyEvents (void)
+{
+#ifndef DEDICATED_ONLY
+	KBD_Update();
+#endif
+	sys_frame_time = Sys_Milliseconds();	// grab frame time 
+}
+
+char *Sys_GetClipboardData (void)
+{
+	return nil;
+}
+
+void Sys_CopyProtect (void)
+{
+}
+
+void croak (void *, char *note)
+{
+	if(!strncmp(note, "sys:", 4)){
+		IN_Shutdown();
+		SNDDMA_Shutdown();
+		NET_Shutdown();
+	}
+	noted(NDFLT);
+}
+
+void threadmain (int argc, char *argv[])
+{
+	int time, oldtime, newtime;
+
+	setfcr(getfcr() & ~(FPOVFL|FPUNFL|FPINVAL|FPZDIV));	/* assumed ignored in code */
+	notify(croak);
+
+	Qcommon_Init(argc, argv);
+
+	oldtime = Sys_Milliseconds();
+	for(;;){
+		do{
+			newtime = Sys_Milliseconds();
+			time = newtime - oldtime;
+		}while(time < 1);	// find time spent rendering last frame
+		Qcommon_Frame(time);
+		oldtime = newtime;
+	}
+}
--- a/plan9/sys_9.c
+++ /dev/null
@@ -1,132 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <thread.h>
-#include "../q_shared.h"
-
-mainstacksize = 512*1024;	/* FIXME */
-
-uint sys_frame_time;
-qboolean stdin_active = true;
-
-void KBD_Update(void);
-
-
-/* prints to "debugging console" */
-void Sys_ConsoleOutput (char *string)
-{
-	write(1, string, strlen(string));
-}
-
-void Sys_Quit (void)
-{
-	CL_Shutdown();
-	Qcommon_Shutdown();
-	threadexitsall(nil);
-}
-
-void Sys_Init(void)
-{
-	//Sys_SetFPCW();
-}
-
-void Sys_Error (char *error, ...)
-{ 
-	char buf[1024], *out;
-	va_list arg;
-
-	CL_Shutdown();
-	Qcommon_Shutdown();
-
-	va_start(arg, error);
-	out = vseprint(buf, buf+sizeof(buf), error, arg);
-	va_end(arg);
-	write(2, buf, out-buf);
-	print("\n");
-	sysfatal("ending.");
-}
-
-int Sys_FileTime (char *path)
-{
-	uchar sb[1024];
-
-	if(stat(path, sb, sizeof sb) < 0){
-		fprint(2, "Sys_FileTime:stat: %r\n");
-		return -1;
-	}
-	return *((int *)(sb+25));
-}
-
-char *Sys_ConsoleInput(void)
-{
-	static char text[256];
-	int n;
-
-	if(!dedicated || !dedicated->value || !stdin_active)
-		return nil;
-
-	if((n = read(0, text, sizeof(text))) < 0)
-		return nil;
-	if(n == 0){
-		stdin_active = false;
-		return nil;
-	}
-	text[n-1] = '\0';	/* rip off \n */
-	return text;
-}
-
-void Sys_UnloadGame (void)
-{
-}
-
-void Sys_AppActivate (void)
-{
-}
-
-void Sys_SendKeyEvents (void)
-{
-#ifndef DEDICATED_ONLY
-	KBD_Update();
-#endif
-	sys_frame_time = Sys_Milliseconds();	// grab frame time 
-}
-
-char *Sys_GetClipboardData (void)
-{
-	return nil;
-}
-
-void Sys_CopyProtect (void)
-{
-}
-
-void croak (void *, char *note)
-{
-	if(!strncmp(note, "sys:", 4)){
-		IN_Shutdown();
-		SNDDMA_Shutdown();
-		NET_Shutdown();
-	}
-	noted(NDFLT);
-}
-
-void threadmain (int argc, char *argv[])
-{
-	int time, oldtime, newtime;
-
-	setfcr(getfcr() & ~(FPOVFL|FPUNFL|FPINVAL|FPZDIV));	/* assumed ignored in code */
-	notify(croak);
-
-	Qcommon_Init(argc, argv);
-
-	oldtime = Sys_Milliseconds();
-	for(;;){
-		do{
-			newtime = Sys_Milliseconds();
-			time = newtime - oldtime;
-		}while(time < 1);	// find time spent rendering last frame
-		Qcommon_Frame(time);
-		oldtime = newtime;
-	}
-}
--- /dev/null
+++ b/plan9/udp.c
@@ -1,0 +1,523 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include <thread.h>
+#include <bio.h>
+#include <ndb.h>
+#include <ip.h>
+#include "../q_shared.h"
+
+/* FIXME: this shit SUCKS, and ipv4 only because of other code */
+
+cvar_t	*svport;	/* server port and copy of string value */
+char	srv[6];
+cvar_t	*clport;	/* "client" port and copy */
+char	clsrv[6];
+
+typedef struct Loopmsg Loopmsg;
+typedef struct Loopback Loopback;
+typedef struct Conmsg Conmsg;
+typedef struct Conlist Conlist;
+
+enum{
+	MAX_LOOPBACK	= 4,
+	HDRSZ		= 16+16+16+2+2,	/* sizeof Udphdr w/o padding */
+	BUFSZ		= MAX_MSGLEN,
+	NBUF		= 64,
+	DTHGRP		= 1,
+	CLPORT		= 27909
+};
+struct Loopmsg{
+	byte	data[MAX_MSGLEN];
+	int	datalen;
+};
+struct Loopback{
+	Loopmsg	msgs[MAX_LOOPBACK];
+	int	get;
+	int	send;
+};
+Loopback	loopbacks[2];
+
+struct Conlist{
+	Conlist *p;
+	uchar	u[IPaddrlen+2];
+	char	addr[IPaddrlen*2+8+6];	/* ipv6 + separators + port in decimal */
+	int	dfd;
+	Udphdr	h;
+	int	src;	/* q2 assumes broadcast replies are received on NS_CLIENT */
+};
+Conlist *cnroot;
+
+struct Conmsg{
+	Conlist *p;
+	int	n;
+	uchar	buf[BUFSZ];
+};
+Channel *udpchan;
+Channel *clchan;
+
+netadr_t laddr;		/* 0.0.0.0:0 */
+int cfd = -1, ufd = -1, clfd = -1, cldfd = -1;
+QLock cnlock;
+
+
+qboolean NET_CompareAdr (netadr_t a, netadr_t b)
+{
+	return (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);
+}
+
+/* compares without the port */
+qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b)
+{
+	if(a.type != b.type)
+		return false;
+	switch(a.type){
+	case NA_LOOPBACK:
+		return true;
+	case NA_IP:
+		return (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3]);
+	case NA_IPX:
+		return !memcmp(a.ipx, b.ipx, 10);
+	default:
+		return false;
+	}
+}
+
+char *NET_AdrToString (netadr_t a)
+{
+	static char s[256];
+
+	seprint(s, s+sizeof s, "%ud.%ud.%ud.%ud:%hud", a.ip[0], a.ip[1], a.ip[2], a.ip[3], BigShort(a.port));
+	return s;
+}
+
+char *NET_BaseAdrToString (netadr_t a)
+{
+	static char s[256];
+
+	seprint(s, s+sizeof s, "%ud.%ud.%ud.%ud", 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_StringToAdr (char *addr, netadr_t *a)		/* assumes IPv4 */
+{
+	int i;
+	char s[256], *p, *pp;
+	Ndb *db;
+	Ndbtuple *nt;
+
+	if(!strcmp(addr, "localhost")){
+		memset(a, 0, sizeof *a);
+		a->type = NA_LOOPBACK;
+		return true;
+	}
+
+	strncpy(s, addr, sizeof s);
+	s[sizeof(s)-1] = 0;
+
+	if((p = strrchr(s, ':')) != nil){
+		*p++ = '\0';
+		a->port = BigShort(atoi(p));
+	}
+
+	if((db = ndbopen(nil)) == nil){
+		fprint(2, "NET_StringToAdr:ndbopen: %r\n");
+		return false;
+	}
+	if((nt = ndbgetipaddr(db, s)) == nil){
+		ndbclose(db);
+		fprint(2, "NET_StringToAdr:ndbgetipaddr: %r\n");
+		return false;
+	}
+	strncpy(s, nt->val, sizeof(s)-1);	/* just look at first value found */
+	ndbfree(nt);
+	ndbclose(db);
+
+	for(i = 0, pp = s; i < IPv4addrlen; i++){
+		if((p = strchr(pp, '.')) != nil)
+			*p++ = '\0';
+		a->ip[i] = atoi(pp);
+		pp = p;
+	}
+	a->type = NA_IP;
+	return true;
+}
+
+qboolean NET_IsLocalAddress (netadr_t adr)
+{
+	return NET_CompareAdr(adr, laddr);
+}
+
+qboolean looprecv (netsrc_t sock, netadr_t *net_from, sizebuf_t *d)
+{
+	int i;
+	Loopback *l;
+
+	l = &loopbacks[sock];
+	if(l->send - l->get > MAX_LOOPBACK)
+		l->get = l->send - MAX_LOOPBACK;
+	if(l->get >= l->send)
+		return false;
+	i = l->get & (MAX_LOOPBACK-1);
+	l->get++;
+
+	memcpy(d->data, l->msgs[i].data, l->msgs[i].datalen);
+	d->cursize = l->msgs[i].datalen;
+	*net_from = laddr;
+	return true;
+}
+
+void loopsend (netsrc_t sock, int length, void *data, netadr_t /*to*/)
+{
+	Loopback *l;
+	int i;
+
+	l = &loopbacks[sock^1];
+	i = l->send & (MAX_LOOPBACK-1);
+	l->send++;
+	memcpy(l->msgs[i].data, data, length);
+	l->msgs[i].datalen = length;
+}
+
+void cninit (void)
+{
+	if(cnroot != nil)
+		return;
+	if((cnroot = malloc(sizeof *cnroot)) == nil)
+		sysfatal("cninit:malloc: %r");
+	cnroot->p = cnroot;
+	memset(cnroot->u, 0, sizeof cnroot->u);
+	memset(cnroot->addr, 0, sizeof cnroot->addr);
+	cnroot->dfd = -1;
+}
+
+Conlist *cnins (int fd, char *addr, uchar *u, Udphdr *h, int src)
+{
+	Conlist *p, *l;
+
+	l = cnroot;
+	if((p = malloc(sizeof *p)) == nil)
+		sysfatal("cnins:malloc: %r");
+
+	strncpy(p->addr, addr, sizeof p->addr);
+	memcpy(p->u, u, sizeof p->u);
+	p->dfd = fd;
+	if(h != nil)
+		memcpy(&p->h, h, sizeof p->h);
+	p->src = src;
+	p->p = l->p;
+	l->p = p;
+	return p;
+}
+
+Conlist *cnfind (char *raddr)
+{
+	Conlist *p = cnroot->p;
+
+	while(p != cnroot){
+		if(!strncmp(p->addr, raddr, strlen(p->addr)))
+			return p;
+		p = p->p;
+	}
+	return nil;
+}
+
+void cndel (Conlist *p)
+{
+	Conlist *l = cnroot;
+
+	while(l->p != p){
+		l = l->p;
+		if(l == cnroot)
+			sysfatal("cndel: bad unlink: cnroot 0x%p node 0x%p\n", cnroot, p);
+	}
+	l->p = p->p;
+	if(p->dfd != ufd && p->dfd != cldfd && p->dfd != -1)
+		close(p->dfd);
+	free(p);
+}
+
+void cnnuke (void)
+{
+	Conlist *p, *l = cnroot;
+
+	if(cnroot == nil)
+		return;
+	do{
+		p = l;
+		l = l->p;
+		if(p->dfd != -1)
+			close(p->dfd);
+		free(p);
+	}while(l != cnroot);
+	cnroot = nil;
+}
+
+void dproc (void *me)
+{
+	int n, fd;
+	Conmsg m;
+	Conlist *p;
+	Channel *c;
+
+	if(threadsetgrp(DTHGRP) < 0)
+		sysfatal("dproc:threadsetgrp: %r");
+
+	m.p = p = me;
+	c = p->src == NS_CLIENT ? clchan : udpchan;
+	fd = p->dfd;
+
+	for(;;){
+		if((n = read(fd, m.buf, sizeof m.buf)) <= 0)
+			break;
+		m.n = n;
+		if(send(c, &m) < 0)
+			sysfatal("uproc:send: %r\n");
+	}
+	fprint(2, "dproc %d: %r\n", threadpid(threadid()));
+	cndel(me);
+}
+
+void uproc (void *c)
+{
+	int n, fd;
+	uchar udpbuf[BUFSZ+HDRSZ], u[IPaddrlen+2];
+	char a[IPaddrlen*2+8+6];
+	Udphdr h;
+	Conmsg m;
+	Conlist *p;
+
+	if(threadsetgrp(DTHGRP) < 0)
+		sysfatal("uproc:threadsetgrp: %r");
+
+	fd = ufd;
+	if(c == clchan)
+		fd = cldfd;
+	for(;;){
+		if((n = read(fd, udpbuf, sizeof udpbuf)) <= 0)
+			sysfatal("uproc:read: %r\n");
+		memcpy(&h, udpbuf, HDRSZ);
+
+		memcpy(u, h.raddr, IPaddrlen);
+		memcpy(u+IPaddrlen, h.rport, 2);
+		snprint(a, sizeof a, "%ud.%ud.%ud.%ud:%hud", u[12], u[13], u[14], u[15], u[16]<<8 | u[17]);
+		qlock(&cnlock);
+		if((p = cnfind(a)) == nil)
+			p = cnins(fd, a, u, &h, 0);
+		qunlock(&cnlock);
+		m.p = p;
+
+		if(n - HDRSZ < 0){	/* FIXME */
+			m.n = n;
+			memcpy(m.buf, udpbuf, m.n);
+		}else{
+			m.n = n - HDRSZ;
+			memcpy(m.buf, udpbuf+HDRSZ, m.n);
+		}
+		if(send(c, &m) < 0)
+			sysfatal("uproc:send: %r\n");
+	}
+}
+
+qboolean NET_GetPacket (netsrc_t src, netadr_t *from, sizebuf_t *d)
+{
+	int n;
+	Conmsg m;
+
+	if(looprecv(src, from, d))
+		return true;
+	if(cfd == -1)
+		return false;
+
+	if((n = nbrecv(src == NS_SERVER ? udpchan : clchan, &m)) < 0)
+		sysfatal("NET_GetPacket:nbrecv: %r");
+	if(n == 0)
+		return false;
+
+	memcpy(from->ip, m.p->u+12, 4);
+	from->port = m.p->u[17] << 8 | m.p->u[16];
+	if(m.n == d->maxsize){
+		Com_Printf("Oversize packet from %s\n", NET_AdrToString(*from));
+		return false;
+	}
+	from->type = NA_IP;
+	d->cursize = m.n;
+	memcpy(d->data, m.buf, m.n);
+	return true;
+}
+
+void NET_SendPacket (netsrc_t src, int length, void *data, netadr_t to)
+{
+	int fd;
+	char *addr, *s, *lport;
+	uchar b[BUFSZ+HDRSZ], u[IPaddrlen+2];
+	Conlist *p;
+
+	switch(to.type){
+	case NA_LOOPBACK:
+		loopsend(src, length, data, to);
+		break;
+	case NA_BROADCAST_IPX:
+	case NA_IPX:
+		break;
+	case NA_BROADCAST:
+		memset(to.ip, 0xff, 4);
+		addr = NET_AdrToString(to);	/* port is PORT_SERVER */
+		s = strrchr(addr, ':');
+		*s++ = '\0';
+		if((fd = dial(netmkaddr(addr, "udp", s), clsrv, nil, nil)) < 0)
+			sysfatal("NET_SendPacket:dial bcast: %r");
+		if(write(fd, data, length) != length)
+			sysfatal("NET_SendPacket:write bcast: %r");
+		close(fd);
+		break;
+	case NA_IP:
+		if(cfd == -1)
+			break;
+
+		addr = NET_AdrToString(to);
+		qlock(&cnlock);
+		p = cnfind(addr);
+		qunlock(&cnlock);
+		if(p != nil){
+			fd = p->dfd;
+			if(fd == ufd || fd == cldfd){
+				memcpy(b, &p->h, HDRSZ);
+				memcpy(b+HDRSZ, data, length);
+				write(fd, b, length+HDRSZ);
+				break;
+			}
+		}else{
+			lport = strrchr(addr, ':');
+			*lport++ = '\0';
+			s = netmkaddr(addr, "udp", lport);
+			if((fd = dial(s, srv, nil, nil)) < 0)
+				sysfatal("NET_SendPacket:dial: %r");
+
+			memcpy(u, v4prefix, sizeof v4prefix);
+			memcpy(u+IPv4off, to.ip, IPv4addrlen);
+			u[16] = to.port;
+			u[17] = to.port >> 8;
+			*(lport-1) = ':';
+			qlock(&cnlock);
+			p = cnins(fd, addr, u, nil, src);
+			qunlock(&cnlock);
+
+			if(proccreate(dproc, p, 8196) < 0)
+				sysfatal("NET_SendPacket:proccreate: %r");
+		}
+		if(write(fd, data, length) != length)
+			sysfatal("NET_SendPacket:write: %r");
+		break;
+	default:
+		Com_Error(ERR_FATAL, "NET_SendPacket: bad address type");
+	}
+}
+
+/* sleeps msec or until data is read from dfd */
+void NET_Sleep (int msec)
+{
+	if(cfd == -1 || dedicated != nil && !dedicated->value)
+		return; // we're not a server, just run full speed
+
+	/* FIXME */
+	print("NET_Sleep %d: PORTME\n", msec);
+}
+
+int openname (char *port, int *dfd, Channel **c)
+{
+	int fd;
+	char data[64], adir[40];
+
+	if((fd = announce(netmkaddr("*", "udp", port), adir)) < 0)
+		sysfatal("openname:announce udp!*!%s: %r", port);
+	if(fprint(fd, "headers") < 0)
+		sysfatal("openname: failed to set header mode: %r");
+	snprint(data, sizeof data, "%s/data", adir);
+	if((*dfd = open(data, ORDWR)) < 0)
+		sysfatal("openname:open %r");
+	if((*c = chancreate(sizeof(Conmsg), NBUF)) == nil)
+		sysfatal("openname:chancreate: %r");
+	if(proccreate(uproc, *c, 8196) < 0)
+		sysfatal("openname:proccreate: %r");
+	return fd;
+}
+
+void openudp (void)
+{
+	if(cfd != -1)
+		return;
+
+	/* svport value can be changed at any time */
+	if(svport->value == PORT_ANY || svport->value > 32767)
+		/* FIXME */
+		strncpy(srv, "*", sizeof(srv)-1);
+	else
+		strncpy(srv, svport->string, sizeof(srv)-1);
+	cfd = openname(srv, &ufd, &udpchan);
+
+	/* broadcast kluge */
+	if(clport->value == PORT_ANY || clport->value > 32767)
+		strncpy(clsrv, "*", sizeof(clsrv)-1);
+	else
+		strncpy(clsrv, clport->string, sizeof(clsrv)-1);
+	clfd = openname(clsrv, &cldfd, &clchan);
+}
+
+/* a single player game will only use the loopback code */
+void NET_Config (qboolean multiplayer)
+{
+	if(!multiplayer){	/* shut down existing udp connections */
+		threadkillgrp(DTHGRP);
+		cnnuke();
+		if(udpchan != nil){
+			chanfree(udpchan);
+			udpchan = nil;
+		}
+		if(clchan != nil){
+			chanfree(clchan);
+			clchan = nil;
+		}
+		if(cfd != -1){
+			close(cfd);
+			cfd = -1;
+		}
+		if(clfd != -1){
+			close(clfd);
+			clfd = -1;
+		}
+		if(ufd != -1){
+			close(ufd);
+			ufd = -1;
+		}
+		if(cldfd != -1){
+			close(cldfd);
+			cldfd = -1;
+		}
+	}else{			/* announce open line and get cfd for it */
+		cninit();
+		openudp();
+	}
+}
+
+void NET_Shutdown (void)
+{
+	NET_Config(false);
+}
+
+void NET_Init (void)
+{
+	svport = Cvar_Get("port", va("%d", PORT_SERVER), CVAR_NOSET);
+	clport = Cvar_Get("clport", va("%hud", CLPORT), CVAR_NOSET);
+}
--- /dev/null
+++ b/plan9/vid.c
@@ -1,0 +1,173 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "../q_shared.h"
+
+qboolean rwon;
+uchar *framebuf;
+Image *fbim;
+int resized;
+Point center;
+
+typedef ulong PIXEL;
+PIXEL st2d_8to24table[256];
+int shiftmask_fl;
+int r_shift, g_shift, b_shift;
+uint r_mask, g_mask, b_mask;
+
+
+void shiftmask_init (void)
+{
+	uint x;
+
+	r_mask = 0xff0000;
+	g_mask = 0xff00;
+	b_mask = 0xff;
+	for(r_shift = -8, x = 1; x < r_mask; x <<= 1)
+		r_shift++;
+	for(g_shift = -8, x = 1; x < g_mask; x <<= 1)
+		g_shift++;
+	for(b_shift = -8, x = 1; x < b_mask; x <<= 1)
+		b_shift++;
+	shiftmask_fl = 1;
+}
+
+PIXEL rgb24 (int r, int g, int b)
+{
+	PIXEL p = 0;
+
+	if(shiftmask_fl == 0)
+		shiftmask_init();
+
+	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 st3_fixup (void)
+{
+	int x, y;
+	uchar *src;
+	PIXEL *dest;
+
+	for(y = 0; y < vid.height; y++){
+		src = &framebuf[y*vid.rowbytes];
+		dest = (PIXEL*)src;
+
+		/* vid.width % 8 not always 0
+		for(x = vid.width-1; x >= 0; x -= 8) {
+			dest[x  ] = st2d_8to24table[src[x  ]];
+			dest[x-1] = st2d_8to24table[src[x-1]];
+			dest[x-2] = st2d_8to24table[src[x-2]];
+			dest[x-3] = st2d_8to24table[src[x-3]];
+			dest[x-4] = st2d_8to24table[src[x-4]];
+			dest[x-5] = st2d_8to24table[src[x-5]];
+			dest[x-6] = st2d_8to24table[src[x-6]];
+			dest[x-7] = st2d_8to24table[src[x-7]];
+		}
+		*/
+
+		for(x = vid.width-1; x >= 0; x--)
+			dest[x] = st2d_8to24table[src[x]];
+	}
+}
+
+void resetfb (void)
+{
+	vid.width = Dx(screen->r);
+	vid.height = Dy(screen->r);
+	if(framebuf != nil){
+		free(framebuf);
+		framebuf = nil;
+	}
+	if(fbim != nil){
+		freeimage(fbim);
+		fbim = nil;
+	}
+	if((framebuf = malloc(sizeof *framebuf * vid.width * vid.height * screen->depth/8)) == nil)
+		sysfatal("resetfb:malloc: %r");
+	if((fbim = allocimage(display, Rect(0, 0, vid.width, vid.height), screen->chan, 1, DNofill)) == nil)
+		sysfatal("resetfb: %r");
+	vid.buffer = framebuf;
+	vid.rowbytes = vid.width * screen->depth/8;
+	center = addpt(screen->r.min, Pt(vid.width/2, vid.height/2));
+	sw_mode->modified = true;	/* make ref_soft refresh its shit */
+}
+
+int SWimp_Init (void */*hInstance*/, void */*wndProc*/)
+{
+	srand(getpid());
+
+	if(initdraw(nil, nil, "quake2") < 0)
+		sysfatal("VID_Init:initdraw: %r\n");
+	resetfb();
+	rwon = true;
+	return true;
+}
+
+/* copy backbuffer to front buffer */
+void SWimp_EndFrame (void)
+{
+	if(resized){		/* skip frame if window resizes */
+		resized = 0;
+		if(getwindow(display, Refnone) < 0)
+			sysfatal("SWimp_EndFrame:getwindow: %r\n");
+		resetfb();
+		return;
+	}
+	st3_fixup();
+	loadimage(fbim, fbim->r, framebuf, vid.height * vid.rowbytes);
+	draw(screen, screen->r, fbim, nil, ZP);
+	flushimage(display, 1);
+}
+
+rserr_t SWimp_SetMode (int */*pwidth*/, int */*pheight*/, int /*mode*/, qboolean /*fullscreen*/)
+{
+	return rserr_ok;
+}
+
+/* nil palette == use existing; palette is expected to be in padded 4-byte xRGB format */
+void SWimp_SetPalette (uchar *palette)
+{
+	int i;
+
+	if(!rwon)
+		return;
+	if(!palette)
+        	palette = (uchar *)sw_state.currentpalette;
+	for(i = 0; i < 256; i++)
+		st2d_8to24table[i] = rgb24(palette[i*4], palette[i*4+1], palette[i*4+2]);
+}
+
+void SWimp_Shutdown (void)
+{
+	if(!rwon)
+		return;
+	if(framebuf != nil)
+		free(framebuf);
+	if(fbim != nil)
+		freeimage(fbim);
+	rwon = false;
+}
+
+void SWimp_AppActivate (qboolean /*active*/)
+{
+}
--- a/plan9/vid_menu.c
+++ /dev/null
@@ -1,137 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-extern cvar_t *vid_fullscreen;
-extern cvar_t *vid_gamma;
-extern cvar_t *scr_viewsize;
-
-extern void M_PopMenu(void);
-
-menuframework_s	vmenu;
-menuslider_s	ssizeslide;
-menuslider_s	gammaslide;
-menulist_s	fullscrbox;
-menuaction_s	applyaction;
-menuaction_s	defaultsaction;
-
-
-void vmssize (void *s)
-{
-	Cvar_SetValue("viewsize", ((menuslider_s *)s)->curvalue * 10);
-}
-
-void vmgamma (void *s)
-{
-	// invert sense so greater = brighter, and scale to a range of 0.5 to 1.3
-	Cvar_SetValue("vid_gamma", 0.8 - (((menuslider_s *)s)->curvalue/10.0 - 0.5) + 0.5);
-}
-
-void vmreset (void *)
-{
-	VID_MenuInit();
-}
-
-void vmapply (void *)
-{
-	Cvar_SetValue("vid_gamma", 0.8 - (gammaslide.curvalue/10.0 - 0.5) + 0.5);
-	Cvar_SetValue("vid_fullscreen", fullscrbox.curvalue);
-	M_ForceMenuOff();
-}
-
-void VID_MenuInit (void)
-{
-	static char *yesno[] = {"no", "yes", nil};
-
-	if(!scr_viewsize)
-		scr_viewsize = Cvar_Get("viewsize", "100", CVAR_ARCHIVE);
-	ssizeslide.curvalue = scr_viewsize->value/10;
-
-	vmenu.x = vid.width * 0.50;
-	vmenu.nitems = 0;
-
-	ssizeslide.generic.type = MTYPE_SLIDER;
-	ssizeslide.generic.x = 0;
-	ssizeslide.generic.y = 20;
-	ssizeslide.generic.name = "screen size";
-	ssizeslide.minvalue = 3;
-	ssizeslide.maxvalue = 12;
-	ssizeslide.generic.callback = vmssize;
-
-	gammaslide.generic.type = MTYPE_SLIDER;
-	gammaslide.generic.x = 0;
-	gammaslide.generic.y = 30;
-	gammaslide.generic.name = "gamma";
-	gammaslide.generic.callback = vmgamma;
-	gammaslide.minvalue = 5;
-	gammaslide.maxvalue = 13;
-	gammaslide.curvalue = (1.3 - vid_gamma->value + 0.5) * 10;
-
-	fullscrbox.generic.type = MTYPE_SPINCONTROL;
-	fullscrbox.generic.x = 0;
-	fullscrbox.generic.y = 40;
-	fullscrbox.generic.name = "fullscreen";
-	fullscrbox.itemnames = yesno;
-	fullscrbox.curvalue = vid_fullscreen->value;
-
-	defaultsaction.generic.type = MTYPE_ACTION;
-	defaultsaction.generic.name = "reset to default";
-	defaultsaction.generic.x = 0;
-	defaultsaction.generic.y = 90;
-	defaultsaction.generic.callback = vmreset;
-
-	applyaction.generic.type = MTYPE_ACTION;
-	applyaction.generic.name = "apply";
-	applyaction.generic.x = 0;
-	applyaction.generic.y = 100;
-	applyaction.generic.callback = vmapply;
-
-	Menu_AddItem(&vmenu, (void *)&ssizeslide);
-	Menu_AddItem(&vmenu, (void *)&gammaslide);
-	Menu_AddItem(&vmenu, (void *)&fullscrbox);
-	Menu_AddItem(&vmenu, (void *)&defaultsaction);
-	Menu_AddItem(&vmenu, (void *)&applyaction);
-
-	Menu_Center(&vmenu);
-	vmenu.x -= 8;
-}
-
-void VID_MenuDraw (void)
-{
-	int w, h;
-
-	re.DrawGetPicSize(&w, &h, "m_banner_video");
-	re.DrawPic(vid.width/2 - w/2, vid.height/2 - 110, "m_banner_video");
-	Menu_AdjustCursor(&vmenu, 1);	// starting position
-	Menu_Draw(&vmenu);
-}
-
-char *VID_MenuKey (int key)
-{
-	static char *sound = "misc/menu1.wav";
-
-	switch(key){
-	case K_ESCAPE:
-		M_PopMenu();
-		return NULL;
-	case K_UPARROW:
-		vmenu.cursor--;
-		Menu_AdjustCursor(&vmenu, -1);
-		break;
-	case K_DOWNARROW:
-		vmenu.cursor++;
-		Menu_AdjustCursor(&vmenu, 1);
-		break;
-	case K_LEFTARROW:
-		Menu_SlideItem(&vmenu, -1);
-		break;
-	case K_RIGHTARROW:
-		Menu_SlideItem(&vmenu, 1);
-		break;
-	case K_ENTER:
-		Menu_SelectItem(&vmenu);
-		break;
-	}
-	return sound;
-}
--- a/plan9/vid_so.c
+++ /dev/null
@@ -1,77 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-refexport_t	GetRefAPI(refimport_t);
-
-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;
-refexport_t re;			/* exported functions from refresh DLL */
-
-
-void VID_Printf (int print_level, char *fmt, ...)
-{
-	va_list argptr;
-	char msg[4096];
-	
-	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[4096];
-	
-	va_start(argptr, fmt);
-	vsprintf(msg, fmt, argptr);
-	va_end(argptr);
-	Com_Error(err_level, "%s", msg);
-}
-
-void VID_CheckChanges (void)
-{
-}
-
-void VID_Shutdown (void)
-{
-	re.Shutdown();
-}
-
-void VID_Init (void)
-{
-	refimport_t ri;
-
-	vid_ref = Cvar_Get("vid_ref", "libdraw", 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);
-
-	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_MenuInit = VID_MenuInit;
-
-	re = GetRefAPI(ri);
-	re.Init(nil, nil);
-}