From c0c21309789e25452a03b113db987eb6e7cdc361 Mon Sep 17 00:00:00 2001
From: Spoike <acceptthis@users.sourceforge.net>
Date: Mon, 13 Sep 2004 03:20:04 +0000
Subject: [PATCH] Adding stuff like specular highlights - required changes to
 texture loading to prevent gamma adjustments on all textures.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@203 fc73d0e0-1445-4013-8a0c-d673dee63da5
---
 engine/client/image.c    |   55 +-
 engine/client/r_part.c   |    4 +-
 engine/common/gl_q2bsp.c |    2 +-
 engine/gl/gl_alias.c     |   14 +-
 engine/gl/gl_draw.c      |   15 +-
 engine/gl/gl_model.c     |   24 +-
 engine/gl/gl_model.h     |    8 +-
 engine/gl/gl_ppl.c       | 2631 ++++++++++++++++++++++----------------
 engine/gl/gl_rmisc.c     |    3 +-
 engine/gl/gl_rsurf.c     |   35 +-
 engine/gl/gl_vidcommon.c |   34 +-
 engine/gl/gl_warp.c      |    2 +-
 engine/gl/glmod_doom.c   |    2 +-
 engine/gl/glquake.h      |   17 +-
 engine/gl/glsupp.h       |  185 +++
 15 files changed, 1814 insertions(+), 1217 deletions(-)

diff --git a/engine/client/image.c b/engine/client/image.c
index f27556311..c68adc165 100644
--- a/engine/client/image.c
+++ b/engine/client/image.c
@@ -1478,7 +1478,7 @@ int GL_LoadTexture8Bump (char *identifier, int width, int height, unsigned char
 
 int image_width, image_height;
 qbyte *COM_LoadFile (char *path, int usehunk);
-int Mod_LoadHiResTexture(char *name, qboolean mipmap, qboolean alpha)
+int Mod_LoadHiResTexture(char *name, qboolean mipmap, qboolean alpha, qboolean colouradjust)
 {
 	qboolean alphaed;
 	char *buf, *data;
@@ -1605,7 +1605,7 @@ int Mod_LoadReplacementTexture(char *name, qboolean mipmap, qboolean alpha)
 {
 	if (!gl_load24bit.value)
 		return 0;
-	return Mod_LoadHiResTexture(name, mipmap, alpha);
+	return Mod_LoadHiResTexture(name, mipmap, alpha, true);
 }
 
 int Mod_LoadBumpmapTexture(char *name)
@@ -1671,7 +1671,6 @@ int Mod_LoadBumpmapTexture(char *name)
 				}
 				else
 				{
-	//				Sys_Error("Unsupported picture \"%s\"", name);
 					BZ_Free(buf);
 					continue;
 				}
@@ -1683,56 +1682,6 @@ int Mod_LoadBumpmapTexture(char *name)
 		}
 	}
 	return 0;
-
-
-
-/*
-
-	char *buf, *data;
-	int len;
-//	int h;
-
-	int width, height;
-
-	char *path[] ={
-		"%s",
-		"override/%s.tga",
-		"%s.tga",
-		"progs/%s"};
-
-	int i;	
-
-	if ((len = GL_FindTexture(name))!= -1)	//don't bother if it already exists.
-		return len;
-
-	//should write this nicer.
-	for (i = 0; i < sizeof(path)/sizeof(char *); i++)
-	{
-		if ((buf = COM_LoadFile (va(path[i], name), 5)))
-		{
-			if ((data = ReadTargaFile(buf, com_filesize, &width, &height, 2)))	//Only load a greyscale image.
-			{
-				len = GL_LoadTexture8Bump(name, width, height, data, true);
-				BZ_Free(data);
-			}
-			else if ((data = ReadTargaFile(buf, com_filesize, &width, &height, false)))	//Image is more than just greyscale.
-			{
-				len = GL_LoadTexture32(name, width, height, (unsigned*)data, true, false);	//must be normal
-				BZ_Free(data);
-			}
-			else
-			{
-//				Sys_Error("Unsupported picture \"%s\"", name);
-				BZ_Free(buf);
-				continue;
-			}
-		
-			BZ_Free(buf);
-			
-			return len;
-		}
-	}
-	return 0;*/	
 }
 
 
diff --git a/engine/client/r_part.c b/engine/client/r_part.c
index 3a5ca552f..db9b8902c 100644
--- a/engine/client/r_part.c
+++ b/engine/client/r_part.c
@@ -630,7 +630,7 @@ void R_ParticleEffect_f(void)
 #ifdef RGLQUAKE
 	if (qrenderer == QR_OPENGL)
 	{
-		ptype->texturenum = Mod_LoadHiResTexture(ptype->texname, true, true);
+		ptype->texturenum = Mod_LoadHiResTexture(ptype->texname, true, true, true);
 		if (!ptype->texturenum)
 			ptype->texturenum = explosiontexture;
 	}
@@ -840,7 +840,7 @@ void R_ClearParticles (void)
 		{
 			if (*part_type[i].texname)
 			{
-				part_type[i].texturenum = Mod_LoadHiResTexture(part_type[i].texname, true, true);
+				part_type[i].texturenum = Mod_LoadHiResTexture(part_type[i].texname, true, true, true);
 				if (!part_type[i].texturenum)
 					part_type[i].texturenum = explosiontexture;
 			}
diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c
index 7a5fe9b96..91d8ad92a 100644
--- a/engine/common/gl_q2bsp.c
+++ b/engine/common/gl_q2bsp.c
@@ -1865,7 +1865,7 @@ void CModQ3_LoadShaders (lump_t *l)
 #ifdef RGLQUAKE
 		if (qrenderer == QR_OPENGL)
 		{
-			loadmodel->texinfo[i].texture->gl_texturenum = Mod_LoadHiResTexture(in->shadername, true, false);
+			loadmodel->texinfo[i].texture->gl_texturenum = Mod_LoadHiResTexture(in->shadername, true, false, true);
 			loadmodel->texinfo[i].texture->gl_texturenumfb = 0;
 			loadmodel->texinfo[i].texture->gl_texturenumbumpmap = 0;
 		}
diff --git a/engine/gl/gl_alias.c b/engine/gl/gl_alias.c
index cb297de6e..703eb05d8 100644
--- a/engine/gl/gl_alias.c
+++ b/engine/gl/gl_alias.c
@@ -1713,13 +1713,13 @@ static void *Q1_LoadSkins (daliasskintype_t *pskintype, qboolean alpha)
 						char name[MAX_QPATH];
 						COM_StripExtension(skinname, name);	//go for the normalmap
 						strcat(name, "_norm");
-						texnums->bump = Mod_LoadHiResTexture(name, true, true);
+						texnums->bump = Mod_LoadHiResTexture(name, true, true, false);
 						if (!texnums->bump)
 						{
 							strcpy(name, loadmodel->name);
 							COM_StripExtension(COM_SkipPath(skinname), COM_SkipPath(name));
 							strcat(name, "_norm");
-							texnums->bump = Mod_LoadHiResTexture(name, true, true);
+							texnums->bump = Mod_LoadHiResTexture(name, true, true, false);
 							if (!texnums->bump)
 							{
 								COM_StripExtension(skinname, name);	//bother, go for heightmap and convert
@@ -2459,12 +2459,12 @@ void GL_LoadQ3Model(model_t *mod, void *buffer)
 				skin->skinheight = 0;
 				skin->skinspeed = 0;
 
-				texnum->base = Mod_LoadHiResTexture(inshader->name, true, true);
+				texnum->base = Mod_LoadHiResTexture(inshader->name, true, true, true);
 				if (!texnum->base)
 				{
 					strcpy(name, loadmodel->name);
 					strcpy(COM_SkipPath(name), COM_SkipPath(inshader->name));	//eviile eh?
-					texnum->base = Mod_LoadHiResTexture(name, true, true);
+					texnum->base = Mod_LoadHiResTexture(name, true, true, true);
 				}
 
 				texnum->bump = 0;
@@ -2472,13 +2472,13 @@ void GL_LoadQ3Model(model_t *mod, void *buffer)
 				{
 					COM_StripExtension(inshader->name, name);	//go for the normalmap
 					strcat(name, "_norm");
-					texnum->bump = Mod_LoadHiResTexture(name, true, true);
+					texnum->bump = Mod_LoadHiResTexture(name, true, true, false);
 					if (!texnum->bump)
 					{
 						strcpy(name, loadmodel->name);
 						COM_StripExtension(COM_SkipPath(inshader->name), COM_SkipPath(name));
 						strcat(name, "_norm");
-						texnum->bump = Mod_LoadHiResTexture(name, true, true);
+						texnum->bump = Mod_LoadHiResTexture(name, true, true, false);
 						if (!texnum->bump)
 						{
 							COM_StripExtension(inshader->name, name);	//bother, go for heightmap and convert
@@ -2499,7 +2499,7 @@ void GL_LoadQ3Model(model_t *mod, void *buffer)
 				{
 					COM_StripExtension(inshader->name, name);	//go for the normalmap
 					strcat(name, "_luma");
-					texnum->fullbright = Mod_LoadHiResTexture(name, true, true);
+					texnum->fullbright = Mod_LoadHiResTexture(name, true, true, true);
 					if (!texnum->base)
 					{
 						strcpy(name, loadmodel->name);
diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c
index 7634805ca..137f2982e 100644
--- a/engine/gl/gl_draw.c
+++ b/engine/gl/gl_draw.c
@@ -244,7 +244,7 @@ qboolean Draw_RealPicFromWad (qpic_t	*out, char *name)
 	if (!in && !texnum)	//try a q2 texture
 	{
 		sprintf(name2, "pics/%s", name);
-		texnum = Mod_LoadHiResTexture(name2, false, true);
+		texnum = Mod_LoadHiResTexture(name2, false, true, true);
 	}
 	
 	if (texnum)
@@ -700,7 +700,7 @@ void GLDraw_ReInit (void)
 	{
 		if (!draw_chars)	//or low res.
 		{
-			if (!(char_texture=Mod_LoadHiResTexture("pics/conchars.pcx", false, true)))	//try low res q2 path
+			if (!(char_texture=Mod_LoadHiResTexture("pics/conchars.pcx", false, true, true)))	//try low res q2 path
 			{
 				char *tempchars = COM_LoadMallocFile("gfx/menu/conchars.lmp");
 				char *in, *out;
@@ -896,7 +896,7 @@ void GLDraw_ReInit (void)
 	{
 		if (!ncdata)	//no fallback
 		{
-			if (!(gl->texnum=Mod_LoadHiResTexture("pics/conback.pcx", false, true)))
+			if (!(gl->texnum=Mod_LoadHiResTexture("pics/conback.pcx", false, true, true)))
 				if (!(gl->texnum=Mod_LoadReplacementTexture("gfx/menu/conback.lmp", false, true)))
 					Sys_Error ("Couldn't load gfx/conback.lmp");	//that's messed it up, hasn't it?...
 		}
@@ -948,6 +948,9 @@ void GLDraw_ReInit (void)
 	detailtexture = Mod_LoadReplacementTexture("textures/detail", true, false);
 
 	inited15to8 = false;
+
+
+	PPL_LoadSpecularFragmentProgram();
 }
 
 void GLDraw_Init (void)
@@ -1171,7 +1174,7 @@ void GLDraw_Crosshair(void)
 	}
 	else if ((*crosshair.string>='a' && *crosshair.string<='z') || (*crosshair.string>='A' && *crosshair.string<='Z'))
 	{				
-		int i = Mod_LoadHiResTexture (crosshair.string, false, true);
+		int i = Mod_LoadHiResTexture (crosshair.string, false, true, true);
 		GL_Bind (i);
 	}
 	else
@@ -1704,7 +1707,7 @@ void GL_Set2D (void)
 	if (gl_font.modified)
 	{
 		gl_font.modified = 0;
-		if (!*gl_font.string || !(char_texture=Mod_LoadHiResTexture(va("fonts/%s", gl_font.string), false, true)))
+		if (!*gl_font.string || !(char_texture=Mod_LoadHiResTexture(va("fonts/%s", gl_font.string), false, true, true)))
 			char_texture = default_char_texture;
 
 		gl_smoothfont.modified = 1;
@@ -1713,7 +1716,7 @@ void GL_Set2D (void)
 	{
 		int newtex = 0;
 		gl_conback.modified = 0;
-		if (!*gl_conback.string || !(newtex=Mod_LoadHiResTexture(va("conbacks/%s", gl_conback.string), false, true)))
+		if (!*gl_conback.string || !(newtex=Mod_LoadHiResTexture(va("conbacks/%s", gl_conback.string), false, true, true)))
 			conback = default_conback;
 		else
 		{
diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c
index 07f94ca61..b3638104b 100644
--- a/engine/gl/gl_model.c
+++ b/engine/gl/gl_model.c
@@ -83,6 +83,9 @@ extern int		mod_numknown;
 #endif
 
 extern cvar_t r_loadlits;
+#ifdef SPECULAR
+extern cvar_t gl_specular;
+#endif
 extern cvar_t r_fb_bmodels;
 extern cvar_t gl_subdivide_size;
 extern cvar_t gl_subdivide_water;
@@ -808,12 +811,12 @@ void GLMod_LoadAdvancedTextureSection(char *section, char *name, int *base, int
 		*base = 0;
 		*norm = 0;
 		if (!*norm && *normname)
-			*norm = Mod_LoadHiResTexture(normname, true, false);
+			*norm = Mod_LoadHiResTexture(normname, true, false, false);
 		if (!*norm && *bumpname)
 			*norm = Mod_LoadBumpmapTexture(bumpname);
 
 		if (*norm && *flatname)
-			*base = Mod_LoadHiResTexture(flatname, true, false);
+			*base = Mod_LoadHiResTexture(flatname, true, false, true);
 	}
 	else
 	{
@@ -822,11 +825,11 @@ void GLMod_LoadAdvancedTextureSection(char *section, char *name, int *base, int
 			*norm = 0;
 	}
 	if (!*base && *stdname)
-		*base = Mod_LoadHiResTexture(stdname, true, false);
+		*base = Mod_LoadHiResTexture(stdname, true, false, true);
 	if (!*base && *flatname)
-		*base = Mod_LoadHiResTexture(flatname, true, false);
+		*base = Mod_LoadHiResTexture(flatname, true, false, true);
 	if (luma && *lumaname)
-		*luma = Mod_LoadHiResTexture(lumaname, true, true);
+		*luma = Mod_LoadHiResTexture(lumaname, true, true, true);
 }
 
 void GLMod_LoadAdvancedTexture(char *name, int *base, int *norm, int *luma, int *alphamode, qboolean *cull)	//fixme: add gloss
@@ -972,6 +975,13 @@ void GLMod_LoadTextures (lump_t *l)
 
 					tx->gl_texturenumbumpmap = GL_LoadTexture8Bump(altname, tx->width, tx->height, base, true);	//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, true, false, false);
+				}
 			}
 		}
 	}
@@ -1097,7 +1107,7 @@ void GLMod_NowLoadExternal(void)
 					tx->alphaed = alphaed;
 				}
 				
-				if (!(tx->gl_texturenum = Mod_LoadHiResTexture(tx->name, true, false)))
+				if (!(tx->gl_texturenum = Mod_LoadHiResTexture(tx->name, true, false, true)))
 					tx->gl_texturenum = Mod_LoadReplacementTexture("light1_4", true, false);
 				texture_mode = GL_LINEAR;
 			}
@@ -2897,7 +2907,7 @@ void GLMod_LoadSprite2Model (model_t *mod, void *buffer)
 
 		frame = psprite->frames[i].frameptr = Hunk_AllocName(sizeof(mspriteframe_t), loadname);
 
-		frame->gl_texturenum = Mod_LoadHiResTexture(pframetype->name, true, true);
+		frame->gl_texturenum = Mod_LoadHiResTexture(pframetype->name, true, true, true);
 		frame->width = LittleLong(pframetype->width);
 		frame->height = LittleLong(pframetype->height);
 		origin[0] = LittleLong (pframetype->origin_x);
diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h
index b40e4477d..b17df7e70 100644
--- a/engine/gl/gl_model.h
+++ b/engine/gl/gl_model.h
@@ -143,6 +143,7 @@ typedef struct texture_s
 	int			gl_texturenum;
 	int			gl_texturenumfb;
 	int			gl_texturenumbumpmap;
+	int			gl_texturenumspec;
 	struct msurface_s	*texturechain;	// for gl_texsort drawing
 	int			anim_total;				// total tenths in sequence ( 0 = no)
 	int			anim_min, anim_max;		// time for this frame min <=time< max
@@ -182,7 +183,12 @@ typedef struct mtexinfo_s
 	struct mtexinfo_s	*next;
 } mtexinfo_t;
 
+#define SPECULAR
+#ifdef SPECULAR
+#define	VERTEXSIZE	10
+#else
 #define	VERTEXSIZE	7
+#endif
 
 typedef struct glpoly_s
 {
@@ -191,7 +197,7 @@ typedef struct glpoly_s
 #ifdef SHADERS
 	float	texcenter[2];	//center of texture made by adveraging the tex coords
 #endif
-	float	verts[4][VERTEXSIZE];	// variable sized (xyz s1t1 s2t2)
+	float	verts[4][VERTEXSIZE];	// variable sized (xyz s1t1 s2t2 (ldir_xyz)
 } glpoly_t;
 
 typedef struct msurface_s
diff --git a/engine/gl/gl_ppl.c b/engine/gl/gl_ppl.c
index d035ae6c8..9fba9ced0 100644
--- a/engine/gl/gl_ppl.c
+++ b/engine/gl/gl_ppl.c
@@ -24,6 +24,9 @@ extern int		detailtexture;
 extern lightmapinfo_t **lightmap;
 
 extern model_t *currentmodel;
+extern int		*deluxmap_textures;
+
+extern int normalisationCubeMap;
 
 int r_shadowframe;
 
@@ -31,13 +34,13 @@ int shadowsurfcount;
 int shadowedgecount;
 int shadowlightfaces;
 
+int ppl_specular_fragmentprogram;
+
 //#define glBegin glEnd
 
 
 #define	Q2RF_WEAPONMODEL		4		// only draw through eyes
 
-#define EDGEOPTIMISE
-#ifdef EDGEOPTIMISE
 struct {
 	short count;
 	short count2;
@@ -45,338 +48,24 @@ struct {
 	short prev;
 } edge[MAX_MAP_EDGES];
 int firstedge;
-#endif
 
 vec3_t lightorg = {0, 0, 0};
 float lightradius;
 
-#ifndef WORLDVERTEXARRAYS
-static void PPL_BaseTextureChain(msurface_t *first)
-{
-	extern int		*deluxmap_textures;
-	extern cvar_t gl_bump;
-	texture_t	*t;
 
-	msurface_t *s = first;
-
-	int vi;
-	glRect_t    *theRect;
-	glpoly_t *p;
-	float *v;
-
-	glEnable(GL_TEXTURE_2D);
-
-	t = GLR_TextureAnimation (s->texinfo->texture);
-
-	if (s->flags & SURF_DRAWTURB)
-	{
-		GL_DisableMultitexture();
-		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-		GL_Bind (t->gl_texturenum);
-		for (; s ; s=s->texturechain)
-			EmitWaterPolys (s, r_wateralphaval);
-
-		glDisable(GL_BLEND);
-		glColor4f(1,1,1, 1);
-
-		t->texturechain = NULL;	//no lighting effects. (good job these don't animate eh?)
-		return;
-	}
-
-	if (s->lightmaptexturenum < 0)	//no lightmap
-	{
-		GL_DisableMultitexture();
-		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-		GL_Bind (t->gl_texturenum);
-
-
-		for (; 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)
-			{
-				glTexCoord2f (v[3], v[4]);
-				glVertex3fv (v);
-			}
-			glEnd ();
-		}
-	}
-	else if (!gl_mtexable)
-	{	//multitexture isn't supported.
-		glDisable(GL_BLEND);
-		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-		GL_Bind (t->gl_texturenum);
-		for (s = first; 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)
-				{
-					glTexCoord2f (v[3], v[4]);
-					glVertex3fv (v);
-				}
-				glEnd ();
-			}
-		}
-
-		glEnable(GL_BLEND);
-		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-
-		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);
-		}
-
-		for (s = first; s ; s=s->texturechain)
-		{
-			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)
-				{
-					glTexCoord2f (v[5], v[6]);
-					glVertex3fv (v);
-				}
-				glEnd ();
-			}
-		}
-	}
-	else
-	{
-		if (gl_bump.value && currentmodel->deluxdata && t->gl_texturenumbumpmap)
-		{
-			qglActiveTextureARB(GL_TEXTURE0_ARB);
-
-			//Bind normal map to texture unit 0
-			GL_BindType(GL_TEXTURE_2D, t->gl_texturenumbumpmap);
-			glEnable(GL_TEXTURE_2D);
-			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 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);	//the deluxmap
-			glEnable(GL_TEXTURE_2D);
-			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 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);
-//we now have normalmap.deluxmap on the screen.
-			if (gl_mtexarbable>=4)	//go the whole hog. bumpmapping in one pass.
-			{
-				//continue going to give (normalmap.deluxemap)*texture*lightmap.
-				qglActiveTextureARB(GL_TEXTURE2_ARB);
-				glEnable(GL_TEXTURE_2D);
-				glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-				GL_Bind (t->gl_texturenum);
-
-				qglActiveTextureARB(GL_TEXTURE3_ARB);
-				glEnable(GL_TEXTURE_2D);
-				glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
-
-				vi = -1;
-				for (; s ; s=s->texturechain)
-				{
-//					if (vi != s->lightmaptexturenum)
-					{
-						vi = s->lightmaptexturenum;
-						qglActiveTextureARB(GL_TEXTURE1_ARB);
-						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;
-						}
-						qglActiveTextureARB(GL_TEXTURE3_ARB);
-						GL_BindType(GL_TEXTURE_2D, 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)
-						{									
-							qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, v[3], v[4]);
-							qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, v[5], v[6]);
-							qglMultiTexCoord2fARB(GL_TEXTURE2_ARB, v[3], v[4]);
-							qglMultiTexCoord2fARB(GL_TEXTURE3_ARB, v[5], v[6]);
-							glVertex3fv (v);
-						}
-						glEnd ();
-					}
-				}
-
-				qglActiveTextureARB(GL_TEXTURE3_ARB);
-				glDisable(GL_TEXTURE_2D);
-				qglActiveTextureARB(GL_TEXTURE2_ARB);
-				glDisable(GL_TEXTURE_2D);
-				qglActiveTextureARB(GL_TEXTURE1_ARB);
-				glDisable(GL_TEXTURE_2D);
-				qglActiveTextureARB(GL_TEXTURE0_ARB);	//the deluxmap
-
-				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-				return;
-			}
-
-			glDisable(GL_BLEND);
-			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-			for (; 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);
-			qglActiveTextureARB(GL_TEXTURE0_ARB);
-
-			glBlendFunc(GL_DST_COLOR, GL_ZERO);	//tell the texture + lightmap to do current*tex*light (where current is normalmap.deluxemap)
-			glEnable(GL_BLEND);
-
-			s = first;
-
-			GL_SelectTexture(mtexid0);
-			GL_Bind(t->gl_texturenum);
-			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-			GL_EnableMultitexture();
-			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);
-			if (t->alphaed || currententity->alpha < 1)
-			{
-				glEnable(GL_BLEND);
-				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-			}
-			else
-			{
-				glDisable(GL_BLEND);
-				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; s=s->texturechain)
-		{
-			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 ();
-			}
-		}
-	}
-}
-#else	//vertex arrays
 
 typedef struct {
-	float xyz[3];
-	float stw[2];
-	float stl[2];
+	float xyz[3];	//xyz world coordinates
+	float stw[2];	//base texture/normalmap/specular map st coords
+	float stl[3];	//lightmap/deluxmap st coords (or attenuated distance*colour)
+	float ncm[3];	//normalisation cube map (reflected light dir)
 } surfvertexarray_t;
 
 #define MAXARRAYVERTS	512
 static surfvertexarray_t varray_v[MAXARRAYVERTS];
-static int vararry_i[MAXARRAYVERTS];
+static unsigned int varray_i[MAXARRAYVERTS];
+static unsigned int varray_i_forward[MAXARRAYVERTS];
+static unsigned int varray_i_polytotri[MAXARRAYVERTS];	//012 023 034 045...
 int varray_ic;
 int varray_vc;
 
@@ -386,12 +75,12 @@ inline void PPL_EnableVertexArrays(void)
 {
 	glDisableClientState(GL_COLOR_ARRAY);
 	glEnableClientState(GL_VERTEX_ARRAY);
-	glVertexPointer(3, GL_FLOAT, 7*sizeof(float), varray_v->xyz);
+	glVertexPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->xyz);
 }
 inline void PPL_FlushArrays(void)
 {
 	if (varray_ic)
-		glDrawElements(GL_TRIANGLES, varray_ic, GL_UNSIGNED_INT, vararry_i);
+		glDrawElements(GL_TRIANGLES, varray_ic, GL_UNSIGNED_INT, varray_i);
 	varray_ic = 0;
 	varray_vc = 0;
 }
@@ -432,9 +121,9 @@ static void PPL_GenerateArrays(msurface_t *surf)
 		v += VERTEXSIZE;
 		for (vi=2 ; vi<p->numverts ; vi++, v+= VERTEXSIZE)
 		{
-			vararry_i[varray_ic] = vc_s;
-			vararry_i[varray_ic+1] = varray_vc-1;
-			vararry_i[varray_ic+2] = varray_vc;
+			varray_i[varray_ic] = vc_s;
+			varray_i[varray_ic+1] = varray_vc-1;
+			varray_i[varray_ic+2] = varray_vc;
 			varray_ic+=3;
 
 			varray_v[varray_vc].xyz[0] = v[0];
@@ -448,103 +137,149 @@ static void PPL_GenerateArrays(msurface_t *surf)
 		}
 	}
 }
-
-static void PPL_BaseTextureChain(msurface_t *first)
+#ifdef SPECULAR
+//same as above, but also generates cubemap texture coords for light reflection (based on blinn's formula)
+static void PPL_GenerateArraysBlinnCubeMap(msurface_t *surf)
 {
-	extern int		*deluxmap_textures;
-	extern cvar_t gl_bump;
-	texture_t	*t;
-
-	msurface_t *s = first;
-
-	int vi;
-	glRect_t    *theRect;
 	glpoly_t *p;
+	int vi;
+	int vc_s;
 	float *v;
 
-	glEnable(GL_TEXTURE_2D);
+	vec3_t eye, halfdir;
 
-	t = GLR_TextureAnimation (s->texinfo->texture);
-
-	if (s->flags & SURF_DRAWTURB)
+	for (p = surf->polys; p; p=p->next)
 	{
-		/*
-		GL_DisableMultitexture();
-		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-		GL_Bind (t->gl_texturenum);
-		for (; s ; s=s->texturechain)
-			EmitWaterPolys (s);
+		if (varray_ic + p->numverts*3>MAXARRAYVERTS)
+		{
+			PPL_FlushArrays();
+		}
 
-		glDisable(GL_BLEND);
-		glColor4f(1,1,1, 1);
+		vc_s = varray_vc;
+		v = p->verts[0];
 
-		t->texturechain = NULL;	//no lighting effects. (good job these don't animate eh?)
-	*/	return;
+		varray_v[varray_vc].xyz[0] = v[0];
+		varray_v[varray_vc].xyz[1] = v[1];
+		varray_v[varray_vc].xyz[2] = v[2];
+		varray_v[varray_vc].stw[0] = v[3];
+		varray_v[varray_vc].stw[1] = v[4];
+		varray_v[varray_vc].stl[0] = v[5];
+		varray_v[varray_vc].stl[1] = v[6];
+		VectorSubtract(cl.simorg[0], v, eye);
+		VectorNormalize(eye);
+		VectorAdd(eye, (v+7), halfdir);
+//		VectorCopy(eye, halfdir);
+		varray_v[varray_vc].ncm[0] = DotProduct(surf->texinfo->vecs[0], halfdir);
+		varray_v[varray_vc].ncm[1] = DotProduct(surf->texinfo->vecs[1], halfdir);
+		if (surf->flags & SURF_PLANEBACK)
+			varray_v[varray_vc].ncm[2] = -DotProduct(surf->plane->normal, halfdir);
+		else
+			varray_v[varray_vc].ncm[2] = DotProduct(surf->plane->normal, halfdir);
+		varray_vc++;
+		v += VERTEXSIZE;
+		varray_v[varray_vc].xyz[0] = v[0];
+		varray_v[varray_vc].xyz[1] = v[1];
+		varray_v[varray_vc].xyz[2] = v[2];
+		varray_v[varray_vc].stw[0] = v[3];
+		varray_v[varray_vc].stw[1] = v[4];
+		varray_v[varray_vc].stl[0] = v[5];
+		varray_v[varray_vc].stl[1] = v[6];
+		VectorSubtract(r_refdef.vieworg, v, eye);
+		VectorNormalize(eye);
+		VectorAdd(eye, (v+7), halfdir);
+		varray_v[varray_vc].ncm[0] = DotProduct(surf->texinfo->vecs[0], halfdir);
+		varray_v[varray_vc].ncm[1] = DotProduct(surf->texinfo->vecs[1], halfdir);
+		if (surf->flags & SURF_PLANEBACK)
+			varray_v[varray_vc].ncm[2] = -DotProduct(surf->plane->normal, halfdir);
+		else
+			varray_v[varray_vc].ncm[2] = DotProduct(surf->plane->normal, halfdir);
+		varray_vc++;
+		v += VERTEXSIZE;
+		for (vi=2 ; vi<p->numverts ; vi++, v+= VERTEXSIZE)
+		{
+			varray_i[varray_ic] = vc_s;
+			varray_i[varray_ic+1] = varray_vc-1;
+			varray_i[varray_ic+2] = varray_vc;
+			varray_ic+=3;
+
+			varray_v[varray_vc].xyz[0] = v[0];
+			varray_v[varray_vc].xyz[1] = v[1];
+			varray_v[varray_vc].xyz[2] = v[2];
+			varray_v[varray_vc].stw[0] = v[3];
+			varray_v[varray_vc].stw[1] = v[4];
+			varray_v[varray_vc].stl[0] = v[5];
+			varray_v[varray_vc].stl[1] = v[6];
+			VectorSubtract(cl.simorg[0], v, eye);
+			VectorNormalize(eye);
+			VectorAdd(eye, (v+7), halfdir);
+			varray_v[varray_vc].ncm[0] = DotProduct(surf->texinfo->vecs[0], halfdir);
+			varray_v[varray_vc].ncm[1] = DotProduct(surf->texinfo->vecs[1], halfdir);
+			if (surf->flags & SURF_PLANEBACK)
+				varray_v[varray_vc].ncm[2] = -DotProduct(surf->plane->normal, halfdir);
+			else
+				varray_v[varray_vc].ncm[2] = DotProduct(surf->plane->normal, halfdir);
+			varray_vc++;
+		}
+	}
+}
+#endif
+/*
+static void PPL_BaseChain_NoLightmap(msurface_t *first, texture_t *tex)
+{
+	Sys_Error("1 TMU is disabled for now (surface has no lightmap)\n");
+}
+*/
+
+static void PPL_BaseChain_NoBump_1TMU(msurface_t *first, texture_t *tex)
+{
+	int vi;
+	glRect_t    *theRect;
+	msurface_t *s;
+
+	PPL_EnableVertexArrays();
+
+	glDisable(GL_BLEND);
+	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
+
+	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+	GL_Bind (tex->gl_texturenum);
+
+	for (s=first; s ; s=s->texturechain)
+	{
+		PPL_GenerateArrays(s);
+	}
+	PPL_FlushArrays();
+
+	glEnable(GL_BLEND);
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+	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 (s->lightmaptexturenum < 0)	//no lightmap
+	glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
+
+	vi = -1;
+	for (s=first; s ; s=s->texturechain)
 	{
-	/*	GL_DisableMultitexture();
-		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-		GL_Bind (t->gl_texturenum);
-
-
-		for (; 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)
-			{
-				glTexCoord2f (v[3], v[4]);
-				glVertex3fv (v);
-			}
-			glEnd ();
-		}
-*/	}
-	else if (!gl_mtexarbable)
-	{	//multitexture isn't supported.
-/*		glDisable(GL_BLEND);
-		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-		GL_Bind (t->gl_texturenum);
-		for (s = first; 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)
-				{
-					glTexCoord2f (v[3], v[4]);
-					glVertex3fv (v);
-				}
-				glEnd ();
-			}
-		}
-
-		glEnable(GL_BLEND);
-		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-
-		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);
-		}
-
-		for (s = first; s ; s=s->texturechain)
+		if (vi != s->lightmaptexturenum)
 		{
+			PPL_FlushArrays();
 			vi = s->lightmaptexturenum;
-			// Binds lightmap to texenv 1
-			GL_Bind (lightmap_textures[vi]);
+
+			GL_BindType(GL_TEXTURE_2D, lightmap_textures[vi] );
 			if (lightmap[vi]->modified)
 			{
 				lightmap[vi]->modified = false;
@@ -557,245 +292,1004 @@ static void PPL_BaseTextureChain(msurface_t *first)
 				theRect->h = 0;
 				theRect->w = 0;
 			}
+		}
 
-			for (p = s->polys; p; p=p->next)
+		PPL_GenerateArrays(s);
+	}
+	PPL_FlushArrays();
+}
+
+static void PPL_BaseChain_NoBump_2TMU(msurface_t *s, texture_t *tex)
+{
+	int vi;
+	glRect_t    *theRect;
+
+	PPL_EnableVertexArrays();
+
+	if (tex->alphaed)
+	{
+		glEnable(GL_BLEND);
+		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+	}
+	else
+	{
+		glDisable(GL_BLEND);
+		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+	}
+
+
+	GL_Bind (tex->gl_texturenum);
+	qglClientActiveTextureARB(GL_TEXTURE0_ARB);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
+
+	qglClientActiveTextureARB(GL_TEXTURE1_ARB);
+	qglActiveTextureARB(GL_TEXTURE1_ARB);
+	glEnable(GL_TEXTURE_2D);
+	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
+
+	vi = -1;
+	for (; s ; s=s->texturechain)
+	{
+		if (vi != s->lightmaptexturenum)
+		{
+			PPL_FlushArrays();
+			vi = s->lightmaptexturenum;
+
+			GL_BindType(GL_TEXTURE_2D, lightmap_textures[vi] );
+			if (lightmap[vi]->modified)
 			{
-				glBegin(GL_POLYGON);
-				v = p->verts[0];
-				for (vi=0 ; vi<p->numverts ; vi++, v+= VERTEXSIZE)
-				{
-					glTexCoord2f (v[5], v[6]);
-					glVertex3fv (v);
-				}
-				glEnd ();
+				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;
 			}
 		}
-*/	}
+
+		PPL_GenerateArrays(s);
+	}
+	PPL_FlushArrays();
+
+	glDisable(GL_TEXTURE_2D);
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+	qglClientActiveTextureARB(GL_TEXTURE0_ARB);
+	qglActiveTextureARB(GL_TEXTURE0_ARB);
+
+}
+
+static void PPL_BaseChain_Bump_2TMU(msurface_t *first, texture_t *tex)
+{
+	int vi;
+	glRect_t    *theRect;
+	msurface_t *s;
+	PPL_EnableVertexArrays();
+
+	if (tex->alphaed)
+	{
+		glEnable(GL_BLEND);
+		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+	}
+	else
+	{
+		glDisable(GL_BLEND);
+		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+	}
+
+	//Bind normal map to texture unit 0
+	GL_BindType(GL_TEXTURE_2D, tex->gl_texturenumbumpmap);
+	glEnable(GL_TEXTURE_2D);
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
+	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
+
+	qglClientActiveTextureARB(GL_TEXTURE0_ARB);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
+
+	qglActiveTextureARB(GL_TEXTURE1_ARB);	//the deluxmap
+	glEnable(GL_TEXTURE_2D);
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 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);
+
+	qglClientActiveTextureARB(GL_TEXTURE1_ARB);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
+
+
+	vi = -1;
+	for (s=first; s ; s=s->texturechain)
+	{
+		if (vi != s->lightmaptexturenum)
+		{
+			PPL_FlushArrays();
+			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_lightmap_format, GL_UNSIGNED_BYTE,
+					lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*3);
+				theRect->l = LMBLOCK_WIDTH;
+				theRect->t = LMBLOCK_HEIGHT;
+				theRect->h = 0;
+				theRect->w = 0;
+			}
+		}
+
+		PPL_GenerateArrays(s);
+	}
+	PPL_FlushArrays();
+
+	qglActiveTextureARB(GL_TEXTURE0_ARB);
+	GL_Bind (tex->gl_texturenum);
+
+	qglActiveTextureARB(GL_TEXTURE1_ARB);
+	glEnable(GL_TEXTURE_2D);
+	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
+
+	vi = -1;
+	for (s=first; s ; s=s->texturechain)
+	{
+		if (vi != s->lightmaptexturenum)
+		{
+			PPL_FlushArrays();
+			vi = s->lightmaptexturenum;
+
+			GL_BindType(GL_TEXTURE_2D, 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;
+			}
+		}
+
+		PPL_GenerateArrays(s);
+	}
+	PPL_FlushArrays();
+
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+	qglClientActiveTextureARB(GL_TEXTURE0_ARB);
+	qglActiveTextureARB(GL_TEXTURE0_ARB);
+}
+
+static void PPL_BaseChain_Bump_4TMU(msurface_t *s, texture_t *tex)
+{
+	int vi;
+	glRect_t    *theRect;
+
+	PPL_EnableVertexArrays();
+	qglActiveTextureARB(GL_TEXTURE0_ARB);
+
+	//Bind normal map to texture unit 0
+	GL_BindType(GL_TEXTURE_2D, tex->gl_texturenumbumpmap);
+	glEnable(GL_TEXTURE_2D);
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
+	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
+
+	qglClientActiveTextureARB(GL_TEXTURE0_ARB);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
+
+	qglActiveTextureARB(GL_TEXTURE1_ARB);	//the deluxmap
+	glEnable(GL_TEXTURE_2D);
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 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);
+
+	qglClientActiveTextureARB(GL_TEXTURE1_ARB);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
+
+	qglActiveTextureARB(GL_TEXTURE2_ARB);
+	glEnable(GL_TEXTURE_2D);
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+	GL_Bind (tex->gl_texturenum);
+
+	qglClientActiveTextureARB(GL_TEXTURE2_ARB);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
+
+	qglActiveTextureARB(GL_TEXTURE3_ARB);
+	glEnable(GL_TEXTURE_2D);
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
+
+	qglClientActiveTextureARB(GL_TEXTURE3_ARB);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
+
+	vi = -1;
+	for (; s ; s=s->texturechain)
+	{
+		if (vi != s->lightmaptexturenum)
+		{
+			PPL_FlushArrays();
+			vi = s->lightmaptexturenum;
+
+			qglActiveTextureARB(GL_TEXTURE1_ARB);
+			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;
+			}
+			qglActiveTextureARB(GL_TEXTURE3_ARB);
+			GL_BindType(GL_TEXTURE_2D, 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;
+			}
+		}
+
+		PPL_GenerateArrays(s);
+	}
+	PPL_FlushArrays();
+
+	qglActiveTextureARB(GL_TEXTURE3_ARB);
+	glDisable(GL_TEXTURE_2D);
+	qglActiveTextureARB(GL_TEXTURE2_ARB);
+	glDisable(GL_TEXTURE_2D);
+	qglActiveTextureARB(GL_TEXTURE1_ARB);
+	glDisable(GL_TEXTURE_2D);
+	qglActiveTextureARB(GL_TEXTURE0_ARB);
+
+
+	qglClientActiveTextureARB(GL_TEXTURE3_ARB);
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+	qglClientActiveTextureARB(GL_TEXTURE2_ARB);
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+	qglClientActiveTextureARB(GL_TEXTURE1_ARB);
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+	qglClientActiveTextureARB(GL_TEXTURE0_ARB);
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+
+	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+}
+
+#ifdef SPECULAR
+//Draw a texture chain with specular exponant 1.
+/*
+static void PPL_BaseChain_Specular_4TMU(msurface_t *first, texture_t *tex)
+{
+//if I ever do write this function, It'll take a couple of passes.
+	int vi;
+	glRect_t    *theRect;
+	msurface_t *s;
+
+	glColorMask(1,1,1,0);
+
+	PPL_EnableVertexArrays();
+
+	if (qglGetError())
+		Con_Printf("Error before PPL_BaseChain_Specular\n");
+
+	//first 4 texture units: (N.((L+V)/2))^2
+glDisable(GL_BLEND);
+	qglActiveTextureARB(GL_TEXTURE0_ARB);
+	GL_BindType(GL_TEXTURE_2D, tex->gl_texturenumbumpmap);
+	glEnable(GL_TEXTURE_2D);
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+	qglClientActiveTextureARB(GL_TEXTURE0_ARB);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
+
+	if (qglGetError())
+		Con_Printf("Error binding dot3 tmu1\n");
+
+	qglActiveTextureARB(GL_TEXTURE1_ARB);
+	glDisable(GL_TEXTURE_2D);
+	GL_BindType(GL_TEXTURE_CUBE_MAP_ARB, normalisationCubeMap);
+	glEnable(GL_TEXTURE_CUBE_MAP_ARB);
+	if (qglGetError())
+		Con_Printf("Error binding dot3 cubemap\n");
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 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 (qglGetError())
+		Con_Printf("Error binding dot3 combine\n");
+	qglClientActiveTextureARB(GL_TEXTURE1_ARB);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->ncm);
+
+	if (qglGetError())
+		Con_Printf("Error binding dot3 tmu2\n");
+
+	//prev*prev (the exponential)
+	qglActiveTextureARB(GL_TEXTURE2_ARB);
+	GL_BindType(GL_TEXTURE_2D, tex->gl_texturenumbumpmap);	//need to bind something.
+	glEnable(GL_TEXTURE_2D);
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
+
+	if (qglGetError())
+		Con_Printf("Error binding prev*prev\n");
+
+	qglActiveTextureARB(GL_TEXTURE3_ARB);
+	GL_BindType(GL_TEXTURE_2D, tex->gl_texturenumspec);
+	glEnable(GL_TEXTURE_2D);
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 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_MODULATE);
+	qglClientActiveTextureARB(GL_TEXTURE3_ARB);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
+
+	if (qglGetError())
+		Con_Printf("Error binding specular in PPL_BaseChain_Specular\n");
+
+	for (s = first; s ; s=s->texturechain)
+	{
+		PPL_GenerateArraysBlinnCubeMap(s);
+	}
+	PPL_FlushArrays();
+
+glEnable(GL_BLEND);
+glBlendFunc(GL_DST_COLOR, GL_ZERO);
+	// Add normal dot delux times diffusemap then multiple the entire lot by the lightmap.
+	qglActiveTextureARB(GL_TEXTURE0_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+	qglActiveTextureARB(GL_TEXTURE1_ARB);
+	glDisable(GL_TEXTURE_CUBE_MAP_ARB);
+	glEnable(GL_TEXTURE_2D);
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 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);
+	qglClientActiveTextureARB(GL_TEXTURE1_ARB);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
+
+	qglActiveTextureARB(GL_TEXTURE2_ARB);
+	glEnable(GL_TEXTURE_2D);
+	GL_BindType(GL_TEXTURE_2D, tex->gl_texturenum);
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 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_MODULATE);
+	qglClientActiveTextureARB(GL_TEXTURE2_ARB);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
+
+	qglActiveTextureARB(GL_TEXTURE3_ARB);
+	glEnable(GL_TEXTURE_2D);
+	glDisable(GL_TEXTURE_2D);
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 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_MODULATE);
+	qglClientActiveTextureARB(GL_TEXTURE3_ARB);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
+
+	vi = -1;
+	for (s = first; s ; s=s->texturechain)
+	{
+		if (vi != s->lightmaptexturenum)
+		{
+			PPL_FlushArrays();
+			vi = s->lightmaptexturenum;
+
+			qglActiveTextureARB(GL_TEXTURE1_ARB);
+			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;
+			}
+			qglActiveTextureARB(GL_TEXTURE3_ARB);
+			GL_BindType(GL_TEXTURE_2D, 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;
+			}
+		}
+		PPL_GenerateArrays(s);
+	}
+	PPL_FlushArrays();
+
+	glColorMask(1,1,1,0);
+
+	if (qglGetError())
+		Con_Printf("Error drawing in PPL_BaseChain_Specular\n");
+
+	
+	glDisable(GL_TEXTURE_2D);
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+	qglClientActiveTextureARB(GL_TEXTURE2_ARB);
+	glDisable(GL_TEXTURE_2D);
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+	qglClientActiveTextureARB(GL_TEXTURE1_ARB);
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+	glDisable(GL_TEXTURE_2D);
+
+	qglActiveTextureARB(GL_TEXTURE0_ARB);
+	qglClientActiveTextureARB(GL_TEXTURE0_ARB);
+}
+*/
+
+void PPL_LoadSpecularFragmentProgram(void)
+{
+	GLint errorPos, isNative;
+	int i;
+	const char *error;
+
+	  //What should the minimum resource limits be?
+
+      //RESOLVED: 10 attributes, 24 parameters, 4 texture indirections,
+      //48 ALU instructions, 24 texture instructions, and 16 temporaries.
+
+	//16 temps? hmm. that means we should be keeping the indirections instead of temp usage.
+	//temps should be same speed, indirections could prevent texture loading for a bit.
+
+	char *fp =
+	//FP to do:
+	//(diffuse*n.l + gloss*(n.h)^8)*lm
+	//note excessive temp reuse...
+	"!!ARBfp1.0\n"
+
+	"OUTPUT      ocol  = result.color;\n"
+
+	"PARAM       half  = { 0.5, 0.5, 0.5, 0.5 };\n"
+	"PARAM       negone  = { -1,-1,-1,-1 };\n"
+
+	"ATTRIB   tm_tc  = fragment.texcoord[0];\n"
+	"ATTRIB   lm_tc  = fragment.texcoord[1];\n"
+	"ATTRIB   cm_tc  = fragment.texcoord[2];\n"
+
+
+
+	"TEMP diff, spec, nm, ld, cm, gm, lm, dm;\n"
+
+
+	"TEX nm.rgb, tm_tc, texture[1], 2D;\n"		//t1 = n
+	"TEX ld.rgb, lm_tc, texture[3], 2D;\n"		//t2 = l
+	"TEX dm.rgb, tm_tc, texture[0], 2D;\n"		//t2 = d
+	"TEX gm.rgb, tm_tc, texture[4], 2D;\n"		//t2 = gloss
+	"TEX lm.rgb, lm_tc, texture[2], 2D;\n"	//specular = lm
+	"TEX cm.rgb, cm_tc, texture[5], CUBE;\n"		//t2 = d
+
+	//textures loaded - get diffuse
+	"MAD nm, nm, 2, negone;\n"
+	"MAD ld, ld, 2, negone;\n"
+	"DP3 diff, nm, ld;\n"						//diff = n.l
+	"MUL diff.rgb, diff, dm;\n"			//diff = diff*t2
+	//diff now contains the entire diffuse part of the equation.
+
+	//time for specular
+	//t1 still = n
+	"MAD cm, cm, 2, negone;\n"
+	"DP3 spec, nm, cm;\n"				//spec = t1.t2
+
+	"MUL spec, spec, spec;\n"
+	"MUL spec, spec, spec;\n"
+	"MUL spec, spec, spec;\n"
+
+	"MUL spec, spec, gm;\n"
+	//that's the specular part done.
+
+	//we have diffuse and specular - wahoo
+	//combine then halve.
+	"ADD diff.rgb, diff, spec;\n"
+	"MUL diff.rgb, diff, half;\n"
+
+
+	//multiply by inverse lm and output the result.
+	"SUB lm.rgb, 1, lm;\n"
+	"MUL_SAT ocol.rgb, diff, lm;\n"
+	//that's all folks.
+	"END";
+
+	ppl_specular_fragmentprogram = 0;
+
+	for (i = 0; i < MAXARRAYVERTS; i++)
+	{
+		varray_i_forward[i] = i;
+	}
+	for (i = 0; i < MAXARRAYVERTS/3; i++)
+	{
+		varray_i_polytotri[i*3+0] = 0;
+		varray_i_polytotri[i*3+1] = i+1;
+		varray_i_polytotri[i*3+2] = i+2;
+	}
+
+	if (!gl_arb_fragment_program)
+		return;
+
+	glEnable(GL_FRAGMENT_PROGRAM_ARB);
+
+	qglGenProgramsARB( 1, &ppl_specular_fragmentprogram ); 
+	qglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, ppl_specular_fragmentprogram); 
+
+	if (qglGetError())
+		Con_Printf("GL Error binding fragment program\n");
+
+	qglProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(fp), fp);
+	if (qglGetError())
+	{
+		glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
+		error = glGetString(GL_PROGRAM_ERROR_STRING_ARB);
+		Con_Printf("Fragment program error \'%s\'\n", error);
+		ppl_specular_fragmentprogram = 0;
+	}
+	else
+	{
+		qglGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &isNative);
+		if (!isNative)
+			Con_Printf("Warning: Fragment program is emulated. You will likly experience poor performace.\n");
+	}
+
+	if (qglGetError())
+		Con_Printf("GL Error loading fragment program\n");
+
+	glDisable(GL_FRAGMENT_PROGRAM_ARB);
+}
+
+static void PPL_BaseChain_Specular_FP(msurface_t *s, texture_t *tex)
+{
+	int vi;
+	glRect_t    *theRect;
+
+	PPL_EnableVertexArrays();
+
+	glEnable(GL_FRAGMENT_PROGRAM_ARB);
+	qglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, ppl_specular_fragmentprogram); 
+
+	if (qglGetError())
+		Con_Printf("GL Error on shadow lighting\n");
+
+	qglActiveTextureARB(GL_TEXTURE0_ARB);
+	GL_BindType(GL_TEXTURE_2D, tex->gl_texturenum);
+
+	qglActiveTextureARB(GL_TEXTURE1_ARB);
+	GL_BindType(GL_TEXTURE_2D, tex->gl_texturenumbumpmap);
+
+	//qglActiveTextureARB(GL_TEXTURE2_ARB);
+	//GL_BindType(GL_TEXTURE_2D, );	//lightmap
+
+	//qglActiveTextureARB(GL_TEXTURE3_ARB);
+	//GL_BindType(GL_TEXTURE_2D, );	//deluxmap
+
+	if (qglGetError())
+		Con_Printf("GL Error on shadow lighting\n");
+
+	qglActiveTextureARB(GL_TEXTURE4_ARB);
+	GL_BindType(GL_TEXTURE_2D, tex->gl_texturenumspec);
+
+	qglActiveTextureARB(GL_TEXTURE5_ARB);
+	GL_BindType(GL_TEXTURE_CUBE_MAP_ARB, normalisationCubeMap);
+
+
+	qglClientActiveTextureARB(GL_TEXTURE0_ARB);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
+
+	qglClientActiveTextureARB(GL_TEXTURE1_ARB);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
+
+	qglClientActiveTextureARB(GL_TEXTURE2_ARB);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->ncm);
+
+	if (qglGetError())
+		Con_Printf("GL Error on shadow lighting\n");
+
+	vi = -1;
+	for (; s ; s=s->texturechain)
+	{
+		if (vi != s->lightmaptexturenum)
+		{
+			PPL_FlushArrays();
+			vi = s->lightmaptexturenum;
+
+			qglActiveTextureARB(GL_TEXTURE3_ARB);
+			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;
+			}
+			qglActiveTextureARB(GL_TEXTURE2_ARB);
+			GL_BindType(GL_TEXTURE_2D, 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;
+			}
+		}
+		PPL_GenerateArraysBlinnCubeMap(s);
+	}
+	PPL_FlushArrays();
+
+	if (qglGetError())
+		Con_Printf("GL Error on shadow lighting\n");
+
+	glDisable(GL_FRAGMENT_PROGRAM_ARB);
+
+
+	qglClientActiveTextureARB(GL_TEXTURE1_ARB);
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+	qglClientActiveTextureARB(GL_TEXTURE2_ARB);
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+	qglClientActiveTextureARB(GL_TEXTURE0_ARB);
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+	qglActiveTextureARB(GL_TEXTURE0_ARB);
+
+	if (qglGetError())
+		Con_Printf("GL Error on shadow lighting\n");
+}
+
+#define GL_MODULATE_ADD_ATI                   0x8744
+//we actually only use 7, so nur.
+static void PPL_BaseChain_Specular_8TMU(msurface_t *first, texture_t *tex)
+{	//uses blinn shading instead of phong. This way we don't have to generate lots of complex stuff.
+	int vi;
+	glRect_t    *theRect;
+	msurface_t *s;
+
+	float fourhalffloats[4] = {0.5,0.5,0.5,0.5};
+
+	glColorMask(1,1,1,1);
+
+	PPL_EnableVertexArrays();
+
+/* lets do things in parallel.
+normalmap -> rgb
+rgb . halfvector -> alpha
+alpha*alpha -> alpha			normalmap -> rgb
+(alpha*alpha -> alpha)			rgb . luxmap -> rgb
+alpha*gloss -> alpha			rgb * diffuse -> rgb
+rgb + alpha -> rgb
+rgb * lightmap -> rgb
+
+  //note: crossbar could use third input texture removing the first tmu.
+  //note: could combine3 combine the last two?
+  //note: 5 tmus: not enough to work on a gf4.
+*/
+	glDisable(GL_BLEND);
+
+//0 takes a normalmap
+	qglActiveTextureARB(GL_TEXTURE0_ARB);
+	GL_BindType(GL_TEXTURE_2D, tex->gl_texturenumbumpmap);
+	qglClientActiveTextureARB(GL_TEXTURE0_ARB);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+//1 takes a cubemap for specular half-vectors.
+	qglActiveTextureARB(GL_TEXTURE1_ARB);
+	GL_BindType(GL_TEXTURE_CUBE_MAP_ARB, normalisationCubeMap);
+	glDisable(GL_TEXTURE_2D);
+	glEnable(GL_TEXTURE_CUBE_MAP_ARB);
+	qglClientActiveTextureARB(GL_TEXTURE1_ARB);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->ncm);
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 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_RGBA_ARB);	//writes alpha
+//2 takes a normalmap
+	qglActiveTextureARB(GL_TEXTURE2_ARB);
+	glEnable(GL_TEXTURE_2D);
+	GL_BindType(GL_TEXTURE_2D, tex->gl_texturenumbumpmap);
+	qglClientActiveTextureARB(GL_TEXTURE2_ARB);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
+	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
+
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB);	//square the alpha
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);
+//3 takes the deluxmap
+	qglActiveTextureARB(GL_TEXTURE3_ARB);
+	glEnable(GL_TEXTURE_2D);	//bind with the surface texturenum
+	qglClientActiveTextureARB(GL_TEXTURE3_ARB);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 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);
+
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB);	//square the alpha again.
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);
+//4 multiplies with diffuse
+	qglActiveTextureARB(GL_TEXTURE4_ARB);
+	glEnable(GL_TEXTURE_2D);
+	GL_BindType(GL_TEXTURE_2D, tex->gl_texturenum);
+	qglClientActiveTextureARB(GL_TEXTURE4_ARB);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
+
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
+	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
+
+	//nothing to the alpha (square yet again?)
+//	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB);
+//	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
+
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB);	//square the alpha again.
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);
+
+//5 halves rgb and alpha (so that adding will not clamp)
+	qglActiveTextureARB(GL_TEXTURE5_ARB);
+	glEnable(GL_TEXTURE_2D);
+	GL_BindType(GL_TEXTURE_2D, tex->gl_texturenum);	//need to bind something.
+	qglClientActiveTextureARB(GL_TEXTURE5_ARB);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
+/*	glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, fourhalffloats);
+
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
+	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
+*/
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_ALPHA);
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_CONSTANT_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_ALPHA);
+	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);
+
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
+	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
+
+//6 adds rgb and alpha, using the glossmap...
+	qglActiveTextureARB(GL_TEXTURE6_ARB);
+	glEnable(GL_TEXTURE_2D);
+	GL_BindType(GL_TEXTURE_2D, tex->gl_texturenumspec);
+	qglClientActiveTextureARB(GL_TEXTURE6_ARB);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
+
+	//broken diffuse + specular
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_ALPHA);
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);
+	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_COLOR);
+	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB,  GL_MODULATE_ADD_ATI);
+	//perfect diffuse
+/*	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
+	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB,  GL_REPLACE);
+*/
+	//perfect specular
+/*	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_ALPHA);
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
+	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
+	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB,  GL_MODULATE);
+*/
+//7 multiplies by lightmap
+	qglActiveTextureARB(GL_TEXTURE7_ARB);
+	glEnable(GL_TEXTURE_2D);	//bind with the surface texturenum
+	qglClientActiveTextureARB(GL_TEXTURE7_ARB);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
+
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
+	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_ONE_MINUS_SRC_COLOR);
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
+	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
+
+	vi = -1;
+	for (s = first; s ; s=s->texturechain)
+	{
+		if (vi != s->lightmaptexturenum)
+		{
+			PPL_FlushArrays();
+			vi = s->lightmaptexturenum;
+
+			qglActiveTextureARB(GL_TEXTURE3_ARB);
+			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;
+			}
+			qglActiveTextureARB(GL_TEXTURE7_ARB);
+			GL_BindType(GL_TEXTURE_2D, 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;
+			}
+		}
+		PPL_GenerateArraysBlinnCubeMap(s);
+	}
+	PPL_FlushArrays();
+
+	glColorMask(1,1,1,0);
+
+	for (vi = 7; vi > 0; vi--)
+	{
+		qglActiveTextureARB(GL_TEXTURE0_ARB+vi);
+		glDisable(GL_TEXTURE_2D);
+		qglClientActiveTextureARB(GL_TEXTURE0_ARB+vi);
+		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+	}
+	glDisable(GL_TEXTURE_CUBE_MAP_ARB);
+	
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+	qglActiveTextureARB(GL_TEXTURE0_ARB);
+	qglClientActiveTextureARB(GL_TEXTURE0_ARB);
+}
+#endif
+
+static void PPL_BaseTextureChain(msurface_t *first)
+{
+	extern int		*deluxmap_textures;
+	extern cvar_t gl_bump, gl_specular;
+	texture_t	*t;
+
+
+	glEnable(GL_TEXTURE_2D);
+
+	t = GLR_TextureAnimation (first->texinfo->texture);
+
+	if (first->flags & SURF_DRAWTURB)
+	{
+		GL_DisableMultitexture();
+		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+		GL_Bind (t->gl_texturenum);
+		for (; first ; first=first->texturechain)
+			EmitWaterPolys (first, currententity->alpha);
+
+		glDisable(GL_BLEND);
+		glColor4f(1,1,1, 1);
+
+		t->texturechain = NULL;	//no lighting effects. (good job these don't animate eh?)
+		return;
+	}
+/*	else if (s->lightmaptexturenum < 0)	//no lightmap
+	{
+		PPL_BaseChain_NoLightmap(first, t);
+	}*/
+	else if (gl_mtexarbable < 2)
+	{	//multitexture isn't supported.
+		PPL_BaseChain_NoBump_1TMU(first, t);
+	}
 	else
 	{
 		if (gl_bump.value && currentmodel->deluxdata && t->gl_texturenumbumpmap)
 		{
-PPL_EnableVertexArrays();
-			qglActiveTextureARB(GL_TEXTURE0_ARB);
-
-			//Bind normal map to texture unit 0
-			GL_BindType(GL_TEXTURE_2D, t->gl_texturenumbumpmap);
-			glEnable(GL_TEXTURE_2D);
-			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
-			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
-			glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
-
-			qglClientActiveTextureARB(GL_TEXTURE0_ARB);
-			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-			glTexCoordPointer(2, GL_FLOAT, 7*sizeof(float), varray_v->stw);
-
-			qglActiveTextureARB(GL_TEXTURE1_ARB);	//the deluxmap
-			glEnable(GL_TEXTURE_2D);
-			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 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);
-
-			qglClientActiveTextureARB(GL_TEXTURE1_ARB);
-			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-			glTexCoordPointer(2, GL_FLOAT, 7*sizeof(float), varray_v->stl);
-
-//we now have normalmap.deluxmap on the screen.
-			if (gl_mtexarbable>=4)	//go the whole hog. bumpmapping in one pass.
+			if (gl_mtexarbable>=4)
 			{
-				//continue going to give (normalmap.deluxemap)*texture*lightmap.
-				qglActiveTextureARB(GL_TEXTURE2_ARB);
-				glEnable(GL_TEXTURE_2D);
-				glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-				GL_Bind (t->gl_texturenum);
-
-				qglClientActiveTextureARB(GL_TEXTURE2_ARB);
-				glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-				glTexCoordPointer(2, GL_FLOAT, 7*sizeof(float), varray_v->stw);
-
-				qglActiveTextureARB(GL_TEXTURE3_ARB);
-				glEnable(GL_TEXTURE_2D);
-				glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
-
-				qglClientActiveTextureARB(GL_TEXTURE3_ARB);
-				glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-				glTexCoordPointer(2, GL_FLOAT, 7*sizeof(float), varray_v->stl);
-
-				vi = -1;
-				for (; s ; s=s->texturechain)
+				if (t->gl_texturenumspec && gl_specular.value)
 				{
-					if (vi != s->lightmaptexturenum)
-					{
-						PPL_FlushArrays();
-						vi = s->lightmaptexturenum;
-
-						qglActiveTextureARB(GL_TEXTURE1_ARB);
-						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;
-						}
-						qglActiveTextureARB(GL_TEXTURE3_ARB);
-						GL_BindType(GL_TEXTURE_2D, 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;
-						}
-					}
-
-					PPL_GenerateArrays(s);
-					PPL_FlushArrays();
+					if (ppl_specular_fragmentprogram)
+						PPL_BaseChain_Specular_FP(first, t);
+					else if (gl_mtexarbable>=8)
+						PPL_BaseChain_Specular_8TMU(first, t);
+					else
+						PPL_BaseChain_Bump_4TMU(first, t);	//can't do specular.
 				}
-
-				qglActiveTextureARB(GL_TEXTURE3_ARB);
-				glDisable(GL_TEXTURE_2D);
-				qglActiveTextureARB(GL_TEXTURE2_ARB);
-				glDisable(GL_TEXTURE_2D);
-				qglActiveTextureARB(GL_TEXTURE1_ARB);
-				glDisable(GL_TEXTURE_2D);
-				qglActiveTextureARB(GL_TEXTURE0_ARB);	//the deluxmap
-
-				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-				return;
+				else
+					PPL_BaseChain_Bump_4TMU(first, t);
 			}
-
-			glDisable(GL_BLEND);
-			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-			for (; 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);
-			qglActiveTextureARB(GL_TEXTURE0_ARB);
-
-			glBlendFunc(GL_DST_COLOR, GL_ZERO);	//tell the texture + lightmap to do current*tex*light (where current is normalmap.deluxemap)
-			glEnable(GL_BLEND);
-
-			s = first;
-
-			GL_SelectTexture(mtexid0);
-			GL_Bind(t->gl_texturenum);
-			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-			GL_EnableMultitexture();
-			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
+			else
+				PPL_BaseChain_Bump_2TMU(first, t);
 		}
 		else
 		{
-PPL_EnableVertexArrays();
-			// Binds world to texture env 0
-			GL_Bind (t->gl_texturenum);
-			if (t->alphaed)
-			{
-				glEnable(GL_BLEND);
-				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-			}
-			else
-			{
-				glDisable(GL_BLEND);
-				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-			}
-
-			qglClientActiveTextureARB(GL_TEXTURE0_ARB);
-			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-			glTexCoordPointer(2, GL_FLOAT, 7*sizeof(float), varray_v->stw);
-
-			qglClientActiveTextureARB(GL_TEXTURE1_ARB);
-			qglActiveTextureARB(GL_TEXTURE1_ARB);
-			glEnable(GL_TEXTURE_2D);
-			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
-			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-			glTexCoordPointer(2, GL_FLOAT, 7*sizeof(float), varray_v->stl);
+			PPL_BaseChain_NoBump_2TMU(first, t);
 		}
-
-		vi = -1;
-		for (; s; s=s->texturechain)
-		{
-			if (vi != s->lightmaptexturenum)
-			{
-				PPL_FlushArrays();
-
-				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;
-				}
-			}
-			PPL_GenerateArrays(s);
-		}
-		PPL_FlushArrays();
-
-		qglActiveTextureARB(GL_TEXTURE1_ARB);
-		glDisable(GL_TEXTURE_2D);
-
-		qglActiveTextureARB(GL_TEXTURE0_ARB);
-		qglClientActiveTextureARB(GL_TEXTURE0_ARB);
-
-		glDisableClientState(GL_VERTEX_ARRAY);
-		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 	}
 }
-#endif
+
 
 static void PPL_FullBrightTextureChain(msurface_t *first)
 {
-	glpoly_t	*p;
-	float		*v;
 	texture_t	*t;
 	msurface_t	*s;
-	int i;
 
 	t = GLR_TextureAnimation (first->texinfo->texture);
 
@@ -804,41 +1298,29 @@ static void PPL_FullBrightTextureChain(msurface_t *first)
 		GL_Bind(detailtexture);
 		glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
 
+		PPL_EnableVertexArrays();
+		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+		glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
 		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();
-			}
+			PPL_GenerateArrays(s);
 		}
+		PPL_FlushArrays();
 	}
 
 	if (t->gl_texturenumfb && r_fb_bmodels.value && cls.allow_luma)
 	{
 		GL_Bind(t->gl_texturenumfb);
-		glBlendFunc(GL_DST_COLOR, GL_ONE);
+		glBlendFunc(GL_ONE, GL_ONE);
 
+		PPL_EnableVertexArrays();
+		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+		glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
 		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[3], v[4]);
-					glVertex3fv (v);
-				}
-				glEnd();
-			}
+			PPL_GenerateArrays(s);
 		}
+		PPL_FlushArrays();
 	}
 }
 
@@ -1033,6 +1515,100 @@ void PPL_BaseEntTextures(void)
 	currentmodel = cl.worldmodel;
 }
 
+static void PPL_GenerateLightArrays(msurface_t *surf, vec3_t relativelightorigin, dlight_t *light)
+{
+	glpoly_t *p;
+	int vi;
+	int vc_s;
+	float *v;
+
+	vec3_t lightdir;
+	float dist;
+
+	for (p = surf->polys; p; p=p->next)
+	{
+		shadowlightfaces++;
+
+		if (varray_ic + p->numverts*3>MAXARRAYVERTS)
+		{
+			PPL_FlushArrays();
+		}
+
+		vc_s = varray_vc;
+		v = p->verts[0];
+
+		varray_v[varray_vc].xyz[0] = v[0];
+		varray_v[varray_vc].xyz[1] = v[1];
+		varray_v[varray_vc].xyz[2] = v[2];
+		varray_v[varray_vc].stw[0] = v[3];
+		varray_v[varray_vc].stw[1] = v[4];
+		lightdir[0] = relativelightorigin[0] - v[0];
+		lightdir[1] = relativelightorigin[1] - v[1];
+		lightdir[2] = relativelightorigin[2] - v[2];
+		dist = 1-(sqrt(	(lightdir[0])*(lightdir[0]) +
+						(lightdir[1])*(lightdir[1]) +
+						(lightdir[2])*(lightdir[2])) / light->radius);
+		VectorNormalize(lightdir);
+		varray_v[varray_vc].stl[0] = light->color[0]*dist;
+		varray_v[varray_vc].stl[1] = light->color[1]*dist;
+		varray_v[varray_vc].stl[2] = light->color[2]*dist;
+		varray_v[varray_vc].ncm[0] = DotProduct(lightdir, surf->texinfo->vecs[0]);
+		varray_v[varray_vc].ncm[1] = -DotProduct(lightdir, surf->texinfo->vecs[1]);
+		varray_v[varray_vc].ncm[2] = DotProduct(lightdir, surf->normal);
+
+
+		varray_vc++;
+		v += VERTEXSIZE;
+		varray_v[varray_vc].xyz[0] = v[0];
+		varray_v[varray_vc].xyz[1] = v[1];
+		varray_v[varray_vc].xyz[2] = v[2];
+		varray_v[varray_vc].stw[0] = v[3];
+		varray_v[varray_vc].stw[1] = v[4];
+		lightdir[0] = relativelightorigin[0] - v[0];
+		lightdir[1] = relativelightorigin[1] - v[1];
+		lightdir[2] = relativelightorigin[2] - v[2];
+		dist = 1-(sqrt(	(lightdir[0])*(lightdir[0]) +
+						(lightdir[1])*(lightdir[1]) +
+						(lightdir[2])*(lightdir[2])) / light->radius);
+		VectorNormalize(lightdir);
+		varray_v[varray_vc].stl[0] = light->color[0]*dist;
+		varray_v[varray_vc].stl[1] = light->color[1]*dist;
+		varray_v[varray_vc].stl[2] = light->color[2]*dist;
+		varray_v[varray_vc].ncm[0] = DotProduct(lightdir, surf->texinfo->vecs[0]);
+		varray_v[varray_vc].ncm[1] = -DotProduct(lightdir, surf->texinfo->vecs[1]);
+		varray_v[varray_vc].ncm[2] = DotProduct(lightdir, surf->normal);
+		varray_vc++;
+		v += VERTEXSIZE;
+		for (vi=2 ; vi<p->numverts ; vi++, v+= VERTEXSIZE)
+		{
+			varray_i[varray_ic] = vc_s;
+			varray_i[varray_ic+1] = varray_vc-1;
+			varray_i[varray_ic+2] = varray_vc;
+			varray_ic+=3;
+
+			varray_v[varray_vc].xyz[0] = v[0];
+			varray_v[varray_vc].xyz[1] = v[1];
+			varray_v[varray_vc].xyz[2] = v[2];
+			varray_v[varray_vc].stw[0] = v[3];
+			varray_v[varray_vc].stw[1] = v[4];
+			lightdir[0] = relativelightorigin[0] - v[0];
+			lightdir[1] = relativelightorigin[1] - v[1];
+			lightdir[2] = relativelightorigin[2] - v[2];
+			dist = 1-(sqrt(	(lightdir[0])*(lightdir[0]) +
+							(lightdir[1])*(lightdir[1]) +
+							(lightdir[2])*(lightdir[2])) / light->radius);
+			VectorNormalize(lightdir);
+			varray_v[varray_vc].stl[0] = light->color[0]*dist;
+			varray_v[varray_vc].stl[1] = light->color[1]*dist;
+			varray_v[varray_vc].stl[2] = light->color[2]*dist;
+			varray_v[varray_vc].ncm[0] = DotProduct(lightdir, surf->texinfo->vecs[0]);
+			varray_v[varray_vc].ncm[1] = -DotProduct(lightdir, surf->texinfo->vecs[1]);
+			varray_v[varray_vc].ncm[2] = DotProduct(lightdir, surf->normal);
+			varray_vc++;
+		}
+	}
+}
+
 void PPL_LightTextures(model_t *model, vec3_t modelorigin, dlight_t *light)
 {
 	int		i;
@@ -1040,206 +1616,124 @@ void PPL_LightTextures(model_t *model, vec3_t modelorigin, dlight_t *light)
 	texture_t	*t;
 	extern cvar_t gl_bump;
 
-	int vi;
-	glpoly_t *p;
-	float *v;
-	float dist;
+	vec3_t relativelightorigin;
 
-	if (gl_bump.value)
+	PPL_EnableVertexArrays();
+
+	VectorSubtract(light->origin, modelorigin, relativelightorigin);
+	glShadeModel(GL_SMOOTH);
+	for (i=0 ; i<model->numtextures ; i++)
 	{
-		vec3_t relativelightorigin;
+		t = model->textures[i];
+		if (!t)
+			continue;
+		s = t->texturechain;
+		if (!s)
+			continue;
+
 
-		VectorSubtract(light->origin, modelorigin, relativelightorigin);
-		glShadeModel(GL_SMOOTH);
-		for (i=0 ; i<model->numtextures ; i++)
 		{
-			t = model->textures[i];
-			if (!t)
-				continue;
-			s = t->texturechain;
-			if (!s)
-				continue;
+			extern int normalisationCubeMap;
+
+			t = GLR_TextureAnimation (t);
 
 
+			glEnableClientState(GL_COLOR_ARRAY);
+			glColorPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
+			if (t->gl_texturenumbumpmap && gl_mtexarbable>2)
 			{
-				extern int normalisationCubeMap;
-				vec3_t lightdir;
+				qglActiveTextureARB(GL_TEXTURE0_ARB);
+				GL_BindType(GL_TEXTURE_2D, t->gl_texturenumbumpmap);
+				glEnable(GL_TEXTURE_2D);
+				//Set up texture environment to do (tex0 dot tex1)*color
+				glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);	//make texture normalmap available.
+				glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
+				glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
 
-				t = GLR_TextureAnimation (t);
+				qglClientActiveTextureARB(GL_TEXTURE0_ARB);
+				glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+				glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
+
+				qglActiveTextureARB(GL_TEXTURE1_ARB);
+				GL_BindType(GL_TEXTURE_CUBE_MAP_ARB, normalisationCubeMap);
+				glEnable(GL_TEXTURE_CUBE_MAP_ARB);
+				glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);	//normalisation cubemap * normalmap
+				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);
+
+				qglClientActiveTextureARB(GL_TEXTURE1_ARB);
+				glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+				glTexCoordPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->ncm);
+
+				qglActiveTextureARB(GL_TEXTURE2_ARB);
+				GL_BindType(GL_TEXTURE_2D, t->gl_texturenumbumpmap);
+				glEnable(GL_TEXTURE_2D);
+				glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);	//bumps * color		(the attenuation)
+				glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB); //(doesn't actually use the bound texture)
+				glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
+				glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
+				glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
+			}
+			else
+			{
+				glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+				glDisable(GL_TEXTURE_2D);
+				qglActiveTextureARB(GL_TEXTURE1_ARB);
+				glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+				glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+				glDisable(GL_TEXTURE_CUBE_MAP_ARB);
+				qglActiveTextureARB(GL_TEXTURE0_ARB);
+
+				qglClientActiveTextureARB(GL_TEXTURE0_ARB);
+				glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+				glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
+			}
+
+			for (; s; s=s->texturechain)
+			{
+
+				if (s->shadowframe != r_shadowframe)
+					continue;
+
+			/*	if (fabs(s->center[0] - lightorg[0]) > lightradius+s->radius ||
+					fabs(s->center[1] - lightorg[1]) > lightradius+s->radius ||
+					fabs(s->center[2] - lightorg[2]) > lightradius+s->radius)
+					continue;*/
 
 
-				if (t->gl_texturenumbumpmap)
-				{
-					qglActiveTextureARB(GL_TEXTURE0_ARB);
-					GL_BindType(GL_TEXTURE_2D, t->gl_texturenumbumpmap);
-					glEnable(GL_TEXTURE_2D);
-					//Set up texture environment to do (tex0 dot tex1)*color
-					glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);	//make texture normalmap available.
-					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_BindType(GL_TEXTURE_CUBE_MAP_ARB, normalisationCubeMap);
-					glEnable(GL_TEXTURE_CUBE_MAP_ARB);
-					glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);	//normalisation cubemap * normalmap
-					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);
-
-					qglActiveTextureARB(GL_TEXTURE2_ARB);
-					GL_BindType(GL_TEXTURE_2D, t->gl_texturenumbumpmap);
-					glEnable(GL_TEXTURE_2D);
-					glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);	//bumps * color		(the attenuation)
-					glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB); //(doesn't actually use the bound texture)
-					glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
-					glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
-					glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
+				if (s->flags & SURF_PLANEBACK)
+				{//inverted normal.
+					if (-DotProduct(s->plane->normal, relativelightorigin)+s->plane->dist > lightradius)
+						continue;
 				}
 				else
 				{
-					glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-					glDisable(GL_TEXTURE_2D);
-					qglActiveTextureARB(GL_TEXTURE1_ARB);
-					glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-					glDisable(GL_TEXTURE_CUBE_MAP_ARB);
-					qglActiveTextureARB(GL_TEXTURE0_ARB);
-				}
-
-				for (; s; s=s->texturechain)
-				{
-
-				/*	if (fabs(s->center[0] - lightorg[0]) > lightradius+s->radius ||
-						fabs(s->center[1] - lightorg[1]) > lightradius+s->radius ||
-						fabs(s->center[2] - lightorg[2]) > lightradius+s->radius)
-						continue;*/
-
-
-					if (s->flags & SURF_PLANEBACK)
-					{//inverted normal.
-						if (-DotProduct(s->plane->normal, relativelightorigin)+s->plane->dist > lightradius)
-							continue;
-					}
-					else
-					{
-						if (DotProduct(s->plane->normal, relativelightorigin)-s->plane->dist > lightradius)
-							continue;
-					}
-					for (p = s->polys; p; p=p->next)
-					{
-						shadowlightfaces++;
-						glBegin(GL_POLYGON);
-						v = p->verts[0];
-						for (vi=0 ; vi<p->numverts ; vi++, v+= VERTEXSIZE)
-						{
-							lightdir[0] = relativelightorigin[0] - v[0];
-							lightdir[1] = relativelightorigin[1] - v[1];
-							lightdir[2] = relativelightorigin[2] - v[2];
-
-							dist = 1-(sqrt(	(lightdir[0])*(lightdir[0]) +
-											(lightdir[1])*(lightdir[1]) +
-											(lightdir[2])*(lightdir[2])) / light->radius);
-
-							VectorNormalize(lightdir);
-
-							glColor3f(light->color[0]*dist, light->color[1]*dist, light->color[2]*dist);
-							qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, v[3], v[4]);
-							qglMultiTexCoord3fARB(GL_TEXTURE1_ARB, DotProduct(lightdir, s->texinfo->vecs[0]), -DotProduct(lightdir, s->texinfo->vecs[1]), DotProduct(lightdir, s->normal));
-							glVertex3fv (v);
-						}
-						glEnd ();
-					}
-				}
-			}
-		}
-
-		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-		glDisable(GL_TEXTURE_2D);
-		qglActiveTextureARB(GL_TEXTURE1_ARB);
-		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-		glDisable(GL_TEXTURE_CUBE_MAP_ARB);
-		qglActiveTextureARB(GL_TEXTURE0_ARB);
-	}
-	else
-	{
-		vec3_t relativelightorigin;
-		vec3_t lightdir;
-
-		glDisable(GL_TEXTURE_2D);
-//		glColor4f(1,1,1,1);
-
-		VectorSubtract(light->origin, modelorigin, relativelightorigin);
-
-		glShadeModel(GL_SMOOTH);
-		for (i=0 ; i<model->numtextures ; i++)
-		{
-			t = model->textures[i];
-			if (!t)
-				continue;
-			s = t->texturechain;
-			if (!s)
-				continue;
-
-
-
-			{
-//				t = GLR_TextureAnimation (t);
-
-
-//				GL_Bind (t->gl_texturenum);
-				for (; s; s=s->texturechain)
-				{
-					if (s->shadowframe != r_shadowframe)
+					if (DotProduct(s->plane->normal, relativelightorigin)-s->plane->dist > lightradius)
 						continue;
-
-					if (fabs(s->center[0] - lightorg[0]) > lightradius+s->radius ||
-						fabs(s->center[1] - lightorg[1]) > lightradius+s->radius ||
-						fabs(s->center[2] - lightorg[2]) > lightradius+s->radius)
-						continue;
-
-
-					if (s->flags & SURF_PLANEBACK)
-					{//inverted normal.
-						if (DotProduct(s->plane->normal, lightorg)-s->plane->dist <= -lightradius)
-							continue;
-					}
-					else
-					{
-						if (DotProduct(s->plane->normal, lightorg)-s->plane->dist >= lightradius)
-							continue;
-					}
-
-					for (p = s->polys; p; p=p->next)
-					{
-						shadowlightfaces++;
-						glBegin(GL_POLYGON);
-						v = p->verts[0];
-						for (vi=0 ; vi<p->numverts ; vi++, v+= VERTEXSIZE)
-						{
-							lightdir[0] = relativelightorigin[0] - v[0];
-							lightdir[1] = relativelightorigin[1] - v[1];
-							lightdir[2] = relativelightorigin[2] - v[2];
-
-							dist = 1-(sqrt(	(lightdir[0])*(lightdir[0]) +
-											(lightdir[1])*(lightdir[1]) +
-											(lightdir[2])*(lightdir[2])) / light->radius);
-
-							VectorNormalize(lightdir);
-
-							glColor3f(light->color[0]*dist, light->color[1]*dist, light->color[2]*dist);
-//							glTexCoord2f (v[3], v[4]);
-							glVertex3fv (v);
-						}
-						glEnd ();
-					}
 				}
+				PPL_GenerateLightArrays(s, relativelightorigin, light);
 			}
+			PPL_FlushArrays();
 		}
 	}
+
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+	glDisable(GL_TEXTURE_2D);
+	qglClientActiveTextureARB(GL_TEXTURE1_ARB);
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+	qglClientActiveTextureARB(GL_TEXTURE0_ARB);
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+	qglActiveTextureARB(GL_TEXTURE1_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+	glDisable(GL_TEXTURE_CUBE_MAP_ARB);
+	qglActiveTextureARB(GL_TEXTURE0_ARB);
+	glDisable(GL_TEXTURE_2D);
+
 }
+
 void PPL_LightBModelTextures(entity_t *e, dlight_t *light)
 {
-	glpoly_t *p;
-
 	int i;
 	model_t *model = e->model;
 
@@ -1247,17 +1741,12 @@ void PPL_LightBModelTextures(entity_t *e, dlight_t *light)
 	texture_t	*t;
 	extern cvar_t gl_bump;
 
-	int vi;
-	float *v;
-	float dist;
+			vec3_t relativelightorigin;
 
 	glPushMatrix();
 	R_RotateForEntity(e);
 	glColor4f(1, 1, 1, 1);
 
-	if (gl_bump.value)
-	{
-		vec3_t relativelightorigin;
 
 		VectorSubtract(light->origin, e->origin, relativelightorigin);
 		glShadeModel(GL_SMOOTH);
@@ -1266,162 +1755,96 @@ void PPL_LightBModelTextures(entity_t *e, dlight_t *light)
 		{
 			t = GLR_TextureAnimation (s->texinfo->texture);
 
+			glEnableClientState(GL_COLOR_ARRAY);
+			glColorPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
+			if (t->gl_texturenumbumpmap && gl_mtexarbable>2)
 			{
-				extern int normalisationCubeMap;
-				vec3_t lightdir;
+				qglActiveTextureARB(GL_TEXTURE0_ARB);
+				GL_BindType(GL_TEXTURE_2D, t->gl_texturenumbumpmap);
+				glEnable(GL_TEXTURE_2D);
+				//Set up texture environment to do (tex0 dot tex1)*color
+				glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);	//make texture normalmap available.
+				glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
+				glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
 
-				if (t->gl_texturenumbumpmap)
-				{
-					qglActiveTextureARB(GL_TEXTURE0_ARB);
-					GL_BindType(GL_TEXTURE_2D, t->gl_texturenumbumpmap);
-					glEnable(GL_TEXTURE_2D);
-					//Set up texture environment to do (tex0 dot tex1)*color
-					glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);	//make texture normalmap available.
-					glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
-					glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
+				qglClientActiveTextureARB(GL_TEXTURE0_ARB);
+				glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+				glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
 
-					qglActiveTextureARB(GL_TEXTURE1_ARB);
-					GL_BindType(GL_TEXTURE_CUBE_MAP_ARB, normalisationCubeMap);
-					glEnable(GL_TEXTURE_CUBE_MAP_ARB);
-					glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);	//normalisation cubemap * normalmap
-					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);
+				qglActiveTextureARB(GL_TEXTURE1_ARB);
+				GL_BindType(GL_TEXTURE_CUBE_MAP_ARB, normalisationCubeMap);
+				glEnable(GL_TEXTURE_CUBE_MAP_ARB);
+				glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);	//normalisation cubemap * normalmap
+				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);
 
-					qglActiveTextureARB(GL_TEXTURE2_ARB);
-					GL_BindType(GL_TEXTURE_2D, t->gl_texturenumbumpmap);
-					glEnable(GL_TEXTURE_2D);
-					glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);	//bumps * color
-					glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB); //(doesn't actually use the bound texture)
-					glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
-					glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
-					glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
+				qglClientActiveTextureARB(GL_TEXTURE1_ARB);
+				glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+				glTexCoordPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->ncm);
+
+				qglActiveTextureARB(GL_TEXTURE2_ARB);
+				GL_BindType(GL_TEXTURE_2D, t->gl_texturenumbumpmap);
+				glEnable(GL_TEXTURE_2D);
+				glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);	//bumps * color		(the attenuation)
+				glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB); //(doesn't actually use the bound texture)
+				glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
+				glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
+				glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
+			}
+			else
+			{
+				glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+				glDisable(GL_TEXTURE_2D);
+				qglActiveTextureARB(GL_TEXTURE1_ARB);
+				glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+				glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+				glDisable(GL_TEXTURE_CUBE_MAP_ARB);
+				qglActiveTextureARB(GL_TEXTURE0_ARB);
+
+				qglClientActiveTextureARB(GL_TEXTURE0_ARB);
+				glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+				glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
+			}
+
+//			for (; s; s=s->texturechain)
+			{
+
+				if (s->shadowframe != r_shadowframe)
+					continue;
+
+			/*	if (fabs(s->center[0] - lightorg[0]) > lightradius+s->radius ||
+					fabs(s->center[1] - lightorg[1]) > lightradius+s->radius ||
+					fabs(s->center[2] - lightorg[2]) > lightradius+s->radius)
+					continue;*/
+
+
+				if (s->flags & SURF_PLANEBACK)
+				{//inverted normal.
+					if (-DotProduct(s->plane->normal, relativelightorigin)+s->plane->dist > lightradius)
+						continue;
 				}
 				else
 				{
-					glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-					glDisable(GL_TEXTURE_2D);
-					qglActiveTextureARB(GL_TEXTURE1_ARB);
-					glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-					glDisable(GL_TEXTURE_CUBE_MAP_ARB);
-					qglActiveTextureARB(GL_TEXTURE0_ARB);
-					glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-				}
-
-				{
-/*
-					if (fabs(s->center[0] - lightorg[0]) > lightradius+s->radius ||
-						fabs(s->center[1] - lightorg[1]) > lightradius+s->radius ||
-						fabs(s->center[2] - lightorg[2]) > lightradius+s->radius)
+					if (DotProduct(s->plane->normal, relativelightorigin)-s->plane->dist > lightradius)
 						continue;
-*/
-
-					if (s->flags & SURF_PLANEBACK)
-					{//inverted normal.
-						if (-DotProduct(s->plane->normal, relativelightorigin)-s->plane->dist >= lightradius)
-							continue;
-					}
-					else
-					{
-						if (DotProduct(s->plane->normal, relativelightorigin)-s->plane->dist >= lightradius)
-							continue;
-					}
-					for (p = s->polys; p; p=p->next)
-					{
-						glBegin(GL_POLYGON);
-						v = p->verts[0];
-						for (vi=0 ; vi<p->numverts ; vi++, v+= VERTEXSIZE)
-						{
-							lightdir[0] = relativelightorigin[0] - v[0];
-							lightdir[1] = relativelightorigin[1] - v[1];
-							lightdir[2] = relativelightorigin[2] - v[2];
-
-							dist = 1-(sqrt(	(lightdir[0])*(lightdir[0]) +
-											(lightdir[1])*(lightdir[1]) +
-											(lightdir[2])*(lightdir[2])) / light->radius);
-
-							VectorNormalize(lightdir);
-
-							glColor3f(light->color[0]*dist, light->color[1]*dist, light->color[2]*dist);
-							qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, v[3], v[4]);
-							qglMultiTexCoord3fARB(GL_TEXTURE1_ARB, DotProduct(lightdir, s->texinfo->vecs[0]), -DotProduct(lightdir, s->texinfo->vecs[1]), DotProduct(lightdir, s->normal));
-							glVertex3fv (v);
-						}
-						glEnd ();
-					}
 				}
+				PPL_GenerateLightArrays(s, relativelightorigin, light);
 			}
+			PPL_FlushArrays();
 		}
 
-		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-		glDisable(GL_TEXTURE_2D);
-		qglActiveTextureARB(GL_TEXTURE1_ARB);
-		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-		glDisable(GL_TEXTURE_CUBE_MAP_ARB);
-		qglActiveTextureARB(GL_TEXTURE0_ARB);
-		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-	}
-	else
-	{
-		vec3_t relativelightorigin;
-		vec3_t lightdir;
-
-		glDisable(GL_TEXTURE_2D);
-
-		VectorSubtract(light->origin, e->origin, relativelightorigin);
-
-		glShadeModel(GL_SMOOTH);
-		for (s = model->surfaces+model->firstmodelsurface,i = 0; i < model->nummodelsurfaces; i++, s++)
-		{
-			{
-				{
-
-				/*	if (fabs(s->center[0] - lightorg[0]) > lightradius+s->radius ||
-						fabs(s->center[1] - lightorg[1]) > lightradius+s->radius ||
-						fabs(s->center[2] - lightorg[2]) > lightradius+s->radius)
-						continue;*/
-
-
-					if (s->flags & SURF_PLANEBACK)
-					{//inverted normal.
-						if (DotProduct(s->plane->normal, lightorg)-s->plane->dist <= -lightradius)
-							continue;
-					}
-					else
-					{
-						if (DotProduct(s->plane->normal, lightorg)-s->plane->dist >= lightradius)
-							continue;
-					}
-
-					for (p = s->polys; p; p=p->next)
-					{
-						glBegin(GL_POLYGON);
-						v = p->verts[0];
-						for (vi=0 ; vi<p->numverts ; vi++, v+= VERTEXSIZE)
-						{
-							lightdir[0] = relativelightorigin[0] - v[0];
-							lightdir[1] = relativelightorigin[1] - v[1];
-							lightdir[2] = relativelightorigin[2] - v[2];
-
-							dist = 1-(sqrt(	(lightdir[0])*(lightdir[0]) +
-											(lightdir[1])*(lightdir[1]) +
-											(lightdir[2])*(lightdir[2])) / light->radius);
-
-							VectorNormalize(lightdir);
-
-							glColor3f(light->color[0]*dist, light->color[1]*dist, light->color[2]*dist);
-//							glTexCoord2f (v[3], v[4]);
-							glVertex3fv (v);
-						}
-						glEnd ();
-					}
-				}
-			}
-		}
-	}
-
-
-
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+	glDisable(GL_TEXTURE_2D);
+	qglClientActiveTextureARB(GL_TEXTURE1_ARB);
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+	qglClientActiveTextureARB(GL_TEXTURE0_ARB);
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+	qglActiveTextureARB(GL_TEXTURE1_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+	glDisable(GL_TEXTURE_CUBE_MAP_ARB);
+	qglActiveTextureARB(GL_TEXTURE0_ARB);
+	glDisable(GL_TEXTURE_2D);
 
 	glPopMatrix();
 }
@@ -1640,10 +2063,7 @@ void PPL_RecursiveWorldNode_r (mnode_t *node)
 	double		dot;
 	glpoly_t *p;
 	int v;
-#ifndef EDGEOPTIMISE
-	float *v2;
-	vec3_t v4;
-#endif
+
 	float *v1;
 	vec3_t v3;
 
@@ -1751,7 +2171,7 @@ void PPL_RecursiveWorldNode_r (mnode_t *node)
 					continue;
 */				
 #define PROJECTION_DISTANCE (float)(lightradius*2)//0x7fffffff
-#ifdef EDGEOPTIMISE
+
 				//build a list of the edges that are to be drawn.
 				for (v = 0; v < surf->numedges; v++)
 				{
@@ -1794,45 +2214,16 @@ void PPL_RecursiveWorldNode_r (mnode_t *node)
 						}
 					}
 				}
-#endif
+
 				for (p = surf->polys; p; p=p->next)
 				{
 					shadowsurfcount++;
 
 					//front face
-					glBegin(GL_POLYGON);
-					for (v = 0; v < p->numverts; v++)
-						glVertex3fv(p->verts[v]);
-					glEnd();
-					
-#ifndef EDGEOPTIMISE
-					for (v = 0; v < p->numverts; v++)
-					{
-					//border
-						v1 = p->verts[v];
-						v2 = p->verts[( v+1 )%p->numverts];
+					glVertexPointer(3, GL_FLOAT, sizeof(GLfloat)*VERTEXSIZE, p->verts[0]);
+					glDrawElements(GL_TRIANGLES, (p->numverts-2)*3, GL_UNSIGNED_INT, varray_i_polytotri);
 
-						//get positions of v3 and v4 based on the light position
-						v3[0] = ( v1[0]-lightorg[0] )*PROJECTION_DISTANCE;
-						v3[1] = ( v1[1]-lightorg[1] )*PROJECTION_DISTANCE;
-						v3[2] = ( v1[2]-lightorg[2] )*PROJECTION_DISTANCE;
-
-						v4[0] = ( v2[0]-lightorg[0] )*PROJECTION_DISTANCE;
-						v4[1] = ( v2[1]-lightorg[1] )*PROJECTION_DISTANCE;
-						v4[2] = ( v2[2]-lightorg[2] )*PROJECTION_DISTANCE;
-
-						//Now draw the quad from the two verts to the projected light
-						//verts
-						glBegin( GL_QUADS );
-							glVertex3f( v1[0]+v3[0], v1[1]+v3[1], v1[2]+v3[2] );
-							glVertex3f( v2[0]+v4[0], v2[1]+v4[1], v2[2]+v4[2] );
-							glVertex3f( v2[0], v2[1], v2[2] );
-							glVertex3f( v1[0], v1[1], v1[2] );
-						glEnd();
-					}
-#endif
-//back
-					
+					//back
 					glBegin(GL_POLYGON);
 					for (v = p->numverts-1; v >=0; v--)
 					{
@@ -1864,10 +2255,7 @@ void PPL_RecursiveWorldNodeQ2_r (mnode_t *node)
 	double		dot;
 	glpoly_t *p;
 	int v;
-#ifndef EDGEOPTIMISE
-	float *v2;
-	vec3_t v4;
-#endif
+
 	float *v1;
 	vec3_t v3;
 
@@ -1961,7 +2349,6 @@ void PPL_RecursiveWorldNodeQ2_r (mnode_t *node)
 					continue;
 				}
 
-#ifdef EDGEOPTIMISE
 				//build a list of the edges that are to be drawn.
 				for (v = 0; v < surf->numedges; v++)
 				{
@@ -2004,41 +2391,14 @@ void PPL_RecursiveWorldNodeQ2_r (mnode_t *node)
 						}
 					}
 				}
-#endif
+
 
 				for (p = surf->polys; p; p=p->next)
 				{
 					//front face
-					glBegin(GL_POLYGON);
-					for (v = 0; v < p->numverts; v++)
-						glVertex3fv(p->verts[v]);
-					glEnd();
-#ifndef EDGEOPTIMISE
-					for (v = 0; v < p->numverts; v++)
-					{
-					//border
-						v1 = p->verts[v];
-						v2 = p->verts[( v+1 )%p->numverts];
+					glVertexPointer(3, GL_FLOAT, sizeof(GLfloat)*VERTEXSIZE, p->verts);
+					glDrawElements(GL_TRIANGLES, (p->numverts-2)*3, GL_UNSIGNED_INT, varray_i_polytotri);
 
-						//get positions of v3 and v4 based on the light position
-						v3[0] = ( v1[0]-lightorg[0] )*PROJECTION_DISTANCE;
-						v3[1] = ( v1[1]-lightorg[1] )*PROJECTION_DISTANCE;
-						v3[2] = ( v1[2]-lightorg[2] )*PROJECTION_DISTANCE;
-
-						v4[0] = ( v2[0]-lightorg[0] )*PROJECTION_DISTANCE;
-						v4[1] = ( v2[1]-lightorg[1] )*PROJECTION_DISTANCE;
-						v4[2] = ( v2[2]-lightorg[2] )*PROJECTION_DISTANCE;
-
-						//Now draw the quad from the two verts to the projected light
-						//verts
-						glBegin( GL_QUAD_STRIP );
-							glVertex3f( v1[0], v1[1], v1[2] );
-							glVertex3f( v1[0]+v3[0], v1[1]+v3[1], v1[2]+v3[2] );
-							glVertex3f( v2[0], v2[1], v2[2] );
-							glVertex3f( v2[0]+v4[0], v2[1]+v4[1], v2[2]+v4[2] );
-						glEnd();
-					}
-#endif
 //back
 					glBegin(GL_POLYGON);
 					for (v = p->numverts-1; v >=0; v--)
@@ -2070,10 +2430,10 @@ void PPL_RecursiveWorldNodeQ3_r (mnode_t *node)
 	double		dot;
 	glpoly_t *p;
 	int v;
-//#ifndef EDGEOPTIMISE
+
 	float *v2;
 	vec3_t v4;
-//#endif
+
 	float *v1;
 	vec3_t v3;
 
@@ -2125,59 +2485,14 @@ void PPL_RecursiveWorldNodeQ3_r (mnode_t *node)
 					continue;
 				}*/
 
-/*#ifdef EDGEOPTIMISE
-				//build a list of the edges that are to be drawn.
-				for (v = 0; v < surf->numedges; v++)
-				{
-					int e, delta;
-					e = cl.worldmodel->surfedges[surf->firstedge+v];
-					//negative edge means backwards edge.
-					if (e < 0)
-					{
-						e=-e;
-						delta = -1;
-					}
-					else
-					{
-						delta = 1;
-					}
 
-					if (!edge[e].count)
-					{
-						if (firstedge)
-							edge[firstedge].prev = e;
-						edge[e].next = firstedge;
-						edge[e].prev = 0;
-						firstedge = e;
-						edge[e].count = delta;
-					}
-					else
-					{
-						edge[e].count += delta;
-
-						if (!edge[e].count)	//unlink
-						{
-							if (edge[e].next)
-							{
-								edge[edge[e].next].prev = edge[e].prev;
-							}
-							if (edge[e].prev)
-								edge[edge[e].prev].next = edge[e].next;
-							else
-								firstedge = edge[e].next;
-						}
-					}
-				}
-#endif*/
 
 				for (p = surf->polys; p; p=p->next)
 				{
 					//front face
-					glBegin(GL_POLYGON);
-					for (v = 0; v < p->numverts; v++)
-						glVertex3fv(p->verts[v]);
-					glEnd();
-//#ifndef EDGEOPTIMISE
+					glVertexPointer(3, GL_FLOAT, sizeof(GLfloat)*VERTEXSIZE, p->verts);
+					glDrawElements(GL_TRIANGLES, (p->numverts-2)*3, GL_UNSIGNED_INT, varray_i_polytotri);
+//fixme...
 					for (v = 0; v < p->numverts; v++)
 					{
 					//border
@@ -2202,7 +2517,7 @@ void PPL_RecursiveWorldNodeQ3_r (mnode_t *node)
 							glVertex3f( v2[0]+v4[0], v2[1]+v4[1], v2[2]+v4[2] );
 						glEnd();
 					}
-//#endif
+
 //back
 					glBegin(GL_POLYGON);
 					for (v = p->numverts-1; v >=0; v--)
@@ -2285,17 +2600,23 @@ void PPL_RecursiveWorldNode (dlight_t *dl)
 	modelorg[1] = lightorg[1];
 	modelorg[2] = lightorg[2];
 
+	glEnableClientState(GL_VERTEX_ARRAY);
+
+	if (qglGetError())
+		Con_Printf("GL Error on entities\n");
 	if (cl.worldmodel->fromgame == fg_quake3)
 		PPL_RecursiveWorldNodeQ3_r(cl.worldmodel->nodes);
 	else if (cl.worldmodel->fromgame == fg_quake2)
 		PPL_RecursiveWorldNodeQ2_r(cl.worldmodel->nodes);
 	else
 		PPL_RecursiveWorldNode_r(cl.worldmodel->nodes);
+	if (qglGetError())
+		Con_Printf("GL Error on entities\n");
 
-#ifdef EDGEOPTIMISE
-	glBegin( GL_QUADS );
+	glVertexPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v[0].xyz);
+	if (qglGetError())
+		Con_Printf("GL Error on entities\n");
 	while(firstedge)
-//	for (firstedge = 0; firstedge < cl.worldmodel->numedges; firstedge++)
 	{
 		//border
 		v1 = cl.worldmodel->vertexes[cl.worldmodel->edges[firstedge].v[0]].position;
@@ -2310,34 +2631,66 @@ void PPL_RecursiveWorldNode (dlight_t *dl)
 		v4[1] = ( v2[1]-lightorg[1] )*PROJECTION_DISTANCE;
 		v4[2] = ( v2[2]-lightorg[2] )*PROJECTION_DISTANCE;
 
-		//Now draw the quad from the two verts to the projected light
-		//verts
-		while (edge[firstedge].count > 0)
+		if (varray_vc + 4>MAXARRAYVERTS)
 		{
-			glVertex3f( v1[0]+v3[0], v1[1]+v3[1], v1[2]+v3[2] );
-			glVertex3f( v2[0]+v4[0], v2[1]+v4[1], v2[2]+v4[2] );
-			glVertex3f( v2[0], v2[1], v2[2] );
-			glVertex3f( v1[0], v1[1], v1[2] );
-			edge[firstedge].count--;
+			glDrawElements(GL_QUADS, varray_vc, GL_UNSIGNED_INT, varray_i_forward);
+			if (qglGetError())
+				Con_Printf("GL Error on entities\n");
+			varray_vc=0;
 		}
-		while (edge[firstedge].count < 0)
+
+		if (edge[firstedge].count > 0)
 		{
-			glVertex3f( v1[0], v1[1], v1[2] );
-			glVertex3f( v2[0], v2[1], v2[2] );
-			glVertex3f( v2[0]+v4[0], v2[1]+v4[1], v2[2]+v4[2] );
-			glVertex3f( v1[0]+v3[0], v1[1]+v3[1], v1[2]+v3[2] );
-			edge[firstedge].count++;
+			varray_v[varray_vc].xyz[0] = v1[0]+v3[0];
+			varray_v[varray_vc].xyz[1] = v1[1]+v3[1];
+			varray_v[varray_vc].xyz[2] = v1[2]+v3[2];
+			varray_vc++;
+			varray_v[varray_vc].xyz[0] = v2[0]+v4[0];
+			varray_v[varray_vc].xyz[1] = v2[1]+v4[1];
+			varray_v[varray_vc].xyz[2] = v2[2]+v4[2];
+			varray_vc++;
+			varray_v[varray_vc].xyz[0] = v2[0];
+			varray_v[varray_vc].xyz[1] = v2[1];
+			varray_v[varray_vc].xyz[2] = v2[2];
+			varray_vc++;
+			varray_v[varray_vc].xyz[0] = v1[0];
+			varray_v[varray_vc].xyz[1] = v1[1];
+			varray_v[varray_vc].xyz[2] = v1[2];
+			varray_vc++;
 		}
+		else
+		{
+			varray_v[varray_vc].xyz[0] = v1[0];
+			varray_v[varray_vc].xyz[1] = v1[1];
+			varray_v[varray_vc].xyz[2] = v1[2];
+			varray_vc++;
+			varray_v[varray_vc].xyz[0] = v2[0];
+			varray_v[varray_vc].xyz[1] = v2[1];
+			varray_v[varray_vc].xyz[2] = v2[2];
+			varray_vc++;
+			varray_v[varray_vc].xyz[0] = v2[0]+v4[0];
+			varray_v[varray_vc].xyz[1] = v2[1]+v4[1];
+			varray_v[varray_vc].xyz[2] = v2[2]+v4[2];
+			varray_vc++;
+			varray_v[varray_vc].xyz[0] = v1[0]+v3[0];
+			varray_v[varray_vc].xyz[1] = v1[1]+v3[1];
+			varray_v[varray_vc].xyz[2] = v1[2]+v3[2];
+			varray_vc++;
+		}
+		edge[firstedge].count=0;
 
 		firstedge = edge[firstedge].next;
 
 		shadowedgecount++;
 	}
-	glEnd();
-	for (firstedge = 0; firstedge < cl.worldmodel->numedges; firstedge++)
-		edge[firstedge].count = 0;
+	glDrawElements(GL_QUADS, varray_vc, GL_UNSIGNED_INT, varray_i_forward);
+
+	if (qglGetError())
+		Con_Printf("GL Error on entities\n");
+
+	varray_vc=0;
+
 	firstedge=0;
-#endif
 }
 
 void PPL_DrawBrushModel(dlight_t *dl, entity_t *e)
@@ -2618,15 +2971,25 @@ void PPL_AddLight(dlight_t *dl)
 	}
 //our stencil writes.
 
+	PPL_EnableVertexArrays();
+
 #ifdef _DEBUG
 	if (r_shadows.value == 666)	//testing (visible shadow volumes)
 	{
+		if (qglGetError())
+			Con_Printf("GL Error on entities\n");
 		glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
 		glColor3f(dl->color[0], dl->color[1], dl->color[2]);
 		glDisable(GL_STENCIL_TEST);
 		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+		if (qglGetError())
+			Con_Printf("GL Error on entities\n");
 		PPL_RecursiveWorldNode(dl);
+		if (qglGetError())
+			Con_Printf("GL Error on entities\n");
 		PPL_DrawShadowMeshes(dl);
+		if (qglGetError())
+			Con_Printf("GL Error on entities\n");
 		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 	}
 	else
@@ -2730,11 +3093,19 @@ void PPL_DrawWorld (void)
 
 	if (maxshadowlights < 1)
 		maxshadowlights = 1;
+	if (qglGetError())
+		Con_Printf("GL Error before world\n");
 //glColorMask(0,0,0,0);
 	PPL_BaseTextures(cl.worldmodel);
+	if (qglGetError())
+		Con_Printf("GL Error during base textures\n");
 //glColorMask(1,1,1,1);
 	PPL_BaseEntTextures();
 //	CL_NewDlightRGB(1, r_refdef.vieworg[0], r_refdef.vieworg[1]-16, r_refdef.vieworg[2]-24, 128, 1, 1, 1, 1);
+
+	if (qglGetError())
+		Con_Printf("GL Error on entities\n");
+
 	if (r_shadows.value && glStencilFunc)
 	{
 		if (cl.worldmodel->fromgame == fg_quake || cl.worldmodel->fromgame == fg_halflife || cl.worldmodel->fromgame == fg_quake2 /*|| cl.worldmodel->fromgame == fg_quake3*/)
@@ -2758,9 +3129,19 @@ void PPL_DrawWorld (void)
 			}
 			glEnable(GL_TEXTURE_2D);
 		}
+
+		glDisableClientState(GL_COLOR_ARRAY);
+		glDisableClientState(GL_VERTEX_ARRAY);
 	}
+
+	if (qglGetError())
+		Con_Printf("GL Error on shadow lighting\n");
+
 	PPL_DrawEntFullBrights();
 
+	if (qglGetError())
+		Con_Printf("GL Error on fullbrights/details\n");
+
 //	Con_Printf("%i %i %i\n", shadowsurfcount, shadowedgecount, shadowlightfaces);
 	shadowsurfcount	= 0;
 	shadowedgecount = 0;
diff --git a/engine/gl/gl_rmisc.c b/engine/gl/gl_rmisc.c
index e29716074..b20d91e1d 100644
--- a/engine/gl/gl_rmisc.c
+++ b/engine/gl/gl_rmisc.c
@@ -21,13 +21,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 #include "glquake.h"
+#include "gl_draw.h"
 
 #ifdef WATERLAYERS
 cvar_t	r_waterlayers = {"r_waterlayers","3"};
 #endif
 
-cvar_t	gl_skyboxname = {"r_skybox", ""};
-
 extern void R_InitBubble();
 
 /*
diff --git a/engine/gl/gl_rsurf.c b/engine/gl/gl_rsurf.c
index 12cd3e368..1da561cef 100644
--- a/engine/gl/gl_rsurf.c
+++ b/engine/gl/gl_rsurf.c
@@ -3146,6 +3146,7 @@ void BuildSurfaceDisplayList (msurface_t *fa)
 	float	distoff;
 	vec3_t	offcenter;
 	glpoly_t	*poly;
+	int	lm;
 
 // reconstruct the polygon
 	pedges = currentmodel->edges;
@@ -3180,35 +3181,51 @@ void BuildSurfaceDisplayList (msurface_t *fa)
 			r_pedge = &pedges[-lindex];
 			vec = r_pcurrentvertbase[r_pedge->v[1]].position;
 		}
-		s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];
-		s /= fa->texinfo->texture->width;
-
-		t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];
-		t /= fa->texinfo->texture->height;
 
 		VectorAdd(vec, fa->center, fa->center);
 
+		s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];
+		t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];
+
 		VectorCopy (vec, poly->verts[i]);
-		poly->verts[i][3] = s;
-		poly->verts[i][4] = t;
+		poly->verts[i][3] = s/fa->texinfo->texture->width;
+		poly->verts[i][4] = t/fa->texinfo->texture->height;
 
 		//
 		// lightmap texture coordinates
 		//
-		s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];
 		s -= fa->texturemins[0];
+		lm = s*fa->light_t;
 		s += fa->light_s*16;
 		s += 8;
 		s /= LMBLOCK_WIDTH*16; //fa->texinfo->texture->width;
 
-		t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];
 		t -= fa->texturemins[1];
+		lm += t;
 		t += fa->light_t*16;
 		t += 8;
 		t /= LMBLOCK_HEIGHT*16; //fa->texinfo->texture->height;
 
 		poly->verts[i][5] = s;
 		poly->verts[i][6] = t;
+
+#ifdef SPECULAR
+/*		if (currentmodel->deluxdata&&fa->samples)
+		{
+			qbyte *dlm = fa->samples - currentmodel->lightdata + currentmodel->deluxdata;
+			dlm += lm;
+			poly->verts[i][7] = (dlm[0]-127)/128.0f;
+			poly->verts[i][8] = (dlm[1]-127)/128.0f;
+			poly->verts[i][9] = (dlm[2]-127)/128.0f;
+		}
+		else*/
+			if (fa->flags & SURF_PLANEBACK)
+		{
+				VectorNegate(fa->plane->normal, (poly->verts[i]+7));
+		}
+		else
+			VectorCopy(fa->plane->normal, (poly->verts[i]+7));
+#endif
 	}
 
 	fa->center[0]/=lnumverts;
diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c
index 1170848f5..3a48bf833 100644
--- a/engine/gl/gl_vidcommon.c
+++ b/engine/gl/gl_vidcommon.c
@@ -28,6 +28,7 @@ void (APIENTRY *qglEnd) (void);
 void (APIENTRY *qglFinish) (void);
 void (APIENTRY *qglFlush) (void);
 void (APIENTRY *qglFrustum) (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+GLenum (APIENTRY *qglGetError) (void);
 void (APIENTRY *qglGetFloatv) (GLenum pname, GLfloat *params);
 void (APIENTRY *qglGetIntegerv) (GLenum pname, GLint *params);
 const GLubyte * (APIENTRY *qglGetString) (GLenum name);
@@ -51,6 +52,7 @@ void (APIENTRY *qglTexCoord1f) (GLfloat s);
 void (APIENTRY *qglTexCoord2f) (GLfloat s, GLfloat t);
 void (APIENTRY *qglTexCoord2fv) (const GLfloat *v);
 void (APIENTRY *qglTexEnvf) (GLenum target, GLenum pname, GLfloat param);
+void (APIENTRY *qglTexEnvfv) (GLenum target, GLenum pname, const GLfloat *param);
 void (APIENTRY *qglTexEnvi) (GLenum target, GLenum pname, GLint param);
 void (APIENTRY *qglTexGeni) (GLenum coord, GLenum pname, GLint param);
 void (APIENTRY *qglTexImage2D) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
@@ -69,6 +71,7 @@ void (APIENTRY *qglVertexPointer) (GLint size, GLenum type, GLsizei stride, cons
 void (APIENTRY *qglNormalPointer) (GLenum type, GLsizei stride, const GLvoid *pointer);
 void (APIENTRY *qglTexCoordPointer) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
 void (APIENTRY *qglColorPointer) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+void (APIENTRY *qglDrawArrays) (GLenum mode, GLint first, GLsizei count);
 void (APIENTRY *qglDisableClientState) (GLenum array);
 void (APIENTRY *qglEnableClientState) (GLenum array);
 
@@ -78,6 +81,12 @@ void (APIENTRY *qglStencilFunc) (GLenum func, GLint ref, GLuint mask);
 void (APIENTRY *qglPushAttrib) (GLbitfield mask);
 void (APIENTRY *qglPopAttrib) (void);
 
+PFNGLPROGRAMSTRINGARBPROC qglProgramStringARB;
+PFNGLGETPROGRAMIVARBPROC qglGetProgramivARB;
+PFNGLBINDPROGRAMARBPROC qglBindProgramARB;
+PFNGLGENPROGRAMSARBPROC qglGenProgramsARB;
+
+
 
 
 
@@ -112,6 +121,8 @@ qboolean gl_mtexable = false;
 qboolean gl_compressable=false;
 int gl_bumpmappingpossible;
 
+qboolean gl_arb_fragment_program;
+
 
 
 
@@ -162,6 +173,13 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name))
 	qglPNTrianglesfATI = NULL;
 	qglPNTrianglesiATI = NULL;
 
+	//fragment programs
+	gl_arb_fragment_program = false;
+	qglProgramStringARB = NULL;
+	qglGetProgramivARB = NULL;
+	qglBindProgramARB = NULL;
+	qglGenProgramsARB = NULL;
+
 	if (strstr(gl_extensions, "GL_ARB_multitexture") && !COM_CheckParm("-noamtex"))
 	{	//ARB multitexture is the popular choice.
 		Con_SafePrintf("ARB Multitexture extensions found. Use -noamtex to disable.\n");
@@ -243,6 +261,16 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name))
 
 	if (gl_mtexarbable && support_GL_ARB_texture_cube_map && support_GL_ARB_texture_env_combine && support_GL_ARB_texture_env_dot3 && !COM_CheckParm("-nobump") && gl_bump.value)
 		gl_bumpmappingpossible = true;
+
+	
+	if (!!strstr(gl_extensions, "GL_ARB_fragment_program"))
+	{
+		gl_arb_fragment_program = true;
+		qglProgramStringARB = (void *)getglext("glProgramStringARB");
+		qglGetProgramivARB = (void *)getglext("glGetProgramivARB");
+		qglBindProgramARB = (void *)getglext("glBindProgramARB");
+		qglGenProgramsARB = (void *)getglext("glGenProgramsARB");
+	}
 }
 
 //the vid routines have initialised a window, and now they are giving us a reference to some of of GetProcAddress to get pointers to the funcs.
@@ -299,6 +327,7 @@ void GL_Init(void *(*getglfunction) (char *name))
 	qglTexCoord2f		= (void *)getglcore("glTexCoord2f");
 	qglTexCoord2fv		= (void *)getglcore("glTexCoord2fv");
 	qglTexEnvf			= (void *)getglcore("glTexEnvf");
+	qglTexEnvfv			= (void *)getglcore("glTexEnvfv");
 	qglTexEnvi			= (void *)getglcore("glTexEnvi");
 	qglTexGeni			= (void *)getglcore("glTexGeni");
 	qglTexImage2D		= (void *)getglcore("glTexImage2D");
@@ -311,12 +340,15 @@ void GL_Init(void *(*getglfunction) (char *name))
 	qglVertex3fv		= (void *)getglcore("glVertex3fv");
 	qglViewport			= (void *)getglcore("glViewport");
 
-	//fixme: make non-core?
+	qglGetError			= (void *)getglcore("glGetError");
+
+	//various vertex array stuff.
 	qglDrawElements			= (void *)getglcore("glDrawElements");
 	qglVertexPointer		= (void *)getglcore("glVertexPointer");
 	qglNormalPointer		= (void *)getglcore("glNormalPointer");
 	qglTexCoordPointer		= (void *)getglcore("glTexCoordPointer");
 	qglColorPointer			= (void *)getglcore("glColorPointer");
+	qglDrawArrays			= (void *)getglcore("glDrawArrays");
 	qglEnableClientState	= (void *)getglcore("glEnableClientState");
 	qglDisableClientState	= (void *)getglcore("glDisableClientState");
 
diff --git a/engine/gl/gl_warp.c b/engine/gl/gl_warp.c
index c2fcfc152..704b12b42 100644
--- a/engine/gl/gl_warp.c
+++ b/engine/gl/gl_warp.c
@@ -433,7 +433,7 @@ void R_LoadSkys (void)
 	{		
 		sprintf (name, "env/%s%s.tga", gl_skyboxname.string, suf[i]);
 
-		skyboxtex[i] = Mod_LoadHiResTexture(name, false, false);
+		skyboxtex[i] = Mod_LoadHiResTexture(name, false, false, true);
 
 		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
diff --git a/engine/gl/glmod_doom.c b/engine/gl/glmod_doom.c
index 2ee1b8b34..0625117a5 100644
--- a/engine/gl/glmod_doom.c
+++ b/engine/gl/glmod_doom.c
@@ -1080,7 +1080,7 @@ static int Doom_LoadPatch(char *name)
 			return texnum;
 	}
 	//all else failed.
-	return Mod_LoadHiResTexture(name, true, false);
+	return Mod_LoadHiResTexture(name, true, false, true);
 }
 #endif
 static void CleanWalls(dsidedef_t *sidedefsl)
diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h
index 1e31fae10..19ba018ea 100644
--- a/engine/gl/glquake.h
+++ b/engine/gl/glquake.h
@@ -61,6 +61,13 @@ void GLR_DrawAlphaSurfaces (void);
 void GL_FlushSkinCache(void);
 void GL_GAliasFlushSkinCache(void);
 
+void PPL_LoadSpecularFragmentProgram(void);
+void PPL_BaseBModelTextures(entity_t *e);
+
+#ifdef RUNTIMELIGHTING
+void LightFace (int surfnum);
+void LightLoadEntities(char *entstring);
+#endif
 
 // Function prototypes for the Texture Object Extension routines
 typedef GLboolean (APIENTRY *ARETEXRESFUNCPTR)(GLsizei, const GLuint *,
@@ -286,7 +293,7 @@ void GL_BuildLightmaps (void);
 
 void GL_LoadShaders(void);
 int Mod_LoadReplacementTexture(char *name, qboolean mipmap, qboolean alpha);
-int Mod_LoadHiResTexture(char *name, qboolean mipmap, qboolean alpha);
+int Mod_LoadHiResTexture(char *name, qboolean mipmap, qboolean alpha, qboolean colouradjust);
 int Mod_LoadBumpmapTexture(char *name);
 
 #define	LMBLOCK_WIDTH		128
@@ -675,6 +682,12 @@ extern BOOL  (WINAPI *qwglMakeCurrent)(HDC, HGLRC);
 extern BOOL  (WINAPI *qSwapBuffers)(HDC);
 #endif
 
+extern qboolean gl_arb_fragment_program;
+extern PFNGLPROGRAMSTRINGARBPROC qglProgramStringARB;
+extern PFNGLGETPROGRAMIVARBPROC qglGetProgramivARB;
+extern PFNGLBINDPROGRAMARBPROC qglBindProgramARB;
+extern PFNGLGENPROGRAMSARBPROC qglGenProgramsARB;
+
 
 #define glAlphaFunc qglAlphaFunc
 #define glBlendFunc qglBlendFunc
@@ -704,6 +717,7 @@ extern BOOL  (WINAPI *qSwapBuffers)(HDC);
 #define glMultMatrixf	qglMultMatrixf
 #define glGetIntegerv	qglGetIntegerv
 #define glTexEnvf	qglTexEnvf
+#define glTexEnvfv	qglTexEnvfv
 #define glTexEnvi	qglTexEnvi
 #define glTexGeni	qglTexGeni
 #define glVertex2f	qglVertex2f
@@ -745,6 +759,7 @@ extern BOOL  (WINAPI *qSwapBuffers)(HDC);
 #define glDrawElements qglDrawElements
 #define glDisableClientState qglDisableClientState
 #define glEnableClientState qglEnableClientState
+#define glDrawArrays qglDrawArrays
 
 //stencil functions
 #define glStencilOp		qglStencilOp
diff --git a/engine/gl/glsupp.h b/engine/gl/glsupp.h
index 0853371dc..f9d146017 100644
--- a/engine/gl/glsupp.h
+++ b/engine/gl/glsupp.h
@@ -1,5 +1,7 @@
 //gl suppliment for Quake
 
+#define APIENTRYP APIENTRY *
+
 //contains the extra things that would otherwise be found in glext.h
 
 typedef void (APIENTRY *qlpMTex2FUNC) (GLenum, GLfloat, GLfloat);
@@ -201,4 +203,187 @@ typedef void (APIENTRY * PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face);
 #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT			0x84FF
 #endif
 
+
+
+
+
+
+
+#ifndef GL_ARB_vertex_program
+#define GL_COLOR_SUM_ARB                  0x8458
+#define GL_VERTEX_PROGRAM_ARB             0x8620
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB   0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB   0x8625
+#define GL_CURRENT_VERTEX_ATTRIB_ARB      0x8626
+#define GL_PROGRAM_LENGTH_ARB             0x8627
+#define GL_PROGRAM_STRING_ARB             0x8628
+#define GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E
+#define GL_MAX_PROGRAM_MATRICES_ARB       0x862F
+#define GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640
+#define GL_CURRENT_MATRIX_ARB             0x8641
+#define GL_VERTEX_PROGRAM_POINT_SIZE_ARB  0x8642
+#define GL_VERTEX_PROGRAM_TWO_SIDE_ARB    0x8643
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645
+#define GL_PROGRAM_ERROR_POSITION_ARB     0x864B
+#define GL_PROGRAM_BINDING_ARB            0x8677
+#define GL_MAX_VERTEX_ATTRIBS_ARB         0x8869
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A
+#define GL_PROGRAM_ERROR_STRING_ARB       0x8874
+#define GL_PROGRAM_FORMAT_ASCII_ARB       0x8875
+#define GL_PROGRAM_FORMAT_ARB             0x8876
+#define GL_PROGRAM_INSTRUCTIONS_ARB       0x88A0
+#define GL_MAX_PROGRAM_INSTRUCTIONS_ARB   0x88A1
+#define GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2
+#define GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3
+#define GL_PROGRAM_TEMPORARIES_ARB        0x88A4
+#define GL_MAX_PROGRAM_TEMPORARIES_ARB    0x88A5
+#define GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6
+#define GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7
+#define GL_PROGRAM_PARAMETERS_ARB         0x88A8
+#define GL_MAX_PROGRAM_PARAMETERS_ARB     0x88A9
+#define GL_PROGRAM_NATIVE_PARAMETERS_ARB  0x88AA
+#define GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB
+#define GL_PROGRAM_ATTRIBS_ARB            0x88AC
+#define GL_MAX_PROGRAM_ATTRIBS_ARB        0x88AD
+#define GL_PROGRAM_NATIVE_ATTRIBS_ARB     0x88AE
+#define GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF
+#define GL_PROGRAM_ADDRESS_REGISTERS_ARB  0x88B0
+#define GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1
+#define GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2
+#define GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3
+#define GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4
+#define GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5
+#define GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6
+#define GL_TRANSPOSE_CURRENT_MATRIX_ARB   0x88B7
+#define GL_MATRIX0_ARB                    0x88C0
+#define GL_MATRIX1_ARB                    0x88C1
+#define GL_MATRIX2_ARB                    0x88C2
+#define GL_MATRIX3_ARB                    0x88C3
+#define GL_MATRIX4_ARB                    0x88C4
+#define GL_MATRIX5_ARB                    0x88C5
+#define GL_MATRIX6_ARB                    0x88C6
+#define GL_MATRIX7_ARB                    0x88C7
+#define GL_MATRIX8_ARB                    0x88C8
+#define GL_MATRIX9_ARB                    0x88C9
+#define GL_MATRIX10_ARB                   0x88CA
+#define GL_MATRIX11_ARB                   0x88CB
+#define GL_MATRIX12_ARB                   0x88CC
+#define GL_MATRIX13_ARB                   0x88CD
+#define GL_MATRIX14_ARB                   0x88CE
+#define GL_MATRIX15_ARB                   0x88CF
+#define GL_MATRIX16_ARB                   0x88D0
+#define GL_MATRIX17_ARB                   0x88D1
+#define GL_MATRIX18_ARB                   0x88D2
+#define GL_MATRIX19_ARB                   0x88D3
+#define GL_MATRIX20_ARB                   0x88D4
+#define GL_MATRIX21_ARB                   0x88D5
+#define GL_MATRIX22_ARB                   0x88D6
+#define GL_MATRIX23_ARB                   0x88D7
+#define GL_MATRIX24_ARB                   0x88D8
+#define GL_MATRIX25_ARB                   0x88D9
+#define GL_MATRIX26_ARB                   0x88DA
+#define GL_MATRIX27_ARB                   0x88DB
+#define GL_MATRIX28_ARB                   0x88DC
+#define GL_MATRIX29_ARB                   0x88DD
+#define GL_MATRIX30_ARB                   0x88DE
+#define GL_MATRIX31_ARB                   0x88DF
+#endif
+
+#ifndef GL_ARB_fragment_program
+#define GL_FRAGMENT_PROGRAM_ARB           0x8804
+#define GL_PROGRAM_ALU_INSTRUCTIONS_ARB   0x8805
+#define GL_PROGRAM_TEX_INSTRUCTIONS_ARB   0x8806
+#define GL_PROGRAM_TEX_INDIRECTIONS_ARB   0x8807
+#define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808
+#define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809
+#define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A
+#define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B
+#define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C
+#define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D
+#define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E
+#define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F
+#define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810
+#define GL_MAX_TEXTURE_COORDS_ARB         0x8871
+#define GL_MAX_TEXTURE_IMAGE_UNITS_ARB    0x8872
+#endif
+
+
+
+
+
+#ifndef GL_ARB_vertex_program
+#define GL_ARB_vertex_program 1
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DARBPROC) (GLuint index, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FARBPROC) (GLuint index, GLfloat x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SARBPROC) (GLuint index, GLshort x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DARBPROC) (GLuint index, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FARBPROC) (GLuint index, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SARBPROC) (GLuint index, GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVARBPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVARBPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBARBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVARBPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVARBPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVARBPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVARBPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVARBPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYARBPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const GLvoid *string);
+typedef void (APIENTRYP PFNGLBINDPROGRAMARBPROC) (GLenum target, GLuint program);
+typedef void (APIENTRYP PFNGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs);
+typedef void (APIENTRYP PFNGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, GLvoid *string);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVARBPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVARBPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, GLvoid* *pointer);
+typedef GLboolean (APIENTRYP PFNGLISPROGRAMARBPROC) (GLuint program);
+#endif
+
+#ifndef GL_ARB_fragment_program
+#define GL_ARB_fragment_program 1
+/* All ARB_fragment_program entry points are shared with ARB_vertex_program. */
+#endif
+
+
+
 #endif