[iortcw] 56/89: All: Allow more than 32 surfaces in skin files

Simon McVittie smcv at debian.org
Fri Sep 8 10:44:27 UTC 2017


This is an automated email from the git hooks/post-receive script.

smcv pushed a commit to tag 1.51b
in repository iortcw.

commit f040cfb7f42ebb6a60f921f13f77c80c22187002
Author: MAN-AT-ARMS <M4N4T4RMS at gmail.com>
Date:   Thu Jul 20 10:53:36 2017 -0400

    All: Allow more than 32 surfaces in skin files
---
 MP/code/rend2/tr_animation.c    | 18 +++++++++++-------
 MP/code/rend2/tr_image.c        | 23 ++++++++++++++---------
 MP/code/rend2/tr_local.h        | 16 +++++++++++-----
 MP/code/rend2/tr_mesh.c         |  9 ++++-----
 MP/code/rend2/tr_model_iqm.c    |  9 +++++++--
 MP/code/renderer/tr_animation.c | 18 +++++++++++-------
 MP/code/renderer/tr_cmesh.c     | 10 ++++------
 MP/code/renderer/tr_image.c     | 23 ++++++++++++++---------
 MP/code/renderer/tr_local.h     | 16 +++++++++++-----
 MP/code/renderer/tr_mesh.c      | 12 ++++--------
 MP/code/renderer/tr_model_iqm.c |  9 +++++++--
 SP/code/rend2/tr_animation.c    | 14 +++++++++-----
 SP/code/rend2/tr_image.c        | 23 ++++++++++++++---------
 SP/code/rend2/tr_local.h        | 16 +++++++++++-----
 SP/code/rend2/tr_mesh.c         |  4 ++--
 SP/code/rend2/tr_model_iqm.c    |  9 +++++++--
 SP/code/renderer/tr_animation.c | 14 +++++++++-----
 SP/code/renderer/tr_cmesh.c     | 25 +++++++++++--------------
 SP/code/renderer/tr_image.c     | 23 ++++++++++++++---------
 SP/code/renderer/tr_local.h     | 16 +++++++++++-----
 SP/code/renderer/tr_mesh.c      | 24 +++++++++++-------------
 SP/code/renderer/tr_model_iqm.c |  9 +++++++--
 22 files changed, 204 insertions(+), 136 deletions(-)

diff --git a/MP/code/rend2/tr_animation.c b/MP/code/rend2/tr_animation.c
index 80b7679..7cfd936 100644
--- a/MP/code/rend2/tr_animation.c
+++ b/MP/code/rend2/tr_animation.c
@@ -355,8 +355,8 @@ void R_AddAnimSurfaces( trRefEntity_t *ent ) {
 			if ( ent->e.renderfx & RF_BLINK ) {
 				const char *s = va( "%s_b", surface->name );   // append '_b' for 'blink'
 				for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
-					if ( !strcmp( skin->surfaces[j]->name, s ) ) {
-						shader = skin->surfaces[j]->shader;
+					if ( !strcmp( skin->surfaces[j].name, s ) ) {
+						shader = skin->surfaces[j].shader;
 						break;
 					}
 				}
@@ -366,8 +366,8 @@ void R_AddAnimSurfaces( trRefEntity_t *ent ) {
 				for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
 					// the names have both been lowercased
 
-					if ( !strcmp( skin->surfaces[j]->name, surface->name ) ) {
-						shader = skin->surfaces[j]->shader;
+					if ( !strcmp( skin->surfaces[j].name, surface->name ) ) {
+						shader = skin->surfaces[j].shader;
 						break;
 					}
 				}
@@ -1605,9 +1605,9 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) {
 			
 			for(j = 0; j < skin->numSurfaces; j++)
 			{
-				if (!strcmp(skin->surfaces[j]->name, surface->name))
+				if (!strcmp(skin->surfaces[j].name, surface->name))
 				{
-					shader = skin->surfaces[j]->shader;
+					shader = skin->surfaces[j].shader;
 					break;
 				}
 			}
@@ -1638,7 +1638,11 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) {
 			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse, qfalse, 0 );
 		}
 
-		if (!personalModel)
+		// for testing polygon shadows (on /all/ models)
+		if ( r_shadows->integer == 4 )
+			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse, qfalse, 0 );
+
+		if ( !personalModel )
 			R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse, qfalse, cubemapIndex );
 
 		surface = (mdrSurface_t *)( (byte *)surface + surface->ofsEnd );
diff --git a/MP/code/rend2/tr_image.c b/MP/code/rend2/tr_image.c
index dca835f..834dc2a 100644
--- a/MP/code/rend2/tr_image.c
+++ b/MP/code/rend2/tr_image.c
@@ -3223,6 +3223,7 @@ RE_RegisterSkin
 ===============
 */
 qhandle_t RE_RegisterSkin( const char *name ) {
+	skinSurface_t parseSurfaces[MAX_SKIN_SURFACES];
 	qhandle_t hSkin;
 	skin_t      *skin;
 	skinSurface_t   *surf;
@@ -3279,8 +3280,8 @@ qhandle_t RE_RegisterSkin( const char *name ) {
 		skin->numSurfaces   = 0;
 		skin->numModels     = 0;    //----(SA) added
 		skin->numSurfaces = 1;
-		skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low );
-		skin->surfaces[0]->shader = R_FindShader( name, LIGHTMAP_NONE, qtrue );
+		skin->surfaces = ri.Hunk_Alloc( sizeof( skinSurface_t ), h_low );
+		skin->surfaces[0].shader = R_FindShader( name, LIGHTMAP_NONE, qtrue );
 		return hSkin;
 	}
 
@@ -3350,12 +3351,12 @@ qhandle_t RE_RegisterSkin( const char *name ) {
 		// parse the shader name
 		token = CommaParse( &text_p );
 
-		if ( skin->numSurfaces >= MD3_MAX_SURFACES ) {
-			ri.Printf( PRINT_WARNING, "WARNING: Ignoring surfaces in '%s', the max is %d surfaces!\n", name, MD3_MAX_SURFACES );
+		if ( skin->numSurfaces >= MAX_SKIN_SURFACES ) {
+			ri.Printf( PRINT_WARNING, "WARNING: Ignoring surfaces in '%s', the max is %d surfaces!\n", name, MAX_SKIN_SURFACES );
 			break;
 		}
 
-		surf = skin->surfaces[ skin->numSurfaces ] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low );
+		surf = &parseSurfaces[skin->numSurfaces];
 		Q_strncpyz( surf->name, surfName, sizeof( surf->name ) );
 		surf->shader = R_FindShader( token, LIGHTMAP_NONE, qtrue );
 		skin->numSurfaces++;
@@ -3374,6 +3375,10 @@ qhandle_t RE_RegisterSkin( const char *name ) {
 		}
 	}
 
+	// copy surfaces to skin
+	skin->surfaces = ri.Hunk_Alloc( skin->numSurfaces * sizeof( skinSurface_t ), h_low );
+	memcpy( skin->surfaces, parseSurfaces, skin->numSurfaces * sizeof( skinSurface_t ) );
+
 	return hSkin;
 }
 
@@ -3392,8 +3397,8 @@ void    R_InitSkins( void ) {
 	skin = tr.skins[0] = ri.Hunk_Alloc( sizeof( skin_t ), h_low );
 	Q_strncpyz( skin->name, "<default skin>", sizeof( skin->name )  );
 	skin->numSurfaces = 1;
-	skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low );
-	skin->surfaces[0]->shader = tr.defaultShader;
+	skin->surfaces = ri.Hunk_Alloc( sizeof( skinSurface_t ), h_low );
+	skin->surfaces[0].shader = tr.defaultShader;
 }
 
 /*
@@ -3422,10 +3427,10 @@ void    R_SkinList_f( void ) {
 	for ( i = 0 ; i < tr.numSkins ; i++ ) {
 		skin = tr.skins[i];
 
-		ri.Printf( PRINT_ALL, "%3i:%s\n", i, skin->name );
+		ri.Printf( PRINT_ALL, "%3i:%s (%d surfaces)\n", i, skin->name, skin->numSurfaces );
 		for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
 			ri.Printf( PRINT_ALL, "       %s = %s\n",
-					   skin->surfaces[j]->name, skin->surfaces[j]->shader->name );
+				skin->surfaces[j].name, skin->surfaces[j].shader->name );
 		}
 	}
 	ri.Printf( PRINT_ALL, "------------------\n" );
diff --git a/MP/code/rend2/tr_local.h b/MP/code/rend2/tr_local.h
index 3895bfd..cc146d1 100644
--- a/MP/code/rend2/tr_local.h
+++ b/MP/code/rend2/tr_local.h
@@ -860,6 +860,12 @@ typedef struct {
 
 //=================================================================================
 
+// max surfaces per-skin
+// This is an arbitry limit. Vanilla Q3 only supported 32 surfaces in skins but failed to
+// enforce the maximum limit when reading skin files. It was possile to use more than 32
+// surfaces which accessed out of bounds memory past end of skin->surfaces hunk block.
+#define MAX_SKIN_SURFACES	256
+
 // skins allow models to be retextured without modifying the model file
 typedef struct {
 	char name[MAX_QPATH];
@@ -870,17 +876,17 @@ typedef struct {
 #define MAX_PART_MODELS 5
 
 typedef struct {
-	char type[MAX_QPATH];           // md3_lower, md3_lbelt, md3_rbelt, etc.
-	char model[MAX_QPATH];          // lower.md3, belt1.md3, etc.
+	char type[MAX_QPATH];		// md3_lower, md3_lbelt, md3_rbelt, etc.
+	char model[MAX_QPATH];		// lower.md3, belt1.md3, etc.
 } skinModel_t;
 
 typedef struct skin_s {
-	char name[MAX_QPATH];               // game path, including extension
+	char name[MAX_QPATH];		// game path, including extension
 	int numSurfaces;
 	int numModels;
-	skinSurface_t   *surfaces[MD3_MAX_SURFACES];
+	skinSurface_t	*surfaces;	// dynamically allocated array of surfaces
 	skinModel_t     *models[MAX_PART_MODELS];
-	vec3_t scale;       //----(SA)	added
+	vec3_t scale;			//----(SA)	added
 } skin_t;
 //----(SA) end
 
diff --git a/MP/code/rend2/tr_mesh.c b/MP/code/rend2/tr_mesh.c
index 695491f..538fe1e 100644
--- a/MP/code/rend2/tr_mesh.c
+++ b/MP/code/rend2/tr_mesh.c
@@ -382,8 +382,8 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) {
 			if ( ent->e.renderfx & RF_BLINK ) {
 				const char *s = va( "%s_b", surface->name );   // append '_b' for 'blink'
 				for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
-					if ( !strcmp( skin->surfaces[j]->name, s ) ) {
-						shader = skin->surfaces[j]->shader;
+					if ( !strcmp( skin->surfaces[j].name, s ) ) {
+						shader = skin->surfaces[j].shader;
 						break;
 					}
 				}
@@ -392,9 +392,8 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) {
 			if ( shader == tr.defaultShader ) {    // blink reference in skin was not found
 				for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
 					// the names have both been lowercased
-
-					if ( !strcmp( skin->surfaces[j]->name, surface->name ) ) {
-						shader = skin->surfaces[j]->shader;
+					if ( !strcmp( skin->surfaces[j].name, surface->name ) ) {
+						shader = skin->surfaces[j].shader;
 						break;
 					}
 				}
diff --git a/MP/code/rend2/tr_model_iqm.c b/MP/code/rend2/tr_model_iqm.c
index 5b528d0..507158c 100644
--- a/MP/code/rend2/tr_model_iqm.c
+++ b/MP/code/rend2/tr_model_iqm.c
@@ -907,9 +907,9 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) {
 
 			for(j = 0; j < skin->numSurfaces; j++)
 			{
-				if (!strcmp(skin->surfaces[j]->name, surface->name))
+				if (!strcmp(skin->surfaces[j].name, surface->name))
 				{
-					shader = skin->surfaces[j]->shader;
+					shader = skin->surfaces[j].shader;
 					break;
 				}
 			}
@@ -936,6 +936,11 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) {
 			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, 0, 0, 0 );
 		}
 
+		// for testing polygon shadows (on /all/ models)
+		if ( r_shadows->integer == 4 ) {
+			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse, qfalse, 0 );
+		}
+
 		if( !personalModel ) {
 			R_AddDrawSurf( (void *)surface, shader, fogNum, 0, 0, cubemapIndex );
 		}
diff --git a/MP/code/renderer/tr_animation.c b/MP/code/renderer/tr_animation.c
index ce92d56..2dc73b8 100644
--- a/MP/code/renderer/tr_animation.c
+++ b/MP/code/renderer/tr_animation.c
@@ -353,8 +353,8 @@ void R_AddAnimSurfaces( trRefEntity_t *ent ) {
 			if ( ent->e.renderfx & RF_BLINK ) {
 				const char *s = va( "%s_b", surface->name );   // append '_b' for 'blink'
 				for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
-					if ( !strcmp( skin->surfaces[j]->name, s ) ) {
-						shader = skin->surfaces[j]->shader;
+					if ( !strcmp( skin->surfaces[j].name, s ) ) {
+						shader = skin->surfaces[j].shader;
 						break;
 					}
 				}
@@ -364,8 +364,8 @@ void R_AddAnimSurfaces( trRefEntity_t *ent ) {
 				for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
 					// the names have both been lowercased
 
-					if ( !strcmp( skin->surfaces[j]->name, surface->name ) ) {
-						shader = skin->surfaces[j]->shader;
+					if ( !strcmp( skin->surfaces[j].name, surface->name ) ) {
+						shader = skin->surfaces[j].shader;
 						break;
 					}
 				}
@@ -1603,9 +1603,9 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) {
 			
 			for(j = 0; j < skin->numSurfaces; j++)
 			{
-				if (!strcmp(skin->surfaces[j]->name, surface->name))
+				if (!strcmp(skin->surfaces[j].name, surface->name))
 				{
-					shader = skin->surfaces[j]->shader;
+					shader = skin->surfaces[j].shader;
 					break;
 				}
 			}
@@ -1636,7 +1636,11 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) {
 			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse );
 		}
 
-		if (!personalModel)
+		// for testing polygon shadows (on /all/ models)
+		if ( r_shadows->integer == 4 )
+			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse );
+
+		if ( !personalModel )
 			R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse );
 
 		surface = (mdrSurface_t *)( (byte *)surface + surface->ofsEnd );
diff --git a/MP/code/renderer/tr_cmesh.c b/MP/code/renderer/tr_cmesh.c
index aca1fea..365e461 100644
--- a/MP/code/renderer/tr_cmesh.c
+++ b/MP/code/renderer/tr_cmesh.c
@@ -376,8 +376,8 @@ void R_AddMDCSurfaces( trRefEntity_t *ent ) {
 			if ( ent->e.renderfx & RF_BLINK ) {
 				const char *s = va( "%s_b", surface->name );   // append '_b' for 'blink'
 				for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
-					if ( !strcmp( skin->surfaces[j]->name, s ) ) {
-						shader = skin->surfaces[j]->shader;
+					if ( !strcmp( skin->surfaces[j].name, s ) ) {
+						shader = skin->surfaces[j].shader;
 						break;
 					}
 				}
@@ -387,8 +387,8 @@ void R_AddMDCSurfaces( trRefEntity_t *ent ) {
 				for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
 					// the names have both been lowercased
 
-					if ( !strcmp( skin->surfaces[j]->name, surface->name ) ) {
-						shader = skin->surfaces[j]->shader;
+					if ( !strcmp( skin->surfaces[j].name, surface->name ) ) {
+						shader = skin->surfaces[j].shader;
 						break;
 					}
 				}
@@ -426,7 +426,6 @@ void R_AddMDCSurfaces( trRefEntity_t *ent ) {
 		if ( r_shadows->integer == 4 ) {
 			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse );
 		}
-
 //----(SA)	done testing
 
 		// don't add third_person objects if not viewing through a portal
@@ -436,6 +435,5 @@ void R_AddMDCSurfaces( trRefEntity_t *ent ) {
 
 		surface = ( mdcSurface_t * )( (byte *)surface + surface->ofsEnd );
 	}
-
 }
 
diff --git a/MP/code/renderer/tr_image.c b/MP/code/renderer/tr_image.c
index 6b3ce45..402f117 100644
--- a/MP/code/renderer/tr_image.c
+++ b/MP/code/renderer/tr_image.c
@@ -1879,6 +1879,7 @@ RE_RegisterSkin
 ===============
 */
 qhandle_t RE_RegisterSkin( const char *name ) {
+	skinSurface_t parseSurfaces[MAX_SKIN_SURFACES];
 	qhandle_t hSkin;
 	skin_t      *skin;
 	skinSurface_t   *surf;
@@ -1935,8 +1936,8 @@ qhandle_t RE_RegisterSkin( const char *name ) {
 		skin->numSurfaces   = 0;
 		skin->numModels     = 0;    //----(SA) added
 		skin->numSurfaces = 1;
-		skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low );
-		skin->surfaces[0]->shader = R_FindShader( name, LIGHTMAP_NONE, qtrue );
+		skin->surfaces = ri.Hunk_Alloc( sizeof( skinSurface_t ), h_low );
+		skin->surfaces[0].shader = R_FindShader( name, LIGHTMAP_NONE, qtrue );
 		return hSkin;
 	}
 
@@ -2006,12 +2007,12 @@ qhandle_t RE_RegisterSkin( const char *name ) {
 		// parse the shader name
 		token = CommaParse( &text_p );
 
-		if ( skin->numSurfaces >= MD3_MAX_SURFACES ) {
-			ri.Printf( PRINT_WARNING, "WARNING: Ignoring surfaces in '%s', the max is %d surfaces!\n", name, MD3_MAX_SURFACES );
+		if ( skin->numSurfaces >= MAX_SKIN_SURFACES ) {
+			ri.Printf( PRINT_WARNING, "WARNING: Ignoring surfaces in '%s', the max is %d surfaces!\n", name, MAX_SKIN_SURFACES );
 			break;
 		}
 
-		surf = skin->surfaces[ skin->numSurfaces ] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low );
+		surf = &parseSurfaces[skin->numSurfaces];
 		Q_strncpyz( surf->name, surfName, sizeof( surf->name ) );
 		surf->shader = R_FindShader( token, LIGHTMAP_NONE, qtrue );
 		skin->numSurfaces++;
@@ -2030,6 +2031,10 @@ qhandle_t RE_RegisterSkin( const char *name ) {
 		}
 	}
 
+	// copy surfaces to skin
+	skin->surfaces = ri.Hunk_Alloc( skin->numSurfaces * sizeof( skinSurface_t ), h_low );
+	memcpy( skin->surfaces, parseSurfaces, skin->numSurfaces * sizeof( skinSurface_t ) );
+
 	return hSkin;
 }
 
@@ -2048,8 +2053,8 @@ void    R_InitSkins( void ) {
 	skin = tr.skins[0] = ri.Hunk_Alloc( sizeof( skin_t ), h_low );
 	Q_strncpyz( skin->name, "<default skin>", sizeof( skin->name )  );
 	skin->numSurfaces = 1;
-	skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low );
-	skin->surfaces[0]->shader = tr.defaultShader;
+	skin->surfaces = ri.Hunk_Alloc( sizeof( skinSurface_t ), h_low );
+	skin->surfaces[0].shader = tr.defaultShader;
 }
 
 /*
@@ -2078,10 +2083,10 @@ void    R_SkinList_f( void ) {
 	for ( i = 0 ; i < tr.numSkins ; i++ ) {
 		skin = tr.skins[i];
 
-		ri.Printf( PRINT_ALL, "%3i:%s\n", i, skin->name );
+		ri.Printf( PRINT_ALL, "%3i:%s (%d surfaces)\n", i, skin->name, skin->numSurfaces );
 		for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
 			ri.Printf( PRINT_ALL, "       %s = %s\n",
-					   skin->surfaces[j]->name, skin->surfaces[j]->shader->name );
+				skin->surfaces[j].name, skin->surfaces[j].shader->name );
 		}
 	}
 	ri.Printf( PRINT_ALL, "------------------\n" );
diff --git a/MP/code/renderer/tr_local.h b/MP/code/renderer/tr_local.h
index c036572..e0722f6 100644
--- a/MP/code/renderer/tr_local.h
+++ b/MP/code/renderer/tr_local.h
@@ -502,6 +502,12 @@ typedef struct {
 
 //=================================================================================
 
+// max surfaces per-skin
+// This is an arbitry limit. Vanilla Q3 only supported 32 surfaces in skins but failed to
+// enforce the maximum limit when reading skin files. It was possile to use more than 32
+// surfaces which accessed out of bounds memory past end of skin->surfaces hunk block.
+#define MAX_SKIN_SURFACES	256
+
 // skins allow models to be retextured without modifying the model file
 typedef struct {
 	char name[MAX_QPATH];
@@ -512,17 +518,17 @@ typedef struct {
 #define MAX_PART_MODELS 5
 
 typedef struct {
-	char type[MAX_QPATH];           // md3_lower, md3_lbelt, md3_rbelt, etc.
-	char model[MAX_QPATH];          // lower.md3, belt1.md3, etc.
+	char type[MAX_QPATH];		// md3_lower, md3_lbelt, md3_rbelt, etc.
+	char model[MAX_QPATH];		// lower.md3, belt1.md3, etc.
 } skinModel_t;
 
 typedef struct skin_s {
-	char name[MAX_QPATH];               // game path, including extension
+	char name[MAX_QPATH];		// game path, including extension
 	int numSurfaces;
 	int numModels;
-	skinSurface_t   *surfaces[MD3_MAX_SURFACES];
+	skinSurface_t	*surfaces;	// dynamically allocated array of surfaces
 	skinModel_t     *models[MAX_PART_MODELS];
-	vec3_t scale;       //----(SA)	added
+	vec3_t scale;			//----(SA)	added
 } skin_t;
 //----(SA) end
 
diff --git a/MP/code/renderer/tr_mesh.c b/MP/code/renderer/tr_mesh.c
index e3deb99..8cf262c 100644
--- a/MP/code/renderer/tr_mesh.c
+++ b/MP/code/renderer/tr_mesh.c
@@ -378,8 +378,8 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) {
 			if ( ent->e.renderfx & RF_BLINK ) {
 				const char *s = va( "%s_b", surface->name );   // append '_b' for 'blink'
 				for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
-					if ( !strcmp( skin->surfaces[j]->name, s ) ) {
-						shader = skin->surfaces[j]->shader;
+					if ( !strcmp( skin->surfaces[j].name, s ) ) {
+						shader = skin->surfaces[j].shader;
 						break;
 					}
 				}
@@ -388,9 +388,8 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) {
 			if ( shader == tr.defaultShader ) {    // blink reference in skin was not found
 				for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
 					// the names have both been lowercased
-
-					if ( !strcmp( skin->surfaces[j]->name, surface->name ) ) {
-						shader = skin->surfaces[j]->shader;
+					if ( !strcmp( skin->surfaces[j].name, surface->name ) ) {
+						shader = skin->surfaces[j].shader;
 						break;
 					}
 				}
@@ -430,13 +429,11 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) {
 			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse );
 		}
 
-
 		// for testing polygon shadows (on /all/ models)
 		if ( r_shadows->integer == 4 ) {
 			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse );
 		}
 
-
 		// don't add third_person objects if not viewing through a portal
 		if ( !personalModel ) {
 			R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse );
@@ -444,6 +441,5 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) {
 
 		surface = ( md3Surface_t * )( (byte *)surface + surface->ofsEnd );
 	}
-
 }
 
diff --git a/MP/code/renderer/tr_model_iqm.c b/MP/code/renderer/tr_model_iqm.c
index b6f570e..370fc45 100644
--- a/MP/code/renderer/tr_model_iqm.c
+++ b/MP/code/renderer/tr_model_iqm.c
@@ -903,9 +903,9 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) {
 
 			for(j = 0; j < skin->numSurfaces; j++)
 			{
-				if (!strcmp(skin->surfaces[j]->name, surface->name))
+				if (!strcmp(skin->surfaces[j].name, surface->name))
 				{
-					shader = skin->surfaces[j]->shader;
+					shader = skin->surfaces[j].shader;
 					break;
 				}
 			}
@@ -932,6 +932,11 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) {
 			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, 0 );
 		}
 
+		// for testing polygon shadows (on /all/ models)
+		if ( r_shadows->integer == 4 ) {
+			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse );
+		}
+
 		if( !personalModel ) {
 			R_AddDrawSurf( (void *)surface, shader, fogNum, 0 );
 		}
diff --git a/SP/code/rend2/tr_animation.c b/SP/code/rend2/tr_animation.c
index 5d24a33..d7c9d7c 100644
--- a/SP/code/rend2/tr_animation.c
+++ b/SP/code/rend2/tr_animation.c
@@ -387,8 +387,8 @@ void R_AddAnimSurfaces( trRefEntity_t *ent ) {
 			shader = tr.defaultShader;
 			for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
 				// the names have both been lowercased
-				if ( !strcmp( skin->surfaces[j]->name, surface->name ) ) {
-					shader = skin->surfaces[j]->shader;
+				if ( !strcmp( skin->surfaces[j].name, surface->name ) ) {
+					shader = skin->surfaces[j].shader;
 					break;
 				}
 			}
@@ -1598,9 +1598,9 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) {
 			
 			for(j = 0; j < skin->numSurfaces; j++)
 			{
-				if (!strcmp(skin->surfaces[j]->name, surface->name))
+				if (!strcmp(skin->surfaces[j].name, surface->name))
 				{
-					shader = skin->surfaces[j]->shader;
+					shader = skin->surfaces[j].shader;
 					break;
 				}
 			}
@@ -1631,7 +1631,11 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) {
 			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse, qfalse, 0, ATI_TESS_TRUFORM );
 		}
 
-		if (!personalModel)
+		// for testing polygon shadows (on /all/ models)
+		if ( r_shadows->integer == 4 )
+			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse, qfalse, 0, ATI_TESS_TRUFORM );
+
+		if ( !personalModel )
 			R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse, qfalse, cubemapIndex, ATI_TESS_TRUFORM );
 
 		surface = (mdrSurface_t *)( (byte *)surface + surface->ofsEnd );
diff --git a/SP/code/rend2/tr_image.c b/SP/code/rend2/tr_image.c
index 56e8ab4..32b9c83 100644
--- a/SP/code/rend2/tr_image.c
+++ b/SP/code/rend2/tr_image.c
@@ -3228,6 +3228,7 @@ RE_RegisterSkin
 ===============
 */
 qhandle_t RE_RegisterSkin( const char *name ) {
+	skinSurface_t parseSurfaces[MAX_SKIN_SURFACES];
 	qhandle_t hSkin;
 	skin_t      *skin;
 	skinSurface_t   *surf;
@@ -3284,8 +3285,8 @@ qhandle_t RE_RegisterSkin( const char *name ) {
 		skin->numSurfaces   = 0;
 		skin->numModels     = 0;    //----(SA) added
 		skin->numSurfaces = 1;
-		skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low );
-		skin->surfaces[0]->shader = R_FindShader( name, LIGHTMAP_NONE, qtrue );
+		skin->surfaces = ri.Hunk_Alloc( sizeof( skinSurface_t ), h_low );
+		skin->surfaces[0].shader = R_FindShader( name, LIGHTMAP_NONE, qtrue );
 		return hSkin;
 	}
 
@@ -3355,12 +3356,12 @@ qhandle_t RE_RegisterSkin( const char *name ) {
 		// parse the shader name
 		token = CommaParse( &text_p );
 
-		if ( skin->numSurfaces >= MD3_MAX_SURFACES ) {
-			ri.Printf( PRINT_WARNING, "WARNING: Ignoring surfaces in '%s', the max is %d surfaces!\n", name, MD3_MAX_SURFACES );
+		if ( skin->numSurfaces >= MAX_SKIN_SURFACES ) {
+			ri.Printf( PRINT_WARNING, "WARNING: Ignoring surfaces in '%s', the max is %d surfaces!\n", name, MAX_SKIN_SURFACES );
 			break;
 		}
 
-		surf = skin->surfaces[ skin->numSurfaces ] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low );
+		surf = &parseSurfaces[skin->numSurfaces];
 		Q_strncpyz( surf->name, surfName, sizeof( surf->name ) );
 		surf->shader = R_FindShader( token, LIGHTMAP_NONE, qtrue );
 		skin->numSurfaces++;
@@ -3379,6 +3380,10 @@ qhandle_t RE_RegisterSkin( const char *name ) {
 		}
 	}
 
+	// copy surfaces to skin
+	skin->surfaces = ri.Hunk_Alloc( skin->numSurfaces * sizeof( skinSurface_t ), h_low );
+	memcpy( skin->surfaces, parseSurfaces, skin->numSurfaces * sizeof( skinSurface_t ) );
+
 	return hSkin;
 }
 
@@ -3397,8 +3402,8 @@ void    R_InitSkins( void ) {
 	skin = tr.skins[0] = ri.Hunk_Alloc( sizeof( skin_t ), h_low );
 	Q_strncpyz( skin->name, "<default skin>", sizeof( skin->name )  );
 	skin->numSurfaces = 1;
-	skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low );
-	skin->surfaces[0]->shader = tr.defaultShader;
+	skin->surfaces = ri.Hunk_Alloc( sizeof( skinSurface_t ), h_low );
+	skin->surfaces[0].shader = tr.defaultShader;
 }
 
 /*
@@ -3427,10 +3432,10 @@ void    R_SkinList_f( void ) {
 	for ( i = 0 ; i < tr.numSkins ; i++ ) {
 		skin = tr.skins[i];
 
-		ri.Printf( PRINT_ALL, "%3i:%s\n", i, skin->name );
+		ri.Printf( PRINT_ALL, "%3i:%s (%d surfaces)\n", i, skin->name, skin->numSurfaces );
 		for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
 			ri.Printf( PRINT_ALL, "       %s = %s\n",
-					   skin->surfaces[j]->name, skin->surfaces[j]->shader->name );
+				skin->surfaces[j].name, skin->surfaces[j].shader->name );
 		}
 	}
 	ri.Printf( PRINT_ALL, "------------------\n" );
diff --git a/SP/code/rend2/tr_local.h b/SP/code/rend2/tr_local.h
index 73b22c1..cf78ef2 100644
--- a/SP/code/rend2/tr_local.h
+++ b/SP/code/rend2/tr_local.h
@@ -864,6 +864,12 @@ typedef struct {
 
 //=================================================================================
 
+// max surfaces per-skin
+// This is an arbitry limit. Vanilla Q3 only supported 32 surfaces in skins but failed to
+// enforce the maximum limit when reading skin files. It was possile to use more than 32
+// surfaces which accessed out of bounds memory past end of skin->surfaces hunk block.
+#define MAX_SKIN_SURFACES	256
+
 // skins allow models to be retextured without modifying the model file
 typedef struct {
 	char name[MAX_QPATH];
@@ -874,17 +880,17 @@ typedef struct {
 #define MAX_PART_MODELS 5
 
 typedef struct {
-	char type[MAX_QPATH];           // md3_lower, md3_lbelt, md3_rbelt, etc.
-	char model[MAX_QPATH];          // lower.md3, belt1.md3, etc.
+	char type[MAX_QPATH];		// md3_lower, md3_lbelt, md3_rbelt, etc.
+	char model[MAX_QPATH];		// lower.md3, belt1.md3, etc.
 } skinModel_t;
 
 typedef struct skin_s {
-	char name[MAX_QPATH];               // game path, including extension
+	char name[MAX_QPATH];		// game path, including extension
 	int numSurfaces;
 	int numModels;
-	skinSurface_t   *surfaces[MD3_MAX_SURFACES];
+	skinSurface_t	*surfaces;	// dynamically allocated array of surfaces
 	skinModel_t     *models[MAX_PART_MODELS];
-	vec3_t scale;       //----(SA)	added
+	vec3_t scale;			//----(SA)	added
 } skin_t;
 //----(SA) end
 
diff --git a/SP/code/rend2/tr_mesh.c b/SP/code/rend2/tr_mesh.c
index 15902d6..bbfbc69 100644
--- a/SP/code/rend2/tr_mesh.c
+++ b/SP/code/rend2/tr_mesh.c
@@ -411,8 +411,8 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) {
 			shader = tr.defaultShader;
 			for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
 				// the names have both been lowercased
-				if ( !strcmp( skin->surfaces[j]->name, surface->name ) ) {
-					shader = skin->surfaces[j]->shader;
+				if ( !strcmp( skin->surfaces[j].name, surface->name ) ) {
+					shader = skin->surfaces[j].shader;
 					break;
 				}
 			}
diff --git a/SP/code/rend2/tr_model_iqm.c b/SP/code/rend2/tr_model_iqm.c
index deabf42..5274c0e 100644
--- a/SP/code/rend2/tr_model_iqm.c
+++ b/SP/code/rend2/tr_model_iqm.c
@@ -907,9 +907,9 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) {
 
 			for(j = 0; j < skin->numSurfaces; j++)
 			{
-				if (!strcmp(skin->surfaces[j]->name, surface->name))
+				if (!strcmp(skin->surfaces[j].name, surface->name))
 				{
-					shader = skin->surfaces[j]->shader;
+					shader = skin->surfaces[j].shader;
 					break;
 				}
 			}
@@ -936,6 +936,11 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) {
 			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, 0, 0, 0, ATI_TESS_TRUFORM );
 		}
 
+		// for testing polygon shadows (on /all/ models)
+		if ( r_shadows->integer == 4 ) {
+			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse, qfalse, 0, ATI_TESS_TRUFORM );
+		}
+
 		if( !personalModel ) {
 			R_AddDrawSurf( (void *)surface, shader, fogNum, 0, 0, cubemapIndex, ATI_TESS_TRUFORM );
 		}
diff --git a/SP/code/renderer/tr_animation.c b/SP/code/renderer/tr_animation.c
index e0f4bc6..8b31d55 100644
--- a/SP/code/renderer/tr_animation.c
+++ b/SP/code/renderer/tr_animation.c
@@ -385,8 +385,8 @@ void R_AddAnimSurfaces( trRefEntity_t *ent ) {
 			shader = tr.defaultShader;
 			for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
 				// the names have both been lowercased
-				if ( !strcmp( skin->surfaces[j]->name, surface->name ) ) {
-					shader = skin->surfaces[j]->shader;
+				if ( !strcmp( skin->surfaces[j].name, surface->name ) ) {
+					shader = skin->surfaces[j].shader;
 					break;
 				}
 			}
@@ -1593,9 +1593,9 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) {
 			
 			for(j = 0; j < skin->numSurfaces; j++)
 			{
-				if (!strcmp(skin->surfaces[j]->name, surface->name))
+				if (!strcmp(skin->surfaces[j].name, surface->name))
 				{
-					shader = skin->surfaces[j]->shader;
+					shader = skin->surfaces[j].shader;
 					break;
 				}
 			}
@@ -1626,7 +1626,11 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) {
 			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse, ATI_TESS_TRUFORM );
 		}
 
-		if (!personalModel)
+		// for testing polygon shadows (on /all/ models)
+		if ( r_shadows->integer == 4 )
+			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse, ATI_TESS_TRUFORM );
+
+		if ( !personalModel )
 			R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse, ATI_TESS_TRUFORM );
 
 		surface = (mdrSurface_t *)( (byte *)surface + surface->ofsEnd );
diff --git a/SP/code/renderer/tr_cmesh.c b/SP/code/renderer/tr_cmesh.c
index 607251f..23550ad 100644
--- a/SP/code/renderer/tr_cmesh.c
+++ b/SP/code/renderer/tr_cmesh.c
@@ -407,8 +407,8 @@ void R_AddMDCSurfaces( trRefEntity_t *ent ) {
 			shader = tr.defaultShader;
 			for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
 				// the names have both been lowercased
-				if ( !strcmp( skin->surfaces[j]->name, surface->name ) ) {
-					shader = skin->surfaces[j]->shader;
+				if ( !strcmp( skin->surfaces[j].name, surface->name ) ) {
+					shader = skin->surfaces[j].shader;
 					break;
 				}
 			}
@@ -433,20 +433,18 @@ void R_AddMDCSurfaces( trRefEntity_t *ent ) {
 			R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, qfalse, tr.currentModel->ATI_tess );
 		}
 
-//----(SA)
-
 		// projection shadows work fine with personal models
-//		if ( r_shadows->integer == 3
-//			&& fogNum == 0
-//			&& (ent->e.renderfx & RF_SHADOW_PLANE )
-//			&& shader->sort == SS_OPAQUE ) {
-//			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse );
-//		}
+		if ( r_shadows->integer == 3
+			&& fogNum == 0
+			&& (ent->e.renderfx & RF_SHADOW_PLANE )
+			&& shader->sort == SS_OPAQUE ) {
+			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse, tr.currentModel->ATI_tess );
+		}
 
 //----(SA)	for testing polygon shadows (on /all/ models)
-//		if ( r_shadows->integer == 4)
-//			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse );
-
+		if ( r_shadows->integer == 4 ) {
+			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse, tr.currentModel->ATI_tess );
+		}
 //----(SA)	done testing
 
 		// don't add third_person objects if not viewing through a portal
@@ -457,6 +455,5 @@ void R_AddMDCSurfaces( trRefEntity_t *ent ) {
 
 		surface = ( mdcSurface_t * )( (byte *)surface + surface->ofsEnd );
 	}
-
 }
 
diff --git a/SP/code/renderer/tr_image.c b/SP/code/renderer/tr_image.c
index 2893b58..2ce4d6d 100644
--- a/SP/code/renderer/tr_image.c
+++ b/SP/code/renderer/tr_image.c
@@ -1950,6 +1950,7 @@ RE_RegisterSkin
 ===============
 */
 qhandle_t RE_RegisterSkin( const char *name ) {
+	skinSurface_t parseSurfaces[MAX_SKIN_SURFACES];
 	qhandle_t hSkin;
 	skin_t      *skin;
 	skinSurface_t   *surf;
@@ -2006,8 +2007,8 @@ qhandle_t RE_RegisterSkin( const char *name ) {
 		skin->numSurfaces   = 0;
 		skin->numModels     = 0;    //----(SA) added
 		skin->numSurfaces = 1;
-		skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low );
-		skin->surfaces[0]->shader = R_FindShader( name, LIGHTMAP_NONE, qtrue );
+		skin->surfaces = ri.Hunk_Alloc( sizeof( skinSurface_t ), h_low );
+		skin->surfaces[0].shader = R_FindShader( name, LIGHTMAP_NONE, qtrue );
 		return hSkin;
 	}
 
@@ -2077,12 +2078,12 @@ qhandle_t RE_RegisterSkin( const char *name ) {
 		// parse the shader name
 		token = CommaParse( &text_p );
 
-		if ( skin->numSurfaces >= MD3_MAX_SURFACES ) {
-			ri.Printf( PRINT_WARNING, "WARNING: Ignoring surfaces in '%s', the max is %d surfaces!\n", name, MD3_MAX_SURFACES );
+		if ( skin->numSurfaces >= MAX_SKIN_SURFACES ) {
+			ri.Printf( PRINT_WARNING, "WARNING: Ignoring surfaces in '%s', the max is %d surfaces!\n", name, MAX_SKIN_SURFACES );
 			break;
 		}
 
-		surf = skin->surfaces[ skin->numSurfaces ] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low );
+		surf = &parseSurfaces[skin->numSurfaces];
 		Q_strncpyz( surf->name, surfName, sizeof( surf->name ) );
 		surf->shader = R_FindShader( token, LIGHTMAP_NONE, qtrue );
 		skin->numSurfaces++;
@@ -2101,6 +2102,10 @@ qhandle_t RE_RegisterSkin( const char *name ) {
 		}
 	}
 
+	// copy surfaces to skin
+	skin->surfaces = ri.Hunk_Alloc( skin->numSurfaces * sizeof( skinSurface_t ), h_low );
+	memcpy( skin->surfaces, parseSurfaces, skin->numSurfaces * sizeof( skinSurface_t ) );
+
 	return hSkin;
 }
 
@@ -2119,8 +2124,8 @@ void    R_InitSkins( void ) {
 	skin = tr.skins[0] = ri.Hunk_Alloc( sizeof( skin_t ), h_low );
 	Q_strncpyz( skin->name, "<default skin>", sizeof( skin->name )  );
 	skin->numSurfaces = 1;
-	skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low );
-	skin->surfaces[0]->shader = tr.defaultShader;
+	skin->surfaces = ri.Hunk_Alloc( sizeof( skinSurface_t ), h_low );
+	skin->surfaces[0].shader = tr.defaultShader;
 }
 
 /*
@@ -2149,10 +2154,10 @@ void    R_SkinList_f( void ) {
 	for ( i = 0 ; i < tr.numSkins ; i++ ) {
 		skin = tr.skins[i];
 
-		ri.Printf( PRINT_ALL, "%3i:%s\n", i, skin->name );
+		ri.Printf( PRINT_ALL, "%3i:%s (%d surfaces)\n", i, skin->name, skin->numSurfaces );
 		for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
 			ri.Printf( PRINT_ALL, "       %s = %s\n",
-					   skin->surfaces[j]->name, skin->surfaces[j]->shader->name );
+				skin->surfaces[j].name, skin->surfaces[j].shader->name );
 		}
 	}
 	ri.Printf( PRINT_ALL, "------------------\n" );
diff --git a/SP/code/renderer/tr_local.h b/SP/code/renderer/tr_local.h
index a23037d..a53ee2f 100644
--- a/SP/code/renderer/tr_local.h
+++ b/SP/code/renderer/tr_local.h
@@ -506,6 +506,12 @@ typedef struct {
 
 //=================================================================================
 
+// max surfaces per-skin
+// This is an arbitry limit. Vanilla Q3 only supported 32 surfaces in skins but failed to
+// enforce the maximum limit when reading skin files. It was possile to use more than 32
+// surfaces which accessed out of bounds memory past end of skin->surfaces hunk block.
+#define MAX_SKIN_SURFACES	256
+
 // skins allow models to be retextured without modifying the model file
 typedef struct {
 	char name[MAX_QPATH];
@@ -516,17 +522,17 @@ typedef struct {
 #define MAX_PART_MODELS 5
 
 typedef struct {
-	char type[MAX_QPATH];           // md3_lower, md3_lbelt, md3_rbelt, etc.
-	char model[MAX_QPATH];          // lower.md3, belt1.md3, etc.
+	char type[MAX_QPATH];		// md3_lower, md3_lbelt, md3_rbelt, etc.
+	char model[MAX_QPATH];		// lower.md3, belt1.md3, etc.
 } skinModel_t;
 
 typedef struct skin_s {
-	char name[MAX_QPATH];               // game path, including extension
+	char name[MAX_QPATH];		// game path, including extension
 	int numSurfaces;
 	int numModels;
-	skinSurface_t   *surfaces[MD3_MAX_SURFACES];
+	skinSurface_t	*surfaces;	// dynamically allocated array of surfaces
 	skinModel_t     *models[MAX_PART_MODELS];
-	vec3_t scale;       //----(SA)	added
+	vec3_t scale;			//----(SA)	added
 } skin_t;
 //----(SA) end
 
diff --git a/SP/code/renderer/tr_mesh.c b/SP/code/renderer/tr_mesh.c
index 5f016a4..5390c57 100644
--- a/SP/code/renderer/tr_mesh.c
+++ b/SP/code/renderer/tr_mesh.c
@@ -406,8 +406,8 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) {
 			shader = tr.defaultShader;
 			for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
 				// the names have both been lowercased
-				if ( !strcmp( skin->surfaces[j]->name, surface->name ) ) {
-					shader = skin->surfaces[j]->shader;
+				if ( !strcmp( skin->surfaces[j].name, surface->name ) ) {
+					shader = skin->surfaces[j].shader;
 					break;
 				}
 			}
@@ -439,18 +439,17 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) {
 		}
 
 		// projection shadows work fine with personal models
-//		if ( r_shadows->integer == 3
-//			&& fogNum == 0
-//			&& (ent->e.renderfx & RF_SHADOW_PLANE )
-//			&& shader->sort == SS_OPAQUE ) {
-//			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse );
-//		}
-
+		if ( r_shadows->integer == 3
+			&& fogNum == 0
+			&& (ent->e.renderfx & RF_SHADOW_PLANE )
+			&& shader->sort == SS_OPAQUE ) {
+			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse, tr.currentModel->ATI_tess );
+		}
 
 		// for testing polygon shadows (on /all/ models)
-//		if ( r_shadows->integer == 4)
-//			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse );
-
+		if ( r_shadows->integer == 4 ) {
+			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse, tr.currentModel->ATI_tess );
+		}
 
 		// don't add third_person objects if not viewing through a portal
 		if ( !personalModel ) {
@@ -460,6 +459,5 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) {
 
 		surface = ( md3Surface_t * )( (byte *)surface + surface->ofsEnd );
 	}
-
 }
 
diff --git a/SP/code/renderer/tr_model_iqm.c b/SP/code/renderer/tr_model_iqm.c
index 5ab41c2..b1ab522 100644
--- a/SP/code/renderer/tr_model_iqm.c
+++ b/SP/code/renderer/tr_model_iqm.c
@@ -903,9 +903,9 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) {
 
 			for(j = 0; j < skin->numSurfaces; j++)
 			{
-				if (!strcmp(skin->surfaces[j]->name, surface->name))
+				if (!strcmp(skin->surfaces[j].name, surface->name))
 				{
-					shader = skin->surfaces[j]->shader;
+					shader = skin->surfaces[j].shader;
 					break;
 				}
 			}
@@ -932,6 +932,11 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) {
 			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, 0, ATI_TESS_TRUFORM );
 		}
 
+		// for testing polygon shadows (on /all/ models)
+		if ( r_shadows->integer == 4 ) {
+			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse, ATI_TESS_TRUFORM );
+		}
+
 		if( !personalModel ) {
 			R_AddDrawSurf( (void *)surface, shader, fogNum, 0, ATI_TESS_TRUFORM );
 		}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/iortcw.git



More information about the Pkg-games-commits mailing list