[iortcw] 104/152: SP: Rend2: Store normals/tangents as int16_t[4] Also fix a couple things missed in MP

Simon McVittie smcv at debian.org
Fri Sep 8 10:40:19 UTC 2017


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

smcv pushed a commit to annotated tag 1.5a
in repository iortcw.

commit ac955b4605bc102b4e28649a58d67d0a72b2ea44
Author: MAN-AT-ARMS <M4N4T4RMS at gmail.com>
Date:   Sun Sep 11 16:23:27 2016 -0400

    SP: Rend2: Store normals/tangents as int16_t[4]
    Also fix a couple things missed in MP
---
 MP/code/rend2/tr_animation.c  |   2 +-
 MP/code/rend2/tr_model.c      |   5 +-
 SP/code/rend2/tr_animation.c  |  13 +-
 SP/code/rend2/tr_backend.c    |  18 +-
 SP/code/rend2/tr_bsp.c        | 207 +++++---------
 SP/code/rend2/tr_curve.c      |   6 +-
 SP/code/rend2/tr_extensions.c |  17 --
 SP/code/rend2/tr_init.c       |   2 -
 SP/code/rend2/tr_local.h      |  36 +--
 SP/code/rend2/tr_main.c       | 360 ++----------------------
 SP/code/rend2/tr_marks.c      |  46 +++-
 SP/code/rend2/tr_model.c      | 190 +++++++------
 SP/code/rend2/tr_model_iqm.c  |  15 +-
 SP/code/rend2/tr_shade_calc.c |  36 +--
 SP/code/rend2/tr_surface.c    | 619 ++++--------------------------------------
 SP/code/rend2/tr_vbo.c        | 147 +++-------
 16 files changed, 386 insertions(+), 1333 deletions(-)

diff --git a/MP/code/rend2/tr_animation.c b/MP/code/rend2/tr_animation.c
index 5e00202..013bc31 100644
--- a/MP/code/rend2/tr_animation.c
+++ b/MP/code/rend2/tr_animation.c
@@ -1167,7 +1167,7 @@ void RB_SurfaceAnim( mdsSurface_t *surface ) {
 	v = ( mdsVertex_t * )( (byte *)surface + surface->ofsVerts );
 	tempVert = ( float * )( tess.xyz + baseVertex );
 	tempNormal = ( int16_t * )( tess.normal + baseVertex );
-	for ( j = 0; j < render_count; j++, tempVert += 4, tempNormal++ ) {
+	for ( j = 0; j < render_count; j++, tempVert += 4, tempNormal += 4 ) {
 		mdsWeight_t *w;
 		vec3_t newNormal;
 
diff --git a/MP/code/rend2/tr_model.c b/MP/code/rend2/tr_model.c
index 179ff89..8e36b51 100644
--- a/MP/code/rend2/tr_model.c
+++ b/MP/code/rend2/tr_model.c
@@ -862,9 +862,12 @@ static qboolean R_LoadMDC( model_t *mod, int lod, void *buffer, const char *modN
 				for(k = 0; k < mdcSurf->numVerts; k++, mdcxyzComp++, v++)
 				{
 					vec3_t ofsVec;
-					R_MDC_DecodeXyzCompressed( mdcxyzComp->ofsVec, ofsVec, v->normal );
+					vec3_t fNormal;
+
+					R_MDC_DecodeXyzCompressed(mdcxyzComp->ofsVec, ofsVec, fNormal);
 					VectorAdd( v->xyz, ofsVec, v->xyz );
 
+					R_VaoPackNormal(v->normal, fNormal);
 				}
 			}
 		}
diff --git a/SP/code/rend2/tr_animation.c b/SP/code/rend2/tr_animation.c
index e5e8453..2b7cebb 100644
--- a/SP/code/rend2/tr_animation.c
+++ b/SP/code/rend2/tr_animation.c
@@ -68,7 +68,7 @@ static short           *sh, *sh2;
 static float           *pf;
 static vec3_t angles, tangles, torsoParentOffset, torsoAxis[3], tmpAxis[3];
 static float           *tempVert;
-static uint32_t         *tempNormal;
+static int16_t         *tempNormal;
 static vec3_t vec, v2, dir;
 static float diff, a1, a2;
 static int render_count;
@@ -1178,8 +1178,8 @@ void RB_SurfaceAnim( mdsSurface_t *surface ) {
 	numVerts = surface->numVerts;
 	v = ( mdsVertex_t * )( (byte *)surface + surface->ofsVerts );
 	tempVert = ( float * )( tess.xyz + baseVertex );
-	tempNormal = ( uint32_t * )( tess.normal + baseVertex );
-	for ( j = 0; j < render_count; j++, tempVert += 4, tempNormal++ ) {
+	tempNormal = ( int16_t * )( tess.normal + baseVertex );
+	for ( j = 0; j < render_count; j++, tempVert += 4, tempNormal += 4 ) {
 		mdsWeight_t *w;
 		vec3_t newNormal;
 
@@ -1190,9 +1190,10 @@ void RB_SurfaceAnim( mdsSurface_t *surface ) {
 			bone = &bones[w->boneIndex];
 			LocalAddScaledMatrixTransformVectorTranslate( w->offset, w->boneWeight, bone->matrix, bone->translation, tempVert );
 		}
+
 		LocalMatrixTransformVector( v->normal, bones[v->weights[0].boneIndex].matrix, newNormal );
 		
-		R_VaoPackNormal((byte *)tempNormal, newNormal);
+		R_VaoPackNormal(tempNormal, newNormal);
 
 		tess.texCoords[baseVertex + j][0][0] = v->texCoords[0];
 		tess.texCoords[baseVertex + j][0][1] = v->texCoords[1];
@@ -1241,7 +1242,7 @@ void RB_SurfaceAnim( mdsSurface_t *surface ) {
 
 			// show mesh edges
 			tempVert = ( float * )( tess.xyz + baseVertex );
-			tempNormal = ( uint32_t * )( tess.normal + baseVertex );
+			tempNormal = ( int16_t * )( tess.normal + baseVertex );
 
 			GL_BindToTMU(tr.whiteImage, TB_COLORMAP);
 			qglLineWidth( 1 );
@@ -1742,7 +1743,7 @@ void RB_MDRSurfaceAnim( mdrSurface_t *surface )
 		tess.xyz[baseVertex + j][1] = tempVert[1];
 		tess.xyz[baseVertex + j][2] = tempVert[2];
 
-		R_VaoPackNormal((byte *)&tess.normal[baseVertex + j], tempNormal);
+		R_VaoPackNormal(tess.normal[baseVertex + j], tempNormal);
 
 		tess.texCoords[baseVertex + j][0][0] = v->texCoords[0];
 		tess.texCoords[baseVertex + j][0][1] = v->texCoords[1];
diff --git a/SP/code/rend2/tr_backend.c b/SP/code/rend2/tr_backend.c
index ae3a742..e5a7d08 100644
--- a/SP/code/rend2/tr_backend.c
+++ b/SP/code/rend2/tr_backend.c
@@ -599,7 +599,7 @@ void RB_ZombieFXAddNewHit( int entityNum, const vec3_t hitPos, const vec3_t hitD
 
 void RB_ZombieFXProcessNewHits( trZombieFleshHitverts_t *fleshHitVerts, int oldNumVerts, int numSurfVerts ) {
 	float *xyzTrav;
-	uint32_t *normTrav;
+	int16_t *normTrav;
 	vec3_t hitPos, hitDir, v, testDir;
 	float bestHitDist, thisDist;
 	qboolean foundHit;
@@ -627,9 +627,9 @@ void RB_ZombieFXProcessNewHits( trZombieFleshHitverts_t *fleshHitVerts, int oldN
 		foundHit = qfalse;
 
 		// for each vertex
-		for (   j = 0, bestHitDist = -1, xyzTrav = tess.xyz[oldNumVerts], normTrav = &tess.normal[oldNumVerts];
+		for (   j = 0, bestHitDist = -1, xyzTrav = tess.xyz[oldNumVerts], normTrav = tess.normal[oldNumVerts];
 				j < numSurfVerts;
-				j++, xyzTrav += 4, normTrav++ ) {
+				j++, xyzTrav += 4, normTrav += 4 ) {
 			vec3_t fNormTrav;
 
 			// if this vert has been hit enough times already
@@ -637,7 +637,7 @@ void RB_ZombieFXProcessNewHits( trZombieFleshHitverts_t *fleshHitVerts, int oldN
 				continue;
 			}
 
-			R_VaoUnpackNormal(fNormTrav, *normTrav);
+			R_VaoUnpackNormal(fNormTrav, normTrav);
 
 			// if this normal faces the wrong way, reject it
 			if ( DotProduct( fNormTrav, hitDir ) > 0 ) {
@@ -723,16 +723,16 @@ void RB_ZombieFXShowFleshHits( trZombieFleshHitverts_t *fleshHitVerts, int oldNu
 void RB_ZombieFXDecompose( int oldNumVerts, int numSurfVerts, float deltaTimeScale ) {
 	byte *vertColors;
 	float   *xyz;
-	uint32_t *norm;
+	int16_t *norm;
 	vec3_t fNorm;
 	int i;
 	float alpha;
 
 	vertColors = (byte *)tess.vertexColors[oldNumVerts];
 	xyz = tess.xyz[oldNumVerts];
-	norm = &tess.normal[oldNumVerts];
+	norm = tess.normal[oldNumVerts];
 
-	for ( i = 0; i < numSurfVerts; i++, vertColors += 4, xyz += 4, norm++ ) {
+	for ( i = 0; i < numSurfVerts; i++, vertColors += 4, xyz += 4, norm += 4 ) {
 		alpha = 255.0 * ( (float)( 1 + i % 3 ) / 3.0 ) * deltaTimeScale * 2;
 		if ( alpha > 255.0 ) {
 			alpha = 255.0;
@@ -743,7 +743,7 @@ void RB_ZombieFXDecompose( int oldNumVerts, int numSurfVerts, float deltaTimeSca
 			vertColors[3] -= (byte)alpha;
 		}
 
-		R_VaoUnpackNormal(fNorm, *norm);
+		R_VaoUnpackNormal(fNorm, norm);
 
 		// skin shrinks with age
 		VectorMA( xyz, -2.0 * deltaTimeScale, fNorm, xyz );
@@ -771,8 +771,6 @@ void RB_ZombieFX( int part, drawSurf_t *drawSurf, int oldNumVerts, int oldNumInd
 
 	if ( *drawSurf->surface == SF_MDV ) {
 		surfName = ( (mdvSurface_t *)drawSurf->surface )->name;
-	} else if ( *drawSurf->surface == SF_MDC ) {
-		surfName = ( (mdcSurface_t *)drawSurf->surface )->name;
 	} else {
 		Com_Printf( "RB_ZombieFX: unknown surface type\n" );
 		return;
diff --git a/SP/code/rend2/tr_bsp.c b/SP/code/rend2/tr_bsp.c
index c609a67..4e4fc37 100644
--- a/SP/code/rend2/tr_bsp.c
+++ b/SP/code/rend2/tr_bsp.c
@@ -711,6 +711,66 @@ void *R_GetSurfMemory( int size ) {
 	return (void *)retval;
 }
 
+void LoadDrawVertToSrfVert(srfVert_t *s, drawVert_t *d, int realLightmapNum, float hdrVertColors[3], vec3_t *bounds)
+{
+	vec4_t v;
+
+	s->xyz[0] = LittleFloat(d->xyz[0]);
+	s->xyz[1] = LittleFloat(d->xyz[1]);
+	s->xyz[2] = LittleFloat(d->xyz[2]);
+
+	if (bounds)
+		AddPointToBounds(s->xyz, bounds[0], bounds[1]);
+
+	s->st[0] = LittleFloat(d->st[0]);
+	s->st[1] = LittleFloat(d->st[1]);
+
+	if (realLightmapNum >= 0)
+	{
+		s->lightmap[0] = FatPackU(LittleFloat(d->lightmap[0]), realLightmapNum);
+		s->lightmap[1] = FatPackV(LittleFloat(d->lightmap[1]), realLightmapNum);
+	}
+	else
+	{
+		s->lightmap[0] = LittleFloat(d->lightmap[0]);
+		s->lightmap[1] = LittleFloat(d->lightmap[1]);
+	}
+
+	v[0] = LittleFloat(d->normal[0]);
+	v[1] = LittleFloat(d->normal[1]);
+	v[2] = LittleFloat(d->normal[2]);
+
+	R_VaoPackNormal(s->normal, v);
+
+	if (hdrVertColors)
+	{
+		v[0] = hdrVertColors[0];
+		v[1] = hdrVertColors[1];
+		v[2] = hdrVertColors[2];
+	}
+	else
+	{
+		//hack: convert LDR vertex colors to HDR
+		if (r_hdr->integer)
+		{
+			v[0] = MAX(d->color[0], 0.499f);
+			v[1] = MAX(d->color[1], 0.499f);
+			v[2] = MAX(d->color[2], 0.499f);
+		}
+		else
+		{
+			v[0] = d->color[0];
+			v[1] = d->color[1];
+			v[2] = d->color[2];
+		}
+
+	}
+	v[3] = d->color[3] / 255.0f;
+
+	R_ColorShiftLightingFloats(v, s->vertexColors, 1.0f / 255.0f);
+}
+
+
 /*
 ===============
 ParseFace
@@ -758,50 +818,7 @@ static void ParseFace( dsurface_t *ds, drawVert_t *verts, float *hdrVertColors,
 	ClearBounds(surf->cullinfo.bounds[0], surf->cullinfo.bounds[1]);
 	verts += LittleLong(ds->firstVert);
 	for(i = 0; i < numVerts; i++)
-	{
-		vec4_t color;
-
-		for(j = 0; j < 3; j++)
-		{
-			cv->verts[i].xyz[j] = LittleFloat(verts[i].xyz[j]);
-			cv->verts[i].normal[j] = LittleFloat(verts[i].normal[j]);
-		}
-		AddPointToBounds(cv->verts[i].xyz, surf->cullinfo.bounds[0], surf->cullinfo.bounds[1]);
-		for(j = 0; j < 2; j++)
-		{
-			cv->verts[i].st[j] = LittleFloat(verts[i].st[j]);
-			//cv->verts[i].lightmap[j] = LittleFloat(verts[i].lightmap[j]);
-		}
-		cv->verts[i].lightmap[0] = FatPackU(LittleFloat(verts[i].lightmap[0]), realLightmapNum);
-		cv->verts[i].lightmap[1] = FatPackV(LittleFloat(verts[i].lightmap[1]), realLightmapNum);
-
-		if (hdrVertColors)
-		{
-			color[0] = hdrVertColors[(ds->firstVert + i) * 3    ];
-			color[1] = hdrVertColors[(ds->firstVert + i) * 3 + 1];
-			color[2] = hdrVertColors[(ds->firstVert + i) * 3 + 2];
-		}
-		else
-		{
-			//hack: convert LDR vertex colors to HDR
-			if (r_hdr->integer)
-			{
-				color[0] = MAX(verts[i].color[0], 0.499f);
-				color[1] = MAX(verts[i].color[1], 0.499f);
-				color[2] = MAX(verts[i].color[2], 0.499f);
-			}
-			else
-			{
-				color[0] = verts[i].color[0];
-				color[1] = verts[i].color[1];
-				color[2] = verts[i].color[2];
-			}
-
-		}
-		color[3] = verts[i].color[3] / 255.0f;
-
-		R_ColorShiftLightingFloats( color, cv->verts[i].vertexColors, 1.0f / 255.0f );
-	}
+		LoadDrawVertToSrfVert(&cv->verts[i], &verts[i], realLightmapNum, hdrVertColors ? hdrVertColors + (ds->firstVert + i) * 3 : NULL, surf->cullinfo.bounds);
 
 	// copy triangles
 	badTriangles = 0;
@@ -867,7 +884,7 @@ ParseMesh
 */
 static void ParseMesh ( dsurface_t *ds, drawVert_t *verts, float *hdrVertColors, msurface_t *surf ) {
 	srfBspSurface_t	*grid = (srfBspSurface_t *)surf->data;
-	int i, j;
+	int i;
 	int width, height, numPoints;
 	srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE];
 	vec3_t bounds[2];
@@ -902,49 +919,7 @@ static void ParseMesh ( dsurface_t *ds, drawVert_t *verts, float *hdrVertColors,
 	verts += LittleLong( ds->firstVert );
 	numPoints = width * height;
 	for(i = 0; i < numPoints; i++)
-	{
-		vec4_t color;
-
-		for(j = 0; j < 3; j++)
-		{
-			points[i].xyz[j] = LittleFloat(verts[i].xyz[j]);
-			points[i].normal[j] = LittleFloat(verts[i].normal[j]);
-		}
-
-		for(j = 0; j < 2; j++)
-		{
-			points[i].st[j] = LittleFloat(verts[i].st[j]);
-			//points[i].lightmap[j] = LittleFloat(verts[i].lightmap[j]);
-		}
-		points[i].lightmap[0] = FatPackU(LittleFloat(verts[i].lightmap[0]), realLightmapNum);
-		points[i].lightmap[1] = FatPackV(LittleFloat(verts[i].lightmap[1]), realLightmapNum);
-
-		if (hdrVertColors)
-		{
-			color[0] = hdrVertColors[(ds->firstVert + i) * 3    ];
-			color[1] = hdrVertColors[(ds->firstVert + i) * 3 + 1];
-			color[2] = hdrVertColors[(ds->firstVert + i) * 3 + 2];
-		}
-		else
-		{
-			//hack: convert LDR vertex colors to HDR
-			if (r_hdr->integer)
-			{
-				color[0] = MAX(verts[i].color[0], 0.499f);
-				color[1] = MAX(verts[i].color[1], 0.499f);
-				color[2] = MAX(verts[i].color[2], 0.499f);
-			}
-			else
-			{
-				color[0] = verts[i].color[0];
-				color[1] = verts[i].color[1];
-				color[2] = verts[i].color[2];
-			}
-		}
-		color[3] = verts[i].color[3] / 255.0f;
-
-		R_ColorShiftLightingFloats( color, points[i].vertexColors, 1.0f / 255.0f );
-	}
+		LoadDrawVertToSrfVert(&points[i], &verts[i], realLightmapNum, hdrVertColors ? hdrVertColors + (ds->firstVert + i) * 3 : NULL, NULL);
 
 	// pre-tesseleate
 	R_SubdividePatchToGrid( grid, width, height, points );
@@ -1008,48 +983,7 @@ static void ParseTriSurf( dsurface_t *ds, drawVert_t *verts, float *hdrVertColor
 	ClearBounds(surf->cullinfo.bounds[0], surf->cullinfo.bounds[1]);
 	verts += LittleLong(ds->firstVert);
 	for(i = 0; i < numVerts; i++)
-	{
-		vec4_t color;
-
-		for(j = 0; j < 3; j++)
-		{
-			cv->verts[i].xyz[j] = LittleFloat(verts[i].xyz[j]);
-			cv->verts[i].normal[j] = LittleFloat(verts[i].normal[j]);
-		}
-		AddPointToBounds( cv->verts[i].xyz, surf->cullinfo.bounds[0], surf->cullinfo.bounds[1] );
-
-		for(j = 0; j < 2; j++)
-		{
-			cv->verts[i].st[j] = LittleFloat(verts[i].st[j]);
-			cv->verts[i].lightmap[j] = LittleFloat(verts[i].lightmap[j]);
-		}
-
-		if (hdrVertColors)
-		{
-			color[0] = hdrVertColors[(ds->firstVert + i) * 3    ];
-			color[1] = hdrVertColors[(ds->firstVert + i) * 3 + 1];
-			color[2] = hdrVertColors[(ds->firstVert + i) * 3 + 2];
-		}
-		else
-		{
-			//hack: convert LDR vertex colors to HDR
-			if (r_hdr->integer)
-			{
-				color[0] = MAX(verts[i].color[0], 0.499f);
-				color[1] = MAX(verts[i].color[1], 0.499f);
-				color[2] = MAX(verts[i].color[2], 0.499f);
-			}
-			else
-			{
-				color[0] = verts[i].color[0];
-				color[1] = verts[i].color[1];
-				color[2] = verts[i].color[2];
-			}
-		}
-		color[3] = verts[i].color[3] / 255.0f;
-
-		R_ColorShiftLightingFloats( color, cv->verts[i].vertexColors, 1.0f / 255.0f );
-	}
+		LoadDrawVertToSrfVert(&cv->verts[i], &verts[i], -1, hdrVertColors ? hdrVertColors + (ds->firstVert + i) * 3 : NULL, surf->cullinfo.bounds);
 
 	// copy triangles
 	badTriangles = 0;
@@ -2069,8 +2003,8 @@ static void CopyVert(const srfVert_t * in, srfVert_t * out)
 #ifdef USE_VERT_TANGENT_SPACE
 	VectorCopy4(in->tangent, out->tangent);
 #endif
-	VectorCopy(in->normal,   out->normal);
-	VectorCopy(in->lightdir, out->lightdir);
+	VectorCopy4(in->normal,   out->normal);
+	VectorCopy4(in->lightdir, out->lightdir);
 
 	VectorCopy2(in->st,       out->st);
 	VectorCopy2(in->lightmap, out->lightmap);
@@ -3532,7 +3466,14 @@ void R_CalcVertexLightDirs( void )
 			case SF_GRID:
 			case SF_TRIANGLES:
 				for(i = 0; i < bspSurf->numVerts; i++)
-					R_LightDirForPoint( bspSurf->verts[i].xyz, bspSurf->verts[i].lightdir, bspSurf->verts[i].normal, &s_worldData );
+				{
+					vec3_t lightDir;
+					vec3_t normal;
+
+					R_VaoUnpackNormal(normal, bspSurf->verts[i].normal);
+					R_LightDirForPoint( bspSurf->verts[i].xyz, lightDir, normal, &s_worldData );
+					R_VaoPackNormal(bspSurf->verts[i].lightdir, lightDir);
+				}
 
 				break;
 
diff --git a/SP/code/rend2/tr_curve.c b/SP/code/rend2/tr_curve.c
index 54349cd..c68df99 100644
--- a/SP/code/rend2/tr_curve.c
+++ b/SP/code/rend2/tr_curve.c
@@ -214,7 +214,11 @@ static void MakeMeshNormals( int width, int height, srfVert_t ctrl[MAX_GRID_SIZE
 			//if ( count == 0 ) {
 			//printf("bad normal\n");
 			//}
-			VectorNormalize2( sum, dv->normal );
+			{
+				vec3_t fNormal;
+				VectorNormalize2(sum, fNormal);
+				R_VaoPackNormal(dv->normal, fNormal);
+			}
 		}
 	}
 }
diff --git a/SP/code/rend2/tr_extensions.c b/SP/code/rend2/tr_extensions.c
index 602310b..6c0b8ca 100644
--- a/SP/code/rend2/tr_extensions.c
+++ b/SP/code/rend2/tr_extensions.c
@@ -295,23 +295,6 @@ void GLimp_InitExtraExtensions()
 		ri.Printf(PRINT_ALL, result[2], extension);
 	}
 
-	// GL_ARB_vertex_type_2_10_10_10_rev
-	extension = "GL_ARB_vertex_type_2_10_10_10_rev";
-	glRefConfig.packedNormalDataType = GL_BYTE;
-	if( GLimp_HaveExtension( extension ) )
-	{
-		qboolean useExt = !!r_arb_vertex_type_2_10_10_10_rev->integer;
-
-		if (useExt)
-			glRefConfig.packedNormalDataType = GL_INT_2_10_10_10_REV;
-
-		ri.Printf(PRINT_ALL, result[useExt], extension);
-	}
-	else
-	{
-		ri.Printf(PRINT_ALL, result[2], extension);
-	}
-
 	// use float lightmaps?
 	glRefConfig.floatLightmap = (glRefConfig.textureFloat && glRefConfig.halfFloatPixel && r_floatLightmap->integer && r_hdr->integer);
 
diff --git a/SP/code/rend2/tr_init.c b/SP/code/rend2/tr_init.c
index 267f529..c5ecc71 100644
--- a/SP/code/rend2/tr_init.c
+++ b/SP/code/rend2/tr_init.c
@@ -130,7 +130,6 @@ cvar_t  *r_arb_half_float_pixel;
 cvar_t  *r_arb_half_float_vertex;
 cvar_t  *r_ext_framebuffer_multisample;
 cvar_t  *r_arb_seamless_cube_map;
-cvar_t  *r_arb_vertex_type_2_10_10_10_rev;
 cvar_t  *r_arb_vertex_array_object;
 cvar_t  *r_ext_direct_state_access;
 
@@ -1309,7 +1308,6 @@ void R_Register( void ) {
 	r_arb_half_float_vertex = ri.Cvar_Get( "r_arb_half_float_vertex", "1", CVAR_ARCHIVE | CVAR_LATCH);
 	r_ext_framebuffer_multisample = ri.Cvar_Get( "r_ext_framebuffer_multisample", "0", CVAR_ARCHIVE | CVAR_LATCH);
 	r_arb_seamless_cube_map = ri.Cvar_Get( "r_arb_seamless_cube_map", "0", CVAR_ARCHIVE | CVAR_LATCH);
-	r_arb_vertex_type_2_10_10_10_rev = ri.Cvar_Get( "r_arb_vertex_type_2_10_10_10_rev", "1", CVAR_ARCHIVE | CVAR_LATCH);
 	r_arb_vertex_array_object = ri.Cvar_Get( "r_arb_vertex_array_object", "1", CVAR_ARCHIVE | CVAR_LATCH);
 	r_ext_direct_state_access = ri.Cvar_Get("r_ext_direct_state_access", "1", CVAR_ARCHIVE | CVAR_LATCH);
 
diff --git a/SP/code/rend2/tr_local.h b/SP/code/rend2/tr_local.h
index 01bd9dc..3d935c3 100644
--- a/SP/code/rend2/tr_local.h
+++ b/SP/code/rend2/tr_local.h
@@ -966,7 +966,6 @@ typedef enum {
 	SF_TRIANGLES,
 	SF_POLY,
 	SF_MDV,
-	SF_MDC,
 	SF_MDS,
 	SF_MDR,
 	SF_IQM,
@@ -1014,11 +1013,11 @@ typedef struct
 	vec3_t          xyz;
 	vec2_t          st;
 	vec2_t          lightmap;
-	vec3_t          normal;
+	int16_t         normal[4];
 #ifdef USE_VERT_TANGENT_SPACE
-	vec4_t          tangent;
+	int16_t         tangent[4];
 #endif
-	vec3_t          lightdir;
+	int16_t         lightdir[4];
 	vec4_t			vertexColors;
 
 #if DEBUG_OPTIMIZEVERTICES
@@ -1027,9 +1026,9 @@ typedef struct
 } srfVert_t;
 
 #ifdef USE_VERT_TANGENT_SPACE
-#define srfVert_t_cleared(x) srfVert_t (x) = {{0, 0, 0}, {0, 0}, {0, 0}, {0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0}, {0, 0, 0, 0}}
+#define srfVert_t_cleared(x) srfVert_t (x) = {{0, 0, 0}, {0, 0}, {0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}
 #else
-#define srfVert_t_cleared(x) srfVert_t (x) = {{0, 0, 0}, {0, 0}, {0, 0}, {0, 0, 0}, {0, 0, 0},  {0, 0, 0, 0}}
+#define srfVert_t_cleared(x) srfVert_t (x) = {{0, 0, 0}, {0, 0}, {0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}
 #endif
 
 // srfBspSurface_t covers SF_GRID, SF_TRIANGLES, SF_POLY, and SF_VAO_MESH
@@ -1318,10 +1317,9 @@ typedef struct
 typedef struct
 {
 	vec3_t          xyz;
-	vec3_t          normal;
+	int16_t         normal[4];
 #ifdef USE_VERT_TANGENT_SPACE
-	vec3_t          tangent;
-	vec3_t          bitangent;
+	int16_t         tangent[4];
 #endif
 } mdvVertex_t;
 
@@ -1556,7 +1554,6 @@ typedef struct {
 	qboolean depthClamp;
 	qboolean seamlessCubeMap;
 
-	GLenum packedNormalDataType;
 	GLenum packedTexcoordDataType;
 	GLenum packedColorDataType;
 	int packedTexcoordDataSize;
@@ -1923,7 +1920,6 @@ extern  cvar_t  *r_arb_half_float_pixel;
 extern  cvar_t  *r_arb_half_float_vertex;
 extern  cvar_t  *r_ext_framebuffer_multisample;
 extern  cvar_t  *r_arb_seamless_cube_map;
-extern  cvar_t  *r_arb_vertex_type_2_10_10_10_rev;
 extern  cvar_t  *r_arb_vertex_array_object;
 extern  cvar_t  *r_ext_direct_state_access;
 
@@ -2096,7 +2092,7 @@ void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader,
 
 void R_CalcTexDirs(vec3_t sdir, vec3_t tdir, const vec3_t v1, const vec3_t v2,
 				   const vec3_t v3, const vec2_t w1, const vec2_t w2, const vec2_t w3);
-void R_CalcTbnFromNormalAndTexDirs(vec3_t tangent, vec3_t bitangent, vec3_t normal, vec3_t sdir, vec3_t tdir);
+vec_t R_CalcTangentSpace(vec3_t tangent, vec3_t bitangent, const vec3_t normal, const vec3_t sdir, const vec3_t tdir);
 qboolean R_CalcTangentVectors(srfVert_t * dv[3]);
 
 #define CULL_IN     0       // completely unclipped
@@ -2274,13 +2270,13 @@ typedef struct shaderCommands_s
 {
 	glIndex_t	indexes[SHADER_MAX_INDEXES] QALIGN(16);
 	vec4_t		xyz[SHADER_MAX_VERTEXES] QALIGN(16);
-	uint32_t	normal[SHADER_MAX_VERTEXES] QALIGN(16);
+	int16_t		normal[SHADER_MAX_VERTEXES][4] QALIGN(16);
 #ifdef USE_VERT_TANGENT_SPACE
-	uint32_t	tangent[SHADER_MAX_VERTEXES] QALIGN(16);
+	int16_t		tangent[SHADER_MAX_VERTEXES][4] QALIGN(16);
 #endif
 	vec2_t		texCoords[SHADER_MAX_VERTEXES][2] QALIGN(16);
 	vec4_t		vertexColors[SHADER_MAX_VERTEXES] QALIGN(16);
-	uint32_t    lightdir[SHADER_MAX_VERTEXES] QALIGN(16);
+	int16_t		lightdir[SHADER_MAX_VERTEXES][4] QALIGN(16);
 	//int			vertexDlightBits[SHADER_MAX_VERTEXES] QALIGN(16);
 
 	void *attribPointers[ATTR_INDEX_COUNT];
@@ -2445,12 +2441,12 @@ VERTEX BUFFER OBJECTS
 ============================================================
 */
 
-int R_VaoPackTangent(byte *out, vec4_t v);
-int R_VaoPackNormal(byte *out, vec3_t v);
+void R_VaoPackTangent(int16_t *out, vec4_t v);
+void R_VaoPackNormal(int16_t *out, vec3_t v);
 int R_VaoPackTexCoord(byte *out, vec2_t st);
 int R_VaoPackColors(byte *out, vec4_t color);
-void R_VaoUnpackTangent(vec4_t v, uint32_t b);
-void R_VaoUnpackNormal(vec3_t v, uint32_t b);
+void R_VaoUnpackTangent(vec4_t v, int16_t *pack);
+void R_VaoUnpackNormal(vec3_t v, int16_t *pack);
 
 vao_t          *R_CreateVao(const char *name, byte *vertexes, int vertexesSize, byte *indexes, int indexesSize, vaoUsage_t usage);
 vao_t          *R_CreateVao2(const char *name, int numVertexes, srfVert_t *verts, int numIndexes, glIndex_t *inIndexes);
@@ -2827,8 +2823,6 @@ void R_AddMDCSurfaces( trRefEntity_t *ent );
 // done.
 //------------------------------------------------------------------------------
 
-void R_LatLongToNormal( vec3_t outNormal, short latLong );
-
 
 /*
 ============================================================
diff --git a/SP/code/rend2/tr_main.c b/SP/code/rend2/tr_main.c
index b0d9e0f..fe4def0 100644
--- a/SP/code/rend2/tr_main.c
+++ b/SP/code/rend2/tr_main.c
@@ -190,232 +190,14 @@ qboolean R_CompareVert(srfVert_t * v1, srfVert_t * v2, qboolean checkST)
 	return qtrue;
 }
 
-/*
-=============
-R_CalcNormalForTriangle
-=============
-*/
-void R_CalcNormalForTriangle(vec3_t normal, const vec3_t v0, const vec3_t v1, const vec3_t v2)
-{
-	vec3_t          udir, vdir;
-
-	// compute the face normal based on vertex points
-	VectorSubtract(v2, v0, udir);
-	VectorSubtract(v1, v0, vdir);
-	CrossProduct(udir, vdir, normal);
-
-	VectorNormalize(normal);
-}
 
 /*
 =============
-R_CalcTangentsForTriangle
-http://members.rogers.com/deseric/tangentspace.htm
-=============
-*/
-void R_CalcTangentsForTriangle(vec3_t tangent, vec3_t bitangent,
-							   const vec3_t v0, const vec3_t v1, const vec3_t v2,
-							   const vec2_t t0, const vec2_t t1, const vec2_t t2)
-{
-	int             i;
-	vec3_t          planes[3];
-	vec3_t          u, v;
-
-	for(i = 0; i < 3; i++)
-	{
-		VectorSet(u, v1[i] - v0[i], t1[0] - t0[0], t1[1] - t0[1]);
-		VectorSet(v, v2[i] - v0[i], t2[0] - t0[0], t2[1] - t0[1]);
-
-		VectorNormalize(u);
-		VectorNormalize(v);
-
-		CrossProduct(u, v, planes[i]);
-	}
+R_CalcTexDirs
 
-	//So your tangent space will be defined by this :
-	//Normal = Normal of the triangle or Tangent X Bitangent (careful with the cross product,
-	// you have to make sure the normal points in the right direction)
-	//Tangent = ( dp(Fx(s,t)) / ds,  dp(Fy(s,t)) / ds, dp(Fz(s,t)) / ds )   or     ( -Bx/Ax, -By/Ay, - Bz/Az )
-	//Bitangent =  ( dp(Fx(s,t)) / dt,  dp(Fy(s,t)) / dt, dp(Fz(s,t)) / dt )  or     ( -Cx/Ax, -Cy/Ay, -Cz/Az )
-
-	// tangent...
-	tangent[0] = -planes[0][1] / planes[0][0];
-	tangent[1] = -planes[1][1] / planes[1][0];
-	tangent[2] = -planes[2][1] / planes[2][0];
-	VectorNormalize(tangent);
-
-	// bitangent...
-	bitangent[0] = -planes[0][2] / planes[0][0];
-	bitangent[1] = -planes[1][2] / planes[1][0];
-	bitangent[2] = -planes[2][2] / planes[2][0];
-	VectorNormalize(bitangent);
-}
-
-
-
-
-/*
-=============
-R_CalcTangentSpace
+Lengyel, Eric. “Computing Tangent Space Basis Vectors for an Arbitrary Mesh”. Terathon Software 3D Graphics Library, 2001. http://www.terathon.com/code/tangent.html
 =============
 */
-void R_CalcTangentSpace(vec3_t tangent, vec3_t bitangent, vec3_t normal,
-						const vec3_t v0, const vec3_t v1, const vec3_t v2, const vec2_t t0, const vec2_t t1, const vec2_t t2)
-{
-	vec3_t          cp, u, v;
-	vec3_t          faceNormal;
-
-	VectorSet(u, v1[0] - v0[0], t1[0] - t0[0], t1[1] - t0[1]);
-	VectorSet(v, v2[0] - v0[0], t2[0] - t0[0], t2[1] - t0[1]);
-
-	CrossProduct(u, v, cp);
-	if(fabs(cp[0]) > 10e-6)
-	{
-		tangent[0] = -cp[1] / cp[0];
-		bitangent[0] = -cp[2] / cp[0];
-	}
-
-	u[0] = v1[1] - v0[1];
-	v[0] = v2[1] - v0[1];
-
-	CrossProduct(u, v, cp);
-	if(fabs(cp[0]) > 10e-6)
-	{
-		tangent[1] = -cp[1] / cp[0];
-		bitangent[1] = -cp[2] / cp[0];
-	}
-
-	u[0] = v1[2] - v0[2];
-	v[0] = v2[2] - v0[2];
-
-	CrossProduct(u, v, cp);
-	if(fabs(cp[0]) > 10e-6)
-	{
-		tangent[2] = -cp[1] / cp[0];
-		bitangent[2] = -cp[2] / cp[0];
-	}
-
-	VectorNormalize(tangent);
-	VectorNormalize(bitangent);
-
-	// compute the face normal based on vertex points
-	if ( normal[0] == 0.0f && normal[1] == 0.0f && normal[2] == 0.0f )
-	{
-		VectorSubtract(v2, v0, u);
-		VectorSubtract(v1, v0, v);
-		CrossProduct(u, v, faceNormal);
-	}
-	else
-	{
-		VectorCopy(normal, faceNormal);
-	}
-
-	VectorNormalize(faceNormal);
-
-#if 1
-	// Gram-Schmidt orthogonalize
-	//tangent[a] = (t - n * Dot(n, t)).Normalize();
-	VectorMA(tangent, -DotProduct(faceNormal, tangent), faceNormal, tangent);
-	VectorNormalize(tangent);
-
-	// compute the cross product B=NxT
-	//CrossProduct(normal, tangent, bitangent);
-#else
-	// normal, compute the cross product N=TxB
-	CrossProduct(tangent, bitangent, normal);
-	VectorNormalize(normal);
-
-	if(DotProduct(normal, faceNormal) < 0)
-	{
-		//VectorInverse(normal);
-		//VectorInverse(tangent);
-		//VectorInverse(bitangent);
-
-		// compute the cross product T=BxN
-		CrossProduct(bitangent, faceNormal, tangent);
-
-		// compute the cross product B=NxT
-		//CrossProduct(normal, tangent, bitangent);
-	}
-#endif
-
-	VectorCopy(faceNormal, normal);
-}
-
-void R_CalcTangentSpaceFast(vec3_t tangent, vec3_t bitangent, vec3_t normal,
-						const vec3_t v0, const vec3_t v1, const vec3_t v2, const vec2_t t0, const vec2_t t1, const vec2_t t2)
-{
-	vec3_t          cp, u, v;
-	vec3_t          faceNormal;
-
-	VectorSet(u, v1[0] - v0[0], t1[0] - t0[0], t1[1] - t0[1]);
-	VectorSet(v, v2[0] - v0[0], t2[0] - t0[0], t2[1] - t0[1]);
-
-	CrossProduct(u, v, cp);
-	if(fabs(cp[0]) > 10e-6)
-	{
-		tangent[0] = -cp[1] / cp[0];
-		bitangent[0] = -cp[2] / cp[0];
-	}
-
-	u[0] = v1[1] - v0[1];
-	v[0] = v2[1] - v0[1];
-
-	CrossProduct(u, v, cp);
-	if(fabs(cp[0]) > 10e-6)
-	{
-		tangent[1] = -cp[1] / cp[0];
-		bitangent[1] = -cp[2] / cp[0];
-	}
-
-	u[0] = v1[2] - v0[2];
-	v[0] = v2[2] - v0[2];
-
-	CrossProduct(u, v, cp);
-	if(fabs(cp[0]) > 10e-6)
-	{
-		tangent[2] = -cp[1] / cp[0];
-		bitangent[2] = -cp[2] / cp[0];
-	}
-
-	VectorNormalizeFast(tangent);
-	VectorNormalizeFast(bitangent);
-
-	// compute the face normal based on vertex points
-	VectorSubtract(v2, v0, u);
-	VectorSubtract(v1, v0, v);
-	CrossProduct(u, v, faceNormal);
-
-	VectorNormalizeFast(faceNormal);
-
-#if 0
-	// normal, compute the cross product N=TxB
-	CrossProduct(tangent, bitangent, normal);
-	VectorNormalizeFast(normal);
-
-	if(DotProduct(normal, faceNormal) < 0)
-	{
-		VectorInverse(normal);
-		//VectorInverse(tangent);
-		//VectorInverse(bitangent);
-
-		CrossProduct(normal, tangent, bitangent);
-	}
-
-	VectorCopy(faceNormal, normal);
-#else
-	// Gram-Schmidt orthogonalize
-		//tangent[a] = (t - n * Dot(n, t)).Normalize();
-	VectorMA(tangent, -DotProduct(faceNormal, tangent), faceNormal, tangent);
-	VectorNormalizeFast(tangent);
-#endif
-
-	VectorCopy(faceNormal, normal);
-}
-
-/*
-http://www.terathon.com/code/tangent.html
-*/
 void R_CalcTexDirs(vec3_t sdir, vec3_t tdir, const vec3_t v1, const vec3_t v2,
 				   const vec3_t v3, const vec2_t w1, const vec2_t w2, const vec2_t w3)
 {
@@ -434,14 +216,21 @@ void R_CalcTexDirs(vec3_t sdir, vec3_t tdir, const vec3_t v1, const vec3_t v2,
 	t1 = w2[1] - w1[1];
 	t2 = w3[1] - w1[1];
 
-	r = 1.0f / (s1 * t2 - s2 * t1);
+	r = s1 * t2 - s2 * t1;
+	if (r) r = 1.0f / r;
 
 	VectorSet(sdir, (t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
 	VectorSet(tdir, (s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);
 }
 
+/*
+=============
+R_CalcTangentSpace
 
-void R_CalcTbnFromNormalAndTexDirs(vec3_t tangent, vec3_t bitangent, vec3_t normal, vec3_t sdir, vec3_t tdir)
+Lengyel, Eric. “Computing Tangent Space Basis Vectors for an Arbitrary Mesh”. Terathon Software 3D Graphics Library, 2001. http://www.terathon.com/code/tangent.html
+=============
+*/
+vec_t R_CalcTangentSpace(vec3_t tangent, vec3_t bitangent, const vec3_t normal, const vec3_t sdir, const vec3_t tdir)
 {
 	vec3_t n_cross_t;
 	vec_t n_dot_t, handedness;
@@ -455,110 +244,11 @@ void R_CalcTbnFromNormalAndTexDirs(vec3_t tangent, vec3_t bitangent, vec3_t norm
 	CrossProduct(normal, sdir, n_cross_t);
 	handedness = (DotProduct(n_cross_t, tdir) < 0.0f) ? -1.0f : 1.0f;
 
-	// Calculate bitangent
-	CrossProduct(normal, tangent, bitangent);
-	VectorScale(bitangent, handedness, bitangent);
-}
-
-void R_CalcTBN2(vec3_t tangent, vec3_t bitangent, vec3_t normal,
-						const vec3_t v1, const vec3_t v2, const vec3_t v3, const vec2_t t1, const vec2_t t2, const vec2_t t3)
-{
-	vec3_t			v2v1;
-	vec3_t			v3v1;
-
-	float			c2c1_T;
-	float			c2c1_B;
-
-	float			c3c1_T;
-	float			c3c1_B;
-
-	float			denominator;
-	float			scale1, scale2;
-
-	vec3_t			T, B, N, C;
-
-
-	// Calculate the tangent basis for each vertex of the triangle
-	// UPDATE: In the 3rd edition of the accompanying article, the for-loop located here has
-	// been removed as it was redundant (the entire TBN matrix was calculated three times
-	// instead of just one).
-	//
-	// Please note, that this function relies on the fact that the input geometry are triangles
-	// and the tangent basis for each vertex thus is identical!
-	//
-
-	// Calculate the vectors from the current vertex to the two other vertices in the triangle
-	VectorSubtract(v2, v1, v2v1);
-	VectorSubtract(v3, v1, v3v1);
-
-	// The equation presented in the article states that:
-	// c2c1_T = V2.texcoord.x - V1.texcoord.x
-	// c2c1_B = V2.texcoord.y - V1.texcoord.y
-	// c3c1_T = V3.texcoord.x - V1.texcoord.x
-	// c3c1_B = V3.texcoord.y - V1.texcoord.y
-
-	// Calculate c2c1_T and c2c1_B
-	c2c1_T = t2[0] - t1[0];
-	c2c1_B = t2[1] - t2[1];
-
-	// Calculate c3c1_T and c3c1_B
-	c3c1_T = t3[0] - t1[0];
-	c3c1_B = t3[1] - t1[1];
-
-	denominator = c2c1_T * c3c1_B - c3c1_T * c2c1_B;
-	//if(ROUNDOFF(fDenominator) == 0.0f)
-	if(denominator == 0.0f)
-	{
-		// We won't risk a divide by zero, so set the tangent matrix to the identity matrix
-		VectorSet(tangent, 1, 0, 0);
-		VectorSet(bitangent, 0, 1, 0);
-		VectorSet(normal, 0, 0, 1);
-	}
-	else
-	{
-		// Calculate the reciprocal value once and for all (to achieve speed)
-		scale1 = 1.0f / denominator;
-
-		// T and B are calculated just as the equation in the article states
-		VectorSet(T, (c3c1_B * v2v1[0] - c2c1_B * v3v1[0]) * scale1,
-					 (c3c1_B * v2v1[1] - c2c1_B * v3v1[1]) * scale1,
-					 (c3c1_B * v2v1[2] - c2c1_B * v3v1[2]) * scale1);
-
-		VectorSet(B, (-c3c1_T * v2v1[0] + c2c1_T * v3v1[0]) * scale1,
-					 (-c3c1_T * v2v1[1] + c2c1_T * v3v1[1]) * scale1,
-					 (-c3c1_T * v2v1[2] + c2c1_T * v3v1[2]) * scale1);
-
-		// The normal N is calculated as the cross product between T and B
-		CrossProduct(T, B, N);
-
-#if 0
-		VectorCopy(T, tangent);
-		VectorCopy(B, bitangent);
-		VectorCopy(N, normal);
-#else
-		// Calculate the reciprocal value once and for all (to achieve speed)
-		scale2 = 1.0f / ((T[0] * B[1] * N[2] - T[2] * B[1] * N[0]) +
-					(B[0] * N[1] * T[2] - B[2] * N[1] * T[0]) +
-					(N[0] * T[1] * B[2] - N[2] * T[1] * B[0]));
-
-		// Calculate the inverse if the TBN matrix using the formula described in the article.
-		// We store the basis vectors directly in the provided TBN matrix: pvTBNMatrix
-		CrossProduct(B, N, C); tangent[0] = C[0] * scale2;
-		CrossProduct(N, T, C); tangent[1] = -C[0] * scale2;
-		CrossProduct(T, B, C); tangent[2] = C[0] * scale2;
-		VectorNormalize(tangent);
-
-		CrossProduct(B, N, C); bitangent[0] = -C[1] * scale2;
-		CrossProduct(N, T, C); bitangent[1] = C[1] * scale2;
-		CrossProduct(T, B, C); bitangent[2] = -C[1] * scale2;
-		VectorNormalize(bitangent);
+	// Calculate orthogonal bitangent, if necessary
+	if (bitangent)
+		CrossProduct(normal, tangent, bitangent);
 
-		CrossProduct(B, N, C); normal[0] = C[2] * scale2;
-		CrossProduct(N, T, C); normal[1] = -C[2] * scale2;
-		CrossProduct(T, B, C); normal[2] = C[2] * scale2;
-		VectorNormalize(normal);
-#endif
-	}
+	return handedness;	
 }
 
 
@@ -578,7 +268,8 @@ qboolean R_CalcTangentVectors(srfVert_t * dv[3])
 	/* do each vertex */
 	for(i = 0; i < 3; i++)
 	{
-		vec3_t bitangent, nxt;
+		vec4_t tangent;
+		vec3_t normal, bitangent, nxt;
 
 		// calculate s tangent vector
 		s = dv[i]->st[0] + 10.0f;
@@ -587,12 +278,12 @@ qboolean R_CalcTangentVectors(srfVert_t * dv[3])
 		bary[1] = ((dv[2]->st[0] - s) * (dv[0]->st[1] - t) - (dv[0]->st[0] - s) * (dv[2]->st[1] - t)) / bb;
 		bary[2] = ((dv[0]->st[0] - s) * (dv[1]->st[1] - t) - (dv[1]->st[0] - s) * (dv[0]->st[1] - t)) / bb;
 
-		dv[i]->tangent[0] = bary[0] * dv[0]->xyz[0] + bary[1] * dv[1]->xyz[0] + bary[2] * dv[2]->xyz[0];
-		dv[i]->tangent[1] = bary[0] * dv[0]->xyz[1] + bary[1] * dv[1]->xyz[1] + bary[2] * dv[2]->xyz[1];
-		dv[i]->tangent[2] = bary[0] * dv[0]->xyz[2] + bary[1] * dv[1]->xyz[2] + bary[2] * dv[2]->xyz[2];
+		tangent[0] = bary[0] * dv[0]->xyz[0] + bary[1] * dv[1]->xyz[0] + bary[2] * dv[2]->xyz[0];
+		tangent[1] = bary[0] * dv[0]->xyz[1] + bary[1] * dv[1]->xyz[1] + bary[2] * dv[2]->xyz[1];
+		tangent[2] = bary[0] * dv[0]->xyz[2] + bary[1] * dv[1]->xyz[2] + bary[2] * dv[2]->xyz[2];
 
-		VectorSubtract(dv[i]->tangent, dv[i]->xyz, dv[i]->tangent);
-		VectorNormalize(dv[i]->tangent);
+		VectorSubtract(tangent, dv[i]->xyz, tangent);
+		VectorNormalize(tangent);
 
 		// calculate t tangent vector
 		s = dv[i]->st[0];
@@ -609,8 +300,11 @@ qboolean R_CalcTangentVectors(srfVert_t * dv[3])
 		VectorNormalize(bitangent);
 
 		// store bitangent handedness
-		CrossProduct(dv[i]->normal, dv[i]->tangent, nxt);
-		dv[i]->tangent[3] = (DotProduct(nxt, bitangent) < 0.0f) ? -1.0f : 1.0f;
+		R_VaoUnpackNormal(normal, dv[i]->normal);
+		CrossProduct(normal, tangent, nxt);
+		tangent[3] = (DotProduct(nxt, bitangent) < 0.0f) ? -1.0f : 1.0f;
+
+		R_VaoPackTangent(dv[i]->tangent, tangent);
 
 		// debug code
 		//% Sys_FPrintf( SYS_VRB, "%d S: (%f %f %f) T: (%f %f %f)\n", i,
diff --git a/SP/code/rend2/tr_marks.c b/SP/code/rend2/tr_marks.c
index 97e2b50..7cb9194 100644
--- a/SP/code/rend2/tr_marks.c
+++ b/SP/code/rend2/tr_marks.c
@@ -373,17 +373,21 @@ int R_OldMarkFragments( int numPoints, const vec3_t *points, const vec3_t projec
 					// The offset is added in the vertex normal vector direction
 					// so all triangles will still fit together.
 					// The 2 unit offset should avoid pretty much all LOD problems.
+					vec3_t fNormal;
 
 					numClipPoints = 3;
 
 					dv = cv->verts + m * cv->width + n;
 
 					VectorCopy( dv[0].xyz, clipPoints[0][0] );
-					VectorMA( clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0] );
+					R_VaoUnpackNormal(fNormal, dv[0].normal);
+					VectorMA(clipPoints[0][0], MARKER_OFFSET, fNormal, clipPoints[0][0]);
 					VectorCopy( dv[cv->width].xyz, clipPoints[0][1] );
-					VectorMA( clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1] );
+					R_VaoUnpackNormal(fNormal, dv[cv->width].normal);
+					VectorMA(clipPoints[0][1], MARKER_OFFSET, fNormal, clipPoints[0][1]);
 					VectorCopy( dv[1].xyz, clipPoints[0][2] );
-					VectorMA( clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2] );
+					R_VaoUnpackNormal(fNormal, dv[1].normal);
+					VectorMA(clipPoints[0][2], MARKER_OFFSET, fNormal, clipPoints[0][2]);
 					// check the normal of this triangle
 					VectorSubtract( clipPoints[0][0], clipPoints[0][1], v1 );
 					VectorSubtract( clipPoints[0][2], clipPoints[0][1], v2 );
@@ -403,11 +407,14 @@ int R_OldMarkFragments( int numPoints, const vec3_t *points, const vec3_t projec
 					}
 
 					VectorCopy( dv[1].xyz, clipPoints[0][0] );
-					VectorMA( clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0] );
+					R_VaoUnpackNormal(fNormal, dv[1].normal);
+					VectorMA(clipPoints[0][0], MARKER_OFFSET, fNormal, clipPoints[0][0]);
 					VectorCopy( dv[cv->width].xyz, clipPoints[0][1] );
-					VectorMA( clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1] );
+					R_VaoUnpackNormal(fNormal, dv[cv->width].normal);
+					VectorMA(clipPoints[0][1], MARKER_OFFSET, fNormal, clipPoints[0][1]);
 					VectorCopy( dv[cv->width + 1].xyz, clipPoints[0][2] );
-					VectorMA( clipPoints[0][2], MARKER_OFFSET, dv[cv->width + 1].normal, clipPoints[0][2] );
+					R_VaoUnpackNormal(fNormal, dv[cv->width + 1].normal);
+					VectorMA(clipPoints[0][2], MARKER_OFFSET, fNormal, clipPoints[0][2]);
 					// check the normal of this triangle
 					VectorSubtract( clipPoints[0][0], clipPoints[0][1], v1 );
 					VectorSubtract( clipPoints[0][2], clipPoints[0][1], v2 );
@@ -462,8 +469,10 @@ int R_OldMarkFragments( int numPoints, const vec3_t *points, const vec3_t projec
 			{
 				for(j = 0; j < 3; j++)
 				{
+					vec3_t fNormal;
 					v = surf->verts[tri[j]].xyz;
-					VectorMA(v, MARKER_OFFSET, surf->verts[tri[j]].normal, clipPoints[0][j]);
+					R_VaoUnpackNormal(fNormal, surf->verts[tri[j]].normal);
+					VectorMA(v, MARKER_OFFSET, fNormal, clipPoints[0][j]);
 				}
 
 				// add the fragments of this face
@@ -604,17 +613,21 @@ int R_MarkFragments( int orientation, const vec3_t *points, const vec3_t project
 					// The offset is added in the vertex normal vector direction
 					// so all triangles will still fit together.
 					// The 2 unit offset should avoid pretty much all LOD problems.
+					vec3_t fNormal;
 
 					numClipPoints = 3;
 
 					dv = cv->verts + m * cv->width + n;
 
 					VectorCopy( dv[0].xyz, clipPoints[0][0] );
-					VectorMA( clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0] );
+					R_VaoUnpackNormal(fNormal, dv[0].normal);
+					VectorMA(clipPoints[0][0], MARKER_OFFSET, fNormal, clipPoints[0][0]);
 					VectorCopy( dv[cv->width].xyz, clipPoints[0][1] );
-					VectorMA( clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1] );
+					R_VaoUnpackNormal(fNormal, dv[cv->width].normal);
+					VectorMA(clipPoints[0][1], MARKER_OFFSET, fNormal, clipPoints[0][1]);
 					VectorCopy( dv[1].xyz, clipPoints[0][2] );
-					VectorMA( clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2] );
+					R_VaoUnpackNormal(fNormal, dv[1].normal);
+					VectorMA(clipPoints[0][2], MARKER_OFFSET, fNormal, clipPoints[0][2]);
 					// check the normal of this triangle
 					VectorSubtract( clipPoints[0][0], clipPoints[0][1], v1 );
 					VectorSubtract( clipPoints[0][2], clipPoints[0][1], v2 );
@@ -634,11 +647,14 @@ int R_MarkFragments( int orientation, const vec3_t *points, const vec3_t project
 					}
 
 					VectorCopy( dv[1].xyz, clipPoints[0][0] );
-					VectorMA( clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0] );
+					R_VaoUnpackNormal(fNormal, dv[1].normal);
+					VectorMA(clipPoints[0][0], MARKER_OFFSET, fNormal, clipPoints[0][0]);
 					VectorCopy( dv[cv->width].xyz, clipPoints[0][1] );
-					VectorMA( clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1] );
+					R_VaoUnpackNormal(fNormal, dv[cv->width].normal);
+					VectorMA(clipPoints[0][1], MARKER_OFFSET, fNormal, clipPoints[0][1]);
 					VectorCopy( dv[cv->width + 1].xyz, clipPoints[0][2] );
-					VectorMA( clipPoints[0][2], MARKER_OFFSET, dv[cv->width + 1].normal, clipPoints[0][2] );
+					R_VaoUnpackNormal(fNormal, dv[cv->width + 1].normal);
+					VectorMA(clipPoints[0][2], MARKER_OFFSET, fNormal, clipPoints[0][2]);
 					// check the normal of this triangle
 					VectorSubtract( clipPoints[0][0], clipPoints[0][1], v1 );
 					VectorSubtract( clipPoints[0][2], clipPoints[0][1], v2 );
@@ -802,8 +818,10 @@ int R_MarkFragments( int orientation, const vec3_t *points, const vec3_t project
 			{
 				for(j = 0; j < 3; j++)
 				{
+					vec3_t fNormal;
 					v = surf->verts[tri[j]].xyz;
-					VectorMA(v, MARKER_OFFSET, surf->verts[tri[j]].normal, clipPoints[0][j]);
+					R_VaoUnpackNormal(fNormal, surf->verts[tri[j]].normal);
+					VectorMA(v, MARKER_OFFSET, fNormal, clipPoints[0][j]);
 				}
 
 				// add the fragments of this face
diff --git a/SP/code/rend2/tr_model.c b/SP/code/rend2/tr_model.c
index 2504d06..f04572e 100644
--- a/SP/code/rend2/tr_model.c
+++ b/SP/code/rend2/tr_model.c
@@ -824,6 +824,7 @@ static qboolean R_LoadMDC( model_t *mod, int lod, void *buffer, const char *modN
 			{
 				unsigned lat, lng;
 				unsigned short normal;
+				vec3_t fNormal;
 
 				v->xyz[0] = md3xyz->xyz[0] * MD3_XYZ_SCALE;
 				v->xyz[1] = md3xyz->xyz[1] * MD3_XYZ_SCALE;
@@ -836,9 +837,15 @@ static qboolean R_LoadMDC( model_t *mod, int lod, void *buffer, const char *modN
 				lat *= (FUNCTABLE_SIZE/256);
 				lng *= (FUNCTABLE_SIZE/256);
 
-				v->normal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
-				v->normal[1] = tr.sinTable[lat] * tr.sinTable[lng];
-				v->normal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
+				// decode X as cos( lat ) * sin( long )
+				// decode Y as sin( lat ) * sin( long )
+				// decode Z as cos( long )
+
+				fNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
+				fNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
+				fNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
+
+				R_VaoPackNormal(v->normal, fNormal);
 			}
 		}
 
@@ -857,9 +864,12 @@ static qboolean R_LoadMDC( model_t *mod, int lod, void *buffer, const char *modN
 				for(k = 0; k < mdcSurf->numVerts; k++, mdcxyzComp++, v++)
 				{
 					vec3_t ofsVec;
-					R_MDC_DecodeXyzCompressed( mdcxyzComp->ofsVec, ofsVec, v->normal );
+					vec3_t fNormal;
+
+					R_MDC_DecodeXyzCompressed(mdcxyzComp->ofsVec, ofsVec, fNormal);
 					VectorAdd( v->xyz, ofsVec, v->xyz );
 
+					R_VaoPackNormal(v->normal, fNormal);
 				}
 			}
 		}
@@ -867,10 +877,13 @@ static qboolean R_LoadMDC( model_t *mod, int lod, void *buffer, const char *modN
 #ifdef USE_VERT_TANGENT_SPACE
 		// calc tangent spaces
 		{
+			vec3_t *sdirs = ri.Z_Malloc(sizeof(*sdirs) * surf->numVerts * mdvModel->numFrames);
+			vec3_t *tdirs = ri.Z_Malloc(sizeof(*tdirs) * surf->numVerts * mdvModel->numFrames);
+
 			for(j = 0, v = surf->verts; j < (surf->numVerts * mdvModel->numFrames); j++, v++)
 			{
-				VectorClear(v->tangent);
-				VectorClear(v->bitangent);
+				VectorClear(sdirs[j]);
+				VectorClear(tdirs[j]);
 			}
 
 			for(f = 0; f < mdvModel->numFrames; f++)
@@ -895,27 +908,32 @@ static qboolean R_LoadMDC( model_t *mod, int lod, void *buffer, const char *modN
 
 					R_CalcTexDirs(sdir, tdir, v0, v1, v2, t0, t1, t2);
 				
-					VectorAdd(sdir, surf->verts[index0].tangent,   surf->verts[index0].tangent);
-					VectorAdd(sdir, surf->verts[index1].tangent,   surf->verts[index1].tangent);
-					VectorAdd(sdir, surf->verts[index2].tangent,   surf->verts[index2].tangent);
-					VectorAdd(tdir, surf->verts[index0].bitangent, surf->verts[index0].bitangent);
-					VectorAdd(tdir, surf->verts[index1].bitangent, surf->verts[index1].bitangent);
-					VectorAdd(tdir, surf->verts[index2].bitangent, surf->verts[index2].bitangent);
+					VectorAdd(sdir, sdirs[index0], sdirs[index0]);
+					VectorAdd(sdir, sdirs[index1], sdirs[index1]);
+					VectorAdd(sdir, sdirs[index2], sdirs[index2]);
+					VectorAdd(tdir, tdirs[index0], tdirs[index0]);
+					VectorAdd(tdir, tdirs[index1], tdirs[index1]);
+					VectorAdd(tdir, tdirs[index2], tdirs[index2]);
 				}
 			}
 
 			for(j = 0, v = surf->verts; j < (surf->numVerts * mdvModel->numFrames); j++, v++)
 			{
-				vec3_t sdir, tdir;
+				vec3_t normal;
+				vec4_t tangent;
+
+				VectorNormalize(sdirs[j]);
+				VectorNormalize(tdirs[j]);
 
-				VectorCopy(v->tangent,   sdir);
-				VectorCopy(v->bitangent, tdir);
+				R_VaoUnpackNormal(normal, v->normal);
 
-				VectorNormalize(sdir);
-				VectorNormalize(tdir);
+				tangent[3] = R_CalcTangentSpace(tangent, NULL, normal, sdirs[j], tdirs[j]);
 
-				R_CalcTbnFromNormalAndTexDirs(v->tangent, v->bitangent, v->normal, sdir, tdir);
+				R_VaoPackTangent(v->tangent, tangent);
 			}
+
+			ri.Free(sdirs);
+			ri.Free(tdirs);
 		}
 #endif
 
@@ -945,11 +963,11 @@ static qboolean R_LoadMDC( model_t *mod, int lod, void *buffer, const char *modN
 				offset_st      = 0;
 				offset_xyz     = surf->numVerts * glRefConfig.packedTexcoordDataSize;
 				offset_normal  = offset_xyz + sizeof(vec3_t);
-				offset_tangent = offset_normal + sizeof(uint32_t);
+				offset_tangent = offset_normal + sizeof(int16_t) * 4;
 				stride_st  = glRefConfig.packedTexcoordDataSize;
-				stride_xyz = sizeof(vec3_t) + sizeof(uint32_t);
+				stride_xyz = sizeof(vec3_t) + sizeof(int16_t) * 4;
 #ifdef USE_VERT_TANGENT_SPACE
-				stride_xyz += sizeof(uint32_t);
+				stride_xyz += sizeof(int16_t) * 4;
 #endif
 				stride_normal = stride_tangent = stride_xyz;
 
@@ -961,11 +979,11 @@ static qboolean R_LoadMDC( model_t *mod, int lod, void *buffer, const char *modN
 				offset_xyz     = 0;
 				offset_st      = offset_xyz + sizeof(vec3_t);
 				offset_normal  = offset_st + glRefConfig.packedTexcoordDataSize;
-				offset_tangent = offset_normal + sizeof(uint32_t);
+				offset_tangent = offset_normal + sizeof(int16_t) * 4;
 #ifdef USE_VERT_TANGENT_SPACE
-				stride_xyz = offset_tangent + sizeof(uint32_t);
+				stride_xyz = offset_tangent + sizeof(int16_t) * 4;
 #else
-				stride_xyz = offset_normal + sizeof(uint32_t);
+				stride_xyz = offset_normal + sizeof(int16_t) * 4;
 #endif
 				stride_st = stride_normal = stride_tangent = stride_xyz;
 
@@ -986,24 +1004,19 @@ static qboolean R_LoadMDC( model_t *mod, int lod, void *buffer, const char *modN
 				v = surf->verts;
 				for ( j = 0; j < surf->numVerts * mdvModel->numFrames ; j++, v++ )
 				{
-#ifdef USE_VERT_TANGENT_SPACE
-					vec3_t nxt;
-					vec4_t tangent;
-#endif
 					// xyz
 					memcpy(data + dataOfs, &v->xyz, sizeof(vec3_t));
 					dataOfs += sizeof(vec3_t);
 
 					// normal
-					dataOfs += R_VaoPackNormal(data + dataOfs, v->normal);
+					memcpy(data + dataOfs, &v->normal, sizeof(int16_t) * 4);
+					dataOfs += sizeof(int16_t) * 4;
 
 #ifdef USE_VERT_TANGENT_SPACE
-					CrossProduct(v->normal, v->tangent, nxt);
-					VectorCopy(v->tangent, tangent);
-					tangent[3] = (DotProduct(nxt, v->bitangent) < 0.0f) ? -1.0f : 1.0f;
 
 					// tangent
-					dataOfs += R_VaoPackTangent(data + dataOfs, tangent);
+					memcpy(data + dataOfs, &v->tangent, sizeof(int16_t) * 4);
+					dataOfs += sizeof(int16_t) * 4;
 #endif
 				}
 			}
@@ -1013,10 +1026,6 @@ static qboolean R_LoadMDC( model_t *mod, int lod, void *buffer, const char *modN
 				st = surf->st;
 				for ( j = 0; j < surf->numVerts; j++, v++, st++ )
 				{
-#ifdef USE_VERT_TANGENT_SPACE
-					vec3_t nxt;
-					vec4_t tangent;
-#endif
 					// xyz
 					memcpy(data + dataOfs, &v->xyz, sizeof(vec3_t));
 					dataOfs += sizeof(v->xyz);
@@ -1025,15 +1034,14 @@ static qboolean R_LoadMDC( model_t *mod, int lod, void *buffer, const char *modN
 					dataOfs += R_VaoPackTexCoord(data + dataOfs, st->st);
 
 					// normal
-					dataOfs += R_VaoPackNormal(data + dataOfs, v->normal);
+					memcpy(data + dataOfs, &v->normal, sizeof(int16_t) * 4);
+					dataOfs += sizeof(int16_t) * 4;
 
 #ifdef USE_VERT_TANGENT_SPACE
-					CrossProduct(v->normal, v->tangent, nxt);
-					VectorCopy(v->tangent, tangent);
-					tangent[3] = (DotProduct(nxt, v->bitangent) < 0.0f) ? -1.0f : 1.0f;
 
 					// tangent
-					dataOfs += R_VaoPackTangent(data + dataOfs, tangent);
+					memcpy(data + dataOfs, &v->tangent, sizeof(int16_t) * 4);
+					dataOfs += sizeof(int16_t) * 4;
 #endif
 				}
 			}
@@ -1062,8 +1070,8 @@ static qboolean R_LoadMDC( model_t *mod, int lod, void *buffer, const char *modN
 
 			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].type = GL_FLOAT;
 			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].type = glRefConfig.packedTexcoordDataType;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].type = glRefConfig.packedNormalDataType;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].type = glRefConfig.packedNormalDataType;
+			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].type = GL_SHORT;
+			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].type = GL_SHORT;
 
 			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].normalized = GL_FALSE;
 			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].normalized = GL_FALSE;
@@ -1329,6 +1337,7 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, const char *modN
 		{
 			unsigned lat, lng;
 			unsigned short normal;
+			vec3_t fNormal;
 
 			v->xyz[0] = LittleShort(md3xyz->xyz[0]) * MD3_XYZ_SCALE;
 			v->xyz[1] = LittleShort(md3xyz->xyz[1]) * MD3_XYZ_SCALE;
@@ -1341,11 +1350,15 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, const char *modN
 			lat *= (FUNCTABLE_SIZE/256);
 			lng *= (FUNCTABLE_SIZE/256);
 
+			// decode X as cos( lat ) * sin( long )
+			// decode Y as sin( lat ) * sin( long )
+			// decode Z as cos( long )
+ 
+			fNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
+			fNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
+			fNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
 
-
-			v->normal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
-			v->normal[1] = tr.sinTable[lat] * tr.sinTable[lng];
-			v->normal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
+			R_VaoPackNormal(v->normal, fNormal);
 		}
 
 		// swap all the ST
@@ -1361,10 +1374,13 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, const char *modN
 #ifdef USE_VERT_TANGENT_SPACE
 		// calc tangent spaces
 		{
+			vec3_t *sdirs = ri.Z_Malloc(sizeof(*sdirs) * surf->numVerts * mdvModel->numFrames);
+			vec3_t *tdirs = ri.Z_Malloc(sizeof(*tdirs) * surf->numVerts * mdvModel->numFrames);
+
 			for(j = 0, v = surf->verts; j < (surf->numVerts * mdvModel->numFrames); j++, v++)
 			{
-				VectorClear(v->tangent);
-				VectorClear(v->bitangent);
+				VectorClear(sdirs[j]);
+				VectorClear(tdirs[j]);
 			}
 
 			for(f = 0; f < mdvModel->numFrames; f++)
@@ -1389,27 +1405,32 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, const char *modN
 
 					R_CalcTexDirs(sdir, tdir, v0, v1, v2, t0, t1, t2);
 				
-					VectorAdd(sdir, surf->verts[index0].tangent,   surf->verts[index0].tangent);
-					VectorAdd(sdir, surf->verts[index1].tangent,   surf->verts[index1].tangent);
-					VectorAdd(sdir, surf->verts[index2].tangent,   surf->verts[index2].tangent);
-					VectorAdd(tdir, surf->verts[index0].bitangent, surf->verts[index0].bitangent);
-					VectorAdd(tdir, surf->verts[index1].bitangent, surf->verts[index1].bitangent);
-					VectorAdd(tdir, surf->verts[index2].bitangent, surf->verts[index2].bitangent);
+					VectorAdd(sdir, sdirs[index0], sdirs[index0]);
+					VectorAdd(sdir, sdirs[index1], sdirs[index1]);
+					VectorAdd(sdir, sdirs[index2], sdirs[index2]);
+					VectorAdd(tdir, tdirs[index0], tdirs[index0]);
+					VectorAdd(tdir, tdirs[index1], tdirs[index1]);
+					VectorAdd(tdir, tdirs[index2], tdirs[index2]);
 				}
 			}
 
 			for(j = 0, v = surf->verts; j < (surf->numVerts * mdvModel->numFrames); j++, v++)
 			{
-				vec3_t sdir, tdir;
+				vec3_t normal;
+				vec4_t tangent;
+
+				VectorNormalize(sdirs[j]);
+				VectorNormalize(tdirs[j]);
 
-				VectorCopy(v->tangent,   sdir);
-				VectorCopy(v->bitangent, tdir);
+				R_VaoUnpackNormal(normal, v->normal);
 
-				VectorNormalize(sdir);
-				VectorNormalize(tdir);
+				tangent[3] = R_CalcTangentSpace(tangent, NULL, normal, sdirs[j], tdirs[j]);
 
-				R_CalcTbnFromNormalAndTexDirs(v->tangent, v->bitangent, v->normal, sdir, tdir);
+				R_VaoPackTangent(v->tangent, tangent);
 			}
+
+			ri.Free(sdirs);
+			ri.Free(tdirs);
 		}
 #endif
 
@@ -1439,11 +1460,11 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, const char *modN
 				offset_st      = 0;
 				offset_xyz     = surf->numVerts * glRefConfig.packedTexcoordDataSize;
 				offset_normal  = offset_xyz + sizeof(vec3_t);
-				offset_tangent = offset_normal + sizeof(uint32_t);
+				offset_tangent = offset_normal + sizeof(int16_t) * 4;
 				stride_st  = glRefConfig.packedTexcoordDataSize;
-				stride_xyz = sizeof(vec3_t) + sizeof(uint32_t);
+				stride_xyz = sizeof(vec3_t) + sizeof(int16_t) * 4;
 #ifdef USE_VERT_TANGENT_SPACE
-				stride_xyz += sizeof(uint32_t);
+				stride_xyz += sizeof(int16_t) * 4;
 #endif
 				stride_normal = stride_tangent = stride_xyz;
 
@@ -1455,11 +1476,11 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, const char *modN
 				offset_xyz     = 0;
 				offset_st      = offset_xyz + sizeof(vec3_t);
 				offset_normal  = offset_st + glRefConfig.packedTexcoordDataSize;
-				offset_tangent = offset_normal + sizeof(uint32_t);
+				offset_tangent = offset_normal + sizeof(int16_t) * 4;
 #ifdef USE_VERT_TANGENT_SPACE
-				stride_xyz = offset_tangent + sizeof(uint32_t);
+				stride_xyz = offset_tangent + sizeof(int16_t) * 4;
 #else
-				stride_xyz = offset_normal + sizeof(uint32_t);
+				stride_xyz = offset_normal + sizeof(int16_t) * 4;
 #endif
 				stride_st = stride_normal = stride_tangent = stride_xyz;
 
@@ -1480,24 +1501,19 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, const char *modN
 				v = surf->verts;
 				for ( j = 0; j < surf->numVerts * mdvModel->numFrames ; j++, v++ )
 				{
-#ifdef USE_VERT_TANGENT_SPACE
-					vec3_t nxt;
-					vec4_t tangent;
-#endif
 					// xyz
 					memcpy(data + dataOfs, &v->xyz, sizeof(vec3_t));
 					dataOfs += sizeof(vec3_t);
 
 					// normal
-					dataOfs += R_VaoPackNormal(data + dataOfs, v->normal);
+					memcpy(data + dataOfs, &v->normal, sizeof(int16_t) * 4);
+					dataOfs += sizeof(int16_t) * 4;
 
 #ifdef USE_VERT_TANGENT_SPACE
-					CrossProduct(v->normal, v->tangent, nxt);
-					VectorCopy(v->tangent, tangent);
-					tangent[3] = (DotProduct(nxt, v->bitangent) < 0.0f) ? -1.0f : 1.0f;
 
 					// tangent
-					dataOfs += R_VaoPackTangent(data + dataOfs, tangent);
+					memcpy(data + dataOfs, &v->tangent, sizeof(int16_t) * 4);
+					dataOfs += sizeof(int16_t) * 4;
 #endif
 				}
 			}
@@ -1507,10 +1523,6 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, const char *modN
 				st = surf->st;
 				for ( j = 0; j < surf->numVerts; j++, v++, st++ )
 				{
-#ifdef USE_VERT_TANGENT_SPACE
-					vec3_t nxt;
-					vec4_t tangent;
-#endif
 					// xyz
 					memcpy(data + dataOfs, &v->xyz, sizeof(vec3_t));
 					dataOfs += sizeof(v->xyz);
@@ -1519,15 +1531,14 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, const char *modN
 					dataOfs += R_VaoPackTexCoord(data + dataOfs, st->st);
 
 					// normal
-					dataOfs += R_VaoPackNormal(data + dataOfs, v->normal);
+					memcpy(data + dataOfs, &v->normal, sizeof(int16_t) * 4);
+					dataOfs += sizeof(int16_t) * 4;
 
 #ifdef USE_VERT_TANGENT_SPACE
-					CrossProduct(v->normal, v->tangent, nxt);
-					VectorCopy(v->tangent, tangent);
-					tangent[3] = (DotProduct(nxt, v->bitangent) < 0.0f) ? -1.0f : 1.0f;
 
 					// tangent
-					dataOfs += R_VaoPackTangent(data + dataOfs, tangent);
+					memcpy(data + dataOfs, &v->tangent, sizeof(int16_t) * 4);
+					dataOfs += sizeof(int16_t) * 4;
 #endif
 				}
 			}
@@ -1556,8 +1567,8 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, const char *modN
 
 			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].type = GL_FLOAT;
 			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].type = glRefConfig.packedTexcoordDataType;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].type = glRefConfig.packedNormalDataType;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].type = glRefConfig.packedNormalDataType;
+			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].type = GL_SHORT;
+			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].type = GL_SHORT;
 
 			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].normalized = GL_FALSE;
 			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].normalized = GL_FALSE;
@@ -2042,6 +2053,9 @@ static qboolean R_LoadMDS( model_t *mod, void *buffer, const char *mod_name ) {
 			LL( surf->ofsEnd );
 		}
 
+		// change to surface identifier
+		surf->ident = SF_MDS;
+
 		if ( surf->numVerts >= SHADER_MAX_VERTEXES ) {
 			ri.Printf(PRINT_WARNING, "R_LoadMDS: %s has more than %i verts on %s (%i).\n",
 				mod_name, SHADER_MAX_VERTEXES - 1, surf->name[0] ? surf->name : "a surface",
diff --git a/SP/code/rend2/tr_model_iqm.c b/SP/code/rend2/tr_model_iqm.c
index 4e51c18..59b6e28 100644
--- a/SP/code/rend2/tr_model_iqm.c
+++ b/SP/code/rend2/tr_model_iqm.c
@@ -1024,9 +1024,9 @@ void RB_IQMSurfaceAnim( surfaceType_t *surface ) {
 	int		i;
 
 	vec4_t		*outXYZ;
-	uint32_t	*outNormal;
+	int16_t	*outNormal;
 #ifdef USE_VERT_TANGENT_SPACE
-	uint32_t	*outTangent;
+	int16_t	*outTangent;
 #endif
 	vec2_t		(*outTexCoord)[2];
 	vec4_t	*outColor;
@@ -1042,9 +1042,9 @@ void RB_IQMSurfaceAnim( surfaceType_t *surface ) {
 	RB_CHECKOVERFLOW( surf->num_vertexes, surf->num_triangles * 3 );
 
 	outXYZ = &tess.xyz[tess.numVertexes];
-	outNormal = &tess.normal[tess.numVertexes];
+	outNormal = tess.normal[tess.numVertexes];
 #ifdef USE_VERT_TANGENT_SPACE
-	outTangent = &tess.tangent[tess.numVertexes];
+	outTangent = tess.tangent[tess.numVertexes];
 #endif
 	outTexCoord = &tess.texCoords[tess.numVertexes];
 	outColor = &tess.vertexColors[tess.numVertexes];
@@ -1056,7 +1056,7 @@ void RB_IQMSurfaceAnim( surfaceType_t *surface ) {
 
 	// transform vertexes and fill other data
 	for( i = 0; i < surf->num_vertexes;
-	     i++, outXYZ++, outNormal++, outTexCoord++, outColor++ ) {
+		i++, outXYZ++, outNormal+=4, outTexCoord++, outColor++ ) {
 		int	j, k;
 		float	vtxMat[12];
 		float	nrmMat[9];
@@ -1130,7 +1130,7 @@ void RB_IQMSurfaceAnim( surfaceType_t *surface ) {
 			normal[1] = DotProduct(&nrmMat[3], &data->normals[3*vtx]);
 			normal[2] = DotProduct(&nrmMat[6], &data->normals[3*vtx]);
 
-			R_VaoPackNormal((byte *)outNormal, normal);
+			R_VaoPackNormal(outNormal, normal);
 
 #ifdef USE_VERT_TANGENT_SPACE
 			tangent[0] = DotProduct(&nrmMat[0], &data->tangents[4*vtx]);
@@ -1138,7 +1138,8 @@ void RB_IQMSurfaceAnim( surfaceType_t *surface ) {
 			tangent[2] = DotProduct(&nrmMat[6], &data->tangents[4*vtx]);
 			tangent[3] = data->tangents[4*vtx+3];
 
-			R_VaoPackTangent((byte *)outTangent++, tangent);
+			R_VaoPackTangent(outTangent, tangent);
+			outTangent+=4;
 #endif
 		}
 
diff --git a/SP/code/rend2/tr_shade_calc.c b/SP/code/rend2/tr_shade_calc.c
index d1e6b44..ba73d65 100644
--- a/SP/code/rend2/tr_shade_calc.c
+++ b/SP/code/rend2/tr_shade_calc.c
@@ -117,7 +117,7 @@ void RB_CalcDeformVertexes( deformStage_t *ds ) {
 	vec3_t offset;
 	float scale;
 	float   *xyz = ( float * ) tess.xyz;
-	uint32_t	*normal = tess.normal;
+	int16_t	*normal = tess.normal[0];
 	float   *table;
 
 	// Ridah
@@ -147,13 +147,13 @@ void RB_CalcDeformVertexes( deformStage_t *ds ) {
 
 		table = TableForFunc( ds->deformationWave.func );
 
-		for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal++ )
+		for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 )
 		{
 			float off = ( xyz[0] + xyz[1] + xyz[2] ) * ds->deformationSpread;
 			float dot;
 			vec3_t fNormal;
 
-			R_VaoUnpackNormal(fNormal, *normal);
+			R_VaoUnpackNormal(fNormal, normal);
 
 			scale = WAVEVALUE( table, ds->deformationWave.base,
 							   ds->deformationWave.amplitude,
@@ -179,19 +179,19 @@ void RB_CalcDeformVertexes( deformStage_t *ds ) {
 	else if ( ds->deformationWave.frequency == 0 ) {
 		scale = EvalWaveForm( &ds->deformationWave );
 
-		for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal++ )
+		for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 )
 		{
-			R_VaoUnpackNormal(offset, *normal);
+			R_VaoUnpackNormal(offset, normal);
 
 			xyz[0] += offset[0] * scale;
 			xyz[1] += offset[1] * scale;
 			xyz[2] += offset[2] * scale;
 		}
-	} else
-	{
+	}
+	else {
 		table = TableForFunc( ds->deformationWave.func );
 
-		for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal++ )
+		for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 )
 		{
 			float off = ( xyz[0] + xyz[1] + xyz[2] ) * ds->deformationSpread;
 
@@ -200,7 +200,7 @@ void RB_CalcDeformVertexes( deformStage_t *ds ) {
 							   ds->deformationWave.phase + off,
 							   ds->deformationWave.frequency );
 
-			R_VaoUnpackNormal(offset, *normal);
+			R_VaoUnpackNormal(offset, normal);
 
 			xyz[0] += offset[0] * scale;
 			xyz[1] += offset[1] * scale;
@@ -220,12 +220,12 @@ void RB_CalcDeformNormals( deformStage_t *ds ) {
 	int i;
 	float scale;
 	float   *xyz = ( float * ) tess.xyz;
-	uint32_t *normal = tess.normal;
+	int16_t *normal = tess.normal[0];
 
-	for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal++ ) {
+	for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 ) {
 		vec3_t fNormal;
 
-		R_VaoUnpackNormal(fNormal, *normal);
+		R_VaoUnpackNormal(fNormal, normal);
 
 		scale = 0.98f;
 		scale = R_NoiseGet4f( xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,
@@ -244,7 +244,7 @@ void RB_CalcDeformNormals( deformStage_t *ds ) {
 
 		VectorNormalizeFast( fNormal );
 
-		R_VaoPackNormal((byte *)normal, fNormal);
+		R_VaoPackNormal(normal, fNormal);
 	}
 }
 
@@ -258,17 +258,17 @@ void RB_CalcBulgeVertexes( deformStage_t *ds ) {
 	int i;
 	const float	*st = ( const float * ) tess.texCoords[0];
 	float		*xyz = ( float * ) tess.xyz;
-	uint32_t		*normal = tess.normal;
+	int16_t	*normal = tess.normal[0];
 	float now;
 
 	now = backEnd.refdef.time * ds->bulgeSpeed * 0.001f;
 
-	for ( i = 0; i < tess.numVertexes; i++, xyz += 4, st += 4, normal++ ) {
+	for ( i = 0; i < tess.numVertexes; i++, xyz += 4, st += 4, normal += 4 ) {
 		int off;
 		float scale;
 		vec3_t fNormal;
 
-		R_VaoUnpackNormal(fNormal, *normal);
+		R_VaoUnpackNormal(fNormal, normal);
 
 		off = (float)( FUNCTABLE_SIZE / ( M_PI * 2 ) ) * ( st[0] * ds->bulgeWidth + now );
 
@@ -811,7 +811,7 @@ void RB_CalcFogTexCoords( float *st ) {
 void RB_CalcFireRiseEnvTexCoords( float *st ) {
 	int i;
 	float       *v;
-	uint32_t *normal = tess.normal;
+	int16_t *normal = tess.normal[0];
 	vec3_t fNormal, viewer, reflected;
 	float d;
 
@@ -822,7 +822,7 @@ void RB_CalcFireRiseEnvTexCoords( float *st ) {
 	{
 		VectorNormalizeFast( viewer );
 
-		R_VaoUnpackNormal(fNormal, *normal);
+		R_VaoUnpackNormal(fNormal, normal);
 
 		d = DotProduct( fNormal, viewer );
 
diff --git a/SP/code/rend2/tr_surface.c b/SP/code/rend2/tr_surface.c
index c06a743..dd67be6 100644
--- a/SP/code/rend2/tr_surface.c
+++ b/SP/code/rend2/tr_surface.c
@@ -94,7 +94,7 @@ RB_AddQuadStampExt
 */
 void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, float color[4], float s1, float t1, float s2, float t2 ) {
 	vec3_t normal;
-	uint32_t    pNormal;
+	int16_t     iNormal[4];
 	int ndx;
 
 	RB_CheckVao(tess.vao);
@@ -132,11 +132,12 @@ void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, float color[4],
 	// constant normal all the way around
 	VectorSubtract( vec3_origin, backEnd.viewParms.or.axis[0], normal );
 
-	R_VaoPackNormal((byte *)&pNormal, normal);
-	tess.normal[ndx] =
-	tess.normal[ndx+1] =
-	tess.normal[ndx+2] =
-	tess.normal[ndx+3] = pNormal;
+	R_VaoPackNormal(iNormal, normal);
+
+	VectorCopy4(tess.normal[ndx], iNormal);
+	VectorCopy4(tess.normal[ndx+1], iNormal);
+	VectorCopy4(tess.normal[ndx+2], iNormal);
+	VectorCopy4(tess.normal[ndx+3], iNormal);
 
 	// standard square texture coordinates
 	VectorSet2(tess.texCoords[ndx  ][0], s1, t1);
@@ -348,10 +349,10 @@ static void RB_SurfaceVertsAndIndexes( int numVerts, srfVert_t *verts, int numIn
 	glIndex_t      *inIndex;
 	srfVert_t      *dv;
 	float          *xyz, *texCoords, *lightCoords;
-	uint32_t        *lightdir;
-	uint32_t        *normal;
+	int16_t        *lightdir;
+	int16_t        *normal;
 #ifdef USE_VERT_TANGENT_SPACE
-	uint32_t        *tangent;
+	int16_t        *tangent;
 #endif
 	glIndex_t      *outIndex;
 	float		*color;
@@ -378,18 +379,18 @@ static void RB_SurfaceVertsAndIndexes( int numVerts, srfVert_t *verts, int numIn
 	if ( tess.shader->vertexAttribs & ATTR_NORMAL )
 	{
 		dv = verts;
-		normal = &tess.normal[ tess.numVertexes ];
-		for ( i = 0 ; i < numVerts ; i++, dv++, normal++ )
-			R_VaoPackNormal((byte *)normal, dv->normal);
+		normal = tess.normal[ tess.numVertexes ];
+		for ( i = 0 ; i < numVerts ; i++, dv++, normal+=4 )
+			VectorCopy4(dv->normal, normal);
 	}
 
 #ifdef USE_VERT_TANGENT_SPACE
 	if ( tess.shader->vertexAttribs & ATTR_TANGENT )
 	{
 		dv = verts;
-		tangent = &tess.tangent[ tess.numVertexes ];
-		for ( i = 0 ; i < numVerts ; i++, dv++, tangent++ )
-			R_VaoPackTangent((byte *)tangent, dv->tangent);
+		tangent = tess.tangent[ tess.numVertexes ];
+		for ( i = 0 ; i < numVerts ; i++, dv++, tangent+=4 )
+			VectorCopy4(dv->tangent, tangent);
 	}
 #endif
 
@@ -420,9 +421,9 @@ static void RB_SurfaceVertsAndIndexes( int numVerts, srfVert_t *verts, int numIn
 	if ( tess.shader->vertexAttribs & ATTR_LIGHTDIRECTION )
 	{
 		dv = verts;
-		lightdir = &tess.lightdir[ tess.numVertexes ];
-		for ( i = 0 ; i < numVerts ; i++, dv++, lightdir++ )
-			R_VaoPackNormal((byte *)lightdir, dv->lightdir);
+		lightdir = tess.lightdir[ tess.numVertexes ];
+		for ( i = 0 ; i < numVerts ; i++, dv++, lightdir+=4 )
+			VectorCopy4(dv->lightdir, lightdir);
 	}
 
 #if 0  // nothing even uses vertex dlightbits
@@ -866,306 +867,18 @@ static void RB_SurfaceLightningBolt( void ) {
 	}
 }
 
-/*
-** VectorArrayNormalize
-*
-* The inputs to this routing seem to always be close to length = 1.0 (about 0.6 to 2.0)
-* This means that we don't have to worry about zero length or enormously long vectors.
-*/
-#if 0 // Unused in rend2
-static void VectorArrayNormalize( vec4_t *normals, unsigned int count ) {
-//    assert(count);
-
-#if idppc
-	{
-		register float half = 0.5;
-		register float one  = 1.0;
-		float *components = (float *)normals;
-
-		// Vanilla PPC code, but since PPC has a reciprocal square root estimate instruction,
-		// runs *much* faster than calling sqrt().  We'll use a single Newton-Raphson
-		// refinement step to get a little more precision.  This seems to yeild results
-		// that are correct to 3 decimal places and usually correct to at least 4 (sometimes 5).
-		// (That is, for the given input range of about 0.6 to 2.0).
-		do {
-			float x, y, z;
-			float B, y0, y1;
-
-			x = components[0];
-			y = components[1];
-			z = components[2];
-			components += 4;
-			B = x * x + y * y + z * z;
-
-#ifdef __GNUC__
-			asm ( "frsqrte %0,%1" : "=f" ( y0 ) : "f" ( B ) );
-#else
-			y0 = __frsqrte( B );
-#endif
-			y1 = y0 + half * y0 * ( one - B * y0 * y0 );
-
-			x = x * y1;
-			y = y * y1;
-			components[-4] = x;
-			z = z * y1;
-			components[-3] = y;
-			components[-2] = z;
-		} while ( count-- );
-	}
-#else // No assembly version for this architecture, or C_ONLY defined
-	  // given the input, it's safe to call VectorNormalizeFast
-	while ( count-- ) {
-		VectorNormalizeFast( normals[0] );
-		normals++;
-	}
-#endif
-}
-#endif
-
-
-
-/*
-** LerpMeshVertexes
-*/
-#if 0 // Unused
-#if idppc_altivec
-static void LerpMeshVertexes_altivec(md3Surface_t *surf, float backlerp)
-{
-	short	*oldXyz, *newXyz, *oldNormals, *newNormals;
-	float	*outXyz, *outNormal;
-	float	oldXyzScale QALIGN(16);
-	float   newXyzScale QALIGN(16);
-	float	oldNormalScale QALIGN(16);
-	float newNormalScale QALIGN(16);
-	int		vertNum;
-	unsigned lat, lng;
-	int		numVerts;
-
-	outXyz = tess.xyz[tess.numVertexes];
-	outNormal = tess.normal[tess.numVertexes];
-
-	newXyz = (short *)((byte *)surf + surf->ofsXyzNormals)
-		+ (backEnd.currentEntity->e.frame * surf->numVerts * 4);
-	newNormals = newXyz + 3;
-
-	newXyzScale = MD3_XYZ_SCALE * (1.0 - backlerp);
-	newNormalScale = 1.0 - backlerp;
-
-	numVerts = surf->numVerts;
-
-	if ( backlerp == 0 ) {
-		vector signed short newNormalsVec0;
-		vector signed short newNormalsVec1;
-		vector signed int newNormalsIntVec;
-		vector float newNormalsFloatVec;
-		vector float newXyzScaleVec;
-		vector unsigned char newNormalsLoadPermute;
-		vector unsigned char newNormalsStorePermute;
-		vector float zero;
-		
-		newNormalsStorePermute = vec_lvsl(0,(float *)&newXyzScaleVec);
-		newXyzScaleVec = *(vector float *)&newXyzScale;
-		newXyzScaleVec = vec_perm(newXyzScaleVec,newXyzScaleVec,newNormalsStorePermute);
-		newXyzScaleVec = vec_splat(newXyzScaleVec,0);		
-		newNormalsLoadPermute = vec_lvsl(0,newXyz);
-		newNormalsStorePermute = vec_lvsr(0,outXyz);
-		zero = (vector float)vec_splat_s8(0);
-		//
-		// just copy the vertexes
-		//
-		for (vertNum=0 ; vertNum < numVerts ; vertNum++,
-			newXyz += 4, newNormals += 4,
-			outXyz += 4, outNormal += 4) 
-		{
-			newNormalsLoadPermute = vec_lvsl(0,newXyz);
-			newNormalsStorePermute = vec_lvsr(0,outXyz);
-			newNormalsVec0 = vec_ld(0,newXyz);
-			newNormalsVec1 = vec_ld(16,newXyz);
-			newNormalsVec0 = vec_perm(newNormalsVec0,newNormalsVec1,newNormalsLoadPermute);
-			newNormalsIntVec = vec_unpackh(newNormalsVec0);
-			newNormalsFloatVec = vec_ctf(newNormalsIntVec,0);
-			newNormalsFloatVec = vec_madd(newNormalsFloatVec,newXyzScaleVec,zero);
-			newNormalsFloatVec = vec_perm(newNormalsFloatVec,newNormalsFloatVec,newNormalsStorePermute);
-			//outXyz[0] = newXyz[0] * newXyzScale;
-			//outXyz[1] = newXyz[1] * newXyzScale;
-			//outXyz[2] = newXyz[2] * newXyzScale;
-
-			lat = ( newNormals[0] >> 8 ) & 0xff;
-			lng = ( newNormals[0] & 0xff );
-			lat *= (FUNCTABLE_SIZE/256);
-			lng *= (FUNCTABLE_SIZE/256);
-
-			// decode X as cos( lat ) * sin( long )
-			// decode Y as sin( lat ) * sin( long )
-			// decode Z as cos( long )
-
-			outNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
-			outNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
-			outNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
-
-			vec_ste(newNormalsFloatVec,0,outXyz);
-			vec_ste(newNormalsFloatVec,4,outXyz);
-			vec_ste(newNormalsFloatVec,8,outXyz);
-		}
-	} else {
-		//
-		// interpolate and copy the vertex and normal
-		//
-		oldXyz = (short *)((byte *)surf + surf->ofsXyzNormals)
-			+ (backEnd.currentEntity->e.oldframe * surf->numVerts * 4);
-		oldNormals = oldXyz + 3;
-
-		oldXyzScale = MD3_XYZ_SCALE * backlerp;
-		oldNormalScale = backlerp;
-
-		for (vertNum=0 ; vertNum < numVerts ; vertNum++,
-			oldXyz += 4, newXyz += 4, oldNormals += 4, newNormals += 4,
-			outXyz += 4, outNormal += 4) 
-		{
-			vec3_t uncompressedOldNormal, uncompressedNewNormal;
-
-			// interpolate the xyz
-			outXyz[0] = oldXyz[0] * oldXyzScale + newXyz[0] * newXyzScale;
-			outXyz[1] = oldXyz[1] * oldXyzScale + newXyz[1] * newXyzScale;
-			outXyz[2] = oldXyz[2] * oldXyzScale + newXyz[2] * newXyzScale;
-
-			// FIXME: interpolate lat/long instead?
-			lat = ( newNormals[0] >> 8 ) & 0xff;
-			lng = ( newNormals[0] & 0xff );
-			lat *= 4;
-			lng *= 4;
-			uncompressedNewNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
-			uncompressedNewNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
-			uncompressedNewNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
-
-			lat = ( oldNormals[0] >> 8 ) & 0xff;
-			lng = ( oldNormals[0] & 0xff );
-			lat *= 4;
-			lng *= 4;
-
-			uncompressedOldNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
-			uncompressedOldNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
-			uncompressedOldNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
-
-			outNormal[0] = uncompressedOldNormal[0] * oldNormalScale + uncompressedNewNormal[0] * newNormalScale;
-			outNormal[1] = uncompressedOldNormal[1] * oldNormalScale + uncompressedNewNormal[1] * newNormalScale;
-			outNormal[2] = uncompressedOldNormal[2] * oldNormalScale + uncompressedNewNormal[2] * newNormalScale;
-
-//			VectorNormalize (outNormal);
-		}
-    	VectorArrayNormalize((vec4_t *)tess.normal[tess.numVertexes], numVerts);
-   	}
-}
-#endif
-#endif
-
-static void LerpMeshVertexes_scalar(mdvSurface_t *surf, float backlerp)
+static void LerpMeshVertexes(mdvSurface_t *surf, float backlerp)
 {
-#if 0
-	short	*oldXyz, *newXyz, *oldNormals, *newNormals;
-	float	*outXyz, *outNormal;
-	float	oldXyzScale, newXyzScale;
-	float	oldNormalScale, newNormalScale;
-	int		vertNum;
-	unsigned lat, lng;
-	int		numVerts;
-
-	outXyz = tess.xyz[tess.numVertexes];
-	outNormal = tess.normal[tess.numVertexes];
-
-	newXyz = (short *)((byte *)surf + surf->ofsXyzNormals)
-		+ (backEnd.currentEntity->e.frame * surf->numVerts * 4);
-	newNormals = newXyz + 3;
-
-	newXyzScale = MD3_XYZ_SCALE * (1.0 - backlerp);
-	newNormalScale = 1.0 - backlerp;
-
-	numVerts = surf->numVerts;
-
-	if ( backlerp == 0 ) {
-		//
-		// just copy the vertexes
-		//
-		for (vertNum=0 ; vertNum < numVerts ; vertNum++,
-			newXyz += 4, newNormals += 4,
-			outXyz += 4, outNormal += 4) 
-		{
-
-			outXyz[0] = newXyz[0] * newXyzScale;
-			outXyz[1] = newXyz[1] * newXyzScale;
-			outXyz[2] = newXyz[2] * newXyzScale;
-
-			lat = ( newNormals[0] >> 8 ) & 0xff;
-			lng = ( newNormals[0] & 0xff );
-			lat *= (FUNCTABLE_SIZE/256);
-			lng *= (FUNCTABLE_SIZE/256);
-
-			// decode X as cos( lat ) * sin( long )
-			// decode Y as sin( lat ) * sin( long )
-			// decode Z as cos( long )
-
-			outNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
-			outNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
-			outNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
-		}
-	} else {
-		//
-		// interpolate and copy the vertex and normal
-		//
-		oldXyz = (short *)((byte *)surf + surf->ofsXyzNormals)
-			+ (backEnd.currentEntity->e.oldframe * surf->numVerts * 4);
-		oldNormals = oldXyz + 3;
-
-		oldXyzScale = MD3_XYZ_SCALE * backlerp;
-		oldNormalScale = backlerp;
-
-		for (vertNum=0 ; vertNum < numVerts ; vertNum++,
-			oldXyz += 4, newXyz += 4, oldNormals += 4, newNormals += 4,
-			outXyz += 4, outNormal += 4) 
-		{
-			vec3_t uncompressedOldNormal, uncompressedNewNormal;
-
-			// interpolate the xyz
-			outXyz[0] = oldXyz[0] * oldXyzScale + newXyz[0] * newXyzScale;
-			outXyz[1] = oldXyz[1] * oldXyzScale + newXyz[1] * newXyzScale;
-			outXyz[2] = oldXyz[2] * oldXyzScale + newXyz[2] * newXyzScale;
-
-			// FIXME: interpolate lat/long instead?
-			lat = ( newNormals[0] >> 8 ) & 0xff;
-			lng = ( newNormals[0] & 0xff );
-			lat *= 4;
-			lng *= 4;
-			uncompressedNewNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
-			uncompressedNewNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
-			uncompressedNewNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
-
-			lat = ( oldNormals[0] >> 8 ) & 0xff;
-			lng = ( oldNormals[0] & 0xff );
-			lat *= 4;
-			lng *= 4;
-
-			uncompressedOldNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
-			uncompressedOldNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
-			uncompressedOldNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
-
-			outNormal[0] = uncompressedOldNormal[0] * oldNormalScale + uncompressedNewNormal[0] * newNormalScale;
-			outNormal[1] = uncompressedOldNormal[1] * oldNormalScale + uncompressedNewNormal[1] * newNormalScale;
-			outNormal[2] = uncompressedOldNormal[2] * oldNormalScale + uncompressedNewNormal[2] * newNormalScale;
-
-//			VectorNormalize (outNormal);
-		}
-    	VectorArrayNormalize((vec4_t *)tess.normal[tess.numVertexes], numVerts);
-   	}
-#endif
 	float *outXyz;
-	uint32_t *outNormal;
+	int16_t *outNormal, *outTangent;
 	mdvVertex_t *newVerts;
 	int		vertNum;
 
 	newVerts = surf->verts + backEnd.currentEntity->e.frame * surf->numVerts;
 
-	outXyz =    tess.xyz[tess.numVertexes];
-	outNormal = &tess.normal[tess.numVertexes];
+	outXyz =     tess.xyz[tess.numVertexes];
+	outNormal =  tess.normal[tess.numVertexes];
+	outTangent = tess.tangent[tess.numVertexes];
 
 	if (backlerp == 0)
 	{
@@ -1175,16 +888,15 @@ static void LerpMeshVertexes_scalar(mdvSurface_t *surf, float backlerp)
 
 		for (vertNum=0 ; vertNum < surf->numVerts ; vertNum++)
 		{
-			vec3_t normal;
-
 			VectorCopy(newVerts->xyz,    outXyz);
-			VectorCopy(newVerts->normal, normal);
 
-			R_VaoPackNormal((byte *)outNormal, normal);
+			VectorCopy4(newVerts->normal, outNormal);
+			VectorCopy4(newVerts->tangent, outTangent);
 
 			newVerts++;
 			outXyz += 4;
-			outNormal++;
+			outNormal += 4;
+			outTangent += 4;
 		}
 	}
 	else
@@ -1199,36 +911,27 @@ static void LerpMeshVertexes_scalar(mdvSurface_t *surf, float backlerp)
 
 		for (vertNum=0 ; vertNum < surf->numVerts ; vertNum++)
 		{
-			vec3_t normal;
-
 			VectorLerp(newVerts->xyz,    oldVerts->xyz,    backlerp, outXyz);
-			VectorLerp(newVerts->normal, oldVerts->normal, backlerp, normal);
-			VectorNormalize(normal);
 
-			R_VaoPackNormal((byte *)outNormal, normal);
+			outNormal[0] = (int16_t)(newVerts->normal[0] * (1.0f - backlerp) + oldVerts->normal[0] * backlerp);
+			outNormal[1] = (int16_t)(newVerts->normal[1] * (1.0f - backlerp) + oldVerts->normal[1] * backlerp);
+			outNormal[2] = (int16_t)(newVerts->normal[2] * (1.0f - backlerp) + oldVerts->normal[2] * backlerp);
+			outNormal[3] = 0;
+
+			outTangent[0] = (int16_t)(newVerts->tangent[0] * (1.0f - backlerp) + oldVerts->tangent[0] * backlerp);
+			outTangent[1] = (int16_t)(newVerts->tangent[1] * (1.0f - backlerp) + oldVerts->tangent[1] * backlerp);
+			outTangent[2] = (int16_t)(newVerts->tangent[2] * (1.0f - backlerp) + oldVerts->tangent[2] * backlerp);
+			outTangent[3] = newVerts->tangent[3];
 
 			newVerts++;
 			oldVerts++;
 			outXyz += 4;
-			outNormal++;
+			outNormal += 4;
+			outTangent += 4;
 		}
 	}
 }
 
-static void LerpMeshVertexes(mdvSurface_t *surf, float backlerp)
-{
-#if 0
-#if idppc_altivec
-	if (com_altivec->integer) {
-		// must be in a seperate function or G3 systems will crash.
-		LerpMeshVertexes_altivec( surf, backlerp );
-		return;
-	}
-#endif // idppc_altivec
-#endif
-	LerpMeshVertexes_scalar( surf, backlerp );
-}
-
 
 /*
 =============
@@ -1281,228 +984,6 @@ static void RB_SurfaceMesh(mdvSurface_t *surface) {
 
 }
 
-/*
-** R_LatLongToNormal
-*/
-void R_LatLongToNormal( vec3_t outNormal, short latLong ) {
-	unsigned lat, lng;
-
-	lat = ( latLong >> 8 ) & 0xff;
-	lng = ( latLong & 0xff );
-	lat *= ( FUNCTABLE_SIZE / 256 );
-	lng *= ( FUNCTABLE_SIZE / 256 );
-
-	// decode X as cos( lat ) * sin( long )
-	// decode Y as sin( lat ) * sin( long )
-	// decode Z as cos( long )
-
-	outNormal[0] = tr.sinTable[( lat + ( FUNCTABLE_SIZE / 4 ) ) & FUNCTABLE_MASK] * tr.sinTable[lng];
-	outNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
-	outNormal[2] = tr.sinTable[( lng + ( FUNCTABLE_SIZE / 4 ) ) & FUNCTABLE_MASK];
-}
-
-// Ridah
-/*
-** LerpCMeshVertexes
-*/
-static void LerpCMeshVertexes( mdcSurface_t *surf, float backlerp ) {
-	short   *oldXyz, *newXyz, *oldNormals, *newNormals;
-	float   *outXyz;
-	uint32_t *outNormal;
-	vec3_t fNormal;
-	float oldXyzScale, newXyzScale;
-	float oldNormalScale, newNormalScale;
-	int vertNum;
-	unsigned lat, lng;
-	int numVerts;
-
-	int oldBase, newBase;
-	short   *oldComp = NULL, *newComp = NULL; // TTimo: init
-	mdcXyzCompressed_t *oldXyzComp = NULL, *newXyzComp = NULL; // TTimo: init
-	vec3_t oldOfsVec, newOfsVec;
-
-	qboolean hasComp;
-
-	outXyz = tess.xyz[tess.numVertexes];
-	outNormal = &tess.normal[tess.numVertexes];
-
-	newBase = (int)*( ( short * )( (byte *)surf + surf->ofsFrameBaseFrames ) + backEnd.currentEntity->e.frame );
-	newXyz = ( short * )( (byte *)surf + surf->ofsXyzNormals )
-			 + ( newBase * surf->numVerts * 4 );
-	newNormals = newXyz + 3;
-
-	hasComp = ( surf->numCompFrames > 0 );
-	if ( hasComp ) {
-		newComp = ( ( short * )( (byte *)surf + surf->ofsFrameCompFrames ) + backEnd.currentEntity->e.frame );
-		if ( *newComp >= 0 ) {
-			newXyzComp = ( mdcXyzCompressed_t * )( (byte *)surf + surf->ofsXyzCompressed )
-						 + ( *newComp * surf->numVerts );
-		}
-	}
-
-	newXyzScale = MD3_XYZ_SCALE * ( 1.0 - backlerp );
-	newNormalScale = 1.0 - backlerp;
-
-	numVerts = surf->numVerts;
-
-	if ( backlerp == 0 ) {
-		//
-		// just copy the vertexes
-		//
-		for ( vertNum = 0 ; vertNum < numVerts ; vertNum++,
-			  newXyz += 4, newNormals += 4,
-			  outXyz += 4, outNormal++ )
-		{
-
-			outXyz[0] = newXyz[0] * newXyzScale;
-			outXyz[1] = newXyz[1] * newXyzScale;
-			outXyz[2] = newXyz[2] * newXyzScale;
-
-			// add the compressed ofsVec
-			if ( hasComp && *newComp >= 0 ) {
-				R_MDC_DecodeXyzCompressed( newXyzComp->ofsVec, newOfsVec, fNormal );
-				newXyzComp++;
-				VectorAdd( outXyz, newOfsVec, outXyz );
-			} else {
-				lat = ( newNormals[0] >> 8 ) & 0xff;
-				lng = ( newNormals[0] & 0xff );
-				lat *= 4;
-				lng *= 4;
-
-				fNormal[0] = tr.sinTable[( lat + ( FUNCTABLE_SIZE / 4 ) ) & FUNCTABLE_MASK] * tr.sinTable[lng];
-				fNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
-				fNormal[2] = tr.sinTable[( lng + ( FUNCTABLE_SIZE / 4 ) ) & FUNCTABLE_MASK];
-			}
-
-			R_VaoPackNormal((byte *)outNormal, fNormal);
-		}
-	} else {
-		//
-		// interpolate and copy the vertex and normal
-		//
-		oldBase = (int)*( ( short * )( (byte *)surf + surf->ofsFrameBaseFrames ) + backEnd.currentEntity->e.oldframe );
-		oldXyz = ( short * )( (byte *)surf + surf->ofsXyzNormals )
-				 + ( oldBase * surf->numVerts * 4 );
-		oldNormals = oldXyz + 3;
-
-		if ( hasComp ) {
-			oldComp = ( ( short * )( (byte *)surf + surf->ofsFrameCompFrames ) + backEnd.currentEntity->e.oldframe );
-			if ( *oldComp >= 0 ) {
-				oldXyzComp = ( mdcXyzCompressed_t * )( (byte *)surf + surf->ofsXyzCompressed )
-							 + ( *oldComp * surf->numVerts );
-			}
-		}
-
-		oldXyzScale = MD3_XYZ_SCALE * backlerp;
-		oldNormalScale = backlerp;
-
-		for ( vertNum = 0 ; vertNum < numVerts ; vertNum++,
-			  oldXyz += 4, newXyz += 4, oldNormals += 4, newNormals += 4,
-			  outXyz += 4, outNormal++ )
-		{
-			vec3_t uncompressedOldNormal, uncompressedNewNormal;
-
-			// interpolate the xyz
-			outXyz[0] = oldXyz[0] * oldXyzScale + newXyz[0] * newXyzScale;
-			outXyz[1] = oldXyz[1] * oldXyzScale + newXyz[1] * newXyzScale;
-			outXyz[2] = oldXyz[2] * oldXyzScale + newXyz[2] * newXyzScale;
-
-			// add the compressed ofsVec
-			if ( hasComp && *newComp >= 0 ) {
-				R_MDC_DecodeXyzCompressed( newXyzComp->ofsVec, newOfsVec, uncompressedNewNormal );
-				newXyzComp++;
-				VectorMA( outXyz, 1.0 - backlerp, newOfsVec, outXyz );
-			} else {
-				lat = ( newNormals[0] >> 8 ) & 0xff;
-				lng = ( newNormals[0] & 0xff );
-				lat *= 4;
-				lng *= 4;
-
-				uncompressedNewNormal[0] = tr.sinTable[( lat + ( FUNCTABLE_SIZE / 4 ) ) & FUNCTABLE_MASK] * tr.sinTable[lng];
-				uncompressedNewNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
-				uncompressedNewNormal[2] = tr.sinTable[( lng + ( FUNCTABLE_SIZE / 4 ) ) & FUNCTABLE_MASK];
-			}
-
-			if ( hasComp && *oldComp >= 0 ) {
-				R_MDC_DecodeXyzCompressed( oldXyzComp->ofsVec, oldOfsVec, uncompressedOldNormal );
-				oldXyzComp++;
-				VectorMA( outXyz, backlerp, oldOfsVec, outXyz );
-			} else {
-				lat = ( oldNormals[0] >> 8 ) & 0xff;
-				lng = ( oldNormals[0] & 0xff );
-				lat *= 4;
-				lng *= 4;
-
-				uncompressedOldNormal[0] = tr.sinTable[( lat + ( FUNCTABLE_SIZE / 4 ) ) & FUNCTABLE_MASK] * tr.sinTable[lng];
-				uncompressedOldNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
-				uncompressedOldNormal[2] = tr.sinTable[( lng + ( FUNCTABLE_SIZE / 4 ) ) & FUNCTABLE_MASK];
-			}
-
-			fNormal[0] = uncompressedOldNormal[0] * oldNormalScale + uncompressedNewNormal[0] * newNormalScale;
-			fNormal[1] = uncompressedOldNormal[1] * oldNormalScale + uncompressedNewNormal[1] * newNormalScale;
-			fNormal[2] = uncompressedOldNormal[2] * oldNormalScale + uncompressedNewNormal[2] * newNormalScale;
-
-			VectorNormalize( fNormal );
-			
-			R_VaoPackNormal((byte *)outNormal, fNormal);
-		}
-	}
-}
-
-/*
-=============
-RB_SurfaceCMesh
-=============
-*/
-void RB_SurfaceCMesh( mdcSurface_t *surface ) {
-	int j;
-	float backlerp;
-	int             *triangles;
-	float           *texCoords;
-	int indexes;
-	int Bob, Doug;
-	int numVerts;
-
-	// RF, check for REFLAG_HANDONLY
-	if ( backEnd.currentEntity->e.reFlags & REFLAG_ONLYHAND ) {
-		if ( !strstr( surface->name, "hand" ) ) {
-			return;
-		}
-	}
-
-	if (  backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame ) {
-		backlerp = 0;
-	} else  {
-		backlerp = backEnd.currentEntity->e.backlerp;
-	}
-
-	RB_CheckVao(tess.vao);
-
-	RB_CHECKOVERFLOW( surface->numVerts, surface->numTriangles * 3 );
-
-	LerpCMeshVertexes( surface, backlerp );
-
-	triangles = ( int * )( (byte *)surface + surface->ofsTriangles );
-	indexes = surface->numTriangles * 3;
-	Bob = tess.numIndexes;
-	Doug = tess.numVertexes;
-	for ( j = 0 ; j < indexes ; j++ ) {
-		tess.indexes[Bob + j] = Doug + triangles[j];
-	}
-	tess.numIndexes += indexes;
-
-	texCoords = ( float * )( (byte *)surface + surface->ofsSt );
-
-	numVerts = surface->numVerts;
-	for ( j = 0; j < numVerts; j++ ) {
-		tess.texCoords[Doug + j][0][0] = texCoords[j * 2 + 0];
-		tess.texCoords[Doug + j][0][1] = texCoords[j * 2 + 1];
-		// FIXME: fill in lightmapST for completeness?
-	}
-
-	tess.numVertexes += surface->numVerts;
-}
-// done.
 
 /*
 ==============
@@ -1562,12 +1043,12 @@ static void RB_SurfaceGrid( srfBspSurface_t *srf ) {
 	int i, j;
 	float   *xyz;
 	float	*texCoords, *lightCoords;
-	uint32_t *normal;
+	int16_t *normal;
 #ifdef USE_VERT_TANGENT_SPACE
-	uint32_t *tangent;
+	int16_t *tangent;
 #endif
 	float   *color;
-	uint32_t *lightdir;
+	int16_t *lightdir;
 	srfVert_t	*dv;
 	int rows, irows, vrows;
 	int used;
@@ -1652,14 +1133,14 @@ static void RB_SurfaceGrid( srfBspSurface_t *srf ) {
 		numVertexes = tess.numVertexes;
 
 		xyz = tess.xyz[numVertexes];
-		normal = &tess.normal[numVertexes];
+		normal = tess.normal[numVertexes];
 #ifdef USE_VERT_TANGENT_SPACE
-		tangent = &tess.tangent[numVertexes];
+		tangent = tess.tangent[numVertexes];
 #endif
 		texCoords = tess.texCoords[numVertexes][0];
 		lightCoords = tess.texCoords[numVertexes][1];
 		color = tess.vertexColors[numVertexes];
-		lightdir = &tess.lightdir[numVertexes];
+		lightdir = tess.lightdir[numVertexes];
 		//vDlightBits = &tess.vertexDlightBits[numVertexes];
 
 		for ( i = 0 ; i < rows ; i++ ) {
@@ -1675,13 +1156,15 @@ static void RB_SurfaceGrid( srfBspSurface_t *srf ) {
 
 				if ( tess.shader->vertexAttribs & ATTR_NORMAL )
 				{
-					R_VaoPackNormal((byte *)normal++, dv->normal);
+					VectorCopy4(normal, dv->normal);
+					normal += 4;
 				}
 
 #ifdef USE_VERT_TANGENT_SPACE
 				if ( tess.shader->vertexAttribs & ATTR_TANGENT )
 				{
-					R_VaoPackTangent((byte *)tangent++, dv->tangent);
+					VectorCopy4(tangent, dv->tangent);
+					tangent += 4;
 				}
 #endif
 
@@ -1705,7 +1188,8 @@ static void RB_SurfaceGrid( srfBspSurface_t *srf ) {
 
 				if ( tess.shader->vertexAttribs & ATTR_LIGHTDIRECTION )
 				{
-					R_VaoPackNormal((byte *)lightdir++, dv->lightdir);
+					VectorCopy4(lightdir, dv->lightdir);
+					lightdir += 4;
 				}
 
 				//*vDlightBits++ = dlightBits;
@@ -1935,7 +1419,6 @@ void( *rb_surfaceTable[SF_NUM_SURFACE_TYPES] ) ( void * ) = {
 	( void( * ) ( void* ) )RB_SurfaceTriangles,    // SF_TRIANGLES,
 	( void( * ) ( void* ) )RB_SurfacePolychain,    // SF_POLY,
 	( void( * ) ( void* ) )RB_SurfaceMesh,         // SF_MDV,
-	( void( * ) ( void* ) )RB_SurfaceCMesh,        // SF_MDC,
 	( void( * ) ( void* ) )RB_SurfaceAnim,         // SF_MDS,
 	( void( * ) ( void* ) )RB_MDRSurfaceAnim,	// SF_MDR,
 	( void( * ) ( void* ) )RB_IQMSurfaceAnim,	// SF_IQM,
diff --git a/SP/code/rend2/tr_vbo.c b/SP/code/rend2/tr_vbo.c
index b1ff3d6..db3d8eb 100644
--- a/SP/code/rend2/tr_vbo.c
+++ b/SP/code/rend2/tr_vbo.c
@@ -23,73 +23,20 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include "tr_local.h"
 
 
-union pack10_u {
-	struct {
-		signed int x:10;
-		signed int y:10;
-		signed int z:10;
-		signed int w:2;
-	} pack;
-	uint32_t i;
-};
-
-union pack8_u {
-	struct {
-		signed int x:8;
-		signed int y:8;
-		signed int z:8;
-		signed int w:8;
-	} pack;
-	uint32_t i;
-};
-
-
-int R_VaoPackTangent(byte *out, vec4_t v)
+void R_VaoPackTangent(int16_t *out, vec4_t v)
 {
-	if (glRefConfig.packedNormalDataType == GL_INT_2_10_10_10_REV)
-	{
-		union pack10_u *num = (union pack10_u *)out;
-
-		num->pack.x = v[0] * 511.0f;
-		num->pack.y = v[1] * 511.0f;
-		num->pack.z = v[2] * 511.0f;
-		num->pack.w = v[3];
-	}
-	else
-	{
-		union pack8_u *num = (union pack8_u *)out;
-
-		num->pack.x = v[0] * 127.0f;
-		num->pack.y = v[1] * 127.0f;
-		num->pack.z = v[2] * 127.0f;
-		num->pack.w = v[3] * 127.0f;
-	}
-
-	return 4;
+	out[0] = v[0] * 32767.0f + (v[0] > 0.0f ? 0.5f : -0.5f);
+	out[1] = v[1] * 32767.0f + (v[1] > 0.0f ? 0.5f : -0.5f);
+	out[2] = v[2] * 32767.0f + (v[2] > 0.0f ? 0.5f : -0.5f);
+	out[3] = v[3] * 32767.0f + (v[3] > 0.0f ? 0.5f : -0.5f);
 }
 
-int R_VaoPackNormal(byte *out, vec3_t v)
+void R_VaoPackNormal(int16_t *out, vec3_t v)
 {
-	if (glRefConfig.packedNormalDataType == GL_INT_2_10_10_10_REV)
-	{
-		union pack10_u *num = (union pack10_u *)out;
-
-		num->pack.x = v[0] * 511.0f;
-		num->pack.y = v[1] * 511.0f;
-		num->pack.z = v[2] * 511.0f;
-		num->pack.w = 0;
-	}
-	else
-	{
-		union pack8_u *num = (union pack8_u *)out;
-
-		num->pack.x = v[0] * 127.0f;
-		num->pack.y = v[1] * 127.0f;
-		num->pack.z = v[2] * 127.0f;
-		num->pack.w = 0;
-	}
-
-	return 4;
+	out[0] = v[0] * 32767.0f + (v[0] > 0.0f ? 0.5f : -0.5f);
+	out[1] = v[1] * 32767.0f + (v[1] > 0.0f ? 0.5f : -0.5f);
+	out[2] = v[2] * 32767.0f + (v[2] > 0.0f ? 0.5f : -0.5f);
+	out[3] = 0;
 }
 
 int R_VaoPackTexCoord(byte *out, vec2_t st)
@@ -140,50 +87,21 @@ int R_VaoPackColors(byte *out, vec4_t color)
 	}
 }
 
-
-void R_VaoUnpackTangent(vec4_t v, uint32_t b)
+void R_VaoUnpackTangent(vec4_t v, int16_t *pack)
 {
-	if (glRefConfig.packedNormalDataType == GL_INT_2_10_10_10_REV)
-	{
-		union pack10_u *num = (union pack10_u *)&b;
-
-		v[0] = num->pack.x / 511.0f;
-		v[1] = num->pack.y / 511.0f;
-		v[2] = num->pack.z / 511.0f;
-		v[3] = num->pack.w; 
-	}
-	else
-	{
-		union pack8_u *num = (union pack8_u *)&b;
-
-		v[0] = num->pack.x / 127.0f;
-		v[1] = num->pack.y / 127.0f;
-		v[2] = num->pack.z / 127.0f;
-		v[3] = num->pack.w / 127.0f; 
-	}
+	v[0] = pack[0] / 32767.0f;
+	v[1] = pack[1] / 32767.0f;
+	v[2] = pack[2] / 32767.0f;
+	v[3] = pack[3] / 32767.0f;
 }
 
-void R_VaoUnpackNormal(vec3_t v, uint32_t b)
+void R_VaoUnpackNormal(vec3_t v, int16_t *pack)
 {
-	if (glRefConfig.packedNormalDataType == GL_INT_2_10_10_10_REV)
-	{
-		union pack10_u *num = (union pack10_u *)&b;
-
-		v[0] = num->pack.x / 511.0f;
-		v[1] = num->pack.y / 511.0f;
-		v[2] = num->pack.z / 511.0f;
-	}
-	else
-	{
-		union pack8_u *num = (union pack8_u *)&b;
-
-		v[0] = num->pack.x / 127.0f;
-		v[1] = num->pack.y / 127.0f;
-		v[2] = num->pack.z / 127.0f;
-	}
+	v[0] = pack[0] / 32767.0f;
+	v[1] = pack[1] / 32767.0f;
+	v[2] = pack[2] / 32767.0f;
 }
 
-
 void Vao_SetVertexPointers(vao_t *vao)
 {
 	int attribIndex;
@@ -347,12 +265,12 @@ vao_t *R_CreateVao2(const char *name, int numVertexes, srfVert_t *verts, int num
 	vao->attribs[ATTR_INDEX_LIGHTDIRECTION].count = 4;
 
 	vao->attribs[ATTR_INDEX_POSITION      ].type = GL_FLOAT;
-	vao->attribs[ATTR_INDEX_NORMAL        ].type = glRefConfig.packedNormalDataType;
-	vao->attribs[ATTR_INDEX_TANGENT       ].type = glRefConfig.packedNormalDataType;
+	vao->attribs[ATTR_INDEX_NORMAL        ].type = GL_SHORT;
+	vao->attribs[ATTR_INDEX_TANGENT       ].type = GL_SHORT;
 	vao->attribs[ATTR_INDEX_TEXCOORD      ].type = glRefConfig.packedTexcoordDataType;
 	vao->attribs[ATTR_INDEX_LIGHTCOORD    ].type = glRefConfig.packedTexcoordDataType;
 	vao->attribs[ATTR_INDEX_COLOR         ].type = glRefConfig.packedColorDataType;
-	vao->attribs[ATTR_INDEX_LIGHTDIRECTION].type = glRefConfig.packedNormalDataType;
+	vao->attribs[ATTR_INDEX_LIGHTDIRECTION].type = GL_SHORT;
 
 	vao->attribs[ATTR_INDEX_POSITION      ].normalized = GL_FALSE;
 	vao->attribs[ATTR_INDEX_NORMAL        ].normalized = GL_TRUE;
@@ -363,14 +281,14 @@ vao_t *R_CreateVao2(const char *name, int numVertexes, srfVert_t *verts, int num
 	vao->attribs[ATTR_INDEX_LIGHTDIRECTION].normalized = GL_TRUE;
 
 	vao->attribs[ATTR_INDEX_POSITION      ].offset = 0;        dataSize  = sizeof(verts[0].xyz);
-	vao->attribs[ATTR_INDEX_NORMAL        ].offset = dataSize; dataSize += sizeof(uint32_t);
+	vao->attribs[ATTR_INDEX_NORMAL        ].offset = dataSize; dataSize += sizeof(verts[0].normal);
 #ifdef USE_VERT_TANGENT_SPACE
-	vao->attribs[ATTR_INDEX_TANGENT       ].offset = dataSize; dataSize += sizeof(uint32_t);
+	vao->attribs[ATTR_INDEX_TANGENT       ].offset = dataSize; dataSize += sizeof(verts[0].tangent);
 #endif
 	vao->attribs[ATTR_INDEX_TEXCOORD      ].offset = dataSize; dataSize += glRefConfig.packedTexcoordDataSize;
 	vao->attribs[ATTR_INDEX_LIGHTCOORD    ].offset = dataSize; dataSize += glRefConfig.packedTexcoordDataSize;
 	vao->attribs[ATTR_INDEX_COLOR         ].offset = dataSize; dataSize += glRefConfig.packedColorDataSize;
-	vao->attribs[ATTR_INDEX_LIGHTDIRECTION].offset = dataSize; dataSize += sizeof(uint32_t);
+	vao->attribs[ATTR_INDEX_LIGHTDIRECTION].offset = dataSize; dataSize += sizeof(verts[0].lightdir);
 
 	vao->attribs[ATTR_INDEX_POSITION      ].stride = dataSize;
 	vao->attribs[ATTR_INDEX_NORMAL        ].stride = dataSize;
@@ -400,11 +318,13 @@ vao_t *R_CreateVao2(const char *name, int numVertexes, srfVert_t *verts, int num
 		dataOfs += sizeof(verts[i].xyz);
 
 		// normal
-		dataOfs += R_VaoPackNormal(data + dataOfs, verts[i].normal);
+		memcpy(data + dataOfs, &verts[i].normal, sizeof(verts[i].normal));
+		dataOfs += sizeof(verts[i].normal);
 
 #ifdef USE_VERT_TANGENT_SPACE
 		// tangent
-		dataOfs += R_VaoPackTangent(data + dataOfs, verts[i].tangent);
+		memcpy(data + dataOfs, &verts[i].tangent, sizeof(verts[i].tangent));
+		dataOfs += sizeof(verts[i].tangent);
 #endif
 
 		// texcoords
@@ -417,7 +337,8 @@ vao_t *R_CreateVao2(const char *name, int numVertexes, srfVert_t *verts, int num
 		dataOfs += R_VaoPackColors(data + dataOfs, verts[i].vertexColors);
 
 		// light directions
-		dataOfs += R_VaoPackNormal(data + dataOfs, verts[i].lightdir);
+		memcpy(data + dataOfs, &verts[i].lightdir, sizeof(verts[i].lightdir));
+		dataOfs += sizeof(verts[i].lightdir);
 	}
 
 	vao->vertexesSize = dataSize;
@@ -581,12 +502,12 @@ void R_InitVaos(void)
 	tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].count = 4;
 
 	tess.vao->attribs[ATTR_INDEX_POSITION      ].type = GL_FLOAT;
-	tess.vao->attribs[ATTR_INDEX_NORMAL        ].type = glRefConfig.packedNormalDataType;
-	tess.vao->attribs[ATTR_INDEX_TANGENT       ].type = glRefConfig.packedNormalDataType;
+	tess.vao->attribs[ATTR_INDEX_NORMAL        ].type = GL_SHORT;
+	tess.vao->attribs[ATTR_INDEX_TANGENT       ].type = GL_SHORT;
 	tess.vao->attribs[ATTR_INDEX_TEXCOORD      ].type = GL_FLOAT;
 	tess.vao->attribs[ATTR_INDEX_LIGHTCOORD    ].type = GL_FLOAT;
 	tess.vao->attribs[ATTR_INDEX_COLOR         ].type = GL_FLOAT;
-	tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].type = glRefConfig.packedNormalDataType;
+	tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].type = GL_SHORT;
 
 	tess.vao->attribs[ATTR_INDEX_POSITION      ].normalized = GL_FALSE;
 	tess.vao->attribs[ATTR_INDEX_NORMAL        ].normalized = GL_TRUE;

-- 
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