From f2cce499f607456f10ac8b64c618a09785db3fb3 Mon Sep 17 00:00:00 2001
From: Spoike <acceptthis@users.sourceforge.net>
Date: Sun, 21 Jun 2009 17:45:33 +0000
Subject: [PATCH] Multiple minor cleanups. Chunks of dead code removed. Added
 com_parseutf8. Z_EXT_VWEAP is supposedly supported serverside, but not
 clientside. It is not advertised, and not used, yet. Fixed csqc mouse issues
 in linux, supposedly.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@3226 fc73d0e0-1445-4013-8a0c-d673dee63da5
---
 engine/client/cl_ents.c    |   7 +-
 engine/client/cl_main.c    |   4 +-
 engine/client/cl_parse.c   |   4 +
 engine/client/client.h     |   6 +
 engine/client/clq2_ents.c  |   2 +-
 engine/client/console.c    |   4 +-
 engine/client/image.c      |   9 +-
 engine/client/in_macos.c   |  10 +-
 engine/client/in_sdl.c     |   7 +
 engine/client/pr_menu.c    |   4 +-
 engine/client/r_bulleten.c |   2 +-
 engine/client/renderer.c   |   8 +-
 engine/common/bothdefs.h   |   2 +-
 engine/common/cmd.c        |  26 +-
 engine/common/com_mesh.c   |   6 +-
 engine/common/common.c     | 106 +++++-
 engine/common/console.h    |   5 +-
 engine/common/fs.c         |  19 +-
 engine/common/gl_q2bsp.c   |  43 ++-
 engine/common/protocol.h   |   5 +
 engine/common/q1bsp.c      |  25 +-
 engine/gl/gl_alias.c       |   4 +-
 engine/gl/gl_bloom.c       |   2 +-
 engine/gl/gl_draw.c        | 120 +++----
 engine/gl/gl_heightmap.c   |   4 +-
 engine/gl/gl_model.c       |  84 ++---
 engine/gl/gl_model.h       |  35 +-
 engine/gl/gl_ppl.c         | 110 +++---
 engine/gl/gl_rlight.c      |   3 +-
 engine/gl/gl_rmain.c       |  13 +-
 engine/gl/gl_rmisc.c       | 244 +------------
 engine/gl/gl_rsurf.c       | 693 +++----------------------------------
 engine/gl/gl_shader.c      |  40 ++-
 engine/gl/gl_vidcommon.c   |  13 +-
 engine/gl/gl_vidlinuxglx.c |   8 +
 engine/gl/gl_warp.c        | 120 ++-----
 engine/gl/glquake.h        |   7 +-
 engine/gl/shader.h         |   5 +-
 engine/server/pr_cmds.c    |  83 +++--
 engine/server/progdefs.h   |   2 +-
 engine/server/server.h     |   1 +
 engine/server/sv_ents.c    |  66 ++--
 engine/server/sv_init.c    |   7 +-
 engine/server/sv_main.c    |   1 +
 engine/server/sv_send.c    |   2 +-
 engine/server/sv_user.c    |  50 ++-
 engine/server/svhl_game.c  |   2 +-
 engine/server/svq2_ents.c  |  12 +-
 engine/server/svq2_game.c  |   2 +-
 engine/server/svq3_game.c  |   2 +-
 engine/sw/sw_draw.c        |   4 +-
 51 files changed, 681 insertions(+), 1362 deletions(-)

diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c
index bba99c93a..51646e6b5 100644
--- a/engine/client/cl_ents.c
+++ b/engine/client/cl_ents.c
@@ -3076,7 +3076,7 @@ void CL_LinkViewModel(void)
 #ifdef Q3SHADERS
 		if (v_powerupshell.value == 2)
 		{
-			ent.forcedshader = R_RegisterCustom("powerups/quadWeapon", Shader_DefaultSkinShell);
+			ent.forcedshader = R_RegisterCustom("powerups/quadWeapon", Shader_DefaultSkinShell, NULL);
 			V_AddEntity(&ent);
 		}
 		else
@@ -3088,7 +3088,7 @@ void CL_LinkViewModel(void)
 #ifdef Q3SHADERS
 		if (v_powerupshell.value == 2)
 		{
-			ent.forcedshader = R_RegisterCustom("powerups/regen", Shader_DefaultSkinShell);
+			ent.forcedshader = R_RegisterCustom("powerups/regen", Shader_DefaultSkinShell, NULL);
 			ent.fatness = -2.5;
 			V_AddEntity(&ent);
 		}
@@ -3106,11 +3106,10 @@ void CL_LinkViewModel(void)
 	//fixme: this is woefully gl specific. :(
 	if (qrenderer == QR_OPENGL)
 	{
-		extern void Shader_DefaultSkinShell(char *shortname, shader_t *s);
 		ent.shaderRGBAf[0] = (!!(ent.flags & Q2RF_SHELL_RED));
 		ent.shaderRGBAf[1] = (!!(ent.flags & Q2RF_SHELL_GREEN));
 		ent.shaderRGBAf[2] = (!!(ent.flags & Q2RF_SHELL_BLUE));
-		ent.forcedshader = R_RegisterCustom("q2/shell", Shader_DefaultSkinShell);
+		ent.forcedshader = R_RegisterCustom("q2/shell", Shader_DefaultSkinShell, NULL);
 	}
 #endif
 
diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c
index cdafcc608..e12c549f7 100644
--- a/engine/client/cl_main.c
+++ b/engine/client/cl_main.c
@@ -107,7 +107,7 @@ cvar_t	skin = SCVARF("skin",				"",			CVAR_ARCHIVE | CVAR_USERINFO);
 cvar_t	model = SCVARF("model",				"",			CVAR_ARCHIVE | CVAR_USERINFO);
 cvar_t	topcolor = SCVARF("topcolor",		"",			CVAR_ARCHIVE | CVAR_USERINFO);
 cvar_t	bottomcolor = SCVARF("bottomcolor",	"",			CVAR_ARCHIVE | CVAR_USERINFO);
-cvar_t	rate = SCVARF("rate",				"6480",		CVAR_ARCHIVE | CVAR_USERINFO);
+cvar_t	rate = SCVARF("rate",				"10000"/*"6480"*/,		CVAR_ARCHIVE | CVAR_USERINFO);
 cvar_t	drate = SCVARF("drate",				"100000",	CVAR_ARCHIVE | CVAR_USERINFO);		// :)
 cvar_t	noaim = SCVARF("noaim",				"",			CVAR_ARCHIVE | CVAR_USERINFO);
 cvar_t	msg = SCVARF("msg",					"1",		CVAR_ARCHIVE | CVAR_USERINFO);
@@ -517,7 +517,7 @@ void CL_SendConnectPacket (
 	for (c = 1; c < clients; c++)
 	{
 		Info_SetValueForStarKey (playerinfo2, "name", va("%s%i", name.string, c+1), MAX_INFO_STRING);
-		Q_strncatz(data, va(" \"%s\"", playerinfo2, SUPPORTED_Z_EXTENSIONS), sizeof(data));
+		Q_strncatz(data, va(" \"%s\"", playerinfo2), sizeof(data));
 	}
 
 	Q_strncatz(data, "\n", sizeof(data));
diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c
index f6281458e..9e23261c8 100644
--- a/engine/client/cl_parse.c
+++ b/engine/client/cl_parse.c
@@ -4402,6 +4402,10 @@ void CL_ParseStuffCmd(char *msg, int destsplit)	//this protects stuffcmds from n
 					Cbuf_AddText ("\n", RESTRICT_SERVER+destsplit);
 				}
 			}
+			else if (!strncmp(stufftext, "//vweap ", 8))
+			{
+				Con_Printf("vweap!: %s\n", stufftext);
+			}
 			else if (!strncmp(stufftext, "//exectrigger ", 14))
 			{
 				COM_Parse(stufftext + 14);
diff --git a/engine/client/client.h b/engine/client/client.h
index f94e2e8a0..3596582a9 100644
--- a/engine/client/client.h
+++ b/engine/client/client.h
@@ -250,6 +250,7 @@ typedef struct dlight_s
 	int		key;				// so entities can reuse same entry
 	qboolean	noppl, nodynamic, noflash, isstatic;
 	vec3_t	origin;
+	vec3_t	axis[3];
 	float	radius;
 	float	die;				// stop lighting after this time
 	float	decay;				// drop this each second
@@ -257,7 +258,12 @@ typedef struct dlight_s
 	float   color[3];
 	float	channelfade[3];
 
+	//the following are used for rendering (client code should clear on create)
 	struct	shadowmesh_s *worldshadowmesh;
+	int stexture;
+	struct {
+		float updatetime;
+	} face [6];
 	int style;	//multiply by style values if > 0
 	float	dist;
 	struct dlight_s *next;
diff --git a/engine/client/clq2_ents.c b/engine/client/clq2_ents.c
index 0e5accc2f..af7ceddbf 100644
--- a/engine/client/clq2_ents.c
+++ b/engine/client/clq2_ents.c
@@ -1627,7 +1627,7 @@ void CLQ2_AddPacketEntities (q2frame_t *frame)
 			//fixme: this is woefully gl specific. :(
 			if (qrenderer == QR_OPENGL)
 			{
-				ent.forcedshader = R_RegisterCustom("q2/shell", Shader_DefaultSkinShell);
+				ent.forcedshader = R_RegisterCustom("q2/shell", Shader_DefaultSkinShell, NULL);
 			}
 #endif
 			VQ2_AddLerpEntity (&ent);
diff --git a/engine/client/console.c b/engine/client/console.c
index 424dd0a99..d3faac9a3 100644
--- a/engine/client/console.c
+++ b/engine/client/console.c
@@ -581,12 +581,12 @@ void Con_PrintCon (console_t *con, char *txt)
 	c = expanded;
 	while (*c)
 	{
-		if (*c&CON_CHARMASK=='\t')
+		if ((*c&CON_CHARMASK)=='\t')
 			*c = (*c&~CON_CHARMASK)|' ';
 
 	// count word length
 		for (l=0 ; l< con->linewidth ; l++)
-			if ( c[l]&CON_CHARMASK <= ' ')
+			if ( (c[l]&CON_CHARMASK) <= ' ')
 				break;
 
 	// word wrap
diff --git a/engine/client/image.c b/engine/client/image.c
index 3900c9405..0e1e356f8 100644
--- a/engine/client/image.c
+++ b/engine/client/image.c
@@ -1833,12 +1833,10 @@ int GL_LoadTextureDDS(unsigned char *buffer, int filesize)
 		return 0;
 	buffer+=4;
 
-	texnum = texture_extension_number;
-	GL_Bind(texnum);
-
 	memcpy(&fmtheader, buffer, sizeof(fmtheader));
 	if (fmtheader.dwSize != sizeof(fmtheader))
 		return 0;	//corrupt/different version
+
 	buffer += fmtheader.dwSize;
 
 	nummips = fmtheader.dwMipMapCount;
@@ -1866,6 +1864,9 @@ int GL_LoadTextureDDS(unsigned char *buffer, int filesize)
 	if (!qglCompressedTexImage2DARB)
 		return 0;
 
+	texnum = GL_AllocNewTexture();
+	GL_Bind(texnum);
+
 	datasize = fmtheader.dwPitchOrLinearSize;
 	for (mipnum = 0; mipnum < nummips; mipnum++)
 	{
@@ -1893,8 +1894,6 @@ int GL_LoadTextureDDS(unsigned char *buffer, int filesize)
 		qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
 	}
 
-
-	texture_extension_number++;
 	return texnum;
 }
 #endif
diff --git a/engine/client/in_macos.c b/engine/client/in_macos.c
index 67fe04195..d187eddb8 100644
--- a/engine/client/in_macos.c
+++ b/engine/client/in_macos.c
@@ -52,7 +52,15 @@ void IN_ModeChanged (void)
 void IN_Move (float *movements, int pnum)
 {
 	float tx, ty, filterfrac;
-    
+    
+#ifdef PEXT_CSQC
+	if (CSQC_MouseMove(mouse_x, mouse_y))
+	{
+		mouse_x = 0;
+		mouse_y = 0;
+	}
+#endif
+
 	tx = mouse_x;
 	ty = mouse_y;
     
diff --git a/engine/client/in_sdl.c b/engine/client/in_sdl.c
index 0088772ae..842ed5c47 100644
--- a/engine/client/in_sdl.c
+++ b/engine/client/in_sdl.c
@@ -299,6 +299,13 @@ void IN_Init (void)
 }
 void IN_Move (float *movements, int pnum)	//add mouse movement to cmd
 {
+#ifdef PEXT_CSQC
+	if (CSQC_MouseMove(mouse_x, mouse_y))
+	{
+		mouse_x = 0;
+		mouse_y = 0;
+	}
+#endif
 	mouse_x *= sensitivity.value*in_sensitivityscale;
 	mouse_y *= sensitivity.value*in_sensitivityscale;
 
diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c
index e594bc94b..f335fafec 100644
--- a/engine/client/pr_menu.c
+++ b/engine/client/pr_menu.c
@@ -464,7 +464,7 @@ void PF_CL_drawpic (progfuncs_t *prinst, struct globalvars_s *pr_globals)
 #ifdef Q3SHADERS
 		shader_t *s;
 
-		s = R_RegisterCustom(picname, NULL);
+		s = R_RegisterCustom(picname, NULL, NULL);
 		if (s)
 		{
 			GLDraw_ShaderPic(pos[0], pos[1], size[0], size[1], s, rgb[0], rgb[1], rgb[2], alpha);
@@ -520,7 +520,7 @@ void PF_CL_drawsubpic (progfuncs_t *prinst, struct globalvars_s *pr_globals)
 #ifdef Q3SHADERS
 		shader_t *s;
 
-		s = R_RegisterCustom(picname, NULL);
+		s = R_RegisterCustom(picname, NULL, NULL);
 		if (s)
 		{
 			GLDraw_ShaderPic(pos[0], pos[1], size[0], size[1], s, rgb[0], rgb[1], rgb[2], alpha);
diff --git a/engine/client/r_bulleten.c b/engine/client/r_bulleten.c
index fdb58baf3..4cff8e998 100644
--- a/engine/client/r_bulleten.c
+++ b/engine/client/r_bulleten.c
@@ -397,7 +397,7 @@ player_info_t	*s;
 #ifdef RGLQUAKE
 			if (qrenderer == QR_OPENGL)
 			{
-				GL_Bind(a->texture->gl_texturenum);
+				GL_Bind(a->texture->tn.base);
 
 				GL_Upload8 ("bulleten", (qbyte *)a->texture + a->texture->offsets[0], a->texture->width, a->texture->height, false, false);
 			}
diff --git a/engine/client/renderer.c b/engine/client/renderer.c
index 4c4984d8d..241a7f575 100644
--- a/engine/client/renderer.c
+++ b/engine/client/renderer.c
@@ -729,11 +729,13 @@ mpic_t	*(*Draw_CachePic)			(char *path);
 mpic_t	*(*Draw_SafeCachePic)		(char *path);
 void	(*Draw_Init)				(void);
 void	(*Draw_ReInit)				(void);
+
 void	(*Draw_Character)			(int x, int y, unsigned int num);
 void	(*Draw_ColouredCharacter)	(int x, int y, unsigned int num);
 void	(*Draw_String)				(int x, int y, const qbyte *str);
 void	(*Draw_TinyCharacter)		(int x, int y, unsigned int num);
 void	(*Draw_Alt_String)			(int x, int y, const qbyte *str);
+
 void	(*Draw_Crosshair)			(void);
 void	(*Draw_DebugChar)			(qbyte num);
 void	(*Draw_Pic)					(int x, int y, mpic_t *pic);
@@ -2472,7 +2474,7 @@ void R_MarkLeaves_Q3 (void)
 	}
 	else
 	{
-		vis = CM_ClusterPVS (cl.worldmodel, r_viewcluster, NULL);//, cl.worldmodel);
+		vis = CM_ClusterPVS (cl.worldmodel, r_viewcluster, NULL, 0);
 		for (i=0,leaf=cl.worldmodel->leafs ; i<cl.worldmodel->numleafs ; i++, leaf++)
 		{
 			cluster = leaf->cluster;
@@ -2523,12 +2525,12 @@ void R_MarkLeaves_Q2 (void)
 			return;
 		}
 
-		vis = CM_ClusterPVS (cl.worldmodel, r_viewcluster, NULL);//, cl.worldmodel);
+		vis = CM_ClusterPVS (cl.worldmodel, r_viewcluster, NULL, 0);
 		// may have to combine two clusters because of solid water boundaries
 		if (r_viewcluster2 != r_viewcluster)
 		{
 			memcpy (fatvis, vis, (cl.worldmodel->numleafs+7)/8);
-			vis = CM_ClusterPVS (cl.worldmodel, r_viewcluster2, NULL);//, cl.worldmodel);
+			vis = CM_ClusterPVS (cl.worldmodel, r_viewcluster2, NULL, 0);
 			c = (cl.worldmodel->numleafs+31)/32;
 			for (i=0 ; i<c ; i++)
 				((int *)fatvis)[i] |= ((int *)vis)[i];
diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h
index 086cdc1d4..e4f8bef7a 100644
--- a/engine/common/bothdefs.h
+++ b/engine/common/bothdefs.h
@@ -25,7 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #define MACOSX
 #endif
 
-#if defined(__MINGW32_VERSION) || defined(__MINGW__) || defined(__MINGW32__)
+#if defined(__MINGW32_VERSION) || defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__)
 	#define MINGW
 #endif
 #if !defined(MINGW) && defined(__GNUC__) && defined(_WIN32)
diff --git a/engine/common/cmd.c b/engine/common/cmd.c
index fe86d8ca4..78270497e 100644
--- a/engine/common/cmd.c
+++ b/engine/common/cmd.c
@@ -2717,24 +2717,30 @@ void Cmd_WriteConfig_f(void)
 
 	filename = Cmd_Argv(1);
 	if (!*filename)
-		filename = "fte";
-
-	if (strstr(filename, ".."))
 	{
-		Con_Printf ("Couldn't write config %s\n",filename);
-		return;
+		snprintf(fname, sizeof(fname), "fte.cfg");
+		FS_CreatePath(fname, FS_GAMEONLY);
+		f = FS_OpenVFS(fname, "wb", FS_GAMEONLY);
 	}
+	else
+	{
+		if (strstr(filename, ".."))
+		{
+			Con_Printf ("Couldn't write config %s\n",filename);
+			return;
+		}
+		snprintf(fname, sizeof(fname), "configs/%s", filename);
+		COM_DefaultExtension(fname, ".cfg", sizeof(fname));
 
-	snprintf(fname, sizeof(fname), "configs/%s", filename);
-	COM_DefaultExtension(fname, ".cfg", sizeof(fname));
-
-	FS_CreatePath(fname, FS_CONFIGONLY);
-	f = FS_OpenVFS(fname, "wb", FS_CONFIGONLY);
+		FS_CreatePath(fname, FS_CONFIGONLY);
+		f = FS_OpenVFS(fname, "wb", FS_CONFIGONLY);
+	}
 	if (!f)
 	{
 		Con_Printf ("Couldn't write config %s\n",fname);
 		return;
 	}
+
 	VFS_WRITE(f, "// FTE config file\n\n", 20);
 #ifndef SERVERONLY
 	Key_WriteBindings (f);
diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c
index 39d1ddddf..e9723c5ee 100644
--- a/engine/common/com_mesh.c
+++ b/engine/common/com_mesh.c
@@ -1650,7 +1650,7 @@ static void *Q1_LoadSkins_GL (daliasskintype_t *pskintype, qboolean alpha)
 			if (cls.allow_shaders)
 			{
 				sprintf(skinname, "%s_%i", loadname, i);
-				texnums->shader = R_RegisterCustom (skinname, NULL);
+				texnums->shader = R_RegisterCustom (skinname, NULL, NULL);
 			}
 #endif
 
@@ -1750,7 +1750,7 @@ static void *Q1_LoadSkins_GL (daliasskintype_t *pskintype, qboolean alpha)
 				if (cls.allow_shaders)
 				{
 					sprintf(skinname, "%s_%i_%i", loadname, i, t);
-					texnums->shader = R_RegisterCustom (skinname, NULL);
+					texnums->shader = R_RegisterCustom (skinname, NULL, NULL);
 				}
 #endif
 
@@ -2042,7 +2042,7 @@ static void Q2_LoadSkins(md2_t *pq2inmodel, char *skins)
 		COM_CleanUpPath(skins);	//blooming tanks.
 		texnums->base = Mod_LoadReplacementTexture(skins, "models", true, false, true);
 #ifdef Q3SHADERS
-		texnums->shader = R_RegisterCustom(skins, NULL);
+		texnums->shader = R_RegisterCustom(skins, NULL, NULL);
 		if (!texnums->base && !texnums->shader)
 			Con_Printf("Couldn't load %s\n", skins);
 #endif
diff --git a/engine/common/common.c b/engine/common/common.c
index 8a13375ef..a1dad9afd 100644
--- a/engine/common/common.c
+++ b/engine/common/common.c
@@ -48,6 +48,7 @@ cvar_t	registered = SCVAR("registered","0");
 cvar_t	gameversion = SCVARF("gameversion","", CVAR_SERVERINFO);
 cvar_t	com_gamename = SCVAR("com_gamename", "");
 cvar_t	com_modname = SCVAR("com_modname", "");
+cvar_t	com_parseutf8 = SCVAR("com_parseutf8", "0");	//1 parse. 2 parse, but stop parsing that string if a char was malformed.
 
 qboolean	com_modified;	// set true if using non-id files
 
@@ -1750,6 +1751,8 @@ void COM_ParseFunString(conchar_t defaultflags, char *str, conchar_t *out, int o
 {
 	conchar_t extstack[4];
 	int extstackdepth = 0;
+	unsigned int uc, l;
+	int utf8 = com_parseutf8.value;
 
 	conchar_t ext;
 
@@ -1772,6 +1775,99 @@ void COM_ParseFunString(conchar_t defaultflags, char *str, conchar_t *out, int o
 
 	while(*str)
 	{
+		if (*str & 0x80 && utf8)
+		{	//check for utf-8
+
+			//uc is the output unicode char
+			uc = 0;
+			//l is the length
+			l = 0;
+
+			if ((*str & 0xc0) == 0x80)
+			{
+				//one byte... malformed
+				uc = '?';
+			}
+			else if ((*str & 0xe0) == 0xc0)
+			{
+				//two bytes
+				if ((str[1] & 0xc0) == 0x80)
+				{
+					uc = ((str[0] & 0x1f)<<6) | (str[1] & 0x3f);
+					if (uc > 0x7f)
+						l = 2;
+				}
+			}
+			else if ((*str & 0xf0) == 0xe0)
+			{
+				//three bytes
+				if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80)
+				{
+					uc = ((str[0] & 0x0f)<<12) | ((str[1] & 0x3f)<<6) | ((str[2] & 0x3f)<<0);
+					if (uc > 0x7ff)
+						l = 3;
+				}
+			}
+			else if ((*str & 0xf8) == 0xf0)
+			{
+				//four bytes
+				if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80 && (str[3] & 0xc0) == 0x80)
+				{
+					uc = ((str[0] & 0x07)<<18) | ((str[1] & 0x3f)<<12) | ((str[2] & 0x3f)<<6) | ((str[3] & 0x3f)<<0);
+					if (uc > 0xffff)
+						l = 4;
+				}
+			}
+			else if ((*str & 0xfc) == 0xf8)
+			{
+				//five bytes
+				if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80 && (str[3] & 0xc0) == 0x80 && (str[4] & 0xc0) == 0x80)
+				{
+					uc = ((str[0] & 0x03)<<24) | ((str[1] & 0x3f)<<18) | ((str[2] & 0x3f)<<12) | ((str[3] & 0x3f)<<6) | ((str[4] & 0x3f)<<0);
+					if (uc > 0x1fffff)
+						l = 5;
+				}
+			}
+			else if ((*str & 0xfe) == 0xfc)
+			{
+				//six bytes
+				if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80 && (str[3] & 0xc0) == 0x80 && (str[4] & 0xc0) == 0x80)
+				{
+					uc = ((str[0] & 0x01)<<30) | ((str[1] & 0x3f)<<24) | ((str[2] & 0x3f)<<18) | ((str[3] & 0x3f)<<12) | ((str[4] & 0x3f)<<6) | ((str[5] & 0x3f)<<0);
+					if (uc > 0x3ffffff)
+						l = 6;
+				}
+			}
+			//0xfe and 0xff, while plausable leading bytes, are not permitted.
+
+			if (l)
+			{
+				//note that we don't support utf-16 surrogates
+				if (uc == 0xd800 || uc == 0xdb7f || uc == 0xdb80 || uc == 0xdbff || uc == 0xdc00 || uc == 0xdf80 || uc == 0xdfff)
+					l = 0;
+				//these are meant to be illegal too
+				else if (uc == 0xfffe || uc == 0xffff)
+					uc = '?';
+				//too big for our data types
+				else if (uc & ~CON_CHARMASK)
+					l = 0;
+			}
+			else
+				utf8 &= ~1;
+
+			//l is set if we got a valid utf-8 byte sequence
+			if (l)
+			{
+				if (!--outsize)
+					break;
+				*out++ = uc | ext;
+				str += l;
+				continue;
+			}
+
+			//malformed encoding we just drop through
+			//if its just a malformed or overlong string, we end up with a chunk of 'red' chars.
+		}
 		if (*str == '^')
 		{
 			str++;
@@ -1934,6 +2030,7 @@ int COM_FunStringLength(unsigned char *str)
 
 	while(*str)
 	{
+		//fixme: utf8
 		if (*str == '^')
 		{
 			str++;
@@ -2264,7 +2361,7 @@ skipwhite:
 			if (!c)
 			{
 				com_token[len] = 0;
-				return (char*)data;
+				return (char*)data-1;
 			}
 			com_token[len] = c;
 			len++;
@@ -2809,7 +2906,11 @@ void COM_Version_f (void)
 #endif
 
 #ifdef __MINGW32__
-	Con_Printf("Compiled with MinGW version: %i.%i\n",__MINGW32_MAJOR_VERSION, __MINGW32_MINOR_VERSION);
+	Con_Printf("Compiled with MinGW32 version: %i.%i\n",__MINGW32_MAJOR_VERSION, __MINGW32_MINOR_VERSION);
+#endif
+
+#ifdef __MINGW64__
+	Con_Printf("Compiled with MinGW64 version: %i.%i\n",__MINGW64_MAJOR_VERSION, __MINGW64_MINOR_VERSION);
 #endif
 
 #ifdef __CYGWIN__
@@ -2929,6 +3030,7 @@ void COM_Init (void)
 
 	Cvar_Register (&registered, "Copy protection");
 	Cvar_Register (&gameversion, "Gamecode");
+	Cvar_Register (&com_parseutf8, "Internationalisation");
 
 
 
diff --git a/engine/common/console.h b/engine/common/console.h
index 3ed2bcc1f..73fe23606 100644
--- a/engine/common/console.h
+++ b/engine/common/console.h
@@ -37,8 +37,9 @@ extern conchar_t q3codemasks[MAXQ3COLOURS];
 #define CON_HALFALPHA		0x00100000
 #define CON_HIGHCHARSMASK	0x00000080 // Quake's alternative mask
 
-#define CON_FLAGSMASK		0xFFFF0000
-#define CON_CHARMASK		0x000000FF
+#define CON_FLAGSMASK		0xFFF00000
+#define CON_UNUSEDMASK		0x000F0000
+#define CON_CHARMASK		0x0000FFFF
 
 #define CON_FGMASK			0x0F000000
 #define CON_BGMASK			0xF0000000
diff --git a/engine/common/fs.c b/engine/common/fs.c
index 42ea067bc..20e04752f 100644
--- a/engine/common/fs.c
+++ b/engine/common/fs.c
@@ -1762,23 +1762,8 @@ void COM_Gamedir (const char *dir)
 #endif
 }
 
-/*
-typedef struct {
-	char *file;
-	char *path;
-} potentialgamepath_t;
-
-potentialgamepath_t pgp[] = {
-	{"%s/id1/pak0.pak",		"%s/id1"},		//quake1
-	{"%s/baseq2/pak0.pak",	"%s/baseq2"},	//quake2
-	{"%s/data1/pak0.pak",	"%s/data1"},	//hexen2
-	{"%s/data/data.pk3",	"%s/data"},		//nexuiz
-	{"%s/baseq3/pak0.pk3",	"%s/baseq3"},	//quake3
-	{"%s/base/assets0.pk3",	"%s/base"}		//jk2
-};
-*/
-
 #define NEXCFG "set sv_maxairspeed \"400\"\nset sv_mintic \"0.01\"\ncl_nolerp 0\n"
+#define DMFCFG "set com_parseutf8 1\npm_airstep 1\n"
 
 typedef struct {
 	const char *protocolname;	//sent to the master server when this is the current gamemode.
@@ -1796,10 +1781,12 @@ const gamemode_info_t gamemode_info[] = {
 //this is to avoid having too many gamemodes anyway.
 
 //rogue/hipnotic have no special files - the detection conflicts and stops us from running regular quake
+	//protocol name(dpmaster) exename        cmdline switch   identifying file   exec     dir1       dir2    dir3       dir(fte)     full name
 	{"Darkplaces-Quake",	"darkplaces",	"-quake",		"id1/pak0.pak",		NULL,	{"id1",		"qw",				"fte"},		"Quake"},
 	{"Darkplaces-Hipnotic",	"hipnotic",		"-hipnotic",	NULL,				NULL,	{"id1",		"qw",	"hipnotic",	"fte"},		"Quake: Scourge of Armagon"},
 	{"Darkplaces-Rogue",	"rogue",		"-rogue",		NULL,				NULL,	{"id1",		"qw",	"rogue",	"fte"},		"Quake: Dissolution of Eternity"},
 	{"Nexuiz",				"nexuiz",		"-nexuiz",		"nexuiz.exe",		NEXCFG,	{"data",						"ftedata"},	"Nexuiz"},
+	{"DMF",					"dmf",			"-dmf",			"base/src/progs.src",DMFCFG,{"base",						         },		"DMF"},
 
 	//supported commercial mods (some are currently only partially supported)
 	{"FTE-Hexen2",			"hexen",		"-hexen2",		"data1/pak0.pak",	NULL,	{"data1",						"fteh2"},		"Hexen II"},
diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c
index 1ca0cba1c..20325d75b 100644
--- a/engine/common/gl_q2bsp.c
+++ b/engine/common/gl_q2bsp.c
@@ -1082,9 +1082,9 @@ void *Mod_LoadWall(char *name)
 			tex->width = width;
 			tex->height = height;
 
-			if (!(tex->gl_texturenum = Mod_LoadReplacementTexture(name, loadname, true, false, true)))
-				if (!(tex->gl_texturenum = Mod_LoadReplacementTexture(name, "bmodels", true, false, true)))
-					tex->gl_texturenum = GL_LoadTexture32 (name, width, height, (unsigned int *)in, true, false);
+			if (!(tex->tn.base = Mod_LoadReplacementTexture(name, loadname, true, false, true)))
+				if (!(tex->tn.base = Mod_LoadReplacementTexture(name, "bmodels", true, false, true)))
+					tex->tn.base = GL_LoadTexture32 (name, width, height, (unsigned int *)in, true, false);
 		}
 		else
 #endif
@@ -1163,15 +1163,15 @@ void *Mod_LoadWall(char *name)
 		tex->width = wal->width;
 		tex->height = wal->height;
 
-		if (!(tex->gl_texturenum = Mod_LoadReplacementTexture(wal->name, loadname, true, false, true)))
-			if (!(tex->gl_texturenum = Mod_LoadReplacementTexture(wal->name, "bmodels", true, false, true)))
-				tex->gl_texturenum = R_LoadTexture8Pal24 (wal->name, tex->width, tex->height, (qbyte *)wal+wal->offsets[0], d_q28to24table, true, false);
+		if (!(tex->tn.base = Mod_LoadReplacementTexture(wal->name, loadname, true, false, true)))
+			if (!(tex->tn.base = Mod_LoadReplacementTexture(wal->name, "bmodels", true, false, true)))
+				tex->tn.base = R_LoadTexture8Pal24 (wal->name, tex->width, tex->height, (qbyte *)wal+wal->offsets[0], d_q28to24table, true, false);
 
 		in = Hunk_TempAllocMore(wal->width*wal->height);
 		oin = (qbyte *)wal+wal->offsets[0];
 		for (j = 0; j < wal->width*wal->height; j++)
 			in[j] = (d_q28to24table[oin[j]*3+0] + d_q28to24table[oin[j]*3+1] + d_q28to24table[oin[j]*3+2])/3;
-		tex->gl_texturenumbumpmap = R_LoadTexture8Bump (va("%s_bump", wal->name), tex->width, tex->height, in, true, r_shadow_bumpscale_basetexture.value);
+		tex->tn.bump = R_LoadTexture8Bump (va("%s_bump", wal->name), tex->width, tex->height, in, true, r_shadow_bumpscale_basetexture.value);
 	}
 	else
 #endif
@@ -1316,7 +1316,7 @@ qboolean CMod_LoadTexInfo (lump_t *l)	//yes I know these load from the same plac
 #ifdef RGLQUAKE
 			if (qrenderer == QR_OPENGL)
 				if (gl_shadeq2.value)
-					out->texture->shader = R_RegisterCustom (name, NULL);
+					out->texture->shader = R_RegisterCustom (name, NULL, NULL);
 #endif
 			Q_strncpyz(out->texture->name, in->texture, sizeof(out->texture->name));
 
@@ -2117,11 +2117,11 @@ qboolean CModQ3_LoadShaders (lump_t *l, qboolean useshaders)
 #if defined(RGLQUAKE) || defined(D3DQUAKE)
 		if ((qrenderer == QR_OPENGL || qrenderer == QR_DIRECT3D) && !useshaders)
 		{
-			loadmodel->texinfo[i].texture->gl_texturenum = Mod_LoadHiResTexture(in->shadername, loadname, true, false, true);
-			if (!loadmodel->texinfo[i].texture->gl_texturenum)
-				loadmodel->texinfo[i].texture->gl_texturenum = Mod_LoadHiResTexture(in->shadername, "bmodels", true, false, true);
-			loadmodel->texinfo[i].texture->gl_texturenumfb = 0;
-			loadmodel->texinfo[i].texture->gl_texturenumbumpmap = 0;
+			loadmodel->texinfo[i].texture->tn.base = Mod_LoadHiResTexture(in->shadername, loadname, true, false, true);
+			if (!loadmodel->texinfo[i].texture->tn.base)
+				loadmodel->texinfo[i].texture->tn.base = Mod_LoadHiResTexture(in->shadername, "bmodels", true, false, true);
+			loadmodel->texinfo[i].texture->tn.fullbright = 0;
+			loadmodel->texinfo[i].texture->tn.bump = 0;
 
 			if (!strncmp(in->shadername, "textures/skies/", 15))
 			{
@@ -3580,7 +3580,7 @@ void CMQ3_CalcPHS (void)
 	vcount = 0;
 	for (i=0 ; i<numclusters ; i++)
 	{
-		scan = CM_ClusterPVS (sv.worldmodel, i, NULL);
+		scan = CM_ClusterPVS (sv.worldmodel, i, NULL, 0);
 		for (j=0 ; j<numclusters ; j++)
 		{
 			if ( scan[j>>3] & (1<<(j&7)) )
@@ -3625,9 +3625,9 @@ void CMQ3_CalcPHS (void)
 }
 #endif
 
-qbyte *CM_LeafnumPVS (model_t *model, int leafnum, qbyte *buffer)
+qbyte *CM_LeafnumPVS (model_t *model, int leafnum, qbyte *buffer, unsigned int buffersize)
 {
-	return CM_ClusterPVS(model, CM_LeafCluster(model, leafnum), buffer);
+	return CM_ClusterPVS(model, CM_LeafCluster(model, leafnum), buffer, buffersize);
 }
 
 #ifndef SERVERONLY
@@ -3776,8 +3776,8 @@ void SWR_Q2BSP_StainNode (mnode_t *node, float *parms)
 #endif
 
 #ifndef CLIENTONLY
-void Q2BSP_FatPVS (model_t *mod, vec3_t org, qboolean add);
-qboolean Q2BSP_EdictInFatPVS(model_t *mod, edict_t *ent);
+unsigned int Q2BSP_FatPVS (model_t *mod, vec3_t org, qbyte *buffer, unsigned int buffersize, qboolean add);
+qboolean Q2BSP_EdictInFatPVS(model_t *mod, edict_t *ent, qbyte *pvs);
 void Q2BSP_FindTouchedLeafs(model_t *mod, edict_t *ent, float *mins, float *maxs);
 #endif
 void GLQ2BSP_LightPointValues(model_t *mod, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir);
@@ -5685,10 +5685,15 @@ qbyte	phsrow[MAX_MAP_LEAFS/8];
 
 
 
-qbyte	*CM_ClusterPVS (model_t *mod, int cluster, qbyte *buffer)
+qbyte	*CM_ClusterPVS (model_t *mod, int cluster, qbyte *buffer, unsigned int buffersize)
 {
 	if (!buffer)
+	{
 		buffer = pvsrow;
+		buffersize = sizeof(pvsrow);
+	}
+	if (buffersize < (numclusters+7)>>3)
+		Sys_Error("CM_ClusterPVS with too small a buffer\n");
 
 	if (mapisq3)
 	{
diff --git a/engine/common/protocol.h b/engine/common/protocol.h
index fab82fdc9..7aa41f280 100644
--- a/engine/common/protocol.h
+++ b/engine/common/protocol.h
@@ -79,6 +79,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #define Z_EXT_JOIN_OBSERVE	(1<<5)	// server: "join" and "observe" commands are supported
 									// client: on-the-fly spectator <-> player switching supported
 
+//#define Z_EXT_PF_ONGROUND	(1<<6)	// server: PF_ONGROUND is valid for all svc_playerinfo
+#define Z_EXT_VWEP			(1<<7)
+//#define Z_EXT_PF_SOLID		(1<<8)	//conflicts with many FTE extensions.
+
 #define SUPPORTED_Z_EXTENSIONS (Z_EXT_PM_TYPE|Z_EXT_PM_TYPE_NEW|Z_EXT_VIEWHEIGHT|Z_EXT_SERVERTIME|Z_EXT_PITCHLIMITS|Z_EXT_JOIN_OBSERVE)
 
 
@@ -378,6 +382,7 @@ enum clcq2_ops_e
 #endif
 
 #define	PF_COLOURMOD		(1<<19)
+//note that if you add any more, you may need to change the check in the client so more can be parsed
 
 
 
diff --git a/engine/common/q1bsp.c b/engine/common/q1bsp.c
index 64decc148..62d57c43e 100644
--- a/engine/common/q1bsp.c
+++ b/engine/common/q1bsp.c
@@ -858,11 +858,8 @@ Server only functions
 */
 #ifndef CLIENTONLY
 
-extern int		fatbytes;
-extern qbyte	fatpvs[(MAX_MAP_LEAFS+1)/4];
-
 //does the recursive work of Q1BSP_FatPVS
-void SV_Q1BSP_AddToFatPVS (model_t *mod, vec3_t org, mnode_t *node)
+void SV_Q1BSP_AddToFatPVS (model_t *mod, vec3_t org, mnode_t *node, qbyte *buffer, unsigned int buffersize)
 {
 	int		i;
 	qbyte	*pvs;
@@ -877,8 +874,8 @@ void SV_Q1BSP_AddToFatPVS (model_t *mod, vec3_t org, mnode_t *node)
 			if (node->contents != Q1CONTENTS_SOLID)
 			{
 				pvs = Q1BSP_LeafPVS (mod, (mleaf_t *)node, NULL);
-				for (i=0 ; i<fatbytes ; i++)
-					fatpvs[i] |= pvs[i];
+				for (i=0; i<buffersize; i++)
+					buffer[i] |= pvs[i];
 			}
 			return;
 		}
@@ -891,7 +888,7 @@ void SV_Q1BSP_AddToFatPVS (model_t *mod, vec3_t org, mnode_t *node)
 			node = node->children[1];
 		else
 		{	// go down both
-			SV_Q1BSP_AddToFatPVS (mod, org, node->children[0]);
+			SV_Q1BSP_AddToFatPVS (mod, org, node->children[0], buffer, buffersize);
 			node = node->children[1];
 		}
 	}
@@ -905,15 +902,17 @@ Calculates a PVS that is the inclusive or of all leafs within 8 pixels of the
 given point.
 =============
 */
-void Q1BSP_FatPVS (model_t *mod, vec3_t org, qboolean add)
+void Q1BSP_FatPVS (model_t *mod, vec3_t org, qbyte *pvsbuffer, unsigned int buffersize, qboolean add)
 {
-	fatbytes = (mod->numleafs+31)>>3;
+	unsigned int fatbytes = (mod->numleafs+31)>>3;
+	if (fatbytes > buffersize)
+		Sys_Error("map had too much pvs data (too many leaves)\n");;
 	if (!add)
-		Q_memset (fatpvs, 0, fatbytes);
-	SV_Q1BSP_AddToFatPVS (mod, org, mod->nodes);
+		Q_memset (pvsbuffer, 0, fatbytes);
+	SV_Q1BSP_AddToFatPVS (mod, org, mod->nodes, pvsbuffer, fatbytes);
 }
 
-qboolean Q1BSP_EdictInFatPVS(model_t *mod, edict_t *ent)
+qboolean Q1BSP_EdictInFatPVS(model_t *mod, edict_t *ent, qbyte *pvs)
 {
 	int i;
 
@@ -921,7 +920,7 @@ qboolean Q1BSP_EdictInFatPVS(model_t *mod, edict_t *ent)
 		return true;	//it's in too many leafs for us to cope with. Just trivially accept it.
 
 	for (i=0 ; i < ent->num_leafs ; i++)
-		if (fatpvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i]&7) ))
+		if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i]&7) ))
 			return true;	//we might be able to see this one.
 
 	return false;	//none of this ents leafs were visible, so neither is the ent.
diff --git a/engine/gl/gl_alias.c b/engine/gl/gl_alias.c
index c2bcbfccd..f3693d96e 100644
--- a/engine/gl/gl_alias.c
+++ b/engine/gl/gl_alias.c
@@ -612,7 +612,7 @@ static galiastexnum_t *GL_ChooseSkin(galiasinfo_t *inf, char *modelname, int sur
 						frac += fracstep;
 					}
 				}
-				texnums->base = texture_extension_number++;
+				texnums->base = GL_AllocNewTexture();
 				GL_Bind(texnums->base);
 				qglTexImage2D (GL_TEXTURE_2D, 0, gl_solid_format, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
 
@@ -634,7 +634,7 @@ static galiastexnum_t *GL_ChooseSkin(galiasinfo_t *inf, char *modelname, int sur
 						frac += fracstep;
 					}
 				}
-				texnums->fullbright = texture_extension_number++;
+				texnums->fullbright = GL_AllocNewTexture();
 				GL_Bind(texnums->fullbright);
 				qglTexImage2D (GL_TEXTURE_2D, 0, gl_alpha_format, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
 
diff --git a/engine/gl/gl_bloom.c b/engine/gl/gl_bloom.c
index bfa0431a6..910c997ed 100644
--- a/engine/gl/gl_bloom.c
+++ b/engine/gl/gl_bloom.c
@@ -218,7 +218,7 @@ void R_Bloom_InitTextures(void)
 	data = Z_Malloc(size);
 	memset(data, 255, size);
 	if (!bs.tx_screen)
-		bs.tx_screen = texture_extension_number++;
+		bs.tx_screen = GL_AllocNewTexture();
 	GL_Bind(bs.tx_screen);
 	qglTexImage2D (GL_TEXTURE_2D, 0, gl_solid_format, bs.scr_w, bs.scr_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
 	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c
index 605ace709..f5959fe21 100644
--- a/engine/gl/gl_draw.c
+++ b/engine/gl/gl_draw.c
@@ -139,7 +139,7 @@ int			scrap_allocated[MAX_SCRAPS][BLOCK_WIDTH];
 qbyte		scrap_texels[MAX_SCRAPS][BLOCK_WIDTH*BLOCK_HEIGHT];
 qboolean	scrap_dirty;
 int			scrap_usedcount;
-int			scrap_texnum;
+int			scrap_texnum[MAX_SCRAPS];
 
 // returns a texture number and the position inside it
 int Scrap_AllocBlock (int w, int h, int *x, int *y)
@@ -193,7 +193,7 @@ void Scrap_Upload (void)
 	scrap_uploads++;
 	for (i = 0; i < scrap_usedcount; i++)
 	{
-		GL_Bind(scrap_texnum + i);
+		GL_Bind(scrap_texnum[i]);
 		GL_Upload8 ("scrap", scrap_texels[i], BLOCK_WIDTH, BLOCK_HEIGHT, false, true);
 	}
 	scrap_dirty = false;
@@ -297,7 +297,7 @@ qboolean Draw_RealPicFromWad (mpic_t	*out, char *name)
 			for (i=0 ; i<in->height ; i++)
 				for (j=0 ; j<in->width ; j++, k++)
 					scrap_texels[texnum][(y+i)*BLOCK_WIDTH + x + j] = in->data[k];
-			texnum += scrap_texnum;
+			texnum = scrap_texnum[texnum];
 			gl->texnum = texnum;
 			gl->sl = (x+0.25)/(float)BLOCK_WIDTH;
 			gl->sh = (x+in->width-0.25)/(float)BLOCK_WIDTH;
@@ -735,7 +735,7 @@ void GL_InitFogTexture (void)
 		}
 	}
 
-	r_fogtexture = texture_extension_number++;
+	r_fogtexture = GL_AllocNewTexture();
 	GL_Bind(r_fogtexture);
 	qglTexImage2D (GL_TEXTURE_2D, 0, GL_ALPHA, FOG_TEXTURE_WIDTH, FOG_TEXTURE_HEIGHT, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data);
 
@@ -786,7 +786,6 @@ void GLDraw_ReInit (void)
 	Hash_InitTable(&gltexturetable, sizeof(gltexturetablebuckets)/sizeof(gltexturetablebuckets[0]), gltexturetablebuckets);
 
 
-	texture_extension_number=1;
 	solidskytexture=0;
 	alphaskytexture=0;
 	skyboxtex[0] = 0; skyboxtex[1] = 0; skyboxtex[2] = 0; skyboxtex[3] = 0; skyboxtex[4] = 0; skyboxtex[5] = 0;
@@ -1033,7 +1032,7 @@ TRACE(("dbg: GLDraw_ReInit: Allocating upload buffers\n"));
 			char_tex2 = GL_LoadTexture ("charset", 128, 128, draw_chars, false, true);
 	}
 	
-	cs_texture = texture_extension_number++;
+	cs_texture = GL_AllocNewTexture();
 
 	missing_texture = GL_LoadTexture("no_texture", 16, 16, (unsigned char*)r_notexture_mip + r_notexture_mip->offsets[0], true, false);
 
@@ -1159,11 +1158,11 @@ TRACE(("dbg: GLDraw_ReInit: Allocating upload buffers\n"));
 	Hunk_FreeToLowMark (start);
 
 	// save a texture slot for translated picture
-	translate_texture = texture_extension_number++;
+	translate_texture = GL_AllocNewTexture();
 
 	// save slots for scraps
-	scrap_texnum = texture_extension_number;
-	texture_extension_number += MAX_SCRAPS;
+	for (i = 0; i < MAX_SCRAPS; i++)
+		scrap_texnum[i] = GL_AllocNewTexture();
 
 	//
 	// get the other pics we need
@@ -2388,7 +2387,7 @@ void GL_Conback_Callback(struct cvar_s *var, char *oldvalue)
 {
 	int newtex = 0;
 #ifdef Q3SHADERS
-	if (*var->string && (shader_console = R_RegisterCustom(var->string, NULL)))
+	if (*var->string && (shader_console = R_RegisterCustom(var->string, NULL, NULL)))
 	{
 		conback = default_conback;
 	}
@@ -2454,8 +2453,7 @@ void MediaGL_ShowFrame8bit(qbyte *framedata, int inwidth, int inheight, qbyte *p
 {
 	if (!filmtexture)
 	{
-		filmtexture=texture_extension_number;
-		texture_extension_number++;
+		filmtexture=GL_AllocNewTexture();
 	}
 
 	GL_Set2D ();
@@ -2492,8 +2490,7 @@ void MediaGL_ShowFrameRGBA_32(qbyte *framedata, int inwidth, int inheight)//top
 {
 	if (!filmtexture)
 	{
-		filmtexture=texture_extension_number;
-		texture_extension_number++;
+		filmtexture=GL_AllocNewTexture();
 	}
 
 	GL_Set2D ();
@@ -2598,8 +2595,7 @@ void MediaGL_ShowFrameBGR_24_Flip(qbyte *framedata, int inwidth, int inheight)
 
 	if (!filmtexture)
 	{
-		filmtexture=texture_extension_number;
-		texture_extension_number++;
+		filmtexture=GL_AllocNewTexture();
 	}
 
 	GL_Set2D ();
@@ -4036,7 +4032,7 @@ TRACE(("dbg: GL_LoadTexture: new %s\n", identifier));
 	gltextures = glt;
 
 	strcpy (glt->identifier, identifier);
-	glt->texnum = texture_extension_number;
+	glt->texnum = GL_AllocNewTexture();
 	glt->width = width;
 	glt->height = height;
 	glt->bpp = 8;
@@ -4044,13 +4040,11 @@ TRACE(("dbg: GL_LoadTexture: new %s\n", identifier));
 
 	Hash_Add(&gltexturetable, glt->identifier, glt, (bucket_t*)(glt+1));
 
-	GL_Bind(texture_extension_number );
+	GL_Bind(glt->texnum);
 
 	GL_Upload8 ("8bit", data, width, height, mipmap, alpha);
 
-	texture_extension_number++;
-
-	return texture_extension_number-1;
+	return glt->texnum;
 }
 
 int GL_LoadTextureFB (char *identifier, int width, int height, qbyte *data, qboolean mipmap, qboolean alpha)
@@ -4078,7 +4072,7 @@ int GL_LoadTextureFB (char *identifier, int width, int height, qbyte *data, qboo
 	gltextures = glt;
 
 	strcpy (glt->identifier, identifier);
-	glt->texnum = texture_extension_number;
+	glt->texnum = GL_AllocNewTexture();
 	glt->width = width;
 	glt->height = height;
 	glt->bpp = 8;
@@ -4086,13 +4080,11 @@ int GL_LoadTextureFB (char *identifier, int width, int height, qbyte *data, qboo
 
 	Hash_Add(&gltexturetable, glt->identifier, glt, (bucket_t*)(glt+1));
 
-	GL_Bind(texture_extension_number );
+	GL_Bind(glt->texnum);
 
 	GL_Upload8FB (data, width, height, mipmap);
 
-	texture_extension_number++;
-
-	return texture_extension_number-1;
+	return glt->texnum;
 }
 
 int GL_LoadTexture8Pal24 (char *identifier, int width, int height, qbyte *data, qbyte *palette24, qboolean mipmap, qboolean alpha)
@@ -4113,7 +4105,7 @@ int GL_LoadTexture8Pal24 (char *identifier, int width, int height, qbyte *data,
 
 
 	strcpy (glt->identifier, identifier);
-	glt->texnum = texture_extension_number;
+	glt->texnum = GL_AllocNewTexture();
 	glt->width = width;
 	glt->height = height;
 	glt->bpp = 24;
@@ -4121,13 +4113,11 @@ int GL_LoadTexture8Pal24 (char *identifier, int width, int height, qbyte *data,
 
 	Hash_Add(&gltexturetable, glt->identifier, glt, (bucket_t*)(glt+1));
 
-	GL_Bind(texture_extension_number );
+	GL_Bind(glt->texnum);
 
 	GL_Upload8Pal24 (data, palette24, width, height, mipmap, alpha);
 
-	texture_extension_number++;
-
-	return texture_extension_number-1;
+	return glt->texnum;
 }
 int GL_LoadTexture8Pal32 (char *identifier, int width, int height, qbyte *data, qbyte *palette32, qboolean mipmap, qboolean alpha)
 {
@@ -4147,7 +4137,7 @@ int GL_LoadTexture8Pal32 (char *identifier, int width, int height, qbyte *data,
 
 
 	strcpy (glt->identifier, identifier);
-	glt->texnum = texture_extension_number;
+	glt->texnum = GL_AllocNewTexture();
 	glt->width = width;
 	glt->height = height;
 	glt->bpp = 32;
@@ -4155,13 +4145,11 @@ int GL_LoadTexture8Pal32 (char *identifier, int width, int height, qbyte *data,
 
 	Hash_Add(&gltexturetable, glt->identifier, glt, (bucket_t*)(glt+1));
 
-	GL_Bind(texture_extension_number );
+	GL_Bind(glt->texnum);
 
 	GL_Upload8Pal32 (data, palette32, width, height, mipmap, alpha);
 
-	texture_extension_number++;
-
-	return texture_extension_number-1;
+	return glt->texnum;
 }
 
 int GL_LoadTexture32 (char *identifier, int width, int height, unsigned *data, qboolean mipmap, qboolean alpha)
@@ -4183,7 +4171,7 @@ int GL_LoadTexture32 (char *identifier, int width, int height, unsigned *data, q
 	gltextures = glt;
 
 	strcpy (glt->identifier, identifier);
-	glt->texnum = texture_extension_number;
+	glt->texnum = GL_AllocNewTexture();
 	glt->width = width;
 	glt->height = height;
 	glt->bpp = 32;
@@ -4191,16 +4179,11 @@ int GL_LoadTexture32 (char *identifier, int width, int height, unsigned *data, q
 
 	Hash_Add(&gltexturetable, glt->identifier, glt, (bucket_t*)(glt+1));
 
-//	if (!isDedicated)
-	{
-		GL_Bind(texture_extension_number );
+	GL_Bind(glt->texnum);
 
-		GL_Upload32 (identifier, data, width, height, mipmap, alpha);
-	}
+	GL_Upload32 (identifier, data, width, height, mipmap, alpha);
 
-	texture_extension_number++;
-
-	return texture_extension_number-1;
+	return glt->texnum;
 }
 
 int GL_LoadTexture32_BGRA (char *identifier, int width, int height, unsigned *data, qboolean mipmap, qboolean alpha)
@@ -4222,7 +4205,7 @@ int GL_LoadTexture32_BGRA (char *identifier, int width, int height, unsigned *da
 	gltextures = glt;
 
 	strcpy (glt->identifier, identifier);
-	glt->texnum = texture_extension_number;
+	glt->texnum = GL_AllocNewTexture();
 	glt->width = width;
 	glt->height = height;
 	glt->bpp = 32;
@@ -4230,16 +4213,11 @@ int GL_LoadTexture32_BGRA (char *identifier, int width, int height, unsigned *da
 
 	Hash_Add(&gltexturetable, glt->identifier, glt, (bucket_t*)(glt+1));
 
-//	if (!isDedicated)
-	{
-		GL_Bind(texture_extension_number );
+	GL_Bind(glt->texnum);
 
-		GL_Upload32_BGRA (identifier, data, width, height, mipmap, alpha);
-	}
+	GL_Upload32_BGRA (identifier, data, width, height, mipmap, alpha);
 
-	texture_extension_number++;
-
-	return texture_extension_number-1;
+	return glt->texnum;
 }
 
 int GL_LoadCompressed(char *name)
@@ -4274,19 +4252,17 @@ int GL_LoadCompressed(char *name)
 	gltextures = glt;
 
 	strcpy (glt->identifier, name);
-	glt->texnum = texture_extension_number;
+	glt->texnum = GL_AllocNewTexture();
 	glt->bpp = 32;
 
 	Hash_Add(&gltexturetable, glt->identifier, glt, (bucket_t*)(glt+1));
 
-	GL_Bind(texture_extension_number );
+	GL_Bind(glt->texnum);
 
 	if (!GL_UploadCompressed (file, &glt->width, &glt->height, (unsigned int *)&glt->mipmap))
 		return 0;
 
-	texture_extension_number++;
-
-	return texture_extension_number-1;
+	return glt->texnum;
 }
 
 int GL_LoadTexture8Grey (char *identifier, int width, int height, unsigned char *data, qboolean mipmap)
@@ -4308,7 +4284,7 @@ int GL_LoadTexture8Grey (char *identifier, int width, int height, unsigned char
 	gltextures = glt;
 
 	strcpy (glt->identifier, identifier);
-	glt->texnum = texture_extension_number;
+	glt->texnum = GL_AllocNewTexture();
 	glt->width = width;
 	glt->height = height;
 	glt->bpp = 8;
@@ -4316,16 +4292,11 @@ int GL_LoadTexture8Grey (char *identifier, int width, int height, unsigned char
 
 	Hash_Add(&gltexturetable, glt->identifier, glt, (bucket_t*)(glt+1));
 
-//	if (!isDedicated)
-	{
-		GL_Bind(texture_extension_number );
+	GL_Bind(glt->texnum);
 
-		GL_Upload8Grey (data, width, height, mipmap);
-	}
+	GL_Upload8Grey (data, width, height, mipmap);
 
-	texture_extension_number++;
-
-	return texture_extension_number-1;
+	return glt->texnum;
 }
 
 int GL_LoadTexture8Bump (char *identifier, int width, int height, unsigned char *data, qboolean mipmap, float bumpscale)
@@ -4352,7 +4323,7 @@ int GL_LoadTexture8Bump (char *identifier, int width, int height, unsigned char
 	gltextures = glt;
 
 	strcpy (glt->identifier, identifier);
-	glt->texnum = texture_extension_number;
+	glt->texnum = GL_AllocNewTexture();
 	glt->width = width;
 	glt->height = height;
 	glt->bpp = 8;
@@ -4360,16 +4331,11 @@ int GL_LoadTexture8Bump (char *identifier, int width, int height, unsigned char
 
 	Hash_Add(&gltexturetable, glt->identifier, glt, (bucket_t*)(glt+1));
 
-//	if (!isDedicated)
-	{
-		GL_Bind(texture_extension_number );
+	GL_Bind(glt->texnum);
 
-		GL_UploadBump (data, width, height, mipmap, bumpscale);
-	}
+	GL_UploadBump (data, width, height, mipmap, bumpscale);
 
-	texture_extension_number++;
-
-	return texture_extension_number-1;
+	return glt->texnum;
 }
 
 /*
diff --git a/engine/gl/gl_heightmap.c b/engine/gl/gl_heightmap.c
index a5eff6230..1f7358898 100644
--- a/engine/gl/gl_heightmap.c
+++ b/engine/gl/gl_heightmap.c
@@ -585,12 +585,12 @@ qboolean Heightmap_NativeTrace(struct model_s *model, int hulloverride, int fram
 }
 
 #endif
-void Heightmap_FatPVS		(model_t *mod, vec3_t org, qboolean add)
+void Heightmap_FatPVS		(model_t *mod, vec3_t org, qbyte *pvsbuffer, unsigned int pvssize, qboolean add)
 {
 }
 
 #ifndef CLIENTONLY
-qboolean Heightmap_EdictInFatPVS	(model_t *mod, edict_t *edict)
+qboolean Heightmap_EdictInFatPVS	(model_t *mod, edict_t *edict, qbyte *pvsdata)
 {
 	return true;
 }
diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c
index 1fab0c73f..4b1936f58 100644
--- a/engine/gl/gl_model.c
+++ b/engine/gl/gl_model.c
@@ -178,7 +178,7 @@ void GLMod_BlockTextureColour_f (void)
 
 				if (!stricmp(tx->name, match))
 				{
-					tx->gl_texturenum = R_LoadTexture32(texname, 8, 8, colour, true, false);
+					tx->tn.base = R_LoadTexture32(texname, 8, 8, colour, true, false);
 				}
 			}
 		}
@@ -1014,9 +1014,9 @@ TRACE(("dbg: GLMod_LoadTextures: inittexturedescs\n"));
 			if (!R_AddBulleten(tx))
 #endif
 		{
-			tx->gl_texturenum = 0;
-			GLMod_LoadAdvancedTexture(tx->name, &tx->gl_texturenum, &tx->gl_texturenumbumpmap, &tx->gl_texturenumfb, &tx->gl_texturenumspec, NULL, NULL);
-			if (tx->gl_texturenum)
+			tx->tn.base = 0;
+			GLMod_LoadAdvancedTexture(tx->name, &tx->tn.base, &tx->tn.bump, &tx->tn.fullbright, &tx->tn.specular, NULL, NULL);
+			if (tx->tn.base)
 				continue;
 
 			base = (qbyte *)(mt+1);
@@ -1025,75 +1025,79 @@ TRACE(("dbg: GLMod_LoadTextures: inittexturedescs\n"));
 			{//external textures have already been filtered.
 				base = W_ConvertWAD3Texture(mt, &mt->width, &mt->height, &alphaed);	//convert texture to 32 bit.
 				tx->alphaed = alphaed;
-				if (!(tx->gl_texturenum = Mod_LoadReplacementTexture(mt->name, loadname, true, alphaed, true)))
-					if (!(tx->gl_texturenum = Mod_LoadReplacementTexture(mt->name, "bmodels", true, alphaed, true)))
-						tx->gl_texturenum = R_LoadTexture32 (mt->name, tx->width, tx->height, (unsigned int *)base, true, alphaed);
+				if (!(tx->tn.base = Mod_LoadReplacementTexture(mt->name, loadname, true, alphaed, true)))
+					if (!(tx->tn.base = Mod_LoadReplacementTexture(mt->name, "bmodels", true, alphaed, true)))
+						tx->tn.base = R_LoadTexture32 (mt->name, tx->width, tx->height, (unsigned int *)base, true, alphaed);
 
 				*tx->name = *mt->name;
 			}
 			else
 			{
-				if (!(tx->gl_texturenum = Mod_LoadReplacementTexture(mt->name, loadname, true, false, true)))
-					if (!(tx->gl_texturenum = Mod_LoadReplacementTexture(mt->name, "bmodels", true, false, true)))
-						tx->gl_texturenum = R_LoadTexture8 (mt->name, tx->width, tx->height, base, true, false);
+				if (!(tx->tn.base = Mod_LoadReplacementTexture(mt->name, loadname, true, false, true)))
+					if (!(tx->tn.base = Mod_LoadReplacementTexture(mt->name, "bmodels", true, false, true)))
+						tx->tn.base = R_LoadTexture8 (mt->name, tx->width, tx->height, base, true, false);
 
 				if (r_fb_bmodels.value)
 				{
 					snprintf(altname, sizeof(altname)-1, "%s_luma", mt->name);
 					if (gl_load24bit.value)
 					{
-						tx->gl_texturenumfb = Mod_LoadReplacementTexture(altname, loadname, true, false, true);
-						if (!tx->gl_texturenumfb)
-							tx->gl_texturenumfb = Mod_LoadReplacementTexture(altname, "bmodels", true, false, true);
+						tx->tn.fullbright = Mod_LoadReplacementTexture(altname, loadname, true, false, true);
+						if (!tx->tn.fullbright)
+							tx->tn.fullbright = Mod_LoadReplacementTexture(altname, "bmodels", true, false, true);
 					}
-					if (!tx->gl_texturenumfb)	//generate one (if possible).
-						tx->gl_texturenumfb = R_LoadTextureFB(altname, tx->width, tx->height, base, true, true);
+					if (!tx->tn.fullbright)	//generate one (if possible).
+						tx->tn.fullbright = R_LoadTextureFB(altname, tx->width, tx->height, base, true, true);
 				}
 			}
 
-			tx->gl_texturenumbumpmap = 0;
+			tx->tn.bump = 0;
 			if (gl_bumpmappingpossible && cls.allow_bump)
 			{
 				extern cvar_t gl_bump;
 				if (gl_bump.value<2)	//set to 2 to have faster loading.
 				{
 					snprintf(altname, sizeof(altname)-1, "%s_norm", mt->name);
-					tx->gl_texturenumbumpmap = Mod_LoadHiResTexture(altname, loadname, true, false, false);
-					if (!tx->gl_texturenumbumpmap)
-						tx->gl_texturenumbumpmap = Mod_LoadHiResTexture(altname, "bmodels", true, false, false);
+					tx->tn.bump = Mod_LoadHiResTexture(altname, loadname, true, false, false);
+					if (!tx->tn.bump)
+						tx->tn.bump = Mod_LoadHiResTexture(altname, "bmodels", true, false, false);
 				}
-				if (!tx->gl_texturenumbumpmap)
+				if (!tx->tn.bump)
 				{
 					if (gl_load24bit.value)
 					{
 						snprintf(altname, sizeof(altname)-1, "%s_bump", mt->name);
-						tx->gl_texturenumbumpmap = Mod_LoadBumpmapTexture(altname, loadname);
-						if (!tx->gl_texturenumbumpmap)
-							tx->gl_texturenumbumpmap = Mod_LoadBumpmapTexture(altname, "bmodels");
+						tx->tn.bump = Mod_LoadBumpmapTexture(altname, loadname);
+						if (!tx->tn.bump)
+							tx->tn.bump = Mod_LoadBumpmapTexture(altname, "bmodels");
 					}
 					else
 						snprintf(altname, sizeof(altname)-1, "%s_bump", mt->name);
 				}
 
-				if (!(tx->gl_texturenumbumpmap) && loadmodel->fromgame != fg_halflife)
+				if (!(tx->tn.bump) && loadmodel->fromgame != fg_halflife)
 				{
 					base = (qbyte *)(mt+1);	//convert to greyscale.
 					for (j = 0; j < pixels; j++)
 						base[j] = (host_basepal[base[j]*3] + host_basepal[base[j]*3+1] + host_basepal[base[j]*3+2]) / 3;
 
-					tx->gl_texturenumbumpmap = R_LoadTexture8Bump(altname, tx->width, tx->height, base, true, r_shadow_bumpscale_basetexture.value);	//normalise it and then bump it.
+					tx->tn.bump = R_LoadTexture8Bump(altname, tx->width, tx->height, base, true, r_shadow_bumpscale_basetexture.value);	//normalise it and then bump it.
 				}
 
 				//don't do any complex quake 8bit -> glossmap. It would likly look a little ugly...
 				if (gl_specular.value && gl_load24bit.value)
 				{
 					snprintf(altname, sizeof(altname)-1, "%s_gloss", mt->name);
-					tx->gl_texturenumspec = Mod_LoadHiResTexture(altname, loadname, true, false, false);
-					if (!tx->gl_texturenumspec)
-						tx->gl_texturenumspec = Mod_LoadHiResTexture(altname, "bmodels", true, false, false);
+					tx->tn.specular = Mod_LoadHiResTexture(altname, loadname, true, false, false);
+					if (!tx->tn.specular)
+						tx->tn.specular = Mod_LoadHiResTexture(altname, "bmodels", true, false, false);
 				}
 			}
 		}
+#ifdef NEWBACKEND
+		tx->shader = R_RegisterCustom(mt->name, Shader_DefaultBSP, &tx->tn);
+#pragma message("warning: fix the following block")
+#endif
 #ifdef Q3SHADERS	//load q3 syntax shader last, after the textures inside the bsp have been loaded and stuff.
 		if (cls.allow_shaders && gl_shadeq1.value && *gl_shadeq1_name.string)
 		{
@@ -1103,14 +1107,14 @@ TRACE(("dbg: GLMod_LoadTextures: inittexturedescs\n"));
 			//	tx->shader = R_RegisterCustom(mt->name, NULL);	//just load the regular name.
 				tx->shader = R_RegisterShader(mt->name);	//just load the regular name.
 			else if (!(star = strchr(gl_shadeq1_name.string, '*')) || (strlen(gl_shadeq1_name.string)+strlen(mt->name)+1>=sizeof(altname)))	//it's got to fit.
-				tx->shader = R_RegisterCustom(gl_shadeq1_name.string, NULL);
+				tx->shader = R_RegisterCustom(gl_shadeq1_name.string, NULL, NULL);
 			else
 			{
 				strncpy(altname, gl_shadeq1_name.string, star-gl_shadeq1_name.string);	//copy the left
 				altname[star-gl_shadeq1_name.string] = '\0';
 				strcat(altname, mt->name);	//insert the *
 				strcat(altname, star+1);	//add any final text.
-				tx->shader = R_RegisterCustom(altname, NULL);
+				tx->shader = R_RegisterCustom(altname, NULL, NULL);
 			}
 		}
 #endif
@@ -1239,7 +1243,7 @@ void GLMod_NowLoadExternal(void)
 		if (!tx)	//e1m2, this happens
 			continue;
 
-		if (!tx->gl_texturenum)
+		if (!tx->tn.base)
 		{
 #ifdef PEXT_BULLETENS
 			if (!R_AddBulleten(tx))
@@ -1253,17 +1257,17 @@ void GLMod_NowLoadExternal(void)
 					tx->alphaed = alphaed;
 				}
 				
-				if (!(tx->gl_texturenum = Mod_LoadHiResTexture(tx->name, loadname, true, false, true)))
-					if (!(tx->gl_texturenum = Mod_LoadHiResTexture(tx->name, "bmodels", true, false, true)))
-						tx->gl_texturenum = Mod_LoadReplacementTexture("light1_4", NULL, true, false, true);	//a fallback. :/
+				if (!(tx->tn.base = Mod_LoadHiResTexture(tx->name, loadname, true, false, true)))
+					if (!(tx->tn.base = Mod_LoadHiResTexture(tx->name, "bmodels", true, false, true)))
+						tx->tn.base = Mod_LoadReplacementTexture("light1_4", NULL, true, false, true);	//a fallback. :/
 			}
 		}
-		if (!tx->gl_texturenumbumpmap && *tx->name != '{' && gl_bumpmappingpossible && cls.allow_bump)
+		if (!tx->tn.bump && *tx->name != '{' && gl_bumpmappingpossible && cls.allow_bump)
 		{
-			tx->gl_texturenumbumpmap = Mod_LoadBumpmapTexture(va("%s_bump", tx->name), loadname);
-			if (!tx->gl_texturenumbumpmap)
-				tx->gl_texturenumbumpmap = Mod_LoadBumpmapTexture(va("%s_bump", tx->name), "bmodels");
-			if (!tx->gl_texturenumbumpmap)
+			tx->tn.bump = Mod_LoadBumpmapTexture(va("%s_bump", tx->name), loadname);
+			if (!tx->tn.bump)
+				tx->tn.bump = Mod_LoadBumpmapTexture(va("%s_bump", tx->name), "bmodels");
+			if (!tx->tn.bump)
 			{
 				qbyte *data;
 				qbyte *heightmap;
@@ -1280,7 +1284,7 @@ void GLMod_NowLoadExternal(void)
 					*heightmap++ = (data[j*4+0] + data[j*4+1] + data[j*4+2])/3;
 				}
 				
-				tx->gl_texturenumbumpmap = R_LoadTexture8Bump (va("%s_bump", tx->name), width, height, heightmap-j, true, r_shadow_bumpscale_basetexture.value);
+				tx->tn.bump = R_LoadTexture8Bump (va("%s_bump", tx->name), width, height, heightmap-j, true, r_shadow_bumpscale_basetexture.value);
 			}
 		}
 	}
diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h
index 09068635b..d4f6686cc 100644
--- a/engine/gl/gl_model.h
+++ b/engine/gl/gl_model.h
@@ -44,15 +44,15 @@ typedef struct {
 	qboolean (*NativeTrace)		(struct model_s *model, int hulloverride, int frame, vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, unsigned int against, struct trace_s *trace);
 	unsigned int (*NativeContents)(struct model_s *model, int hulloverride, int frame, vec3_t p, vec3_t mins, vec3_t maxs);
 
-	void (*FatPVS)				(struct model_s *model, vec3_t org, qboolean add);
-	qboolean (*EdictInFatPVS)	(struct model_s *model, struct edict_s *edict);
+	unsigned int (*FatPVS)		(struct model_s *model, vec3_t org, qbyte *pvsbuffer, unsigned int buffersize, qboolean merge);
+	qboolean (*EdictInFatPVS)	(struct model_s *model, struct edict_s *edict, qbyte *pvsbuffer);
 	void (*FindTouchedLeafs_Q1)	(struct model_s *model, struct edict_s *ent, vec3_t cullmins, vec3_t cullmaxs);	//edict system as opposed to q2 game dll system.
 
 	void (*LightPointValues)	(struct model_s *model, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir);
 	void (*StainNode)			(struct mnode_s *node, float *parms);
 	void (*MarkLights)			(struct dlight_s *light, int bit, struct mnode_s *node);
 
-	qbyte *(*LeafPVS)			(struct model_s *model, int num, qbyte *buffer);
+	qbyte *(*LeafPVS)			(struct model_s *model, int num, qbyte *buffer, unsigned int buffersize);
 	int	(*LeafnumForPoint)		(struct model_s *model, vec3_t point);
 } bspfuncs_t;
 
@@ -91,8 +91,11 @@ typedef struct mesh_s
 
 	vec3_t			lightaxis[3];
 
+	//FIXME: these can go when the new backend is done
 	unsigned int	patchWidth;
 	unsigned int	patchHeight;
+
+	struct mesh_s	*next;
 } mesh_t;
 struct meshbuffer_s;
 
@@ -163,6 +166,13 @@ typedef struct mplane_s
 	qbyte	pad[2];
 } mplane_t;
 
+typedef struct {
+	int base;
+	int bump;
+	int specular;
+	int fullbright;
+} texnums_t;
+
 typedef struct texture_s
 {
 	char		name[64];
@@ -173,10 +183,7 @@ typedef struct texture_s
 
 	int parttype;
 
-	int			gl_texturenum;
-	int			gl_texturenumfb;
-	int			gl_texturenumbumpmap;
-	int			gl_texturenumspec;
+	texnums_t tn;
 
 	struct shader_s	*shader;
 
@@ -191,8 +198,12 @@ typedef struct texture_s
 	unsigned	offsets[MIPLEVELS];		// four mip maps stored
 } texture_t;
 
-//the per-texture vbos have this stride (v_pos/st/lm_st)
-#define VBOSTRIDE (3+2+2)*sizeof(float)
+typedef struct
+{
+	float coord[3];
+	float texcoord[2];
+	float lmcoord[2];
+} vbovertex_t;
 
 #define SURF_DRAWSKYBOX		0x00001
 #define	SURF_PLANEBACK		0x00002
@@ -409,8 +420,8 @@ void Q1BSP_Init(void);
 
 qboolean Q1BSP_Trace(struct model_s *model, int forcehullnum, int frame, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, struct trace_s *trace);
 qboolean Q1BSP_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, struct trace_s *trace);
-void Q1BSP_FatPVS (struct model_s *mod, vec3_t org, qboolean add);
-qboolean Q1BSP_EdictInFatPVS(struct model_s *mod, struct edict_s *ent);
+void Q1BSP_FatPVS (struct model_s *mod, vec3_t org, qbyte *pvsbuffer, unsigned int buffersize, qboolean add);
+qboolean Q1BSP_EdictInFatPVS(struct model_s *mod, struct edict_s *ent, qbyte *pvs);
 void Q1BSP_FindTouchedLeafs(struct model_s *mod, struct edict_s *ent, float *mins, float *maxs);
 qbyte *Q1BSP_LeafPVS (struct model_s *model, mleaf_t *leaf, qbyte *buffer);
 
@@ -891,7 +902,7 @@ int		CM_LeafCluster (struct model_s *mod, int leafnum);
 int		CM_LeafArea (struct model_s *mod, int leafnum);
 int		CM_WriteAreaBits (struct model_s *mod, qbyte *buffer, int area);
 int		CM_PointLeafnum (struct model_s *mod, vec3_t p);
-qbyte	*CM_ClusterPVS (struct model_s *mod, int cluster, qbyte *buffer);
+qbyte	*CM_ClusterPVS (struct model_s *mod, int cluster, qbyte *buffer, unsigned int buffersize);
 qbyte	*CM_ClusterPHS (struct model_s *mod, int cluster);
 int		CM_BoxLeafnums (struct model_s *mod, vec3_t mins, vec3_t maxs, int *list, int listsize, int *topnode);
 int		CM_PointContents (struct model_s *mod, vec3_t p);
diff --git a/engine/gl/gl_ppl.c b/engine/gl/gl_ppl.c
index f51b654ae..2c23ee0e6 100644
--- a/engine/gl/gl_ppl.c
+++ b/engine/gl/gl_ppl.c
@@ -3,6 +3,9 @@
 //This is bad. lights*3, 33% framerate for no worthwhile effect.
 
 #include "quakedef.h"
+
+#ifndef NEWBACKEND
+
 #ifdef RGLQUAKE
 #include "glquake.h"
 #include "shader.h"
@@ -250,7 +253,7 @@ static void PPL_BaseChain_NoBump_1TMU(msurface_t *first, texture_t *tex)
 	qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
 
 	GL_TexEnv(GL_REPLACE);
-	GL_Bind (tex->gl_texturenum);
+	GL_Bind (tex->tn.base);
 
 	for (s=first; s ; s=s->texturechain)
 	{
@@ -404,7 +407,7 @@ static void PPL_BaseChain_NoBump_2TMU_Overbright(msurface_t *s, texture_t *tex)
 	}
 
 
-	GL_MBind(GL_TEXTURE0_ARB, tex->gl_texturenum);
+	GL_MBind(GL_TEXTURE0_ARB, tex->tn.base);
 	qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
 
 	GL_SelectTexture(GL_TEXTURE1_ARB);
@@ -498,7 +501,7 @@ static void PPL_BaseChain_VBO_NoBump_2TMU_Overbright(msurface_t *s, texture_t *t
 	qglBindBufferARB(GL_ARRAY_BUFFER_ARB, tex->gl_vbov);
 	qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, tex->gl_vboe);
 
-	qglVertexPointer(3, GL_FLOAT, VBOSTRIDE, NULL);
+	qglVertexPointer(3, GL_FLOAT, sizeof(vbovertex_t), ((vbovertex_t*)NULL)->coord);
 
 	if (tex->alphaed || currententity->shaderRGBAf[3]<1)
 	{
@@ -521,13 +524,13 @@ static void PPL_BaseChain_VBO_NoBump_2TMU_Overbright(msurface_t *s, texture_t *t
 	}
 
 
-	GL_MBind(GL_TEXTURE0_ARB, tex->gl_texturenum);
+	GL_MBind(GL_TEXTURE0_ARB, tex->tn.base);
 	qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
-	qglTexCoordPointer(2, GL_FLOAT, VBOSTRIDE, (void*)(3*sizeof(float)));
+	qglTexCoordPointer(2, GL_FLOAT, sizeof(vbovertex_t), ((vbovertex_t*)NULL)->texcoord);
 
 	GL_SelectTexture(GL_TEXTURE1_ARB);
 	qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
-	qglTexCoordPointer(2, GL_FLOAT, VBOSTRIDE, (void*)(5*sizeof(float)));
+	qglTexCoordPointer(2, GL_FLOAT, sizeof(vbovertex_t), ((vbovertex_t*)NULL)->lmcoord);
 
 	GL_TexEnv(GL_MODULATE);
 
@@ -725,7 +728,7 @@ static void PPL_BaseChain_Bump_2TMU(msurface_t *first, texture_t *tex)
 	}
 
 	//Bind normal map to texture unit 0
-	GL_MBind(GL_TEXTURE0_ARB, tex->gl_texturenumbumpmap);
+	GL_MBind(GL_TEXTURE0_ARB, tex->tn.bump);
 	qglEnable(GL_TEXTURE_2D);
 	GL_TexEnv(GL_COMBINE_ARB);
 	qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
@@ -734,7 +737,7 @@ static void PPL_BaseChain_Bump_2TMU(msurface_t *first, texture_t *tex)
 	qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
 	qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
 
-	GL_MBind(GL_TEXTURE1_ARB, tex->gl_texturenumbumpmap);
+	GL_SelectTexture(GL_TEXTURE1_ARB);
 	qglEnable(GL_TEXTURE_2D);
 	GL_TexEnv(GL_COMBINE_ARB);
 	qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
@@ -760,7 +763,7 @@ static void PPL_BaseChain_Bump_2TMU(msurface_t *first, texture_t *tex)
 				theRect = &lightmap[vi]->deluxrectchange;
 				qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, 
 					LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
-					lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*3);
+					lightmap[vi]->deluxmaps+(theRect->t) *LMBLOCK_WIDTH*3);
 				theRect->l = LMBLOCK_WIDTH;
 				theRect->t = LMBLOCK_HEIGHT;
 				theRect->h = 0;
@@ -775,7 +778,7 @@ static void PPL_BaseChain_Bump_2TMU(msurface_t *first, texture_t *tex)
 	qglEnable(GL_BLEND);
 	qglBlendFunc(GL_DST_COLOR, GL_ZERO);
 
-	GL_MBind(GL_TEXTURE0_ARB, tex->gl_texturenum);
+	GL_MBind(GL_TEXTURE0_ARB, tex->tn.base);
 
 	GL_SelectTexture(GL_TEXTURE1_ARB);
 	qglEnable(GL_TEXTURE_2D);
@@ -812,6 +815,7 @@ static void PPL_BaseChain_Bump_2TMU(msurface_t *first, texture_t *tex)
 	qglDisable(GL_BLEND);
 
 	qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
+	qglDisable(GL_TEXTURE_2D);
 	GL_SelectTexture(GL_TEXTURE0_ARB);
 }
 
@@ -823,7 +827,7 @@ static void PPL_BaseChain_Bump_4TMU(msurface_t *s, texture_t *tex)
 	PPL_EnableVertexArrays();
 
 	//Bind normal map to texture unit 0
-	GL_MBind(GL_TEXTURE0_ARB, tex->gl_texturenumbumpmap);
+	GL_MBind(GL_TEXTURE0_ARB, tex->tn.bump);
 	qglEnable(GL_TEXTURE_2D);
 	GL_TexEnv(GL_REPLACE);
 
@@ -842,7 +846,7 @@ static void PPL_BaseChain_Bump_4TMU(msurface_t *s, texture_t *tex)
 	qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
 
 	//2 gets the diffusemap
-	GL_MBind(GL_TEXTURE2_ARB, tex->gl_texturenum);
+	GL_MBind(GL_TEXTURE2_ARB, tex->tn.base);
 	qglEnable(GL_TEXTURE_2D);
 	GL_TexEnv(GL_MODULATE);
 
@@ -1183,7 +1187,7 @@ void PPL_LoadSpecularFragmentProgram(void)
 
 		"	diff = bases * dot(bumps, deluxs);\n"
 		"	float dv = dot(normalize(halfnorm), bumps);\n"
-		"	spec = pow(dv, 8.0) * specs;\n"
+		"	spec = pow(dv, 16.0) * specs;\n"
 		"	gl_FragColor = vec4((diff+spec)*lms, 1.0);\n"
 		"}\n"
 		;
@@ -1221,17 +1225,17 @@ static void PPL_BaseChain_Specular_FP(msurface_t *s, texture_t *tex)
 	if (qglGetError())
 		Con_Printf("GL Error on shadow lighting\n");
 
-	GL_MBind(GL_TEXTURE0_ARB, tex->gl_texturenum);
+	GL_MBind(GL_TEXTURE0_ARB, tex->tn.base);
 	qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
 
-	GL_MBind(GL_TEXTURE1_ARB, tex->gl_texturenumbumpmap);
+	GL_MBind(GL_TEXTURE1_ARB, tex->tn.bump);
 	qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
 
 //	GL_MBind(GL_TEXTURE2_ARB, lightmap_textures[vi] );
 
 //	GL_MBind(GL_TEXTURE3_ARB, deluxmap_textures[vi] );
 
-	GL_MBind(GL_TEXTURE4_ARB, tex->gl_texturenumspec);
+	GL_MBind(GL_TEXTURE4_ARB, tex->tn.specular);
 
 	qglUniform3fvARB(ppl_specular_shader_vieworg, 1, r_refdef.vieworg);
 
@@ -1804,7 +1808,7 @@ static void PPL_BaseTextureChain(msurface_t *first)
 	{
 		GL_DisableMultitexture();
 		qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-		GL_Bind (t->gl_texturenum);
+		GL_Bind (t->tn.base);
 		for (; first ; first=first->texturechain)
 			EmitWaterPolys (first, currententity->shaderRGBAf[3]);
 
@@ -1824,11 +1828,11 @@ static void PPL_BaseTextureChain(msurface_t *first)
 	}
 	else
 	{
-		if (gl_bump.value && currentmodel->deluxdata && t->gl_texturenumbumpmap)
+		if (gl_bump.value && currentmodel->deluxdata && t->tn.bump)
 		{
 			if (gl_mtexarbable>=4)
 			{
-				if (t->gl_texturenumspec && gl_specular.value)
+				if (t->tn.specular && gl_specular.value)
 				{
 					if (ppl_specular_shader)
 						PPL_BaseChain_Specular_FP(first, t);
@@ -1878,9 +1882,9 @@ static void PPL_FullBrightTextureChain(msurface_t *first)
 		PPL_FlushArrays();
 	}
 
-	if (t->gl_texturenumfb && r_fb_bmodels.value && cls.allow_luma)
+	if (t->tn.fullbright && r_fb_bmodels.value && cls.allow_luma)
 	{
-		GL_Bind(t->gl_texturenumfb);
+		GL_Bind(t->tn.fullbright);
 		qglBlendFunc(GL_SRC_ALPHA, GL_ONE);
 		if (gl_mylumassuck.value)
 			qglEnable(GL_ALPHA_TEST);
@@ -2710,11 +2714,11 @@ void PPL_LightTexturesFP_Cached(model_t *model, vec3_t modelorigin, dlight_t *li
 
 
 			p = 0;
-			if (t->gl_texturenumbumpmap && ppl_light_shader[p|PERMUTATION_BUMPMAP])
+			if (t->tn.bump && ppl_light_shader[p|PERMUTATION_BUMPMAP])
 				p |= PERMUTATION_BUMPMAP;
-			if (gl_specular.value && t->gl_texturenumspec && ppl_light_shader[p|PERMUTATION_SPECULAR])
+			if (gl_specular.value && t->tn.specular && ppl_light_shader[p|PERMUTATION_SPECULAR])
 				p |= PERMUTATION_SPECULAR;
-			if (r_shadow_glsl_offsetmapping.value && t->gl_texturenumbumpmap && ppl_light_shader[p|PERMUTATION_OFFSET])
+			if (r_shadow_glsl_offsetmapping.value && t->tn.bump && ppl_light_shader[p|PERMUTATION_OFFSET])
 				p |= PERMUTATION_OFFSET;
 
 			if (p != lp)
@@ -2735,11 +2739,11 @@ void PPL_LightTexturesFP_Cached(model_t *model, vec3_t modelorigin, dlight_t *li
 
 
 			if (p & PERMUTATION_BUMPMAP)
-				GL_MBind(GL_TEXTURE1_ARB, t->gl_texturenumbumpmap);
+				GL_MBind(GL_TEXTURE1_ARB, t->tn.bump);
 			if (p & PERMUTATION_SPECULAR)
-				GL_MBind(GL_TEXTURE2_ARB, t->gl_texturenumspec);
+				GL_MBind(GL_TEXTURE2_ARB, t->tn.specular);
 
-			GL_MBind(GL_TEXTURE0_ARB, t->gl_texturenum);
+			GL_MBind(GL_TEXTURE0_ARB, t->tn.base);
 			qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
 
 
@@ -2805,10 +2809,12 @@ void PPL_LightTexturesFP(model_t *model, vec3_t modelorigin, dlight_t *light, ve
 
 
 		p = 0;
-		if (t->gl_texturenumbumpmap && ppl_light_shader[p|PERMUTATION_BUMPMAP])
+		if (t->tn.bump && ppl_light_shader[p|PERMUTATION_BUMPMAP])
 			p |= PERMUTATION_BUMPMAP;
-		if (gl_specular.value && t->gl_texturenumspec && ppl_light_shader[p|PERMUTATION_SPECULAR])
+		if (gl_specular.value && t->tn.specular && ppl_light_shader[p|PERMUTATION_SPECULAR])
 			p |= PERMUTATION_SPECULAR;
+		if (r_shadow_glsl_offsetmapping.value && t->tn.bump && ppl_light_shader[p|PERMUTATION_OFFSET])
+			p |= PERMUTATION_OFFSET;
 
 		if (p != lp)
 		{
@@ -2819,15 +2825,20 @@ void PPL_LightTexturesFP(model_t *model, vec3_t modelorigin, dlight_t *light, ve
 			qglUniform3fvARB(ppl_light_shader_lightposition[p], 1, relativelightorigin);
 			qglUniform3fvARB(ppl_light_shader_lightcolour[p], 1, colour);
 			qglUniform1fARB(ppl_light_shader_lightradius[p], light->radius);
+
+			if (ppl_light_shader_offset_scale[p]!=-1)
+				qglUniform1fARB(ppl_light_shader_offset_scale[p], r_shadow_glsl_offsetmapping_scale.value);
+			if (ppl_light_shader_offset_bias[p]!=-1)
+				qglUniform1fARB(ppl_light_shader_offset_bias[p], r_shadow_glsl_offsetmapping_bias.value);
 		}
 
 
 		if (p & PERMUTATION_BUMPMAP)
-			GL_MBind(GL_TEXTURE1_ARB, t->gl_texturenumbumpmap);
+			GL_MBind(GL_TEXTURE1_ARB, t->tn.bump);
 		if (p & PERMUTATION_SPECULAR)
-			GL_MBind(GL_TEXTURE2_ARB, t->gl_texturenumspec);
+			GL_MBind(GL_TEXTURE2_ARB, t->tn.specular);
 
-		GL_MBind(GL_TEXTURE0_ARB, t->gl_texturenum);
+		GL_MBind(GL_TEXTURE0_ARB, t->tn.base);
 		qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
 
 		for (; s; s=s->texturechain)
@@ -2910,9 +2921,9 @@ void PPL_LightTextures(model_t *model, vec3_t modelorigin, dlight_t *light, vec3
 
 			qglEnableClientState(GL_COLOR_ARRAY);
 			qglColorPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
-			if (t->gl_texturenumbumpmap && gl_mtexarbable>3)
+			if (t->tn.bump && gl_mtexarbable>3)
 			{
-				GL_MBind(GL_TEXTURE0_ARB, t->gl_texturenumbumpmap);
+				GL_MBind(GL_TEXTURE0_ARB, t->tn.bump);
 				qglEnable(GL_TEXTURE_2D);
 				//Set up texture environment to do (tex0 dot tex1)*color
 				GL_TexEnv(GL_REPLACE);	//make texture normalmap available.
@@ -2931,7 +2942,7 @@ void PPL_LightTextures(model_t *model, vec3_t modelorigin, dlight_t *light, vec3
 				qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
 				qglTexCoordPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->ncm);
 
-				GL_MBind(GL_TEXTURE2_ARB, t->gl_texturenumbumpmap);	//a dummy
+				GL_MBind(GL_TEXTURE2_ARB, t->tn.bump);	//a dummy
 				qglEnable(GL_TEXTURE_2D);
 				GL_TexEnv(GL_COMBINE_ARB);	//bumps * color		(the attenuation)
 				qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB); //(doesn't actually use the bound texture)
@@ -2939,7 +2950,7 @@ void PPL_LightTextures(model_t *model, vec3_t modelorigin, dlight_t *light, vec3
 				qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
 				qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
 
-				GL_MBind(GL_TEXTURE3_ARB, t->gl_texturenum);
+				GL_MBind(GL_TEXTURE3_ARB, t->tn.base);
 				qglEnable(GL_TEXTURE_2D);
 				qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
 				qglTexCoordPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
@@ -3054,9 +3065,9 @@ void PPL_LightBModelTexturesFP(entity_t *e, dlight_t *light, vec3_t colour)
 			t = R_TextureAnimation (tnum);
 
 			p = 0;
-			if (t->gl_texturenumbumpmap && ppl_light_shader[p|PERMUTATION_BUMPMAP])
+			if (t->tn.bump && ppl_light_shader[p|PERMUTATION_BUMPMAP])
 				p |= PERMUTATION_BUMPMAP;
-			if (gl_specular.value && t->gl_texturenumspec && ppl_light_shader[p|PERMUTATION_SPECULAR])
+			if (gl_specular.value && t->tn.specular && ppl_light_shader[p|PERMUTATION_SPECULAR])
 				p |= PERMUTATION_SPECULAR;
 			if (p != lp)
 			{
@@ -3069,10 +3080,10 @@ void PPL_LightBModelTexturesFP(entity_t *e, dlight_t *light, vec3_t colour)
 				qglUniform1fARB(ppl_light_shader_lightradius[p], light->radius);
 			}
 
-			GL_MBind(GL_TEXTURE0_ARB, t->gl_texturenum);
+			GL_MBind(GL_TEXTURE0_ARB, t->tn.base);
 			qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
-			GL_MBind(GL_TEXTURE1_ARB, t->gl_texturenumbumpmap);
-			GL_MBind(GL_TEXTURE2_ARB, t->gl_texturenumspec);
+			GL_MBind(GL_TEXTURE1_ARB, t->tn.bump);
+			GL_MBind(GL_TEXTURE2_ARB, t->tn.specular);
 			GL_SelectTexture(GL_TEXTURE0_ARB);
 		}
 
@@ -3131,9 +3142,9 @@ void PPL_LightBModelTextures(entity_t *e, dlight_t *light, vec3_t colour)
 
 			qglEnableClientState(GL_COLOR_ARRAY);
 			qglColorPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
-			if (t->gl_texturenumbumpmap && gl_mtexarbable>3)
+			if (t->tn.bump && gl_mtexarbable>3)
 			{
-				GL_MBind(GL_TEXTURE0_ARB, t->gl_texturenumbumpmap);
+				GL_MBind(GL_TEXTURE0_ARB, t->tn.bump);
 				qglEnable(GL_TEXTURE_2D);
 				//Set up texture environment to do (tex0 dot tex1)*color
 				GL_TexEnv(GL_REPLACE);	//make texture normalmap available.
@@ -3152,7 +3163,7 @@ void PPL_LightBModelTextures(entity_t *e, dlight_t *light, vec3_t colour)
 				qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
 				qglTexCoordPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->ncm);
 
-				GL_MBind(GL_TEXTURE2_ARB, t->gl_texturenumbumpmap);
+				GL_MBind(GL_TEXTURE2_ARB, t->tn.bump);
 				qglEnable(GL_TEXTURE_2D);
 				GL_TexEnv(GL_COMBINE_ARB);	//bumps * color		(the attenuation)
 				qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB); //(doesn't actually use the bound texture)
@@ -3160,7 +3171,7 @@ void PPL_LightBModelTextures(entity_t *e, dlight_t *light, vec3_t colour)
 				qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
 				qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
 
-				GL_MBind(GL_TEXTURE3_ARB, t->gl_texturenum);
+				GL_MBind(GL_TEXTURE3_ARB, t->tn.base);
 				qglEnable(GL_TEXTURE_2D);
 				qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
 				qglTexCoordPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
@@ -4883,8 +4894,8 @@ qboolean PPL_AddLight(dlight_t *dl)
 			i = r_viewleaf - cl.worldmodel->leafs;
 
 		leaf = cl.worldmodel->funcs.LeafnumForPoint(cl.worldmodel, dl->origin);
-		lvis = cl.worldmodel->funcs.LeafPVS(cl.worldmodel, leaf, lvisb);
-		vvis = cl.worldmodel->funcs.LeafPVS(cl.worldmodel, i, vvisb);
+		lvis = cl.worldmodel->funcs.LeafPVS(cl.worldmodel, leaf, lvisb, sizeof(lvisb));
+		vvis = cl.worldmodel->funcs.LeafPVS(cl.worldmodel, i, vvisb, sizeof(vvisb));
 
 	//	if (!(lvis[i>>3] & (1<<(i&7))))	//light might not be visible, but it's effects probably should be.
 	//		return;
@@ -5550,8 +5561,5 @@ void PPL_FinishShadowMesh(dlight_t *dl)
 }
 
 #endif	//ifdef GLQUAKE
-
-
-
-
+#endif
 
diff --git a/engine/gl/gl_rlight.c b/engine/gl/gl_rlight.c
index 1d286e22e..4ac7bae10 100644
--- a/engine/gl/gl_rlight.c
+++ b/engine/gl/gl_rlight.c
@@ -98,7 +98,8 @@ void AddLightBlend (float r, float g, float b, float a2)
 
 float bubble_sintable[17], bubble_costable[17];
 
-void R_InitBubble() {
+void R_InitBubble(void)
+{
 	float a;
 	int i;
 	float *bub_sin, *bub_cos;
diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c
index 19401582d..7071e70d9 100644
--- a/engine/gl/gl_rmain.c
+++ b/engine/gl/gl_rmain.c
@@ -66,7 +66,6 @@ int			particletexture;	// little dot for particles
 int			particlecqtexture;	// little dot for particles
 int			explosiontexture;
 int			balltexture;
-int			playertextures;		// up to 16 color translated skins
 
 int			mirrortexturenum;	// quake texturenum, not gltexturenum
 qboolean	mirror;
@@ -288,14 +287,14 @@ void GL_SetupSceneProcessingTextures (void)
 	unsigned char pp_warp_tex[PP_WARP_TEX_SIZE*PP_WARP_TEX_SIZE*3];
 	unsigned char pp_edge_tex[PP_AMP_TEX_SIZE*PP_AMP_TEX_SIZE*3];
 
-	sceneblur_texture = texture_extension_number++;
+	sceneblur_texture = GL_AllocNewTexture();
 
 	if (!gl_config.arb_shader_objects)
 		return;
 
-	scenepp_texture = texture_extension_number++;
-	scenepp_texture_warp = texture_extension_number++;
-	scenepp_texture_edge = texture_extension_number++;
+	scenepp_texture = GL_AllocNewTexture();
+	scenepp_texture_warp = GL_AllocNewTexture();
+	scenepp_texture_edge = GL_AllocNewTexture();
 
 	// init warp texture - this specifies offset in 
 	for (y=0; y<PP_WARP_TEX_SIZE; y++)
@@ -1151,6 +1150,10 @@ void R_RenderScene (void)
 	if (!cl.worldmodel || (!cl.worldmodel->nodes && cl.worldmodel->type != mod_heightmap))
 		r_refdef.flags |= Q2RDF_NOWORLDMODEL;
 
+#ifdef NEWBACKEND
+	PPL_GenShadowMaps();
+#endif
+
 	GLR_SetupFrame ();
 
 	TRACE(("dbg: calling R_SetupGL\n"));
diff --git a/engine/gl/gl_rmisc.c b/engine/gl/gl_rmisc.c
index 1779e4715..00e0f85d0 100644
--- a/engine/gl/gl_rmisc.c
+++ b/engine/gl/gl_rmisc.c
@@ -136,7 +136,7 @@ void R_InitParticleTexture (void)
 	//
 	// particle texture
 	//
-	particletexture = texture_extension_number++;
+	particletexture = GL_AllocNewTexture();
     GL_Bind(particletexture);
 
 	for (x=0 ; x<8 ; x++)
@@ -160,7 +160,7 @@ void R_InitParticleTexture (void)
 	//
 	// particle triangle texture
 	//
-	particlecqtexture = texture_extension_number++;
+	particlecqtexture = GL_AllocNewTexture();
     GL_Bind(particlecqtexture);
 
 	// clear to transparent white
@@ -191,7 +191,7 @@ void R_InitParticleTexture (void)
 
 
 
-	explosiontexture = texture_extension_number++;
+	explosiontexture = GL_AllocNewTexture();
     GL_Bind(explosiontexture);
 
 	for (x=0 ; x<16 ; x++)
@@ -224,7 +224,7 @@ void R_InitParticleTexture (void)
 			data[y*PARTICLETEXTURESIZE+x][3] = (qbyte) d;
 		}
 	}
-	balltexture = texture_extension_number++;
+	balltexture = GL_AllocNewTexture();
     GL_Bind(balltexture);
 	qglTexImage2D (GL_TEXTURE_2D, 0, gl_alpha_format, PARTICLETEXTURESIZE, PARTICLETEXTURESIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
 	qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
@@ -480,16 +480,12 @@ void GLR_ReInit (void)
 	Test_Init ();
 #endif
 
-	netgraphtexture = texture_extension_number;
-	texture_extension_number++;
-
-	playertextures = texture_extension_number;
-	texture_extension_number += MAX_CLIENTS;
+	netgraphtexture = GL_AllocNewTexture();
 
 	if (gl_bumpmappingpossible)
 	{
 		//Create normalisation cube map
-		normalisationCubeMap = texture_extension_number++;
+		normalisationCubeMap = GL_AllocNewTexture();
 		GL_BindType(GL_TEXTURE_CUBE_MAP_ARB, normalisationCubeMap);
 		GenerateNormalisationCubeMap();
 		qglTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -783,209 +779,6 @@ void GLR_Init (void)
 	GLR_ReInit();
 }
 
-/*
-===============
-R_TranslatePlayerSkin
-
-Translates a skin texture by the per-player color lookup
-===============
-*/
-/*
-void R_TranslatePlayerSkin (int playernum)
-{
-	int		top, bottom;
-	qbyte	translate[256];
-	unsigned	translate32[256];
-	int		i, j;
-	qbyte	*original;
-	unsigned	pixels[512*256], *out;
-	unsigned	scaled_width, scaled_height;
-	int			inwidth, inheight;
-	int			tinwidth, tinheight;
-	qbyte		*inrow;
-	unsigned	frac, fracstep;
-	player_info_t *player;
-	extern	qbyte		*player_8bit_texels;
-	char s[512];
-
-	GL_DisableMultitexture();
-
-	player = &cl.players[playernum];
-	if (!player->name[0])
-		return;
-
-	strcpy(s, Info_ValueForKey(player->userinfo, "skin"));
-	COM_StripExtension(s, s);
-	if (player->skin && !stricmp(s, player->skin->name))
-		player->skin = NULL;
-
-	if (player->_topcolor != player->topcolor ||
-		player->_bottomcolor != player->bottomcolor || !player->skin) {
-		player->_topcolor = player->topcolor;
-		player->_bottomcolor = player->bottomcolor;
-
-		top = player->topcolor;
-		bottom = player->bottomcolor;
-		top = (top < 0) ? 0 : ((top > 13) ? 13 : top);
-		bottom = (bottom < 0) ? 0 : ((bottom > 13) ? 13 : bottom);
-		top *= 16;
-		bottom *= 16;
-
-		for (i=0 ; i<256 ; i++)
-			translate[i] = i;
-
-		for (i=0 ; i<16 ; i++)
-		{
-			if (top < 128)	// the artists made some backwards ranges.  sigh.
-				translate[TOP_RANGE+i] = top+i;
-			else
-				translate[TOP_RANGE+i] = top+15-i;
-					
-			if (bottom < 128)
-				translate[BOTTOM_RANGE+i] = bottom+i;
-			else
-				translate[BOTTOM_RANGE+i] = bottom+15-i;
-		}
-
-		//
-		// locate the original skin pixels
-		//
-		// real model width
-		tinwidth = 296;
-		tinheight = 194;
-
-		if (!player->skin)
-			Skin_Find(player);
-		if ((original = Skin_Cache8(player->skin)) != NULL) {
-			//skin data width
-			inwidth = player->skin->width;
-			inheight = player->skin->height;
-		} else {
-			original = player_8bit_texels;
-			inwidth = 296;
-			inheight = 194;
-		}
-		//tinwidth = 251&~3;
-		//tinheight = 194&~3;
-		//tinwidth = 319&~3;
-		//tinheight = 199&~3;
-
-		if (!original)	//can't.
-			return;
-
-
-		// because this happens during gameplay, do it fast
-		// instead of sending it through gl_upload 8
-		GL_Bind(playertextures + playernum);
-
-	#if 0
-		s = 320*200;
-		qbyte	translated[320*200];
-
-		for (i=0 ; i<s ; i+=4)
-		{
-			translated[i] = translate[original[i]];
-			translated[i+1] = translate[original[i+1]];
-			translated[i+2] = translate[original[i+2]];
-			translated[i+3] = translate[original[i+3]];
-		}
-
-
-		// don't mipmap these, because it takes too long
-		GL_Upload8 (translated, paliashdr->skinwidth, paliashdr->skinheight, 
-			false, false, true);
-	#endif
-
-		scaled_width = gl_max_size.value < 512 ? gl_max_size.value : 512;
-		scaled_height = gl_max_size.value < 256 ? gl_max_size.value : 256;
-		// allow users to crunch sizes down even more if they want
-		scaled_width >>= (int)gl_playermip.value;
-		scaled_height >>= (int)gl_playermip.value;
-
-		if (scaled_width < 8)
-			scaled_width = 8;
-		if (scaled_height < 8)
-			scaled_height = 8;
-#ifdef GL_USE8BITTEX
-#ifdef GL_EXT_paletted_texture
-		if (GLVID_Is8bit())
-		{// 8bit texture upload
-			qbyte *out2;
-
-			out2 = (qbyte *)pixels;
-			memset(pixels, 0, sizeof(pixels));
-			fracstep = tinwidth*0x10000/scaled_width;
-			for (i=0 ; i<scaled_height ; i++, out2 += scaled_width)
-			{
-				inrow = original + inwidth*(i*tinheight/scaled_height);
-				frac = fracstep >> 1;
-				for (j=0 ; j<scaled_width ; j+=4)
-				{
-					out2[j] = translate[inrow[frac>>16]];
-					frac += fracstep;
-					out2[j+1] = translate[inrow[frac>>16]];
-					frac += fracstep;
-					out2[j+2] = translate[inrow[frac>>16]];
-					frac += fracstep;
-					out2[j+3] = translate[inrow[frac>>16]];
-					frac += fracstep;
-				}
-			}
-
-			GL_Upload8_EXT ((qbyte *)pixels, scaled_width, scaled_height, false, false);
-			return;
-		}
-#endif
-#endif
-
-#ifdef Q2BSP
-		if (cls.q2server)
-		{
-			extern unsigned char d_q28to24table[768];
-			for (i=0 ; i<256 ; i++)
-			{
-				translate32[i] = d_q28to24table[i*3] |
-								(d_q28to24table[i*3+1]<<8) |
-								(d_q28to24table[i*3+2]<<16) |
-								255<<24;
-			}
-		}
-		else
-#endif
-			for (i=0 ; i<256 ; i++)
-				translate32[i] = d_8to24rgbtable[translate[i]];
-
-		out = pixels;
-		memset(pixels, 0, sizeof(pixels));
-		fracstep = tinwidth*0x10000/scaled_width;
-		for (i=0 ; i<scaled_height ; i++, out += scaled_width)
-		{
-			inrow = original + inwidth*(i*tinheight/scaled_height);
-			frac = fracstep >> 1;
-			for (j=0 ; j<scaled_width ; j+=4)
-			{
-				out[j] = translate32[inrow[frac>>16]];
-				frac += fracstep;
-				out[j+1] = translate32[inrow[frac>>16]];
-				frac += fracstep;
-				out[j+2] = translate32[inrow[frac>>16]];
-				frac += fracstep;
-				out[j+3] = translate32[inrow[frac>>16]];
-				frac += fracstep;
-			}
-		}
-
-		glTexImage2D (GL_TEXTURE_2D, 0, gl_solid_format, 
-			scaled_width, scaled_height, 0, GL_RGBA, 
-			GL_UNSIGNED_BYTE, pixels);
-
-		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-	}
-}
-*/
-
 
 void R_LoadRTLights(void)
 {
@@ -1038,21 +831,20 @@ void R_LoadRTLights(void)
 		file = COM_Parse(file);
 		style = atoi(com_token);
 
-		if (!file)
-			break;
+		if (file)
+		{
+			dl = CL_AllocDlight(0);
+			VectorCopy(org, dl->origin);
+			dl->radius = radius;
+			VectorCopy(rgb, dl->color);
+			dl->die = cl.time + 0x7fffffff;
+			dl->isstatic = true;
 
-		dl = CL_AllocDlight(0);
-		VectorCopy(org, dl->origin);
-		dl->radius = radius;
-		VectorCopy(rgb, dl->color);
-		dl->die = cl.time + 0x7fffffff;
-		dl->isstatic = true;
-
-		dl->nodynamic = true;
-		dl->noflash = true;
-
-		dl->style = style+1;
+			dl->nodynamic = true;
+			dl->noflash = true;
 
+			dl->style = style+1;
+		}
 		file = end+1;
 	}
 }
diff --git a/engine/gl/gl_rsurf.c b/engine/gl/gl_rsurf.c
index 38b9085b7..a735561fa 100644
--- a/engine/gl/gl_rsurf.c
+++ b/engine/gl/gl_rsurf.c
@@ -1727,125 +1727,8 @@ static void DrawGLPoly (mesh_t *mesh)
 	qglTexCoordPointer(2, GL_FLOAT, 0, mesh->st_array);
 	qglDrawElements(GL_TRIANGLES, mesh->numindexes, GL_INDEX_TYPE, mesh->indexes);
 	R_IBrokeTheArrays();
-
-	/*
-	int		i;
-	float	*v;
-
-	while(p)
-	{
-		qglBegin (GL_POLYGON);
-		v = p->verts[0];
-		for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
-		{
-			qglTexCoord2f (v[3], v[4]);
-			qglVertex3fv (v);
-		}
-		qglEnd ();
-		p=p->next;
-	}
-	*/
 }
 
-
-/*
-================
-R_BlendLightmaps
-================
-*/
-#if 0
-static void R_BlendLightmaps (void)
-{
-	int			i, j;
-	glpoly_t	*p;
-	float		*v;
-	glRect_t	*theRect;
-
-#if 0
-	if (r_fullbright.value)
-		return;
-#endif
-
-	glDepthMask (0);		// don't bother writing Z
-
-	if (gl_lightmap_format == GL_LUMINANCE || gl_lightmap_format == GL_RGB)
-		glBlendFunc (GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
-	else if (gl_lightmap_format == GL_INTENSITY)
-	{
-		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-		glColor4f (0,0,0,1);
-		glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-	}
-	else if (gl_lightmap_format == GL_RGBA)
-	{
-		glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
-	}
-
-	if (!r_lightmap.value)
-	{
-		glEnable (GL_BLEND);
-	}
-	else
-		glDisable (GL_BLEND);
-
-	for (i=0 ; i<numlightmaps ; i++)
-	{
-		if (!lightmap[i])
-			break;
-		p = lightmap[i]->polys;
-		if (!p)
-			continue;
-		lightmap[i]->polys = NULL;
-		GL_Bind(lightmap_textures[i]);
-		if (lightmap[i]->modified)
-		{
-			lightmap[i]->modified = false;
-			theRect = &lightmap[i]->rectchange;
-			glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, 
-				LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
-				lightmap[i]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes);
-			theRect->l = LMBLOCK_WIDTH;
-			theRect->t = LMBLOCK_HEIGHT;
-			theRect->h = 0;
-			theRect->w = 0;
-		}
-		for ( ; p ; p=p->chain)
-		{
-//			if (p->flags & SURF_UNDERWATER)
-//				DrawGLWaterPolyLightmap (p);
-			if (((r_viewleaf->contents==Q1CONTENTS_EMPTY && (p->flags & SURF_UNDERWATER)) ||
-				(r_viewleaf->contents!=Q1CONTENTS_EMPTY && !(p->flags & SURF_UNDERWATER)))
-				&& !(p->flags & SURF_DONTWARP))
-				DrawGLWaterPolyLightmap (p);
-			else
-			{
-				glBegin (GL_POLYGON);
-				v = p->verts[0];
-				for (j=0 ; j<p->numverts ; j++, v+= VERTEXSIZE)
-				{
-					glTexCoord2f (v[5], v[6]);
-					glVertex3fv (v);
-				}
-				glEnd ();
-			}
-		}
-	}
-
-	glDisable (GL_BLEND);
-	if (gl_lightmap_format == GL_LUMINANCE)
-		glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA || gl_lightmap_format == GL_RGB);
-	else if (gl_lightmap_format == GL_INTENSITY)
-	{
-		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-		glColor4f (1,1,1,1);
-	}
-	else if (gl_lightmap_format == GL_RGBA)
-		glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-	glDepthMask (1);		// back to normal Z buffering
-}
-#endif
-
 /*
 ================
 R_RenderBrushPoly
@@ -1853,18 +1736,18 @@ R_RenderBrushPoly
 */
 void R_RenderBrushPoly (msurface_t *fa)
 {
+	//FIXME: this code is only used for mirrors. remove.
 	texture_t	*t;
 
 	c_brush_polys++;
 
 	if (fa->flags & SURF_DRAWSKY)
 	{	// warp texture, no lightmaps
-		GL_EmitBothSkyLayers (fa);
 		return;
 	}
 		
 	t = R_TextureAnimation (fa->texinfo->texture);
-	GL_Bind (t->gl_texturenum);
+	GL_Bind (t->tn.base);
 
 	if (fa->flags & SURF_DRAWTURB)
 	{	// warp texture, no lightmaps
@@ -2044,7 +1927,7 @@ void GLR_DrawWaterSurfaces (void)
 		if ( !(s->flags & SURF_DRAWTURB ) )
 			continue;
 		
-		GL_Bind (t->gl_texturenum);
+		GL_Bind (t->tn.base);
 
 		for ( ; s ; s=s->texturechain)
 			EmitWaterPolys (s, r_wateralphaval);
@@ -2090,7 +1973,7 @@ static void GLR_DrawAlphaSurface(int count, msurface_t	**surfs, void *type)
 		return;
 	}
 #endif
-	GL_Bind(s->texinfo->texture->gl_texturenum);
+	GL_Bind(s->texinfo->texture->tn.base);
 
 	if (s->texinfo->flags & SURF_TRANS33)
 		qglColor4f (1,1,1,0.33);
@@ -2264,507 +2147,6 @@ void GLR_DrawAlphaSurfaces (void)
 	qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 }
 
-#if 0
-static void
-vecMatMult(GLfloat vecIn[3], GLfloat m[16], GLfloat vecOut[3]) {
-  vecOut[0] = (vecIn[0]*m[ 0]) + (vecIn[1]*m[ 4]) + (vecIn[2]*m[ 8]) + m[12];
-  vecOut[1] = (vecIn[0]*m[ 1]) + (vecIn[1]*m[ 5]) + (vecIn[2]*m[ 9]) + m[13];
-  vecOut[2] = (vecIn[0]*m[ 2]) + (vecIn[1]*m[ 6]) + (vecIn[2]*m[10]) + m[14];
-}
-
-static void
-matrixInvert(GLfloat in[16], GLfloat out[16])
-{
-  // Transpose rotation
-  out[ 0] = in[ 0];  out[ 1] = in[ 4];  out[ 2] = in[ 8];
-  out[ 4] = in[ 1];  out[ 5] = in[ 5];  out[ 6] = in[ 9];
-  out[ 8] = in[ 2];  out[ 9] = in[ 6];  out[10] = in[10];
-  
-  // Clear shearing terms
-  out[3] = 0.0f; out[7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f;
-
-  // Translation is minus the dot of tranlation and rotations
-  out[12] = -(in[12]*in[ 0]) - (in[13]*in[ 1]) - (in[14]*in[ 2]);
-  out[13] = -(in[12]*in[ 4]) - (in[13]*in[ 5]) - (in[14]*in[ 6]);
-  out[14] = -(in[12]*in[ 8]) - (in[13]*in[ 9]) - (in[14]*in[10]);
-}
-#endif
-
-/*
-================
-DrawTextureChains
-================
-*/
-/*
-#if 0
-static void DrawTextureChains (model_t *model, float alpha, vec3_t relativelightorigin)
-{
-	int		i;
-	msurface_t	*s, *last = NULL, *first=NULL, *cf;
-	texture_t	*t;
-
-	int vi;
-	glRect_t    *theRect;
-	glpoly_t *p;
-	float *v;
-
-	extern int gl_bumpmappingpossible;
-	extern int normalisationCubeMap;
-	qboolean bumpmapping=gl_bump.value && gl_bumpmappingpossible && (alpha == 1) && (normalisationCubeMap || currentmodel->deluxdata);
-
-	if (model == cl.worldmodel && skytexturenum>=0)
-	{
-		t = model->textures[skytexturenum];
-		if (t)
-		{
-			s = t->texturechain;
-			if (s)
-			{
-				t->texturechain = NULL;
-				GL_DrawSkyChain (s);
-			}
-		}
-	}
-	if (alpha == 1)
-	{
-		glDisable(GL_BLEND);
-		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-	}
-	else
-	{
-		glEnable(GL_BLEND);
-		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-	}
-	if (currententity->drawflags & MLS_ABSLIGHT)
-		glColor4f(currententity->abslight/255.0f, currententity->abslight/255.0f, currententity->abslight/255.0f, alpha);
-	else
-		glColor4f(1, 1, 1, alpha);
-
-	for (i=0 ; i<model->numtextures ; i++)
-	{
-		t = model->textures[i];
-		if (!t)
-			continue;
-		s = t->texturechain;
-		if (!s)
-			continue;
-		t->texturechain = NULL;
-		if (i == skytexturenum && model == cl.worldmodel)
-			GL_DrawSkyChain (s);
-		else if (i == mirrortexturenum && model == cl.worldmodel && r_mirroralpha.value != 1.0)
-			R_MirrorChain (s);
-		else
-		{
-			if ((s->flags & SURF_DRAWTURB) && r_wateralphaval != 1.0)
-			{
-				t->texturechain = s;
-				continue;	// draw translucent water later
-			}
-
-			if (last)
-				last->texturechain = s;
-			else
-				first = s;
-
-			t = R_TextureAnimation (t);
-
-			cf = s;
-
-			if (gl_mtexable && alpha == 1)
-			{
-				if (s->lightmaptexturenum<0 || currententity->drawflags & MLS_ABSLIGHT)
-				{	//vertex lighting required.
-					GL_DisableMultitexture();
-					glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-					for (s=cf ; s ; s=s->texturechain)
-					{
-						R_RenderBrushPoly (s);
-					}
-					continue;
-				}
-
-
-				if (cf->flags & SURF_DRAWTURB)
-				{
-					GL_DisableMultitexture();
-					glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-					GL_Bind (s->texinfo->texture->gl_texturenum);
-					for (s=cf; s ; s=s->texturechain)
-						EmitWaterPolys (s);
-
-					if (alpha == 1)
-					{
-						glDisable(GL_BLEND);
-						glColor4f(1, 1, 1, 1);
-					}
-					else
-					{
-						glEnable(GL_BLEND);
-						glColor4f(1, 1, 1, alpha);
-					}
-
-					if (last)	//don't include this chain for details.
-						last->texturechain = NULL;
-					continue;
-				}
-
-				if (bumpmapping && t->gl_texturenumbumpmap)
-				{
-					vec3_t light;
-
-					GL_DisableMultitexture();
-//					glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-//					glEnable(GL_ALPHA_TEST);
-					glColor4f(1, 1, 1, 1);
-					glDisable(GL_BLEND);
-
-					//Bind normal map to texture unit 0
-					GL_BindType(GL_TEXTURE_2D, t->gl_texturenumbumpmap);
-					glEnable(GL_TEXTURE_2D);
-
-					//Set up texture environment to do (tex0 dot tex1)*color
-					GL_TexEnv(GL_COMBINE_ARB);
-					glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
-					glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
-
-					qglActiveTextureARB(GL_TEXTURE1_ARB);
-				
-					GL_TexEnv(GL_COMBINE_ARB);
-					glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
-					glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
-					glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGB_ARB);
-				
-					if (gl_bump.value < 0)
-					{
-						if (currentmodel->deluxdata)
-						{
-							glEnable(GL_TEXTURE_2D);
-							for (s = cf; s ; s=s->texturechain)
-							{
-								vi = s->lightmaptexturenum;
-								GL_BindType(GL_TEXTURE_2D, deluxmap_textures[vi] );
-								if (lightmap[vi]->deluxmodified)
-								{
-									lightmap[vi]->deluxmodified = false;
-									theRect = &lightmap[vi]->deluxrectchange;
-									glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, 
-										LMBLOCK_WIDTH, theRect->h, GL_RGB, GL_UNSIGNED_BYTE,
-										lightmap[vi]->deluxmaps+(theRect->t) *LMBLOCK_WIDTH*3);
-									theRect->l = LMBLOCK_WIDTH;
-									theRect->t = LMBLOCK_HEIGHT;
-									theRect->h = 0;
-									theRect->w = 0;
-								}
-
-								for (p = s->polys; p; p=p->next)
-								{
-									glBegin(GL_POLYGON);
-									v = p->verts[0];
-									for (vi=0 ; vi<p->numverts ; vi++, v+= VERTEXSIZE)
-									{									
-										qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, v[3], v[4]);
-										qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, v[5], v[6]);
-										glVertex3fv (v);
-									}
-									glEnd ();
-								}
-							}
-							glDisable(GL_TEXTURE_2D);
-						}
-						else
-						{
-							GL_BindType(GL_TEXTURE_CUBE_MAP_ARB, normalisationCubeMap);
-							glEnable(GL_TEXTURE_CUBE_MAP_ARB);
-							qglMultiTexCoord3fARB(GL_TEXTURE1_ARB, sin(-r_refdef.viewangles[1]/180*M_PI), cos(-r_refdef.viewangles[1]/180*M_PI), 1);
-							for (s = cf; s ; s=s->texturechain)
-							{
-								vi = s->lightmaptexturenum;
-								for (p = s->polys; p; p=p->next)
-								{
-									glBegin(GL_POLYGON);
-									v = p->verts[0];
-									for (vi=0 ; vi<p->numverts ; vi++, v+= VERTEXSIZE)
-									{									
-										qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, v[3], v[4]);
-										glVertex3fv (v);
-									}
-									glEnd ();
-								}
-							}
-							glDisable(GL_TEXTURE_CUBE_MAP_ARB);
-						}
-					}
-					else
-					{
-						GL_BindType(GL_TEXTURE_CUBE_MAP_ARB, normalisationCubeMap);
-						glEnable(GL_TEXTURE_CUBE_MAP_ARB);
-						for (s = cf; s ; s=s->texturechain)
-						{
-							for (p = s->polys; p; p=p->next)
-							{
-								glBegin(GL_POLYGON);
-								v = p->verts[0];
-								for (vi=0 ; vi<p->numverts ; vi++, v+= VERTEXSIZE)
-								{
-									light[0] = relativelightorigin[0] - v[0];
-									light[1] = relativelightorigin[1] - v[1];
-									light[2] = relativelightorigin[2] - v[2];
-									
-									qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, v[3], v[4]);
-									qglMultiTexCoord3fARB(GL_TEXTURE1_ARB, -DotProduct(vup, light), -DotProduct(vright, light), gl_bump.value/2*-DotProduct(vpn, light));
-									glVertex3fv (v);
-								}
-								glEnd ();
-							}
-						}
-						glDisable(GL_TEXTURE_CUBE_MAP_ARB);
-					}
-
-					qglActiveTextureARB(GL_TEXTURE0_ARB);
-					currenttexture=0;
-					glEnable (GL_BLEND);
-					glBlendFunc(GL_DST_COLOR, GL_ZERO);
-					glColor4f(1, 1, 1, 1);
-
-
-					// Binds world to texture env 0
-					GL_SelectTexture(mtexid0);
-					GL_Bind (t->gl_texturenum);
-					glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-					GL_EnableMultitexture(); // Same as SelectTexture (TEXTURE1)
-					glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
-				}
-				else
-				{
-
-				// Binds world to texture env 0
-					GL_SelectTexture(mtexid0);
-					GL_Bind (t->gl_texturenum);
-					glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-					GL_EnableMultitexture(); // Same as SelectTexture (TEXTURE1)
-					glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
-				}
-
-				for (s=cf; s; s=s->texturechain)
-				{
-//					R_RenderDynamicLightmaps (s);
-					vi = s->lightmaptexturenum;
-					// Binds lightmap to texenv 1
-					GL_Bind (lightmap_textures[vi]);
-					if (lightmap[vi]->modified)
-					{
-						lightmap[vi]->modified = false;
-						theRect = &lightmap[vi]->rectchange;
-						glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, 
-							LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
-							lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes);
-						theRect->l = LMBLOCK_WIDTH;
-						theRect->t = LMBLOCK_HEIGHT;
-						theRect->h = 0;
-						theRect->w = 0;
-					}
-					for (p = s->polys; p; p=p->next)
-					{
-						glBegin(GL_POLYGON);
-						v = p->verts[0];
-						for (vi=0 ; vi<p->numverts ; vi++, v+= VERTEXSIZE)
-						{
-							qglMTexCoord2fSGIS (mtexid0, v[3], v[4]);
-							qglMTexCoord2fSGIS (mtexid1, v[5], v[6]);
-							glVertex3fv (v);
-						}
-						glEnd ();
-					}
-					last = s;
-				}
-			}
-			else
-			{
-				for (s=cf ; s ; s=s->texturechain)
-				{
-					R_RenderBrushPoly (s);
-					last = s;
-				}
-			}
-
-			if (alpha == 1)
-			{
-				glDisable(GL_BLEND);
-				glColor4f(1, 1, 1, 1);
-			}
-			else
-			{
-				glEnable(GL_BLEND);
-				glColor4f(1, 1, 1, alpha);
-			}
-
-			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-		}
-	}
-
-	if (gl_mtexable)
-		GL_DisableMultitexture();
-	else
-		R_BlendLightmaps();
-
-	//add luminance?
-	if (first && detailtexture && gl_detail.value && alpha == 1)
-	{
-		GL_Bind(detailtexture);
-		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
-		glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
-		glEnable(GL_BLEND);
-		glDepthMask(0);
-
-		for (s=first ; s ; s=s->texturechain)
-		{
-			for (p = s->polys; p; p=p->next)
-			{
-				glBegin(GL_POLYGON);
-				v = p->verts[0];
-				for (i = 0; i < p->numverts; i++, v += VERTEXSIZE)
-				{
-					glTexCoord2f (v[5] * 18, v[6] * 18);
-					glVertex3fv (v);
-				}
-				glEnd();
-			}
-		}
-
-		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-		glDisable(GL_BLEND);
-
-		glDepthMask(1);
-	}
-
-	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-}
-#endif
-*/
-/*
-=================
-R_DrawBrushModel
-=================
-*/
-/*
-#if 0
-static void R_DrawBrushModel (entity_t *e)
-{
-	int			i;
-	int			k;
-	vec3_t		mins, maxs;
-	msurface_t	*psurf, *first;
-	float		dot;
-	mplane_t	*pplane;
-	qboolean	rotated;
-
-	currententity = e;
-	currenttexture = -1;
-
-	currentmodel = e->model;
-
-	if (e->angles[0] || e->angles[1] || e->angles[2])
-	{
-		rotated = true;
-		for (i=0 ; i<3 ; i++)
-		{
-			mins[i] = e->origin[i] - currentmodel->radius;
-			maxs[i] = e->origin[i] + currentmodel->radius;
-		}
-	}
-	else
-	{
-		rotated = false;
-		VectorAdd (e->origin, currentmodel->mins, mins);
-		VectorAdd (e->origin, currentmodel->maxs, maxs);
-	}
-
-	if (R_CullBox (mins, maxs))
-		return;
-
-	VectorSubtract (r_refdef.vieworg, e->origin, modelorg);
-	if (rotated)
-	{
-		vec3_t	temp;
-		vec3_t	forward, right, up;
-
-		VectorCopy (modelorg, temp);
-		AngleVectors (e->angles, forward, right, up);
-		modelorg[0] = DotProduct (temp, forward);
-		modelorg[1] = -DotProduct (temp, right);
-		modelorg[2] = DotProduct (temp, up);
-	}
-
-	psurf = &currentmodel->surfaces[currentmodel->firstmodelsurface];
-
-// calculate dynamic lighting for bmodel if it's not an
-// instanced model
-	if (currentmodel->firstmodelsurface != 0 && !r_flashblend.value)
-	{
-		for (k=0 ; k<dlights_software ; k++)
-		{
-			if ((cl_dlights[k].die < cl.time) ||
-				(!cl_dlights[k].radius))
-				continue;
-
-			currentmodel->funcs.MarkLights (&cl_dlights[k], 1<<k,
-				currentmodel->nodes + currentmodel->hulls[0].firstclipnode);
-		}
-	}
-
-    glPushMatrix ();
-e->angles[0] = -e->angles[0];	// stupid quake bug
-	glTranslatef(-0.03, -0.03, 0.03);
-	R_RotateForEntity (e);
-e->angles[0] = -e->angles[0];	// stupid quake bug
-
-
-	first = NULL;
-	//
-	// draw texture
-	//
-	for (i=0 ; i<currentmodel->nummodelsurfaces ; i++, psurf++)
-	{
-	// find which side of the node we are on
-		pplane = psurf->plane;
-
-//		if (psurf->plane)
-		{
-			dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
-		
-
-	// draw the polygon
-			if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
-				(!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
-			{
-				R_RenderDynamicLightmaps (psurf);
-				if (psurf->flags & SURF_DRAWALPHA || psurf->texinfo->flags & (SURF_TRANS33|SURF_TRANS66) )
-				{	// add to the translucent chain
-					psurf->nextalphasurface = r_alpha_surfaces;
-					r_alpha_surfaces = psurf;
-					psurf->ownerent = e;
-				}
-				else
-				{
-					psurf->texturechain = psurf->texinfo->texture->texturechain;
-					psurf->texinfo->texture->texturechain = psurf;
-				}
-			}
-		}
-	}
-
-	VectorSubtract(r_refdef.vieworg, e->origin, mins);	//fixme: rotation.
-	if (e->drawflags & DRF_TRANSLUCENT)
-		DrawTextureChains(currentmodel, e->alpha*0.4, mins);
-	else
-		DrawTextureChains(currentmodel, e->alpha, mins);
-
-	glPopMatrix ();
-}
-#endif
-*/
 /*
 =============================================================
 
@@ -3260,16 +2642,16 @@ int GLAllocBlock (int w, int h, int *x, int *y)
 			lightmap[numlightmaps+3] = NULL;
 
 			lightmap_textures = BZ_Realloc(lightmap_textures, sizeof(*lightmap_textures)*(numlightmaps+4));
-			lightmap_textures[numlightmaps+0] = texture_extension_number++;
-			lightmap_textures[numlightmaps+1] = texture_extension_number++;
-			lightmap_textures[numlightmaps+2] = texture_extension_number++;
-			lightmap_textures[numlightmaps+3] = texture_extension_number++;
+			lightmap_textures[numlightmaps+0] = GL_AllocNewTexture();
+			lightmap_textures[numlightmaps+1] = GL_AllocNewTexture();
+			lightmap_textures[numlightmaps+2] = GL_AllocNewTexture();
+			lightmap_textures[numlightmaps+3] = GL_AllocNewTexture();
 
 			deluxmap_textures = BZ_Realloc(deluxmap_textures, sizeof(*deluxmap_textures)*(numlightmaps+4));
-			deluxmap_textures[numlightmaps+0] = texture_extension_number++;
-			deluxmap_textures[numlightmaps+1] = texture_extension_number++;
-			deluxmap_textures[numlightmaps+2] = texture_extension_number++;
-			deluxmap_textures[numlightmaps+3] = texture_extension_number++;
+			deluxmap_textures[numlightmaps+0] = GL_AllocNewTexture();
+			deluxmap_textures[numlightmaps+1] = GL_AllocNewTexture();
+			deluxmap_textures[numlightmaps+2] = GL_AllocNewTexture();
+			deluxmap_textures[numlightmaps+3] = GL_AllocNewTexture();
 			numlightmaps+=4;
 		}
 		if (!lightmap[texnum])
@@ -3328,16 +2710,16 @@ int GLFillBlock (int texnum, int w, int h, int x, int y)
 		lightmap[numlightmaps+3] = NULL;
 
 		lightmap_textures = BZ_Realloc(lightmap_textures, sizeof(*lightmap_textures)*(numlightmaps+4)); 
-		lightmap_textures[numlightmaps+0] = texture_extension_number++;
-		lightmap_textures[numlightmaps+1] = texture_extension_number++;
-		lightmap_textures[numlightmaps+2] = texture_extension_number++;
-		lightmap_textures[numlightmaps+3] = texture_extension_number++;
+		lightmap_textures[numlightmaps+0] = GL_AllocNewTexture();
+		lightmap_textures[numlightmaps+1] = GL_AllocNewTexture();
+		lightmap_textures[numlightmaps+2] = GL_AllocNewTexture();
+		lightmap_textures[numlightmaps+3] = GL_AllocNewTexture();
 
 		deluxmap_textures = BZ_Realloc(deluxmap_textures, sizeof(*deluxmap_textures)*(numlightmaps+4)); 
-		deluxmap_textures[numlightmaps+0] = texture_extension_number++;
-		deluxmap_textures[numlightmaps+1] = texture_extension_number++;
-		deluxmap_textures[numlightmaps+2] = texture_extension_number++;
-		deluxmap_textures[numlightmaps+3] = texture_extension_number++;
+		deluxmap_textures[numlightmaps+0] = GL_AllocNewTexture();
+		deluxmap_textures[numlightmaps+1] = GL_AllocNewTexture();
+		deluxmap_textures[numlightmaps+2] = GL_AllocNewTexture();
+		deluxmap_textures[numlightmaps+3] = GL_AllocNewTexture();
 		numlightmaps+=4;
 	}
 	for (i = texnum; i >= 0; i--)
@@ -3540,17 +2922,17 @@ void GLSurf_DeInit(void)
 	numlightmaps=0;
 }
 
-void GL_GenBrushModelVBO(model_t *mod)
+static void GL_GenBrushModelVBO(model_t *mod)
 {
 	unsigned int maxvboverts;
 	unsigned int maxvboelements;
 
 	unsigned int t;
 	unsigned int i;
-	unsigned int vbov, vboe;
+	unsigned int vbos[2];
 	unsigned int v;
 	unsigned int vcount, ecount;
-	void *vbovdata;
+	vbovertex_t *vbovdata;
 	index_t *vboedata;
 	mesh_t *m;
 
@@ -3582,13 +2964,12 @@ void GL_GenBrushModelVBO(model_t *mod)
 			continue;
 
 		//fixme: stop this from leaking!
-		qglGenBuffersARB(1, &vbov);
-		qglGenBuffersARB(1, &vboe);
-		mod->textures[t]->gl_vbov = vbov;
-		mod->textures[t]->gl_vboe = vboe;
+		qglGenBuffersARB(2, vbos);
+		mod->textures[t]->gl_vbov = vbos[0];
+		mod->textures[t]->gl_vboe = vbos[1];
 		vcount = 0;
 		ecount = 0;
-		vbovdata = Hunk_TempAlloc(maxvboverts*VBOSTRIDE);
+		vbovdata = Hunk_TempAlloc(maxvboverts*sizeof(vbovertex_t));
 		vboedata = Hunk_TempAllocMore(maxvboelements*sizeof(index_t));
 		for (i=0 ; i<mod->numsurfaces ; i++)
 		{
@@ -3602,18 +2983,26 @@ void GL_GenBrushModelVBO(model_t *mod)
 				vboedata[ecount++] = vcount + m->indexes[v];
 			for (v = 0; v < m->numvertexes; v++)
 			{
-				memcpy((char*)vbovdata+(vcount+v)*VBOSTRIDE + 0, &m->xyz_array[v], sizeof(vec3_t));
+				vbovdata[vcount+v].coord[0] = m->xyz_array[v][0];
+				vbovdata[vcount+v].coord[1] = m->xyz_array[v][1];
+				vbovdata[vcount+v].coord[2] = m->xyz_array[v][2];
 				if (m->st_array)
-					memcpy((char*)vbovdata+(vcount+v)*VBOSTRIDE + 12, &m->st_array[v], sizeof(vec2_t));
+				{
+					vbovdata[vcount+v].texcoord[0] = m->st_array[v][0];
+					vbovdata[vcount+v].texcoord[1] = m->st_array[v][1];
+				}
 				if (m->lmst_array)
-					memcpy((char*)vbovdata+(vcount+v)*VBOSTRIDE + 20, &m->lmst_array[v], sizeof(vec2_t));
+				{
+					vbovdata[vcount+v].lmcoord[0] = m->lmst_array[v][0];
+					vbovdata[vcount+v].lmcoord[1] = m->lmst_array[v][1];
+				}
 			}
 			vcount += v;
 		}
-		qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbov);
-		qglBufferDataARB(GL_ARRAY_BUFFER_ARB, vcount*VBOSTRIDE, vbovdata, GL_STATIC_DRAW_ARB);
+		qglBindBufferARB(GL_ARRAY_BUFFER_ARB, mod->textures[t]->gl_vbov);
+		qglBufferDataARB(GL_ARRAY_BUFFER_ARB, vcount*sizeof(vbovertex_t), vbovdata, GL_STATIC_DRAW_ARB);
 		qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
-		qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vboe);
+		qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mod->textures[t]->gl_vboe);
 		qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ecount*sizeof(vboedata[0]), vboedata, GL_STATIC_DRAW_ARB);
 		qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
 	}
diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c
index 2408fc71d..d623c9b25 100644
--- a/engine/gl/gl_shader.c
+++ b/engine/gl/gl_shader.c
@@ -772,7 +772,7 @@ static void Shaderpass_VideoMap ( shader_t *shader, shaderpass_t *pass, char **p
 	else
 		Con_DPrintf (CON_WARNING "(shader %s) Couldn't load video %s\n", shader->name, token );
 
-	pass->anim_frames[0] = texture_extension_number++;
+	pass->anim_frames[0] = GL_AllocNewTexture();
 	pass->flags |= SHADER_PASS_VIDEOMAP;
 	shader->flags |= SHADER_VIDEOMAP;
 }
@@ -2020,7 +2020,7 @@ void Shader_RunCinematic (void)
 }
 */
 
-void Shader_DefaultBSP(char *shortname, shader_t *s)
+void Shader_DefaultBSP(char *shortname, shader_t *s, void *args)
 {
 	shaderpass_t *pass;
 
@@ -2030,7 +2030,13 @@ void Shader_DefaultBSP(char *shortname, shader_t *s)
 	if (gl_config.arb_texture_env_dot3)
 	{
 		if (gl_bump.value)
-			bumptex = Mod_LoadHiResTexture(va("normalmaps/%s", shortname), NULL, true, false, false);//GL_FindImage (shortname, 0);
+		{
+			bumptex = GL_FindTexture(va("%s_bump", shortname));
+			if (bumptex == -1)
+				bumptex = GL_FindTexture(va("%s_norm", shortname));
+			if (bumptex == -1)
+				bumptex = Mod_LoadHiResTexture(va("normalmaps/%s", shortname), NULL, true, false, false);//GL_FindImage (shortname, 0);
+		}
 		else
 			bumptex = 0;
 	}
@@ -2147,7 +2153,7 @@ void Shader_DefaultBSP(char *shortname, shader_t *s)
 	s->style = SSTYLE_LIGHTMAPPED;
 }
 
-void Shader_DefaultBSPVertex(char *shortname, shader_t *s)
+void Shader_DefaultBSPVertex(char *shortname, shader_t *s, void *args)
 {
 	shaderpass_t *pass;
 	pass = &s->passes[0];
@@ -2173,7 +2179,7 @@ void Shader_DefaultBSPVertex(char *shortname, shader_t *s)
 	s->sort = SHADER_SORT_OPAQUE;
 	s->registration_sequence = 1;//fizme: registration_sequence;
 }
-void Shader_DefaultBSPFlare(char *shortname, shader_t *s)
+void Shader_DefaultBSPFlare(char *shortname, shader_t *s, void *args)
 {
 	shaderpass_t *pass;
 	pass = &s->passes[0];
@@ -2202,7 +2208,7 @@ void Shader_DefaultBSPFlare(char *shortname, shader_t *s)
 	s->sort = SHADER_SORT_ADDITIVE;
 	s->registration_sequence = 1;//fizme: registration_sequence;
 }
-void Shader_DefaultSkin(char *shortname, shader_t *s)
+void Shader_DefaultSkin(char *shortname, shader_t *s, void *args)
 {
 	int tex;
 	shaderpass_t *pass;
@@ -2305,7 +2311,7 @@ void Shader_DefaultSkin(char *shortname, shader_t *s)
 	s->sort = SHADER_SORT_OPAQUE;
 	s->registration_sequence = 1;//fizme: registration_sequence;
 }
-void Shader_DefaultSkinShell(char *shortname, shader_t *s)
+void Shader_DefaultSkinShell(char *shortname, shader_t *s, void *args)
 {
 	shaderpass_t *pass;
 	pass = &s->passes[0];
@@ -2336,7 +2342,7 @@ void Shader_DefaultSkinShell(char *shortname, shader_t *s)
 	s->sort = SHADER_SORT_OPAQUE;
 	s->registration_sequence = 1;//fizme: registration_sequence;
 }
-void Shader_Default2D(char *shortname, shader_t *s)
+void Shader_Default2D(char *shortname, shader_t *s, void *genargs)
 {
 	mpic_t *mp;
 
@@ -2447,7 +2453,7 @@ qboolean Shader_ParseShader(char *shortname, char *usename, shader_t *s)
 	return false;
 }
 
-int R_LoadShader ( char *name, void(*defaultgen)(char *name, shader_t*))
+int R_LoadShader ( char *name, void(*defaultgen)(char *name, shader_t*, void *args), void *genargs)
 {
 	int i, f = -1;
 	char shortname[MAX_QPATH];
@@ -2496,7 +2502,7 @@ int R_LoadShader ( char *name, void(*defaultgen)(char *name, shader_t*))
 	{
 		memset ( s, 0, sizeof( shader_t ) );
 		Com_sprintf ( s->name, MAX_QPATH, shortname );
-		defaultgen(shortname, s);
+		defaultgen(shortname, s, genargs);
 
 		return f;
 	}
@@ -2537,32 +2543,32 @@ cin_t *R_ShaderGetCinematic(char *name)
 
 shader_t *R_RegisterPic (char *name) 
 {
-	return &r_shaders[R_LoadShader (name, Shader_Default2D)];
+	return &r_shaders[R_LoadShader (name, Shader_Default2D, NULL)];
 }
 
 shader_t *R_RegisterShader (char *name)
 {
-	return &r_shaders[R_LoadShader (name, Shader_DefaultBSP)];
+	return &r_shaders[R_LoadShader (name, Shader_DefaultBSP, NULL)];
 }
 
 shader_t *R_RegisterShader_Vertex (char *name)
 {
-	return &r_shaders[R_LoadShader (name, Shader_DefaultBSPVertex)];
+	return &r_shaders[R_LoadShader (name, Shader_DefaultBSPVertex, NULL)];
 }
 
 shader_t *R_RegisterShader_Flare (char *name)
 {
-	return &r_shaders[R_LoadShader (name, Shader_DefaultBSPFlare)];
+	return &r_shaders[R_LoadShader (name, Shader_DefaultBSPFlare, NULL)];
 }
 
 shader_t *R_RegisterSkin (char *name)
 {
-	return &r_shaders[R_LoadShader (name, Shader_DefaultSkin)];
+	return &r_shaders[R_LoadShader (name, Shader_DefaultSkin, NULL)];
 }
-shader_t *R_RegisterCustom (char *name, void(*defaultgen)(char *name, shader_t*))
+shader_t *R_RegisterCustom (char *name, void(*defaultgen)(char *name, shader_t*, void *args), void *args)
 {
 	int i;
-	i = R_LoadShader (name, defaultgen);
+	i = R_LoadShader (name, defaultgen, args);
 	if (i < 0)
 		return NULL;
 	return &r_shaders[i];
diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c
index 6e6e1002c..09f904759 100644
--- a/engine/gl/gl_vidcommon.c
+++ b/engine/gl/gl_vidcommon.c
@@ -104,6 +104,8 @@ void (APIENTRY *qglDeleteBuffersARB)(GLsizei n, GLuint* ids);
 void (APIENTRY *qglBindBufferARB)(GLenum target, GLuint id);
 void (APIENTRY *qglBufferDataARB)(GLenum target, GLsizei size, const void* data, GLenum usage);
 void (APIENTRY *qglBufferSubDataARB)(GLenum target, GLint offset, GLsizei size, void* data);
+void *(APIENTRY *qglMapBufferARB)(GLenum target, GLenum access);
+GLboolean (APIENTRY *qglUnmapBufferARB)(GLenum target);
 
 /*
 PFNGLPROGRAMSTRINGARBPROC qglProgramStringARB;
@@ -175,7 +177,12 @@ const char *gl_renderer;
 const char *gl_version;
 const char *gl_extensions;
 
-int		texture_extension_number = 1;
+static int texture_extension_number = 1;
+
+int GL_AllocNewTexture(void)
+{
+	return texture_extension_number++;
+}
 
 void APIENTRY GL_DrawRangeElementsEmul(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices)
 {
@@ -351,6 +358,8 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name))
 		qglBindBufferARB = (void *)getglext("glBindBufferARB");
 		qglBufferDataARB = (void *)getglext("glBufferDataARB");
 		qglBufferSubDataARB = (void *)getglext("glBufferSubDataARB");
+		qglMapBufferARB = (void *)getglext("glMapBufferARB");
+		qglUnmapBufferARB = (void *)getglext("glUnmapBufferARB");
 	}
 
 /*
@@ -623,6 +632,8 @@ void GL_Init(void *(*getglfunction) (char *name))
 	qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
 	qglShadeModel (GL_FLAT);
 
+	texture_extension_number = 1;
+
 	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
diff --git a/engine/gl/gl_vidlinuxglx.c b/engine/gl/gl_vidlinuxglx.c
index 3d61728b1..a59a22604 100644
--- a/engine/gl/gl_vidlinuxglx.c
+++ b/engine/gl/gl_vidlinuxglx.c
@@ -1066,6 +1066,14 @@ void IN_MouseMove (float *movements, int pnum)
 #endif
 	}
 
+#ifdef PEXT_CSQC
+	if (CSQC_MouseMove(mx, my))
+	{
+		mx = 0;
+		my = 0;
+	}
+#endif
+
 	if (m_filter.value)
 	{
 		float fraction = bound(0, m_filter.value, 2) * 0.5;
diff --git a/engine/gl/gl_warp.c b/engine/gl/gl_warp.c
index 01340477a..7432e35b6 100644
--- a/engine/gl/gl_warp.c
+++ b/engine/gl/gl_warp.c
@@ -43,23 +43,23 @@ int		skytexturenum;
 
 int		solidskytexture;
 int		alphaskytexture;
-float	speedscale;		// for top sky and bottom sky
+static float	speedscale;		// for top sky and bottom sky
 
-float skyrotate;
-vec3_t skyaxis;
+static float skyrotate;
+static vec3_t skyaxis;
 
-qboolean usingskybox;
+static qboolean usingskybox;
 
-msurface_t	*warpface;
+static msurface_t	*warpface;
 
 extern cvar_t r_skyboxname;
 extern cvar_t gl_skyboxdist;
 extern cvar_t r_fastsky;
 extern cvar_t r_fastskycolour;
-char defaultskybox[MAX_QPATH];
+static char defaultskybox[MAX_QPATH];
 
 int skyboxtex[6];
-vec3_t glskycolor;
+static vec3_t glskycolor;
 
 void GLR_Fastskycolour_Callback(struct cvar_s *var, char *oldvalue)
 {
@@ -67,7 +67,7 @@ void GLR_Fastskycolour_Callback(struct cvar_s *var, char *oldvalue)
 }
 
 void GL_DrawSkyBox (msurface_t *s);
-void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
+static void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
 {
 	int		i, j;
 	float	*v;
@@ -142,7 +142,7 @@ void EmitWaterPolys (msurface_t *fa, float basealpha)
 			qglPushMatrix();
 			qglColor4f(1, 1, 1, a);
 			qglTranslatef (sin(cl.time+l*4) * 0.04f+cos(cl.time/2+l)*0.02f+cl.time/(64+l*8), cos(cl.time+l*4) * 0.06f+sin(cl.time/2+l)*0.02f+cl.time/(16+l*2), 0);
-			GL_DrawAliasMesh(fa->mesh, fa->texinfo->texture->gl_texturenum);
+			GL_DrawAliasMesh(fa->mesh, fa->texinfo->texture->tn.base);
 			qglPopMatrix();
 		}
 		qglMatrixMode(GL_MODELVIEW);
@@ -154,51 +154,12 @@ void EmitWaterPolys (msurface_t *fa, float basealpha)
 		qglPushMatrix();
 		qglTranslatef (sin(cl.time) * 0.4f, cos(cl.time) * 0.06f, 0);
 		fa->mesh->colors_array = NULL;
-		GL_DrawAliasMesh(fa->mesh, fa->texinfo->texture->gl_texturenum);
+		GL_DrawAliasMesh(fa->mesh, fa->texinfo->texture->tn.base);
 		qglPopMatrix();
 		qglMatrixMode(GL_MODELVIEW);
 	}
 }
 
-/*
-=============
-EmitSkyPolys
-=============
-*/
-void EmitSkyPolys (msurface_t *fa)
-{
-
-}
-
-/*
-===============
-EmitBothSkyLayers
-
-Does a sky warp on the pre-fragmented glpoly_t chain
-This will be called for brushmodels, the world
-will have them chained together.
-===============
-*/
-void GL_EmitBothSkyLayers (msurface_t *fa)
-{
-	GL_DisableMultitexture();
-
-	GL_Bind (solidskytexture);
-	speedscale = cl.gametime*8;
-	speedscale -= (int)speedscale & ~127 ;
-
-	EmitSkyPolys (fa);
-
-	qglEnable (GL_BLEND);
-	GL_Bind (alphaskytexture);
-	speedscale = cl.gametime*16;
-	speedscale -= (int)speedscale & ~127 ;
-
-	EmitSkyPolys (fa);
-
-	qglDisable (GL_BLEND);
-}
-
 #endif
 
 /*
@@ -207,7 +168,7 @@ GL_DrawSkyChain
 =================
 */
 #ifdef RGLQUAKE
-void R_DrawSkyBoxChain (msurface_t *s);
+static void R_DrawSkyBoxChain (msurface_t *s);
 void GL_DrawSkyChain (msurface_t *s)
 {
 	msurface_t	*fa;
@@ -250,37 +211,14 @@ void GL_DrawSkyChain (msurface_t *s)
 		R_DrawSkyBoxChain(s);
 		return;
 	}
-//	if (usingskydome)
-	{
-		GL_DrawSkySphere(s);
-		return;
-	}
 
-	// used when gl_texsort is on
-	GL_Bind(solidskytexture);
-	speedscale = cl.servertime;
-	speedscale*=8;
-	speedscale -= (int)speedscale & ~127 ;
-
-	for (fa=s ; fa ; fa=fa->texturechain)
-		EmitSkyPolys (fa);
-
-	qglEnable (GL_BLEND);
-	GL_Bind (alphaskytexture);
-	speedscale = cl.servertime;
-	speedscale*=16;
-	speedscale -= (int)speedscale & ~127 ;
-
-	for (fa=s ; fa ; fa=fa->texturechain)
-		EmitSkyPolys (fa);
-
-	qglDisable (GL_BLEND);
+	GL_DrawSkySphere(s);
 }
 #endif
 
 #ifdef D3DQUAKE
-void R_DrawSkyBoxChain (msurface_t *s);
-void D3D7_DrawSkyChain (msurface_t *s)
+static void R_DrawSkyBoxChain (msurface_t *s);
+static void D3D7_DrawSkyChain (msurface_t *s)
 {
 	//msurface_t	*fa;
 
@@ -333,7 +271,7 @@ void D3D7_DrawSkyChain (msurface_t *s)
 	D3D7_DrawSkySphere(s);
 }
 
-void D3D9_DrawSkyChain (msurface_t *s)
+static void D3D9_DrawSkyChain (msurface_t *s)
 {
 	//msurface_t	*fa;
 
@@ -495,7 +433,7 @@ void GLR_SetSky(char *name, float rotate, vec3_t axis)	//called from the client
 	VectorCopy(axis, skyaxis);
 }
 
-vec3_t	skyclip[6] = {
+static vec3_t	skyclip[6] = {
 	{1,1,0},
 	{1,-1,0},
 	{0,-1,1},
@@ -503,10 +441,10 @@ vec3_t	skyclip[6] = {
 	{1,0,1},
 	{-1,0,1} 
 };
-int	c_sky;
+static int	c_sky;
 
 // 1 = s, 2 = t, 3 = 2048
-int	st_to_vec[6][3] =
+static int	st_to_vec[6][3] =
 {
 	{3,-1,2},
 	{-3,1,2},
@@ -522,7 +460,7 @@ int	st_to_vec[6][3] =
 };
 
 // s = [0]/[2], t = [1]/[2]
-int	vec_to_st[6][3] =
+static int	vec_to_st[6][3] =
 {
 	{-2,3,1},
 	{2,3,-1},
@@ -537,9 +475,9 @@ int	vec_to_st[6][3] =
 //	{1,2,-3}
 };
 
-float	skymins[2][6], skymaxs[2][6];
+static float	skymins[2][6], skymaxs[2][6];
 
-void DrawSkyPolygon (int nump, vec3_t vecs)
+static void DrawSkyPolygon (int nump, vec3_t vecs)
 {
 	int		i,j;
 	vec3_t	v, av;
@@ -615,7 +553,7 @@ void DrawSkyPolygon (int nump, vec3_t vecs)
 }
 
 #define	MAX_CLIP_VERTS	64
-void ClipSkyPolygon (int nump, vec3_t vecs, int stage)
+static void ClipSkyPolygon (int nump, vec3_t vecs, int stage)
 {
 	float	*norm;
 	float	*v;
@@ -711,7 +649,7 @@ void ClipSkyPolygon (int nump, vec3_t vecs, int stage)
 R_DrawSkyBoxChain
 =================
 */
-void R_DrawSkyBoxChain (msurface_t *s)
+static void R_DrawSkyBoxChain (msurface_t *s)
 {
 	msurface_t	*fa;
 
@@ -752,7 +690,7 @@ void R_DrawSkyBoxChain (msurface_t *s)
 #define skysphere_numverts (skygridx1 * skygridy1)
 #define skysphere_numtriangles (skygridx * skygridy * 2)
 
-int skymade;
+static int skymade;
 static index_t skysphere_element3i[skysphere_numtriangles * 3];
 static float skysphere_texcoord2f[skysphere_numverts * 2];
 
@@ -844,7 +782,7 @@ static void d3d_skyspherecalc(int skytype)
 
 #ifdef RGLQUAKE
 static float skysphere_vertex3f[skysphere_numverts * 3];
-mesh_t skymesh;
+static mesh_t skymesh;
 
 
 static void gl_skyspherecalc(int skytype)
@@ -917,7 +855,7 @@ static void gl_skyspherecalc(int skytype)
 	}
 }
 
-void GL_DrawSkySphere (msurface_t *fa)
+static void GL_DrawSkySphere (msurface_t *fa)
 {
 	extern cvar_t gl_maxdist;
 	float time = cl.gametime+realtime-cl.gametimemark;
@@ -982,7 +920,7 @@ void GL_DrawSkySphere (msurface_t *fa)
 #endif
 
 #ifdef D3DQUAKE
-void D3D7_DrawSkySphere (msurface_t *fa)
+static void D3D7_DrawSkySphere (msurface_t *fa)
 {
 	extern cvar_t gl_maxdist;
 	float time = cl.gametime+realtime-cl.gametimemark;
@@ -1076,7 +1014,7 @@ void D3D7_DrawSkySphere (msurface_t *fa)
 	}
 	*/
 }
-void D3D9_DrawSkySphere (msurface_t *fa)
+static void D3D9_DrawSkySphere (msurface_t *fa)
 {
 	extern cvar_t gl_maxdist;
 	float time = cl.gametime+realtime-cl.gametimemark;
@@ -1185,7 +1123,7 @@ void R_ForceSkyBox (void)
 }
 
 #ifdef RGLQUAKE
-void GL_MakeSkyVec (float s, float t, int axis)
+static void GL_MakeSkyVec (float s, float t, int axis)
 {
 	vec3_t		v, b;
 	int			j, k;
diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h
index b548bcd93..2491cf10a 100644
--- a/engine/gl/glquake.h
+++ b/engine/gl/glquake.h
@@ -117,7 +117,7 @@ extern FTEPFNGLGETCOMPRESSEDTEXIMAGEARBPROC qglGetCompressedTexImageARB;
 extern	FTEPFNGLPNTRIANGLESIATIPROC qglPNTrianglesiATI;
 extern	FTEPFNGLPNTRIANGLESFATIPROC qglPNTrianglesfATI;
 
-extern	int texture_extension_number;
+int GL_AllocNewTexture(void);
 
 typedef struct {
 	qboolean tex_env_combine;
@@ -235,7 +235,6 @@ extern	int particlecqtexture;
 extern	int explosiontexture;
 extern	int balltexture;
 extern	int	netgraphtexture;	// netgraph texture
-extern	int	playertextures;
 
 extern	int	skytexturenum;		// index in cl.loadmodel, not gl texture object
 
@@ -825,6 +824,10 @@ extern void (APIENTRY *qglDeleteBuffersARB)(GLsizei n, GLuint* ids);
 extern void (APIENTRY *qglBindBufferARB)(GLenum target, GLuint id);
 extern void (APIENTRY *qglBufferDataARB)(GLenum target, GLsizei size, const void* data, GLenum usage);
 extern void (APIENTRY *qglBufferSubDataARB)(GLenum target, GLint offset, GLsizei size, void* data);
+extern void *(APIENTRY *qglMapBufferARB)(GLenum target, GLenum access);
+extern GLboolean (APIENTRY *qglUnmapBufferARB)(GLenum target);
+
+
 
 /*
 extern qboolean gl_arb_fragment_program;
diff --git a/engine/gl/shader.h b/engine/gl/shader.h
index cc1925a07..47da8ba41 100644
--- a/engine/gl/shader.h
+++ b/engine/gl/shader.h
@@ -273,11 +273,12 @@ shader_t *R_RegisterShader (char *name);
 shader_t *R_RegisterShader_Vertex (char *name);
 shader_t *R_RegisterShader_Flare (char *name);
 shader_t *R_RegisterSkin (char *name);
-shader_t *R_RegisterCustom (char *name, void(*defaultgen)(char *name, shader_t*));
+shader_t *R_RegisterCustom (char *name, void(*defaultgen)(char *name, shader_t*, void *args), void *args);
 
 cin_t *R_ShaderGetCinematic(char *name);
 
-void Shader_DefaultSkinShell(char *shortname, shader_t *s);
+void Shader_DefaultSkinShell(char *shortname, shader_t *s, void *args);
+void Shader_DefaultBSP(char *shortname, shader_t *s, void *args);
 
 
 void R_BackendInit (void);
diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c
index 46860b297..4771da28b 100644
--- a/engine/server/pr_cmds.c
+++ b/engine/server/pr_cmds.c
@@ -2774,7 +2774,7 @@ int PF_newcheckclient (progfuncs_t *prinst, int check)
 // get the PVS for the entity
 	VectorAdd (ent->v->origin, ent->v->view_ofs, org);
 	leaf = sv.worldmodel->funcs.LeafnumForPoint(sv.worldmodel, org);
-	checkpvs = sv.worldmodel->funcs.LeafPVS (sv.worldmodel, leaf, checkpvsbuffer);
+	checkpvs = sv.worldmodel->funcs.LeafPVS (sv.worldmodel, leaf, checkpvsbuffer, sizeof(checkpvsbuffer));
 
 	return i;
 }
@@ -3230,14 +3230,14 @@ void PF_precache_sound (progfuncs_t *prinst, struct globalvars_s *pr_globals)
 	PF_precache_sound_Internal(prinst, s);
 }
 
-void PF_precache_model_Internal (progfuncs_t *prinst, char *s)
+int PF_precache_model_Internal (progfuncs_t *prinst, char *s)
 {
 	int		i;
 
 	if (s[0] <= ' ')
 	{
 		Con_Printf ("precache_model: empty string\n");
-		return;
+		return 0;
 	}
 
 	for (i=1 ; i<MAX_MODELS ; i++)
@@ -3247,7 +3247,7 @@ void PF_precache_model_Internal (progfuncs_t *prinst, char *s)
 			if (strlen(s)>=MAX_QPATH-1)	//probably safest to keep this.
 			{
 				PR_BIError (prinst, "Precache name too long");
-				return;
+				return 0;
 			}
 #ifdef VM_Q1
 			if (svs.gametype == GT_Q1QVM)
@@ -3271,14 +3271,15 @@ void PF_precache_model_Internal (progfuncs_t *prinst, char *s)
 #endif
 			}
 
-			return;
+			return i;
 		}
 		if (!strcmp(sv.strings.model_precache[i], s))
 		{
-			return;
+			return i;
 		}
 	}
 	PR_BIError (prinst, "PF_precache_model: overflow");
+	return 0;
 }
 void PF_precache_model (progfuncs_t *prinst, struct globalvars_s *pr_globals)
 {
@@ -3301,48 +3302,55 @@ void PF_precache_puzzle_model (progfuncs_t *prinst, struct globalvars_s *pr_glob
 	PF_precache_model_Internal(prinst, fullname);
 }
 
-void PF_WeapIndex (progfuncs_t *prinst, struct globalvars_s *pr_globals)
+void PF_getmodelindex (progfuncs_t *prinst, struct globalvars_s *pr_globals)
 {
 	char	*s;
-	int		i;
 
 	s = PR_GetStringOfs(prinst, OFS_PARM0);
+	G_INT(OFS_RETURN) = PF_precache_model_Internal(prinst, s);
+}
+void PF_precache_vwep_model (progfuncs_t *prinst, struct globalvars_s *pr_globals)
+{
+	int i;
+	char	*s;
 
-	G_FLOAT(OFS_RETURN) = 1;
-
-	if (s[0] <= ' ')
+	s = PR_GetStringOfs(prinst, OFS_PARM0);
+	if (!*s || strchr(s, '\"') || strchr(s, ';') || strchr(s, '\t') || strchr(s, '\n'))
 	{
-		PR_BIError (prinst, "Bad string");
-		return;
+		Con_Printf("PF_precache_vwep_model: bad string\n");
+		G_FLOAT(OFS_RETURN) = 0;
 	}
-
-	for (i=1 ; i<MAX_MODELS ; i++)
+	else
 	{
-		if (!*sv.strings.model_precache[i])
+		for (i = 0; i < sizeof(sv.strings.vw_model_precache)/sizeof(sv.strings.vw_model_precache[0]); i++)
 		{
-			if (sv.state != ss_loading)	//allow it to be used to find a model too.
+			if (!sv.strings.vw_model_precache[i])
 			{
-				PR_BIError (prinst, "PF_Precache_*: Precache can only be done in spawn functions");
+				if (sv.state != ss_loading)
+				{
+					Con_Printf("PF_precache_vwep_model: not spawning\n");
+					G_FLOAT(OFS_RETURN) = 0;
+					return;
+				}
+#ifdef VM_Q1
+				if (svs.gametype == GT_Q1QVM)
+					sv.strings.vw_model_precache[i] = s;
+				else
+#endif
+					sv.strings.vw_model_precache[i] = PR_AddString(prinst, s, 0);
+				return;
+			}
+			if (!strcmp(sv.strings.vw_model_precache[i], s))
+			{
+				G_FLOAT(OFS_RETURN) = i;
 				return;
 			}
-
-			strcpy(sv.strings.model_precache[i], s);
-			if (!strcmp(s + strlen(s) - 4, ".bsp"))
-				sv.models[i] = Mod_FindName(sv.strings.model_precache[i]);
-
-			G_FLOAT(OFS_RETURN) = i;
-			return;
-		}
-		if (!strcmp(sv.strings.model_precache[i], s))
-		{
-			G_FLOAT(OFS_RETURN) = i;
-			return;
 		}
+		Con_Printf("PF_precache_vwep_model: overflow\n");
+		G_FLOAT(OFS_RETURN) = 0;
 	}
-	PR_BIError (prinst, "PF_precache_model: overflow");
 }
 
-
 void PF_svcoredump (progfuncs_t *prinst, struct globalvars_s *pr_globals)
 {
 	int size = 1024*1024*8;
@@ -8755,6 +8763,7 @@ void PF_getsurfaceclippedpoint(progfuncs_t *prinst, struct globalvars_s *pr_glob
 {
 }
 
+qbyte qcpvs[(MAX_MAP_LEAFS+7)/8];
 //#240 float(vector viewpos, entity viewee) checkpvs (FTE_QC_CHECKPVS)
 //note: this requires a correctly setorigined entity.
 void PF_checkpvs(progfuncs_t *prinst, struct globalvars_s *pr_globals)
@@ -8764,9 +8773,9 @@ void PF_checkpvs(progfuncs_t *prinst, struct globalvars_s *pr_globals)
 
 	//FIXME: Make all alternatives of FatPVS not recalulate the pvs.
 	//and yeah, this is overkill what with the whole fat thing and all.
-	sv.worldmodel->funcs.FatPVS(sv.worldmodel, viewpos, false);
+	sv.worldmodel->funcs.FatPVS(sv.worldmodel, viewpos, qcpvs, sizeof(qcpvs), false);
 
-	G_FLOAT(OFS_RETURN) = sv.worldmodel->funcs.EdictInFatPVS(sv.worldmodel, ent);
+	G_FLOAT(OFS_RETURN) = sv.worldmodel->funcs.EdictInFatPVS(sv.worldmodel, ent, qcpvs);
 }
 
 //entity(string match [, float matchnum]) matchclient = #241;
@@ -9063,7 +9072,7 @@ BuiltinList_t BuiltinList[] = {				//nq	qw		h2		ebfs
 //end telejano
 
 //fte extras
-	{"getmodelindex",	PF_WeapIndex,		0,		0,		0,		200},
+	{"getmodelindex",	PF_getmodelindex,	0,		0,		0,		200},
 	{"externcall",		PF_externcall,		0,		0,		0,		201},
 	{"addprogs",		PF_addprogs,		0,		0,		0,		202},
 	{"externvalue",		PF_externvalue,		0,		0,		0,		203},
@@ -9357,6 +9366,8 @@ BuiltinList_t BuiltinList[] = {				//nq	qw		h2		ebfs
 	//no 504
 //end dp extras
 
+	{"precache_vwep_model",PF_precache_vwep_model,0,0,		0,		532},	// #532 float(string mname) precache_vwep_model
+
 	//don't exceed sizeof(pr_builtin)/sizeof(pr_builtin[0]) (currently 1024) without modifing the size of pr_builtin
 
 	{NULL}
@@ -9735,7 +9746,7 @@ void PR_RegisterFields(void)	//it's just easier to do it this way.
 	fieldxentity(view2);
 	fieldxvector(movement);
 	fieldxfloat(pmove_flags);
-	fieldxfloat(vweapmodelindex);
+	fieldxfloat(vw_index);
 
 	//dp extra fields
 	fieldxentity(nodrawtoclient);
diff --git a/engine/server/progdefs.h b/engine/server/progdefs.h
index 4ff8dce1d..f5340a336 100644
--- a/engine/server/progdefs.h
+++ b/engine/server/progdefs.h
@@ -188,7 +188,7 @@ typedef struct extentvars_s
 	float	fatness;	//FTE_PEXT_FATNESS
 	int		view2;	//FTE_PEXT_VIEW2
 	vec3_t	movement;
-	float	vweapmodelindex;
+	float	vw_index;
 
 	//dp extra fields
 	int		nodrawtoclient;		//
diff --git a/engine/server/server.h b/engine/server/server.h
index 4642ec144..bf25d76e8 100644
--- a/engine/server/server.h
+++ b/engine/server/server.h
@@ -140,6 +140,7 @@ typedef struct
 		};
 #endif
 		struct {
+			char		*vw_model_precache[32];
 			char		*model_precache[MAX_MODELS];	// NULL terminated
 			char		sound_precache[MAX_SOUNDS][MAX_QPATH];	// NULL terminated
 			char		*lightstyles[MAX_LIGHTSTYLES];
diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c
index c95c93a52..083f5df2e 100644
--- a/engine/server/sv_ents.c
+++ b/engine/server/sv_ents.c
@@ -41,18 +41,15 @@ crosses a waterline.
 
 int needcleanup;
 
-int		fatbytes;
+//int		fatbytes;
 int glowsize, glowcolor; // made it a global variable, to suppress msvc warning.
-qbyte	fatpvs[(MAX_MAP_LEAFS+1)/4];
-
-
 
 #ifdef Q2BSPS
-void SV_Q2BSP_FatPVS (model_t *mod, vec3_t org)
+unsigned int  SV_Q2BSP_FatPVS (model_t *mod, vec3_t org, qbyte *resultbuf, unsigned int buffersize)
 {
 	int		leafs[64];
 	int		i, j, count;
-	int		longs;
+	unsigned int		longs;
 	qbyte	*src;
 	vec3_t	mins, maxs;
 
@@ -69,16 +66,17 @@ void SV_Q2BSP_FatPVS (model_t *mod, vec3_t org)
 	if (sv.worldmodel->fromgame == fg_quake3)
 		longs = CM_ClusterSize(mod);
 	else
-		longs = (CM_NumClusters(mod)+31)>>5;
+		longs = (CM_NumClusters(mod)+7)/8;
+	longs = (longs+(sizeof(long)-1))/sizeof(long);
 
 	// convert leafs to clusters
 	for (i=0 ; i<count ; i++)
 		leafs[i] = CM_LeafCluster(mod, leafs[i]);
 
-	CM_ClusterPVS(mod, leafs[0], fatpvs);
+	CM_ClusterPVS(mod, leafs[0], resultbuf, buffersize);
 
 
-//	memcpy (fatpvs, CM_ClusterPVS(leafs[0]), longs<<2);
+//	memcpy (resultbuf, CM_ClusterPVS(leafs[0]), longs<<2);
 	// or in all the other leaf bits
 	for (i=1 ; i<count ; i++)
 	{
@@ -87,10 +85,11 @@ void SV_Q2BSP_FatPVS (model_t *mod, vec3_t org)
 				break;
 		if (j != i)
 			continue;		// already have the cluster we want
-		src = CM_ClusterPVS(mod, leafs[i], NULL);
+		src = CM_ClusterPVS(mod, leafs[i], NULL, 0);
 		for (j=0 ; j<longs ; j++)
-			((long *)fatpvs)[j] |= ((long *)src)[j];
+			((long *)resultbuf)[j] |= ((long *)src)[j];
 	}
+	return longs*sizeof(long);
 }
 #endif
 
@@ -1106,9 +1105,9 @@ typedef struct {
 	qboolean onladder;
 	usercmd_t	*lastcmd;
 	int modelindex;
-	int modelindex2;
 	int frame;
 	int weaponframe;
+	int vw_index;
 	float *angles;
 	float *origin;
 	float *velocity;
@@ -1305,7 +1304,10 @@ void SV_WritePlayerToClient(sizebuf_t *msg, clstate_t *ent)
 			}
 
 			cmd.buttons = 0;	// never send buttons
-			cmd.impulse = 0;	// never send impulses
+			if (ent->zext & Z_EXT_VWEP)
+				cmd.impulse = ent->vw_index;	// never send impulses
+			else
+				cmd.impulse = 0;
 
 			MSG_WriteDeltaUsercmd (msg, &nullcmd, &cmd);
 		}
@@ -1518,7 +1520,6 @@ void SV_WritePlayersToClient (client_t *client, edict_t *clent, qbyte *pvs, size
 				clst.modelindex = sv.demostate[i+1].modelindex;
 				if (!clst.modelindex)
 					continue;
-				clst.modelindex2 = 0;
 				clst.frame = sv.demostate[i+1].frame;
 				clst.weaponframe = sv.recordedplayer[i].weaponframe;
 				clst.angles = ang;
@@ -1539,6 +1540,7 @@ void SV_WritePlayersToClient (client_t *client, edict_t *clent, qbyte *pvs, size
 				clst.fteext = 0;//client->fteprotocolextensions;
 				clst.zext = 0;//client->zquake_extensions;
 				clst.cl = NULL;
+				clst.vw_index = 0;
 
 				lerp = (realtime - olddemotime) / (nextdemotime - olddemotime);
 				if (lerp < 0)
@@ -1589,6 +1591,7 @@ void SV_WritePlayersToClient (client_t *client, edict_t *clent, qbyte *pvs, size
 
 		clst.fteext = 0;//client->fteprotocolextensions;
 		clst.zext = 0;//client->zquake_extensions;
+		clst.vw_index = 0;
 		clst.playernum = MAX_CLIENTS-1;
 		clst.isself = true;
 		clst.modelindex = 0;
@@ -1670,7 +1673,7 @@ void SV_WritePlayersToClient (client_t *client, edict_t *clent, qbyte *pvs, size
 				continue;
 
 			// ignore if not touching a PV leaf
-			if (!sv.worldmodel->funcs.EdictInFatPVS(sv.worldmodel, ent))
+			if (!sv.worldmodel->funcs.EdictInFatPVS(sv.worldmodel, ent, pvs))
 				continue;
 
 			if (!((int)clent->xv->dimension_see & ((int)ent->xv->dimension_seen | (int)ent->xv->dimension_ghost)))
@@ -1689,13 +1692,13 @@ void SV_WritePlayersToClient (client_t *client, edict_t *clent, qbyte *pvs, size
 			clst.onladder = (int)ent->xv->pmove_flags&PMF_LADDER;
 			clst.lastcmd = &cl->lastcmd;
 			clst.modelindex = vent->v->modelindex;
-			clst.modelindex2 = vent->xv->vweapmodelindex;
 			clst.frame = vent->v->frame;
 			clst.weaponframe = ent->v->weaponframe;
 			clst.angles = ent->v->angles;
 			clst.origin = vent->v->origin;
 			clst.velocity = vent->v->velocity;
 			clst.effects = ent->v->effects;
+			clst.vw_index = ent->xv->vw_index;
 
 			if (progstype == PROG_H2 && ((int)vent->v->effects & H2EF_NODRAW))
 			{
@@ -2073,16 +2076,16 @@ qboolean SV_GibFilter(edict_t	*ent)
 #ifdef Q2BSPS
 static int		clientarea;
 
-void Q2BSP_FatPVS(model_t *mod, vec3_t org, qboolean add)
+unsigned int Q2BSP_FatPVS(model_t *mod, vec3_t org, qbyte *buffer, unsigned int buffersize, qboolean add)
 {//fixme: this doesn't add
 	int		leafnum;
 	leafnum = CM_PointLeafnum (mod, org);
 	clientarea = CM_LeafArea (mod, leafnum);
 
-	SV_Q2BSP_FatPVS (mod, org);
+	return SV_Q2BSP_FatPVS (mod, org, buffer, buffersize);
 }
 
-qboolean Q2BSP_EdictInFatPVS(model_t *mod, edict_t *ent)
+qboolean Q2BSP_EdictInFatPVS(model_t *mod, edict_t *ent, qbyte *pvs)
 {
 	int i,l;
 	if (!CM_AreasConnected (mod, clientarea, ent->areanum))
@@ -2095,7 +2098,7 @@ qboolean Q2BSP_EdictInFatPVS(model_t *mod, edict_t *ent)
 
 	if (ent->num_leafs == -1)
 	{	// too many leafs for individual check, go by headnode
-		if (!CM_HeadnodeVisible (mod, ent->headnode, fatpvs))
+		if (!CM_HeadnodeVisible (mod, ent->headnode, pvs))
 			return false;
 	}
 	else
@@ -2103,7 +2106,7 @@ qboolean Q2BSP_EdictInFatPVS(model_t *mod, edict_t *ent)
 		for (i=0 ; i < ent->num_leafs ; i++)
 		{
 			l = ent->leafnums[i];
-			if (fatpvs[l >> 3] & (1 << (l&7) ))
+			if (pvs[l >> 3] & (1 << (l&7) ))
 				break;
 		}
 		if (i == ent->num_leafs)
@@ -2454,12 +2457,12 @@ void SV_Snapshot_BuildQ1(client_t *client, packet_entities_t *pack, qbyte *pvs,
 						{
 							p = EDICT_NUM(svprogfuncs, p->xv->tag_entity);
 						}
-						if (!sv.worldmodel->funcs.EdictInFatPVS(sv.worldmodel, p))
+						if (!sv.worldmodel->funcs.EdictInFatPVS(sv.worldmodel, p, pvs))
 							continue;
 					}
 					else
 					{
-						if (!sv.worldmodel->funcs.EdictInFatPVS(sv.worldmodel, ent))
+						if (!sv.worldmodel->funcs.EdictInFatPVS(sv.worldmodel, ent, pvs))
 							continue;
 					}
 				}
@@ -2615,25 +2618,24 @@ void SV_Snapshot_BuildQ1(client_t *client, packet_entities_t *pack, qbyte *pvs,
 	}
 }
 
-qbyte *SV_Snapshot_SetupPVS(client_t *client)
+qbyte *SV_Snapshot_SetupPVS(client_t *client, qbyte *pvs, unsigned int pvsbufsize)
 {
-//fixme: fatpvs is still a global.
 	vec3_t org;
 	int leavepvs = false;
 
 	for (; client; client = client->controlled)
 	{
 		VectorAdd (client->edict->v->origin, client->edict->v->view_ofs, org);
-		sv.worldmodel->funcs.FatPVS(sv.worldmodel, org, leavepvs);
+		sv.worldmodel->funcs.FatPVS(sv.worldmodel, org, pvs, pvsbufsize, leavepvs);
 		leavepvs = true;
 
 #ifdef PEXT_VIEW2
 		if (client->edict->xv->view2)	//add a second view point to the pvs
-			sv.worldmodel->funcs.FatPVS(sv.worldmodel, PROG_TO_EDICT(svprogfuncs, client->edict->xv->view2)->v->origin, leavepvs);
+			sv.worldmodel->funcs.FatPVS(sv.worldmodel, PROG_TO_EDICT(svprogfuncs, client->edict->xv->view2)->v->origin, pvs, pvsbufsize, leavepvs);
 #endif
 	}
 
-	return fatpvs;
+	return pvs;
 }
 
 void SV_Snapshot_Clear(packet_entities_t *pack)
@@ -2653,9 +2655,10 @@ Builds a temporary q1 style entity packet for a q3 client
 */
 void SVQ3Q1_BuildEntityPacket(client_t *client, packet_entities_t *pack)
 {
+	qbyte pvsbuf[(MAX_MAP_LEAFS+7)>>3];
 	qbyte *pvs;
 	SV_Snapshot_Clear(pack);
-	pvs = SV_Snapshot_SetupPVS(client);
+	pvs = SV_Snapshot_SetupPVS(client, pvsbuf, sizeof(pvsbuf));
 	SV_Snapshot_BuildQ1(client, pack, pvs, client->edict, false);
 }
 
@@ -2676,6 +2679,7 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore
 	packet_entities_t	*pack;
 	edict_t	*clent;
 	client_frame_t	*frame;
+	qbyte pvsbuffer[(MAX_MAP_LEAFS+7)/8];
 
 
 	// this is the frame we are creating
@@ -2692,10 +2696,10 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore
 		clent = client->edict;
 #ifdef HLSERVER
 		if (svs.gametype == GT_HALFLIFE)
-			pvs = SVHL_Snapshot_SetupPVS(client);
+			pvs = SVHL_Snapshot_SetupPVS(client, pvsbuffer, sizeof(pvsbuffer));
 		else
 #endif
-			pvs = SV_Snapshot_SetupPVS(client);
+			pvs = SV_Snapshot_SetupPVS(client, pvsbuffer, sizeof(pvsbuffer));
 	}
 
 	host_client = client;
diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c
index d8b7a0a5f..e6de6d7c6 100644
--- a/engine/server/sv_init.c
+++ b/engine/server/sv_init.c
@@ -435,7 +435,7 @@ void SV_CalcPHS (void)
 	int		i, j, k, l, index, num;
 	int		bitbyte;
 	unsigned	*dest, *src;
-	qbyte	*scan;
+	qbyte	*scan, *lf;
 	int		count, vcount;
 
 	if (sv.worldmodel->fromgame == fg_quake2 || sv.worldmodel->fromgame == fg_quake3)
@@ -456,8 +456,9 @@ void SV_CalcPHS (void)
 	vcount = 0;
 	for (i=0 ; i<num ; i++, scan+=rowbytes)
 	{
-		memcpy (scan, sv.worldmodel->funcs.LeafPVS(sv.worldmodel, i, NULL),
-			rowbytes);
+		lf = sv.worldmodel->funcs.LeafPVS(sv.worldmodel, i, scan, rowbytes);
+		if (lf != scan)
+			memcpy (scan, lf, rowbytes);
 		if (i == 0)
 			continue;
 		for (j=0 ; j<num ; j++)
diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c
index 238a0c4ca..7953256a1 100644
--- a/engine/server/sv_main.c
+++ b/engine/server/sv_main.c
@@ -2128,6 +2128,7 @@ client_t *SVC_DirectConnect(void)
 	{														//so switch on the bits that it should be sending.
 		newcl->zquake_extensions |= Z_EXT_PM_TYPE|Z_EXT_PM_TYPE_NEW;
 	}
+	newcl->zquake_extensions &= SUPPORTED_Z_EXTENSIONS;
 
 	Netchan_Setup (NS_SERVER, &newcl->netchan , adr, qport);
 
diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c
index 606e1753d..ad32481ce 100644
--- a/engine/server/sv_send.c
+++ b/engine/server/sv_send.c
@@ -516,7 +516,7 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
 		case MULTICAST_PVS:
 			leafnum = CM_PointLeafnum (sv.worldmodel, origin);
 			cluster = CM_LeafCluster (sv.worldmodel, leafnum);
-			mask = CM_ClusterPVS (sv.worldmodel, cluster, NULL);
+			mask = CM_ClusterPVS (sv.worldmodel, cluster, NULL, 0);
 			break;
 
 		default:
diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c
index a0d4accd9..b70c1b49e 100644
--- a/engine/server/sv_user.c
+++ b/engine/server/sv_user.c
@@ -920,6 +920,48 @@ void SV_Modellist_f (void)
 
 	n = atoi(Cmd_Argv(2));
 
+	if (n >= MAX_MODELS)
+	{
+		SV_EndRedirect();
+		Con_Printf ("SV_Modellist_f: %s send an invalid index\n", host_client->name);
+		SV_DropClient(host_client);
+		return;
+	}
+
+	if (n == 0 && (host_client->zquake_extensions & Z_EXT_VWEP))
+	{
+		char mname[MAX_QPATH];
+		char vweaplist[1024] = "//vweap";
+		int pos = strlen(vweaplist);
+
+		for (i = 0; sv.strings.vw_model_precache[i]; i++)
+		{
+			//grab the model name... without a progs/ prefix if it has one
+			if (!strncmp(sv.strings.vw_model_precache[i], "progs/", 6))
+				Q_strncpy(mname, sv.strings.vw_model_precache[i]+6, sizeof(mname));
+			else
+				Q_strncpy(mname, sv.strings.vw_model_precache[i], sizeof(mname));
+
+			//strip .mdl extensions
+			if (!strcmp(COM_FileExtension(mname), ".mdl"))
+				COM_StripExtension(mname, mname, sizeof(mname));
+
+			//add it to the vweap command, taking care of any remaining spaces in names.
+			if (strchr(mname, ' '))
+				Q_strncatz(vweaplist, va(" \"%s\"", mname), sizeof(vweaplist));
+			else
+				Q_strncatz(vweaplist, va(" %s", mname), sizeof(vweaplist));
+		}
+
+		if (strlen(vweaplist) <= sizeof(vweaplist)-2)
+		{
+			Q_strncatz(vweaplist, "\n", sizeof(vweaplist));
+
+			ClientReliableWrite_Begin(host_client, svc_stufftext, 2+strlen(vweaplist));
+			ClientReliableWrite_String(host_client, vweaplist);
+		}
+	}
+
 //NOTE:  This doesn't go through ClientReliableWrite since it's before the user
 //spawns.  These functions are written to not overflow
 	if (host_client->num_backbuf)
@@ -931,14 +973,6 @@ void SV_Modellist_f (void)
 		return;
 	}
 
-	if (n >= MAX_MODELS)
-	{
-		SV_EndRedirect();
-		Con_Printf ("SV_Modellist_f: %s send an invalid index\n", host_client->name);
-		SV_DropClient(host_client);
-		return;
-	}
-
 #ifdef PEXT_MODELDBL
 	if (n > 255)
 	{
diff --git a/engine/server/svhl_game.c b/engine/server/svhl_game.c
index d6008ba2f..63115dc1d 100644
--- a/engine/server/svhl_game.c
+++ b/engine/server/svhl_game.c
@@ -1727,7 +1727,7 @@ void SVHL_Snapshot_Build(client_t *client, packet_entities_t *pack, qbyte *pvs,
 	}
 }
 
-void SVHL_Snapshot_SetupPVS(client_t *client)
+void SVHL_Snapshot_SetupPVS(client_t *client, qbyte *pvs, unsigned int pvsbufsize)
 {
 }
 
diff --git a/engine/server/svq2_ents.c b/engine/server/svq2_ents.c
index cafee1a63..68c69d792 100644
--- a/engine/server/svq2_ents.c
+++ b/engine/server/svq2_ents.c
@@ -601,8 +601,6 @@ Build a client frame structure
 =============================================================================
 */
 
-extern qbyte	fatpvs[(MAX_MAP_LEAFS+1)/4];
-
 /*
 =============
 SV_BuildClientFrame
@@ -624,8 +622,8 @@ void SV_BuildClientFrame (client_t *client)
 	int		clientarea, clientcluster;
 	int		leafnum;
 	int		c_fullsend;
+	qbyte	clientpvs[(MAX_MAP_LEAFS+7)>>3];
 	qbyte	*clientphs;
-	qbyte	*bitvector;
 
 	if (client->state < cs_spawned)
 		return;
@@ -661,7 +659,7 @@ void SV_BuildClientFrame (client_t *client)
 	frame->ps = clent->client->ps;
 
 
-	sv.worldmodel->funcs.FatPVS(sv.worldmodel, org, false);
+	sv.worldmodel->funcs.FatPVS(sv.worldmodel, org, clientpvs, sizeof(clientpvs), false);
 	clientphs = CM_ClusterPHS (sv.worldmodel, clientcluster);
 
 	// build up the list of visible entities
@@ -707,11 +705,9 @@ void SV_BuildClientFrame (client_t *client)
 				// FIXME: if an ent has a model and a sound, but isn't
 				// in the PVS, only the PHS, clear the model
 
-				bitvector = fatpvs;
-
 				if (ent->num_clusters == -1)
 				{	// too many leafs for individual check, go by headnode
-					if (!CM_HeadnodeVisible (sv.worldmodel, ent->headnode, bitvector))
+					if (!CM_HeadnodeVisible (sv.worldmodel, ent->headnode, clientpvs))
 						continue;
 					c_fullsend++;
 				}
@@ -720,7 +716,7 @@ void SV_BuildClientFrame (client_t *client)
 					for (i=0 ; i < ent->num_clusters ; i++)
 					{
 						l = ent->clusternums[i];
-						if (bitvector[l >> 3] & (1 << (l&7) ))
+						if (clientpvs[l >> 3] & (1 << (l&7) ))
 							break;
 					}
 					if (i == ent->num_clusters)
diff --git a/engine/server/svq2_game.c b/engine/server/svq2_game.c
index c1ff30787..99ce144ef 100644
--- a/engine/server/svq2_game.c
+++ b/engine/server/svq2_game.c
@@ -350,7 +350,7 @@ static qboolean VARGS PFQ2_inPVS (vec3_t p1, vec3_t p2)
 	leafnum = CM_PointLeafnum (sv.worldmodel, p1);
 	cluster = CM_LeafCluster (sv.worldmodel, leafnum);
 	area1 = CM_LeafArea (sv.worldmodel, leafnum);
-	mask = CM_ClusterPVS (sv.worldmodel, cluster, NULL);
+	mask = CM_ClusterPVS (sv.worldmodel, cluster, NULL, 0);
 
 	leafnum = CM_PointLeafnum (sv.worldmodel, p2);
 	cluster = CM_LeafCluster (sv.worldmodel, leafnum);
diff --git a/engine/server/svq3_game.c b/engine/server/svq3_game.c
index c2e284d26..9195cfbb5 100644
--- a/engine/server/svq3_game.c
+++ b/engine/server/svq3_game.c
@@ -2394,7 +2394,7 @@ void SVQ3_BuildClientSnapshot( client_t *client )
 	org[2] += ps->viewheight;
 
 	clientarea = CM_PointLeafnum(sv.worldmodel, org);
-	bitvector = sv.worldmodel->funcs.LeafPVS(sv.worldmodel, sv.worldmodel->funcs.LeafnumForPoint(sv.worldmodel, org), NULL);
+	bitvector = sv.worldmodel->funcs.LeafPVS(sv.worldmodel, sv.worldmodel->funcs.LeafnumForPoint(sv.worldmodel, org), NULL, 0);
 	clientarea = CM_LeafArea(sv.worldmodel, clientarea);
 /*
 	if (client->areanum != clientarea)
diff --git a/engine/sw/sw_draw.c b/engine/sw/sw_draw.c
index e27cb7f12..aa2610ba0 100644
--- a/engine/sw/sw_draw.c
+++ b/engine/sw/sw_draw.c
@@ -246,7 +246,7 @@ mpic_t	*SWDraw_CachePic (char *path)
 
 	pic = SWDraw_SafeCachePic(path);
 	if (!pic)
-		Sys_Error ("Draw_CachePic: failed to load %s", path);
+		Sys_Error ("Draw_CachePic: failed to load \"%s\"", path);
 		
 	return pic;
 }
@@ -474,7 +474,7 @@ void SWDraw_Init (void)
 	swmenu_numcachepics = 0;
 
 	// lame hack but whatever works
-	strcpy(swmenu_cachepics[swmenu_numcachepics].name, "pics/conchars.pcx");
+	strcpy(swmenu_cachepics[swmenu_numcachepics].name, "conchars");
 	swmenu_cachepics[swmenu_numcachepics].cache.fake = true;
 	swmenu_cachepics[swmenu_numcachepics].cache.data = BZ_Malloc(sizeof(mpic_t) + 128*128);
 	{