diff --git a/src/refresh/header/local.h b/src/refresh/header/local.h
index c1e9de41..ad7b625c 100644
--- a/src/refresh/header/local.h
+++ b/src/refresh/header/local.h
@@ -33,20 +33,20 @@
 #include <GL/gl.h>
 
 #include "../../client/header/ref.h"
-#include "qgl.h"   
+#include "qgl.h"
 
 #ifndef GL_COLOR_INDEX8_EXT
  #define GL_COLOR_INDEX8_EXT GL_COLOR_INDEX
 #endif
- 
+
 #define TEXNUM_LIGHTMAPS    1024
 #define TEXNUM_SCRAPS       1152
 #define TEXNUM_IMAGES       1153
-#define MAX_GLTEXTURES		1024
-#define MAX_SCRAPS			1
-#define BLOCK_WIDTH			128
-#define BLOCK_HEIGHT		128
-#define REF_VERSION			"Yamagi Quake II OpenGL Refresher"
+#define MAX_GLTEXTURES      1024
+#define MAX_SCRAPS          1
+#define BLOCK_WIDTH         128
+#define BLOCK_HEIGHT        128
+#define REF_VERSION         "Yamagi Quake II OpenGL Refresher"
 #define MAX_LBM_HEIGHT      480
 #define BACKFACE_EPSILON    0.01
 #define DYNAMIC_LIGHT_WIDTH  128
@@ -54,7 +54,7 @@
 #define LIGHTMAP_BYTES 4
 #define MAX_LIGHTMAPS 128
 #define GL_LIGHTMAP_FORMAT GL_RGBA
-     
+
 /* up / down */
 #define PITCH   0
 
@@ -75,6 +75,7 @@ typedef struct
 #endif
 
 char *strlwr ( char *s );
+
 extern viddef_t vid;
 
 /*
@@ -246,6 +247,8 @@ void R_TranslatePlayerSkin ( int playernum );
 void R_Bind ( int texnum );
 void R_MBind ( GLenum target, int texnum );
 void R_TexEnv ( GLenum value );
+void R_EnableMultitexture ( qboolean enable );
+void R_SelectTexture ( GLenum );
 
 void R_LightPoint ( vec3_t p, vec3_t color );
 void R_PushDlights ( void );
@@ -254,7 +257,7 @@ extern model_t *r_worldmodel;
 extern unsigned d_8to24table [ 256 ];
 extern int registration_sequence;
 
-void	V_AddBlend ( float r, float g, float b, float a, float *v_blend );
+void    V_AddBlend ( float r, float g, float b, float a, float *v_blend );
 int     R_Init ( void *hinstance, void *hWnd );
 void    R_Shutdown ( void );
 
@@ -370,7 +373,7 @@ typedef struct
 	int allocated [ BLOCK_WIDTH ];
 
 	/* the lightmap texture data needs to be kept in
-	   main memory so texsubimage can update properly */
+	 * main memory so texsubimage can update properly */
 	byte lightmap_buffer [ 4 * BLOCK_WIDTH * BLOCK_HEIGHT ];
 } gllightmapstate_t;
 
diff --git a/src/refresh/header/qgl.h b/src/refresh/header/qgl.h
index a502806b..bc1b86b4 100644
--- a/src/refresh/header/qgl.h
+++ b/src/refresh/header/qgl.h
@@ -31,10 +31,13 @@
 
 #ifndef APIENTRY
  #define APIENTRY
-#endif 
+#endif
 
 #define GL_SHARED_TEXTURE_PALETTE_EXT       0x81FB
 
+#define GL_TEXTURE0_SGIS 0x835E
+#define GL_TEXTURE1_SGIS 0x835F
+
 qboolean QGL_Init ( const char *dllname );
 void     QGL_Shutdown ( void );
 
@@ -391,12 +394,19 @@ extern void ( APIENTRY *qglPointParameterfvEXT )( GLenum param, const GLfloat *v
 extern void ( APIENTRY *qglColorTableEXT )( GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid * );
 
 extern void ( APIENTRY *qglLockArraysEXT )( int, int );
+
 extern void ( APIENTRY *qglUnlockArraysEXT )( void );
+extern void ( APIENTRY *qglMTexCoord2fSGIS )( GLenum, GLfloat, GLfloat );
+extern void ( APIENTRY *qglSelectTextureSGIS )( GLenum );
+
+extern void ( APIENTRY *qglActiveTextureARB )( GLenum );
+extern void ( APIENTRY *qglClientActiveTextureARB )( GLenum );
 
 /* local function in dll */
 extern void *qwglGetProcAddress ( char *symbol );
 
 void Fake_glColorTableEXT ( GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table );
+
 extern int QGL_TEXTURE0, QGL_TEXTURE1;
 
 #endif
diff --git a/src/refresh/r_image.c b/src/refresh/r_image.c
index 28570d94..e88595d2 100644
--- a/src/refresh/r_image.c
+++ b/src/refresh/r_image.c
@@ -51,7 +51,7 @@ int gl_tex_alpha_format = 4;
 int gl_filter_min = GL_LINEAR_MIPMAP_NEAREST;
 int gl_filter_max = GL_LINEAR;
 
-image_t * LoadWal ( char *name );
+image_t *LoadWal ( char *name );
 void LoadTGA ( char *name, byte **pic, int *width, int *height );
 int Draw_GetPalette ( void );
 
@@ -127,6 +127,68 @@ typedef struct
 int upload_width, upload_height;
 qboolean uploaded_paletted;
 
+void
+R_EnableMultitexture ( qboolean enable )
+{
+	if ( !qglSelectTextureSGIS && !qglActiveTextureARB )
+	{
+		return;
+	}
+
+	if ( enable )
+	{
+		R_SelectTexture( QGL_TEXTURE1 );
+		qglEnable( GL_TEXTURE_2D );
+		R_TexEnv( GL_REPLACE );
+	}
+	else
+	{
+		R_SelectTexture( QGL_TEXTURE1 );
+		qglDisable( GL_TEXTURE_2D );
+		R_TexEnv( GL_REPLACE );
+	}
+
+	R_SelectTexture( QGL_TEXTURE0 );
+	R_TexEnv( GL_REPLACE );
+}
+
+void
+R_SelectTexture ( GLenum texture )
+{
+	int tmu;
+
+	if ( !qglSelectTextureSGIS && !qglActiveTextureARB )
+	{
+		return;
+	}
+
+	if ( texture == QGL_TEXTURE0 )
+	{
+		tmu = 0;
+	}
+	else
+	{
+		tmu = 1;
+	}
+
+	if ( tmu == gl_state.currenttmu )
+	{
+		return;
+	}
+
+	gl_state.currenttmu = tmu;
+
+	if ( qglSelectTextureSGIS )
+	{
+		qglSelectTextureSGIS( texture );
+	}
+	else if ( qglActiveTextureARB )
+	{
+		qglActiveTextureARB( texture );
+		qglClientActiveTextureARB( texture );
+	}
+}
+
 void
 R_TexEnv ( GLenum mode )
 {
@@ -161,6 +223,8 @@ R_Bind ( int texnum )
 void
 R_MBind ( GLenum target, int texnum )
 {
+	R_SelectTexture( target );
+
 	if ( target == QGL_TEXTURE0 )
 	{
 		if ( gl_state.currenttextures [ 0 ] == texnum )
@@ -178,7 +242,7 @@ R_MBind ( GLenum target, int texnum )
 
 	R_Bind( texnum );
 }
- 
+
 void
 R_TextureMode ( char *string )
 {
@@ -691,11 +755,11 @@ R_Upload8 ( byte *data, int width, int height,  qboolean mipmap, qboolean is_sky
 	{
 		p = data [ i ];
 		trans [ i ] = d_8to24table [ p ];
-             
+
 		/* transparent, so scan around for another color
-		   to avoid alpha fringes */ 
+		 * to avoid alpha fringes */
 		if ( p == 255 )
-		{   
+		{
 			if ( ( i > width ) && ( data [ i - width ] != 255 ) )
 			{
 				p = data [ i - width ];
@@ -904,7 +968,7 @@ R_FindImage ( char *name, imagetype_t type )
 
 		if ( !pic )
 		{
-			return ( NULL ); 
+			return ( NULL );
 		}
 
 		image = R_LoadPic( name, pic, width, height, type, 32 );
@@ -934,7 +998,7 @@ R_RegisterSkin ( char *name )
 }
 
 /*
- * Any image that was not touched on 
+ * Any image that was not touched on
  * this registration sequence
  * will be freed.
  */
diff --git a/src/refresh/r_lightmap.c b/src/refresh/r_lightmap.c
index 7aaddd25..f7f7a0df 100644
--- a/src/refresh/r_lightmap.c
+++ b/src/refresh/r_lightmap.c
@@ -22,7 +22,7 @@
  * Lightmap handling
  *
  * =======================================================================
- */  
+ */
 
 #include "header/local.h"
 
@@ -121,7 +121,7 @@ LM_AllocBlock ( int w, int h, int *x, int *y )
 		}
 
 		if ( j == w )
-		{   
+		{
 			/* this is a valid spot */
 			*x = i;
 			*y = best = best2;
@@ -255,10 +255,13 @@ LM_BeginBuildingLightmaps ( model_t *m )
 
 	memset( gl_lms.allocated, 0, sizeof ( gl_lms.allocated ) );
 
-	r_framecount = 1;/* no dlightcache */
+	r_framecount = 1; /* no dlightcache */
+
+	R_EnableMultitexture( true );
+	R_SelectTexture( QGL_TEXTURE1 );
 
 	/* setup the base lightstyles so the lightmaps won't have to be regenerated
-	   the first time they're seen */
+	 * the first time they're seen */
 	for ( i = 0; i < MAX_LIGHTSTYLES; i++ )
 	{
 		lightstyles [ i ].rgb [ 0 ] = 1;
@@ -295,5 +298,6 @@ void
 LM_EndBuildingLightmaps ( void )
 {
 	LM_UploadBlock( false );
+	R_EnableMultitexture( false );
 }
 
diff --git a/src/refresh/r_main.c b/src/refresh/r_main.c
index 89d19549..e551a5c0 100644
--- a/src/refresh/r_main.c
+++ b/src/refresh/r_main.c
@@ -22,7 +22,7 @@
  * Refresher setup and main part of the frame generation
  *
  * =======================================================================
- */ 
+ */
 
 #include "header/local.h"
 
@@ -42,7 +42,7 @@ void    Draw_Char ( int x, int y, int c );
 void    Draw_TileClear ( int x, int y, int w, int h, char *name );
 void    Draw_Fill ( int x, int y, int w, int h, int c );
 void    Draw_FadeScreen ( void );
-                                    
+
 viddef_t vid;
 
 refimport_t ri;
@@ -114,6 +114,7 @@ cvar_t  *gl_particle_att_b;
 cvar_t  *gl_particle_att_c;
 
 cvar_t  *gl_ext_swapinterval;
+cvar_t  *gl_ext_multitexture;
 cvar_t  *gl_ext_pointparameters;
 cvar_t  *gl_ext_compiled_vertex_array;
 
@@ -198,14 +199,14 @@ R_DrawSpriteModel ( entity_t *e )
 	dsprite_t       *psprite;
 
 	/* don't even bother culling, because it's just a single
-	   polygon without a surface cache */
+	 * polygon without a surface cache */
 	psprite = (dsprite_t *) currentmodel->extradata;
 
 	e->frame %= psprite->numframes;
 
 	frame = &psprite->frames [ e->frame ];
 
-	{   
+	{
 		/* normal sprite */
 		up = vup;
 		right = vright;
@@ -369,9 +370,9 @@ R_DrawEntitiesOnList ( void )
 		}
 	}
 
-	/* draw transparent entities 
-	  we could sort these if it ever 
-	  becomes a problem... */
+	/* draw transparent entities
+	 * we could sort these if it ever
+	 * becomes a problem... */
 	qglDepthMask( 0 ); /* no z writes */
 
 	for ( i = 0; i < r_newrefdef.num_entities; i++ )
@@ -891,8 +892,8 @@ R_SetLightLevel ( void )
 	/* save off light value for server to look at */
 	R_LightPoint( r_newrefdef.vieworg, shadelight );
 
-	/* pick the greatest component, which should be the same 
-	   as the mono value returned by software */
+	/* pick the greatest component, which should be the same
+	 * as the mono value returned by software */
 	if ( shadelight [ 0 ] > shadelight [ 1 ] )
 	{
 		if ( shadelight [ 0 ] > shadelight [ 2 ] )
@@ -979,6 +980,7 @@ R_Register ( void )
 	gl_vertex_arrays = ri.Cvar_Get( "gl_vertex_arrays", "0", CVAR_ARCHIVE );
 
 	gl_ext_swapinterval = ri.Cvar_Get( "gl_ext_swapinterval", "1", CVAR_ARCHIVE );
+	gl_ext_multitexture = ri.Cvar_Get( "gl_ext_multitexture", "1", CVAR_ARCHIVE );
 	gl_ext_pointparameters = ri.Cvar_Get( "gl_ext_pointparameters", "1", CVAR_ARCHIVE );
 	gl_ext_compiled_vertex_array = ri.Cvar_Get( "gl_ext_compiled_vertex_array", "1", CVAR_ARCHIVE );
 
@@ -1012,7 +1014,7 @@ R_SetMode ( void )
 	gl_mode->modified = false;
 
 	/* a bit hackish approach to enable custom resolutions:
-	   Glimp_SetMode needs these values set for mode -1 */
+	 * Glimp_SetMode needs these values set for mode -1 */
 	vid.width = gl_customwidth->value;
 	vid.height = gl_customheight->value;
 
@@ -1124,7 +1126,7 @@ R_Init ( void *hinstance, void *hWnd )
 	strncpy( vendor_buffer, gl_config.vendor_string, sizeof ( vendor_buffer ) );
 	vendor_buffer [ sizeof ( vendor_buffer ) - 1 ] = 0;
 	strlwr( vendor_buffer );
-	
+
 	ri.Cvar_Set( "scr_drawall", "0" );
 	gl_config.allow_cds = true;
 
@@ -1146,8 +1148,7 @@ R_Init ( void *hinstance, void *hWnd )
 		if ( gl_ext_pointparameters->value )
 		{
 			qglPointParameterfEXT = ( void (APIENTRY *) ( GLenum, GLfloat ) )qwglGetProcAddress( "glPointParameterfEXT" );
-			qglPointParameterfvEXT = ( void (APIENTRY *) ( GLenum, const GLfloat * ) )qwglGetProcAddress(
-					"glPointParameterfvEXT" );
+			qglPointParameterfvEXT = ( void (APIENTRY *) ( GLenum, const GLfloat * ) )qwglGetProcAddress( "glPointParameterfvEXT" );
 			ri.Con_Printf( PRINT_ALL, "...using GL_EXT_point_parameters\n" );
 		}
 		else
@@ -1160,6 +1161,51 @@ R_Init ( void *hinstance, void *hWnd )
 		ri.Con_Printf( PRINT_ALL, "...GL_EXT_point_parameters not found\n" );
 	}
 
+	if ( strstr( gl_config.extensions_string, "GL_ARB_multitexture" ) )
+	{
+		if ( gl_ext_multitexture->value )
+		{
+			ri.Con_Printf( PRINT_ALL, "...using GL_ARB_multitexture\n" );
+			qglMTexCoord2fSGIS = (void *) qwglGetProcAddress( "glMultiTexCoord2fARB" );
+			qglActiveTextureARB = (void *) qwglGetProcAddress( "glActiveTextureARB" );
+			qglClientActiveTextureARB = (void *) qwglGetProcAddress( "glClientActiveTextureARB" );
+			QGL_TEXTURE0 = GL_TEXTURE0_ARB;
+			QGL_TEXTURE1 = GL_TEXTURE1_ARB;
+		}
+		else
+		{
+			ri.Con_Printf( PRINT_ALL, "...ignoring GL_ARB_multitexture\n" );
+		}
+	}
+	else
+	{
+		ri.Con_Printf( PRINT_ALL, "...GL_ARB_multitexture not found\n" );
+	}
+
+	if ( strstr( gl_config.extensions_string, "GL_SGIS_multitexture" ) )
+	{
+		if ( qglActiveTextureARB )
+		{
+			ri.Con_Printf( PRINT_ALL, "...GL_SGIS_multitexture deprecated in favor of ARB_multitexture\n" );
+		}
+		else if ( gl_ext_multitexture->value )
+		{
+			ri.Con_Printf( PRINT_ALL, "...using GL_SGIS_multitexture\n" );
+			qglMTexCoord2fSGIS = (void *) qwglGetProcAddress( "glMTexCoord2fSGIS" );
+			qglSelectTextureSGIS = (void *) qwglGetProcAddress( "glSelectTextureSGIS" );
+			QGL_TEXTURE0 = GL_TEXTURE0_SGIS;
+			QGL_TEXTURE1 = GL_TEXTURE1_SGIS;
+		}
+		else
+		{
+			ri.Con_Printf( PRINT_ALL, "...ignoring GL_SGIS_multitexture\n" );
+		}
+	}
+	else
+	{
+		ri.Con_Printf( PRINT_ALL, "...GL_SGIS_multitexture not found\n" );
+	}
+
 	R_SetDefaultState();
 
 	R_InitImages();
@@ -1205,7 +1251,7 @@ R_BeginFrame ( float camera_separation )
 
 	/* change modes if necessary */
 	if ( gl_mode->modified || vid_fullscreen->modified )
-	{   
+	{
 		cvar_t  *ref;
 
 		ref = ri.Cvar_Get( "vid_ref", "gl", 0 );
@@ -1435,9 +1481,9 @@ R_GetRefAPI ( refimport_t rimp )
 	return ( re );
 }
 
-/* 
- * this is only here so the functions in 
- * q_shared.c can link 
+/*
+ * this is only here so the functions in
+ * q_shared.c can link
  */
 void
 Sys_Error ( char *error, ... )
diff --git a/src/refresh/r_surf.c b/src/refresh/r_surf.c
index b9112317..25a05d90 100644
--- a/src/refresh/r_surf.c
+++ b/src/refresh/r_surf.c
@@ -22,7 +22,7 @@
  * Surface generation and drawing
  *
  * =======================================================================
- */ 
+ */
 
 #include <assert.h>
 #include "header/local.h"
@@ -205,9 +205,9 @@ R_DrawGLPolyChain ( glpoly_t *p, float soffset, float toffset )
 }
 
 /*
-* This routine takes all the given light mapped surfaces in the world
-* and blends them into the framebuffer.
-*/
+ * This routine takes all the given light mapped surfaces in the world
+ * and blends them into the framebuffer.
+ */
 void
 R_BlendLightmaps ( void )
 {
@@ -228,8 +228,8 @@ R_BlendLightmaps ( void )
 	/* don't bother writing Z */
 	qglDepthMask( 0 );
 
-	/* set the appropriate blending mode unless 
-	   we're only looking at the lightmaps. */
+	/* set the appropriate blending mode unless
+	 * we're only looking at the lightmaps. */
 	if ( !gl_lightmap->value )
 	{
 		qglEnable( GL_BLEND );
@@ -478,7 +478,7 @@ R_DrawAlphaSurfaces ( void )
 	R_TexEnv( GL_MODULATE );
 
 	/* the textures are prescaled up for a better lighting range,
-	   so scale it back down */
+	 * so scale it back down */
 	intens = gl_state.inverse_intensity;
 
 	for ( s = r_alpha_surfaces; s; s = s->texturechain )
@@ -529,33 +529,263 @@ R_DrawTextureChains ( void )
 
 	c_visible_textures = 0;
 
-	for ( i = 0, image = gltextures; i < numgltextures; i++, image++ )
+	if ( !qglSelectTextureSGIS && !qglActiveTextureARB )
 	{
-		if ( !image->registration_sequence )
+		for ( i = 0, image = gltextures; i < numgltextures; i++, image++ )
 		{
-			continue;
+			if ( !image->registration_sequence )
+			{
+				continue;
+			}
+
+			s = image->texturechain;
+
+			if ( !s )
+			{
+				continue;
+			}
+
+			c_visible_textures++;
+
+			for ( ; s; s = s->texturechain )
+			{
+				R_RenderBrushPoly( s );
+			}
+
+			image->texturechain = NULL;
+		}
+	}
+	else
+	{
+		for ( i = 0, image = gltextures; i < numgltextures; i++, image++ )
+		{
+			if ( !image->registration_sequence )
+			{
+				continue;
+			}
+
+			if ( !image->texturechain )
+			{
+				continue;
+			}
+
+			c_visible_textures++;
+
+			for ( s = image->texturechain; s; s = s->texturechain )
+			{
+				if ( !( s->flags & SURF_DRAWTURB ) )
+				{
+					R_RenderBrushPoly( s );
+				}
+			}
 		}
 
-		s = image->texturechain;
+		R_EnableMultitexture( false );
 
-		if ( !s )
+		for ( i = 0, image = gltextures; i < numgltextures; i++, image++ )
 		{
-			continue;
+			if ( !image->registration_sequence )
+			{
+				continue;
+			}
+
+			s = image->texturechain;
+
+			if ( !s )
+			{
+				continue;
+			}
+
+			for ( ; s; s = s->texturechain )
+			{
+				if ( s->flags & SURF_DRAWTURB )
+				{
+					R_RenderBrushPoly( s );
+				}
+			}
+
+			image->texturechain = NULL;
 		}
-
-		c_visible_textures++;
-
-		for ( ; s; s = s->texturechain )
-		{
-			R_RenderBrushPoly( s );
-		}
-
-		image->texturechain = NULL;
 	}
 
 	R_TexEnv( GL_REPLACE );
 }
 
+static void
+R_RenderLightmappedPoly ( msurface_t *surf )
+{
+	int i, nv = surf->polys->numverts;
+	int map;
+	float   *v;
+	image_t *image = R_TextureAnimation( surf->texinfo );
+	qboolean is_dynamic = false;
+	unsigned lmtex = surf->lightmaptexturenum;
+	glpoly_t *p;
+
+	for ( map = 0; map < MAXLIGHTMAPS && surf->styles [ map ] != 255; map++ )
+	{
+		if ( r_newrefdef.lightstyles [ surf->styles [ map ] ].white != surf->cached_light [ map ] )
+		{
+			goto dynamic;
+		}
+	}
+
+	if ( ( surf->dlightframe == r_framecount ) )
+	{
+	dynamic:
+
+		if ( gl_dynamic->value )
+		{
+			if ( !( surf->texinfo->flags & ( SURF_SKY | SURF_TRANS33 | SURF_TRANS66 | SURF_WARP ) ) )
+			{
+				is_dynamic = true;
+			}
+		}
+	}
+
+	if ( is_dynamic )
+	{
+		unsigned temp [ 128 * 128 ];
+		int smax, tmax;
+
+		if ( ( ( surf->styles [ map ] >= 32 ) || ( surf->styles [ map ] == 0 ) ) && ( surf->dlightframe != r_framecount ) )
+		{
+			smax = ( surf->extents [ 0 ] >> 4 ) + 1;
+			tmax = ( surf->extents [ 1 ] >> 4 ) + 1;
+
+			R_BuildLightMap( surf, (void *) temp, smax * 4 );
+			R_SetCacheState( surf );
+
+			R_MBind( QGL_TEXTURE1, gl_state.lightmap_textures + surf->lightmaptexturenum );
+
+			lmtex = surf->lightmaptexturenum;
+
+			qglTexSubImage2D( GL_TEXTURE_2D, 0,
+					surf->light_s, surf->light_t,
+					smax, tmax,
+					GL_LIGHTMAP_FORMAT,
+					GL_UNSIGNED_BYTE, temp );
+		}
+		else
+		{
+			smax = ( surf->extents [ 0 ] >> 4 ) + 1;
+			tmax = ( surf->extents [ 1 ] >> 4 ) + 1;
+
+			R_BuildLightMap( surf, (void *) temp, smax * 4 );
+
+			R_MBind( QGL_TEXTURE1, gl_state.lightmap_textures + 0 );
+
+			lmtex = 0;
+
+			qglTexSubImage2D( GL_TEXTURE_2D, 0,
+					surf->light_s, surf->light_t,
+					smax, tmax,
+					GL_LIGHTMAP_FORMAT,
+					GL_UNSIGNED_BYTE, temp );
+		}
+
+		c_brush_polys++;
+
+		R_MBind( QGL_TEXTURE0, image->texnum );
+		R_MBind( QGL_TEXTURE1, gl_state.lightmap_textures + lmtex );
+
+		if ( surf->texinfo->flags & SURF_FLOWING )
+		{
+			float scroll;
+
+			scroll = -64 * ( ( r_newrefdef.time / 40.0 ) - (int) ( r_newrefdef.time / 40.0 ) );
+
+			if ( scroll == 0.0 )
+			{
+				scroll = -64.0;
+			}
+
+			for ( p = surf->polys; p; p = p->chain )
+			{
+				v = p->verts [ 0 ];
+				qglBegin( GL_POLYGON );
+
+				for ( i = 0; i < nv; i++, v += VERTEXSIZE )
+				{
+					qglMTexCoord2fSGIS( QGL_TEXTURE0, ( v [ 3 ] + scroll ), v [ 4 ] );
+					qglMTexCoord2fSGIS( QGL_TEXTURE1, v [ 5 ], v [ 6 ] );
+					qglVertex3fv( v );
+				}
+
+				qglEnd();
+			}
+		}
+		else
+		{
+			for ( p = surf->polys; p; p = p->chain )
+			{
+				v = p->verts [ 0 ];
+				qglBegin( GL_POLYGON );
+
+				for ( i = 0; i < nv; i++, v += VERTEXSIZE )
+				{
+					qglMTexCoord2fSGIS( QGL_TEXTURE0, v [ 3 ], v [ 4 ] );
+					qglMTexCoord2fSGIS( QGL_TEXTURE1, v [ 5 ], v [ 6 ] );
+					qglVertex3fv( v );
+				}
+
+				qglEnd();
+			}
+		}
+	}
+	else
+	{
+		c_brush_polys++;
+
+		R_MBind( QGL_TEXTURE0, image->texnum );
+		R_MBind( QGL_TEXTURE1, gl_state.lightmap_textures + lmtex );
+
+		if ( surf->texinfo->flags & SURF_FLOWING )
+		{
+			float scroll;
+
+			scroll = -64 * ( ( r_newrefdef.time / 40.0 ) - (int) ( r_newrefdef.time / 40.0 ) );
+
+			if ( scroll == 0.0 )
+			{
+				scroll = -64.0;
+			}
+
+			for ( p = surf->polys; p; p = p->chain )
+			{
+				v = p->verts [ 0 ];
+				qglBegin( GL_POLYGON );
+
+				for ( i = 0; i < nv; i++, v += VERTEXSIZE )
+				{
+					qglMTexCoord2fSGIS( QGL_TEXTURE0, ( v [ 3 ] + scroll ), v [ 4 ] );
+					qglMTexCoord2fSGIS( QGL_TEXTURE1, v [ 5 ], v [ 6 ] );
+					qglVertex3fv( v );
+				}
+
+				qglEnd();
+			}
+		}
+		else
+		{
+			for ( p = surf->polys; p; p = p->chain )
+			{
+				v = p->verts [ 0 ];
+				qglBegin( GL_POLYGON );
+
+				for ( i = 0; i < nv; i++, v += VERTEXSIZE )
+				{
+					qglMTexCoord2fSGIS( QGL_TEXTURE0, v [ 3 ], v [ 4 ] );
+					qglMTexCoord2fSGIS( QGL_TEXTURE1, v [ 5 ], v [ 6 ] );
+					qglVertex3fv( v );
+				}
+
+				qglEnd();
+			}
+		}
+	}
+}
+
 void
 R_DrawInlineBModel ( void )
 {
@@ -598,21 +828,30 @@ R_DrawInlineBModel ( void )
 			 ( !( psurf->flags & SURF_PLANEBACK ) && ( dot > BACKFACE_EPSILON ) ) )
 		{
 			if ( psurf->texinfo->flags & ( SURF_TRANS33 | SURF_TRANS66 ) )
-			{   
+			{
 				/* add to the translucent chain */
 				psurf->texturechain = r_alpha_surfaces;
 				r_alpha_surfaces = psurf;
 			}
+			else if ( qglMTexCoord2fSGIS && !( psurf->flags & SURF_DRAWTURB ) )
+			{
+				R_RenderLightmappedPoly( psurf );
+			}
 			else
 			{
+				R_EnableMultitexture( false );
 				R_RenderBrushPoly( psurf );
+				R_EnableMultitexture( true );
 			}
 		}
 	}
 
 	if ( !( currententity->flags & RF_TRANSLUCENT ) )
 	{
-		R_BlendLightmaps();
+		if ( !qglMTexCoord2fSGIS )
+		{
+			R_BlendLightmaps();
+		}
 	}
 	else
 	{
@@ -678,15 +917,19 @@ R_DrawBrushModel ( entity_t *e )
 
 	qglPushMatrix();
 	e->angles [ 0 ] = -e->angles [ 0 ];
-	e->angles [ 2 ] = -e->angles [ 2 ]; 
+	e->angles [ 2 ] = -e->angles [ 2 ];
 	R_RotateForEntity( e );
-	e->angles [ 0 ] = -e->angles [ 0 ]; 
+	e->angles [ 0 ] = -e->angles [ 0 ];
 	e->angles [ 2 ] = -e->angles [ 2 ];
 
+	R_EnableMultitexture( true );
+	R_SelectTexture( QGL_TEXTURE0 );
 	R_TexEnv( GL_REPLACE );
+	R_SelectTexture( QGL_TEXTURE1 );
 	R_TexEnv( GL_MODULATE );
 
 	R_DrawInlineBModel();
+	R_EnableMultitexture( false );
 
 	qglPopMatrix();
 }
@@ -746,8 +989,8 @@ R_RecursiveWorldNode ( mnode_t *node )
 		return;
 	}
 
-	/* node is just a decision point, so go down the apropriate sides 
-	   find which side of the node we are on */
+	/* node is just a decision point, so go down the apropriate sides
+	 * find which side of the node we are on */
 	plane = node->plane;
 
 	switch ( plane->type )
@@ -794,22 +1037,29 @@ R_RecursiveWorldNode ( mnode_t *node )
 		}
 
 		if ( surf->texinfo->flags & SURF_SKY )
-		{   
+		{
 			/* just adds to visible sky bounds */
 			R_AddSkySurface( surf );
 		}
 		else if ( surf->texinfo->flags & ( SURF_TRANS33 | SURF_TRANS66 ) )
-		{   
+		{
 			/* add to the translucent chain */
 			surf->texturechain = r_alpha_surfaces;
 			r_alpha_surfaces = surf;
 		}
 		else
 		{
-			/* the polygon is visible, so add it to the texture */
-			image = R_TextureAnimation( surf->texinfo );
-			surf->texturechain = image->texturechain;
-			image->texturechain = surf;
+			if ( qglMTexCoord2fSGIS && !( surf->flags & SURF_DRAWTURB ) )
+			{
+				R_RenderLightmappedPoly( surf );
+			}
+			else
+			{
+				/* the polygon is visible, so add it to the texture sorted chain */
+				image = R_TextureAnimation( surf->texinfo );
+				surf->texturechain = image->texturechain;
+				image->texturechain = surf;
+			}
 		}
 	}
 
@@ -846,7 +1096,32 @@ R_DrawWorld ( void )
 	qglColor3f( 1, 1, 1 );
 	memset( gl_lms.lightmap_surfaces, 0, sizeof ( gl_lms.lightmap_surfaces ) );
 	R_ClearSkyBox();
-	R_RecursiveWorldNode( r_worldmodel->nodes );
+
+	if ( qglMTexCoord2fSGIS )
+	{
+		R_EnableMultitexture( true );
+
+		R_SelectTexture( QGL_TEXTURE0 );
+		R_TexEnv( GL_REPLACE );
+		R_SelectTexture( QGL_TEXTURE1 );
+
+		if ( gl_lightmap->value )
+		{
+			R_TexEnv( GL_REPLACE );
+		}
+		else
+		{
+			R_TexEnv( GL_MODULATE );
+		}
+
+		R_RecursiveWorldNode( r_worldmodel->nodes );
+
+		R_EnableMultitexture( false );
+	}
+	else
+	{
+		R_RecursiveWorldNode( r_worldmodel->nodes );
+	}
 
 	R_DrawTextureChains();
 	R_BlendLightmaps();
@@ -877,7 +1152,7 @@ R_MarkLeaves ( void )
 	}
 
 	/* development aid to let you run around and see exactly where
-	   the pvs ends */
+	 * the pvs ends */
 	if ( gl_lockpvs->value )
 	{
 		return;