DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

Model_md5.cpp (43111B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.
     23 
     24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
     25 
     26 ===========================================================================
     27 */
     28 
     29 #pragma hdrstop
     30 #include "../idlib/precompiled.h"
     31 
     32 #include "tr_local.h"
     33 #include "Model_local.h"
     34 
     35 #ifdef ID_WIN_X86_SSE2_INTRIN
     36 
     37 static const __m128 vector_float_posInfinity		= { idMath::INFINITY, idMath::INFINITY, idMath::INFINITY, idMath::INFINITY };
     38 static const __m128 vector_float_negInfinity		= { -idMath::INFINITY, -idMath::INFINITY, -idMath::INFINITY, -idMath::INFINITY };
     39 
     40 #endif
     41 
     42 static const char *MD5_SnapshotName = "_MD5_Snapshot_";
     43 
     44 static const byte MD5B_VERSION = 106;
     45 static const unsigned int MD5B_MAGIC = ( '5' << 24 ) | ( 'D' << 16 ) | ( 'M' << 8 ) | MD5B_VERSION;
     46 
     47 idCVar r_useGPUSkinning( "r_useGPUSkinning", "1", CVAR_INTEGER, "animate normals and tangents instead of deriving" );
     48 
     49 /***********************************************************************
     50 
     51 	idMD5Mesh
     52 
     53 ***********************************************************************/
     54 
     55 static int c_numVerts = 0;
     56 static int c_numWeights = 0;
     57 static int c_numWeightJoints = 0;
     58 
     59 struct vertexWeight_t {
     60 	int							joint;
     61 	idVec3						offset;
     62 	float						jointWeight;
     63 };
     64 
     65 /*
     66 ====================
     67 idMD5Mesh::idMD5Mesh
     68 ====================
     69 */
     70 idMD5Mesh::idMD5Mesh() {
     71 	shader				= NULL;
     72 	numVerts			= 0;
     73 	numTris				= 0;
     74 	meshJoints			= NULL;
     75 	numMeshJoints		= 0;
     76 	maxJointVertDist	= 0.0f;
     77 	deformInfo			= NULL;
     78 	surfaceNum			= 0;
     79 }
     80 
     81 /*
     82 ====================
     83 idMD5Mesh::~idMD5Mesh
     84 ====================
     85 */
     86 idMD5Mesh::~idMD5Mesh() {
     87 	if ( meshJoints != NULL ) {
     88 		Mem_Free( meshJoints );
     89 		meshJoints = NULL;
     90 	}
     91 	if ( deformInfo != NULL ) {
     92 		R_FreeDeformInfo( deformInfo );
     93 		deformInfo = NULL;
     94 	}
     95 }
     96 
     97 /*
     98 ====================
     99 idMD5Mesh::ParseMesh
    100 ====================
    101 */
    102 void idMD5Mesh::ParseMesh( idLexer &parser, int numJoints, const idJointMat *joints ) {
    103 	idToken		token;
    104 	idToken		name;
    105 
    106 	parser.ExpectTokenString( "{" );
    107 
    108 	//
    109 	// parse name
    110 	//
    111 	if ( parser.CheckTokenString( "name" ) ) {
    112 		parser.ReadToken( &name );
    113 	}
    114 
    115 	//
    116 	// parse shader
    117 	//
    118 	parser.ExpectTokenString( "shader" );
    119 
    120 	parser.ReadToken( &token );
    121 	idStr shaderName = token;
    122 
    123     shader = declManager->FindMaterial( shaderName );
    124 
    125 	//
    126 	// parse texture coordinates
    127 	//
    128 	parser.ExpectTokenString( "numverts" );
    129 	int count = parser.ParseInt();
    130 	if ( count < 0 ) {
    131 		parser.Error( "Invalid size: %s", token.c_str() );
    132 	}
    133 
    134 	this->numVerts = count;
    135 
    136 	idList<idVec2> texCoords;
    137 	idList<int> firstWeightForVertex;
    138 	idList<int> numWeightsForVertex;
    139 
    140 	texCoords.SetNum( count );
    141 	firstWeightForVertex.SetNum( count );
    142 	numWeightsForVertex.SetNum( count );
    143 
    144 	int numWeights = 0;
    145 	int maxweight = 0;
    146 	for ( int i = 0; i < texCoords.Num(); i++ ) {
    147 		parser.ExpectTokenString( "vert" );
    148 		parser.ParseInt();
    149 
    150 		parser.Parse1DMatrix( 2, texCoords[ i ].ToFloatPtr() );
    151 
    152 		firstWeightForVertex[ i ]	= parser.ParseInt();
    153 		numWeightsForVertex[ i ]	= parser.ParseInt();
    154 
    155 		if ( !numWeightsForVertex[ i ] ) {
    156 			parser.Error( "Vertex without any joint weights." );
    157 		}
    158 
    159 		numWeights += numWeightsForVertex[ i ];
    160 		if ( numWeightsForVertex[ i ] + firstWeightForVertex[ i ] > maxweight ) {
    161 			maxweight = numWeightsForVertex[ i ] + firstWeightForVertex[ i ];
    162 		}
    163 	}
    164 
    165 	//
    166 	// parse tris
    167 	//
    168 	parser.ExpectTokenString( "numtris" );
    169 	count = parser.ParseInt();
    170 	if ( count < 0 ) {
    171 		parser.Error( "Invalid size: %d", count );
    172 	}
    173 
    174 	idList<int> tris;
    175 	tris.SetNum( count * 3 );
    176 	numTris = count;
    177 	for ( int i = 0; i < count; i++ ) {
    178 		parser.ExpectTokenString( "tri" );
    179 		parser.ParseInt();
    180 
    181 		tris[ i * 3 + 0 ] = parser.ParseInt();
    182 		tris[ i * 3 + 1 ] = parser.ParseInt();
    183 		tris[ i * 3 + 2 ] = parser.ParseInt();
    184 	}
    185 
    186 	//
    187 	// parse weights
    188 	//
    189 	parser.ExpectTokenString( "numweights" );
    190 	count = parser.ParseInt();
    191 	if ( count < 0 ) {
    192 		parser.Error( "Invalid size: %d", count );
    193 	}
    194 
    195 	if ( maxweight > count ) {
    196 		parser.Warning( "Vertices reference out of range weights in model (%d of %d weights).", maxweight, count );
    197 	}
    198 
    199 	idList<vertexWeight_t> tempWeights;
    200 	tempWeights.SetNum( count );
    201 	assert( numJoints < 256 );		// so we can pack into bytes
    202 
    203 	for ( int i = 0; i < count; i++ ) {
    204 		parser.ExpectTokenString( "weight" );
    205 		parser.ParseInt();
    206 
    207 		int jointnum = parser.ParseInt();
    208 		if ( ( jointnum < 0 ) || ( jointnum >= numJoints ) ) {
    209 			parser.Error( "Joint Index out of range(%d): %d", numJoints, jointnum );
    210 		}
    211 
    212 		tempWeights[ i ].joint			= jointnum;
    213 		tempWeights[ i ].jointWeight	= parser.ParseFloat();
    214 
    215 		parser.Parse1DMatrix( 3, tempWeights[ i ].offset.ToFloatPtr() );
    216 	}
    217 
    218 	// create pre-scaled weights and an index for the vertex/joint lookup
    219 	idVec4 * scaledWeights = (idVec4 *) Mem_Alloc16( numWeights * sizeof( scaledWeights[0] ), TAG_MD5_WEIGHT );
    220 	int * weightIndex = (int *) Mem_Alloc16( numWeights * 2 * sizeof( weightIndex[0] ), TAG_MD5_INDEX );
    221 	memset( weightIndex, 0, numWeights * 2 * sizeof( weightIndex[0] ) );
    222 
    223 	count = 0;
    224 	for ( int i = 0; i < texCoords.Num(); i++ ) {
    225 		int num = firstWeightForVertex[i];
    226 		for( int j = 0; j < numWeightsForVertex[i]; j++, num++, count++ ) {
    227 			scaledWeights[count].ToVec3() = tempWeights[num].offset * tempWeights[num].jointWeight;
    228 			scaledWeights[count].w = tempWeights[num].jointWeight;
    229 			weightIndex[count * 2 + 0] = tempWeights[num].joint * sizeof( idJointMat );
    230 		}
    231 		weightIndex[count * 2 - 1] = 1;
    232 	}
    233 
    234 	parser.ExpectTokenString( "}" );
    235 
    236 	// update counters
    237 	c_numVerts += texCoords.Num();
    238 	c_numWeights += numWeights;
    239 	c_numWeightJoints++;
    240 	for ( int i = 0; i < numWeights; i++ ) {
    241 		c_numWeightJoints += weightIndex[i*2+1];
    242 	}
    243 
    244 	//
    245 	// build a base pose that can be used for skinning
    246 	//
    247 	idDrawVert * basePose = (idDrawVert *)Mem_ClearedAlloc( texCoords.Num() * sizeof( *basePose ), TAG_MD5_BASE );
    248 	for( int j = 0, i = 0; i < texCoords.Num(); i++ ) {
    249 		idVec3 v = ( *(idJointMat *) ( (byte *)joints + weightIndex[j*2+0] ) ) * scaledWeights[j];
    250 		while( weightIndex[j*2+1] == 0 ) {
    251 			j++;
    252 			v += ( *(idJointMat *) ( (byte *)joints + weightIndex[j*2+0] ) ) * scaledWeights[j];
    253 		}
    254 		j++;
    255 
    256 		basePose[i].Clear();
    257 		basePose[i].xyz = v;
    258 		basePose[i].SetTexCoord( texCoords[i] );
    259 	}
    260 
    261 	// build the weights and bone indexes into the verts, so they will be duplicated
    262 	// as necessary at mirror seems
    263 
    264 	static int maxWeightsPerVert;
    265 	static float maxResidualWeight;
    266 
    267 	const int MAX_VERTEX_WEIGHTS = 4;
    268 
    269 	idList< bool > jointIsUsed;
    270 	jointIsUsed.SetNum( numJoints );
    271 	for ( int i = 0; i < jointIsUsed.Num(); i++ ) {
    272 		jointIsUsed[i] = false;
    273 	}
    274 
    275 	numMeshJoints = 0;
    276 	maxJointVertDist = 0.0f;
    277 
    278 	//-----------------------------------------
    279 	// new-style setup for fixed four weights and normal / tangent deformation
    280 	//
    281 	// Several important models have >25% residual weight in joints after the
    282 	// first four, which is worrisome for using a fixed four joint deformation.
    283 	//-----------------------------------------
    284 	for ( int i = 0; i < texCoords.Num(); i++ ) {
    285 		idDrawVert & dv = basePose[i];
    286 
    287 		// some models do have >4 joint weights, so it is necessary to sort and renormalize
    288 
    289 		// sort the weights and take the four largest
    290 		int	weights[256];
    291 		const int numWeights = numWeightsForVertex[ i ];
    292 		for ( int j = 0; j < numWeights; j++ ) {
    293 			weights[j] = firstWeightForVertex[i] + j;
    294 		}
    295 		// bubble sort
    296 		for ( int j = 0; j < numWeights; j++ ) {
    297 			for ( int k = 0; k < numWeights - 1 - j; k++ ) {
    298 				if ( tempWeights[weights[k]].jointWeight < tempWeights[weights[k+1]].jointWeight ) {
    299 					SwapValues( weights[k], weights[k+1] );
    300 				}
    301 			}
    302 		}
    303 
    304 		if ( numWeights > maxWeightsPerVert ) {
    305 			maxWeightsPerVert = numWeights;
    306 		}
    307 
    308 		const int usedWeights = Min( MAX_VERTEX_WEIGHTS, numWeights );
    309 
    310 		float totalWeight = 0;
    311 		for ( int j = 0; j < numWeights; j++ ) {
    312 			totalWeight += tempWeights[weights[j]].jointWeight;
    313 		}
    314 		assert( totalWeight > 0.999f && totalWeight < 1.001f );
    315 
    316 		float usedWeight = 0;
    317 		for ( int j = 0; j < usedWeights; j++ ) {
    318 			usedWeight += tempWeights[weights[j]].jointWeight;
    319 		}
    320 
    321 		const float residualWeight = totalWeight - usedWeight;
    322 		if ( residualWeight > maxResidualWeight ) {
    323 			maxResidualWeight = residualWeight;
    324 		}
    325 
    326 		byte finalWeights[MAX_VERTEX_WEIGHTS] = { 0 };
    327 		byte finalJointIndecies[MAX_VERTEX_WEIGHTS] = { 0 };
    328 		for ( int j = 0; j < usedWeights; j++ ) {
    329 			const vertexWeight_t & weight = tempWeights[weights[j]];
    330 			const int jointIndex = weight.joint;
    331 			const float fw = weight.jointWeight;
    332 			assert( fw >= 0.0f && fw <= 1.0f );
    333 			const float normalizedWeight = fw / usedWeight;
    334 			finalWeights[j] = idMath::Ftob( normalizedWeight * 255.0f);
    335 			finalJointIndecies[j] = jointIndex;
    336 		}
    337 
    338 		// Sort the weights and indices for hardware skinning
    339 		for ( int k = 0; k < 3; ++k ) {
    340 			for ( int l = k + 1; l < 4; ++l ) {
    341 				if ( finalWeights[l] > finalWeights[k] ) {
    342 					SwapValues( finalWeights[k], finalWeights[l] );
    343 					SwapValues( finalJointIndecies[k], finalJointIndecies[l] );
    344 				}
    345 			}
    346 		}
    347 
    348 		// Give any left over to the biggest weight
    349 		finalWeights[0] += Max( 255 - finalWeights[0] - finalWeights[1] - finalWeights[2] - finalWeights[3], 0 );
    350 
    351 		dv.color[0] = finalJointIndecies[0];
    352 		dv.color[1] = finalJointIndecies[1];
    353 		dv.color[2] = finalJointIndecies[2];
    354 		dv.color[3] = finalJointIndecies[3];
    355 
    356 		dv.color2[0] = finalWeights[0];
    357 		dv.color2[1] = finalWeights[1];
    358 		dv.color2[2] = finalWeights[2];
    359 		dv.color2[3] = finalWeights[3];
    360 
    361 		for ( int j = usedWeights; j < 4; j++ ) {
    362 			assert( dv.color2[j] == 0 );
    363 		}
    364 
    365 		for ( int j = 0; j < usedWeights; j++ ) {
    366 			if ( !jointIsUsed[finalJointIndecies[j]] ) {
    367 				jointIsUsed[finalJointIndecies[j]] = true;
    368 				numMeshJoints++;
    369 			}
    370 			const idJointMat & joint = joints[finalJointIndecies[j]];
    371 			float dist = ( dv.xyz - joint.GetTranslation() ).Length();
    372 			if ( dist > maxJointVertDist ) {
    373 				maxJointVertDist = dist;
    374 			}
    375 		}
    376 	}
    377 
    378 	meshJoints = (byte *) Mem_Alloc( numMeshJoints * sizeof( meshJoints[0] ), TAG_MODEL );
    379 	numMeshJoints = 0;
    380 	for ( int i = 0; i < numJoints; i++ ) {
    381 		if ( jointIsUsed[i] ) {
    382 			meshJoints[numMeshJoints++] = i;
    383 		}
    384 	}
    385 
    386 	// build the deformInfo and collect a final base pose with the mirror
    387 	// seam verts properly including the bone weights
    388 	deformInfo = R_BuildDeformInfo( texCoords.Num(), basePose, tris.Num(), tris.Ptr(),
    389 										shader->UseUnsmoothedTangents() );
    390 
    391 	for ( int i = 0; i < deformInfo->numOutputVerts; i++ ) {
    392 		for ( int j = 0; j < 4; j++ ) {
    393 			if ( deformInfo->verts[i].color[j] >= numJoints ) {
    394 				idLib::FatalError( "Bad joint index" );
    395 			}
    396 		}
    397 	}
    398 
    399 	Mem_Free( basePose );
    400 }
    401 
    402 /*
    403 ============
    404 TransformVertsAndTangents
    405 ============
    406 */
    407 void TransformVertsAndTangents( idDrawVert * targetVerts, const int numVerts, const idDrawVert *baseVerts, const idJointMat *joints ) {
    408 	for( int i = 0; i < numVerts; i++ ) {
    409 		const idDrawVert & base = baseVerts[i];
    410 
    411 		const idJointMat & j0 = joints[base.color[0]];
    412 		const idJointMat & j1 = joints[base.color[1]];
    413 		const idJointMat & j2 = joints[base.color[2]];
    414 		const idJointMat & j3 = joints[base.color[3]];
    415 
    416 		const float w0 = base.color2[0] * ( 1.0f / 255.0f );
    417 		const float w1 = base.color2[1] * ( 1.0f / 255.0f );
    418 		const float w2 = base.color2[2] * ( 1.0f / 255.0f );
    419 		const float w3 = base.color2[3] * ( 1.0f / 255.0f );
    420 
    421 		idJointMat accum;
    422 		idJointMat::Mul( accum, j0, w0 );
    423 		idJointMat::Mad( accum, j1, w1 );
    424 		idJointMat::Mad( accum, j2, w2 );
    425 		idJointMat::Mad( accum, j3, w3 );
    426 
    427 		targetVerts[i].xyz = accum * idVec4( base.xyz.x, base.xyz.y, base.xyz.z, 1.0f );
    428 		targetVerts[i].SetNormal( accum * base.GetNormal() );
    429 		targetVerts[i].SetTangent( accum * base.GetTangent() );
    430 		targetVerts[i].tangent[3] = base.tangent[3];
    431 	}
    432 }
    433 
    434 /*
    435 ====================
    436 idMD5Mesh::UpdateSurface
    437 ====================
    438 */
    439 void idMD5Mesh::UpdateSurface( const struct renderEntity_s *ent, const idJointMat *entJoints,
    440 								const idJointMat *entJointsInverted, modelSurface_t *surf ) {
    441 
    442 	tr.pc.c_deformedSurfaces++;
    443 	tr.pc.c_deformedVerts += deformInfo->numOutputVerts;
    444 	tr.pc.c_deformedIndexes += deformInfo->numIndexes;
    445 
    446 	surf->shader = shader;
    447 
    448 	if ( surf->geometry != NULL ) {
    449 		// if the number of verts and indexes are the same we can re-use the triangle surface
    450 		if ( surf->geometry->numVerts == deformInfo->numOutputVerts && surf->geometry->numIndexes == deformInfo->numIndexes ) {
    451 			R_FreeStaticTriSurfVertexCaches( surf->geometry );
    452 		} else {
    453 			R_FreeStaticTriSurf( surf->geometry );
    454 			surf->geometry = R_AllocStaticTriSurf();
    455 		}
    456 	} else {
    457 		surf->geometry = R_AllocStaticTriSurf();
    458 	}
    459 
    460 	srfTriangles_t * tri = surf->geometry;
    461 
    462 	// note that some of the data is referenced, and should not be freed
    463 	tri->referencedIndexes = true;
    464 	tri->numIndexes = deformInfo->numIndexes;
    465 	tri->indexes = deformInfo->indexes;
    466 	tri->silIndexes = deformInfo->silIndexes;
    467 	tri->numMirroredVerts = deformInfo->numMirroredVerts;
    468 	tri->mirroredVerts = deformInfo->mirroredVerts;
    469 	tri->numDupVerts = deformInfo->numDupVerts;
    470 	tri->dupVerts = deformInfo->dupVerts;
    471 	tri->numSilEdges = deformInfo->numSilEdges;
    472 	tri->silEdges = deformInfo->silEdges;
    473 
    474 	tri->indexCache = deformInfo->staticIndexCache;
    475 
    476 	tri->numVerts = deformInfo->numOutputVerts;
    477 	if ( r_useGPUSkinning.GetBool() ) {
    478 		if ( tri->verts != NULL && tri->verts != deformInfo->verts ) {
    479 			R_FreeStaticTriSurfVerts( tri );
    480 		}
    481 		tri->verts = deformInfo->verts;
    482 		tri->ambientCache = deformInfo->staticAmbientCache;
    483 		tri->shadowCache = deformInfo->staticShadowCache;
    484 		tri->referencedVerts = true;
    485 	} else {
    486 		if ( tri->verts == NULL || tri->verts == deformInfo->verts ) {
    487 			tri->verts = NULL;
    488 			R_AllocStaticTriSurfVerts( tri, deformInfo->numOutputVerts );
    489 			assert( tri->verts != NULL );	// quiet analyze warning
    490 			memcpy( tri->verts, deformInfo->verts, deformInfo->numOutputVerts * sizeof( deformInfo->verts[0] ) );	// copy over the texture coordinates
    491 		}
    492 		TransformVertsAndTangents( tri->verts, deformInfo->numOutputVerts, deformInfo->verts, entJointsInverted );
    493 		tri->referencedVerts = false;
    494 	}
    495 	tri->tangentsCalculated = true;
    496 
    497 	CalculateBounds( entJoints, tri->bounds );
    498 }
    499 
    500 /*
    501 ====================
    502 idMD5Mesh::CalculateBounds
    503 ====================
    504 */
    505 void idMD5Mesh::CalculateBounds( const idJointMat * entJoints, idBounds & bounds ) const {
    506 #ifdef ID_WIN_X86_SSE2_INTRIN
    507 
    508 	__m128 minX = vector_float_posInfinity;
    509 	__m128 minY = vector_float_posInfinity;
    510 	__m128 minZ = vector_float_posInfinity;
    511 	__m128 maxX = vector_float_negInfinity;
    512 	__m128 maxY = vector_float_negInfinity;
    513 	__m128 maxZ = vector_float_negInfinity;
    514 	for ( int i = 0; i < numMeshJoints; i++ ) {
    515 		const idJointMat & joint = entJoints[meshJoints[i]];
    516 		__m128 x = _mm_load_ps( joint.ToFloatPtr() + 0 * 4 );
    517 		__m128 y = _mm_load_ps( joint.ToFloatPtr() + 1 * 4 );
    518 		__m128 z = _mm_load_ps( joint.ToFloatPtr() + 2 * 4 );
    519 		minX = _mm_min_ps( minX, x );
    520 		minY = _mm_min_ps( minY, y );
    521 		minZ = _mm_min_ps( minZ, z );
    522 		maxX = _mm_max_ps( maxX, x );
    523 		maxY = _mm_max_ps( maxY, y );
    524 		maxZ = _mm_max_ps( maxZ, z );
    525 	}
    526 	__m128 expand = _mm_splat_ps( _mm_load_ss( & maxJointVertDist ), 0 );
    527 	minX = _mm_sub_ps( minX, expand );
    528 	minY = _mm_sub_ps( minY, expand );
    529 	minZ = _mm_sub_ps( minZ, expand );
    530 	maxX = _mm_add_ps( maxX, expand );
    531 	maxY = _mm_add_ps( maxY, expand );
    532 	maxZ = _mm_add_ps( maxZ, expand );
    533 	_mm_store_ss( bounds.ToFloatPtr() + 0, _mm_splat_ps( minX, 3 ) );
    534 	_mm_store_ss( bounds.ToFloatPtr() + 1, _mm_splat_ps( minY, 3 ) );
    535 	_mm_store_ss( bounds.ToFloatPtr() + 2, _mm_splat_ps( minZ, 3 ) );
    536 	_mm_store_ss( bounds.ToFloatPtr() + 3, _mm_splat_ps( maxX, 3 ) );
    537 	_mm_store_ss( bounds.ToFloatPtr() + 4, _mm_splat_ps( maxY, 3 ) );
    538 	_mm_store_ss( bounds.ToFloatPtr() + 5, _mm_splat_ps( maxZ, 3 ) );
    539 
    540 #else
    541 
    542 	bounds.Clear();
    543 	for ( int i = 0; i < numMeshJoints; i++ ) {
    544 		const idJointMat & joint = entJoints[meshJoints[i]];
    545 		bounds.AddPoint( joint.GetTranslation() );
    546 	}
    547 	bounds.ExpandSelf( maxJointVertDist );
    548 
    549 #endif
    550 }
    551 
    552 /*
    553 ====================
    554 idMD5Mesh::NearestJoint
    555 ====================
    556 */
    557 int idMD5Mesh::NearestJoint( int a, int b, int c ) const {
    558 	// duplicated vertices might not have weights
    559 	int vertNum;
    560 	if ( a >= 0 && a < numVerts ) {
    561 		vertNum = a;
    562 	} else if ( b >= 0 && b < numVerts ) {
    563 		vertNum = b;
    564 	} else if ( c >= 0 && c < numVerts ) {
    565 		vertNum = c;
    566 	} else {
    567 		// all vertices are duplicates which shouldn't happen
    568 		return 0;
    569 	}
    570 
    571 	const idDrawVert & v = deformInfo->verts[vertNum];
    572 
    573 	int bestWeight = 0;
    574 	int bestJoint = 0;
    575 	for ( int i = 0; i < 4; i++ ) {
    576 		if ( v.color2[i] > bestWeight ) {
    577 			bestWeight = v.color2[i];
    578 			bestJoint = v.color[i];
    579 		}
    580 	}
    581 
    582 	return bestJoint;
    583 }
    584 
    585 /***********************************************************************
    586 
    587 	idRenderModelMD5
    588 
    589 ***********************************************************************/
    590 
    591 /*
    592 ====================
    593 idRenderModelMD5::ParseJoint
    594 ====================
    595 */
    596 void idRenderModelMD5::ParseJoint( idLexer &parser, idMD5Joint *joint, idJointQuat *defaultPose ) {
    597 	//
    598 	// parse name
    599 	//
    600 	idToken	token;
    601 	parser.ReadToken( &token );
    602 	joint->name = token;
    603 
    604 	//
    605 	// parse parent
    606 	//
    607 	int num = parser.ParseInt();
    608 	if ( num < 0 ) {
    609 		joint->parent = NULL;
    610 	} else {
    611 		if ( num >= joints.Num() - 1 ) {
    612 			parser.Error( "Invalid parent for joint '%s'", joint->name.c_str() );
    613 		}
    614 		joint->parent = &joints[ num ];
    615 	}
    616 
    617 	//
    618 	// parse default pose
    619 	//
    620 	parser.Parse1DMatrix( 3, defaultPose->t.ToFloatPtr() );
    621 	parser.Parse1DMatrix( 3, defaultPose->q.ToFloatPtr() );
    622 	defaultPose->q.w = defaultPose->q.CalcW();
    623 }
    624 
    625 /*
    626 ====================
    627 idRenderModelMD5::InitFromFile
    628 ====================
    629 */
    630 void idRenderModelMD5::InitFromFile( const char *fileName ) {
    631 	name = fileName;
    632 	LoadModel();
    633 }
    634 
    635 /*
    636 ========================
    637 idRenderModelMD5::LoadBinaryModel
    638 ========================
    639 */
    640 bool idRenderModelMD5::LoadBinaryModel( idFile * file, const ID_TIME_T sourceTimeStamp ) {
    641 
    642 	if ( !idRenderModelStatic::LoadBinaryModel( file, sourceTimeStamp ) ) {
    643 		return false;
    644 	}
    645 
    646 	unsigned int magic = 0;
    647 	file->ReadBig( magic );
    648 	if ( magic != MD5B_MAGIC ) {
    649 		return false;
    650 	}
    651 
    652 	int tempNum;
    653 	file->ReadBig( tempNum );
    654 	joints.SetNum( tempNum );
    655 	for ( int i = 0; i < joints.Num(); i++ ) {
    656 		file->ReadString( joints[i].name );
    657 		int offset;
    658 		file->ReadBig( offset );
    659 		if ( offset >= 0 ) {
    660 			joints[i].parent = joints.Ptr() + offset;
    661 		} else {
    662 			joints[i].parent = NULL;
    663 		}
    664 	}
    665 
    666 	file->ReadBig( tempNum );
    667 	defaultPose.SetNum( tempNum );
    668 	for ( int i = 0; i < defaultPose.Num(); i++ ) {
    669 		file->ReadBig( defaultPose[i].q.x );
    670 		file->ReadBig( defaultPose[i].q.y );
    671 		file->ReadBig( defaultPose[i].q.z );
    672 		file->ReadBig( defaultPose[i].q.w );
    673 		file->ReadVec3( defaultPose[i].t );
    674 	}
    675 
    676 	file->ReadBig( tempNum );
    677 	invertedDefaultPose.SetNum( tempNum );
    678 	for ( int i = 0; i < invertedDefaultPose.Num(); i++ ) {
    679 		file->ReadBigArray( invertedDefaultPose[ i ].ToFloatPtr(), JOINTMAT_TYPESIZE );
    680 	}
    681 	SIMD_INIT_LAST_JOINT( invertedDefaultPose.Ptr(), joints.Num() );
    682 
    683 	file->ReadBig( tempNum );
    684 	meshes.SetNum( tempNum );
    685 	for ( int i = 0; i < meshes.Num(); i++ ) {
    686 
    687 		idStr materialName;
    688 		file->ReadString( materialName );
    689 		if ( materialName.IsEmpty() ) {
    690 			meshes[i].shader = NULL;
    691 		} else {
    692 			meshes[i].shader = declManager->FindMaterial( materialName );
    693 		}
    694 		
    695 		file->ReadBig( meshes[i].numVerts );
    696 		file->ReadBig( meshes[i].numTris );
    697 
    698 		file->ReadBig( meshes[i].numMeshJoints );
    699 		meshes[i].meshJoints = (byte *) Mem_Alloc( meshes[i].numMeshJoints * sizeof( meshes[i].meshJoints[0] ), TAG_MODEL );
    700 		file->ReadBigArray( meshes[i].meshJoints, meshes[i].numMeshJoints );
    701 		file->ReadBig( meshes[i].maxJointVertDist );
    702 
    703 		meshes[i].deformInfo = (deformInfo_t *)R_ClearedStaticAlloc( sizeof( deformInfo_t ) );
    704 		deformInfo_t & deform = *meshes[i].deformInfo;
    705 
    706 		file->ReadBig( deform.numSourceVerts );
    707 		file->ReadBig( deform.numOutputVerts );
    708 		file->ReadBig( deform.numIndexes );
    709 		file->ReadBig( deform.numMirroredVerts );
    710 		file->ReadBig( deform.numDupVerts );
    711 		file->ReadBig( deform.numSilEdges );
    712 
    713 		srfTriangles_t	tri;
    714 		memset( &tri, 0, sizeof( srfTriangles_t ) );
    715 		
    716 		if ( deform.numOutputVerts > 0 ) {
    717 			R_AllocStaticTriSurfVerts( &tri, deform.numOutputVerts );
    718 			deform.verts = tri.verts;
    719 			file->ReadBigArray( deform.verts, deform.numOutputVerts );
    720 		}
    721 
    722 		if ( deform.numIndexes > 0 ) {
    723 			R_AllocStaticTriSurfIndexes( &tri, deform.numIndexes );
    724 			R_AllocStaticTriSurfSilIndexes( &tri, deform.numIndexes );
    725 			deform.indexes = tri.indexes;
    726 			deform.silIndexes = tri.silIndexes;
    727 			file->ReadBigArray( deform.indexes, deform.numIndexes );
    728 			file->ReadBigArray( deform.silIndexes, deform.numIndexes );
    729 		}
    730 		
    731 		if ( deform.numMirroredVerts > 0 ) {
    732 			R_AllocStaticTriSurfMirroredVerts( &tri, deform.numMirroredVerts );
    733 			deform.mirroredVerts = tri.mirroredVerts;
    734 			file->ReadBigArray( deform.mirroredVerts, deform.numMirroredVerts );
    735 		}
    736 
    737 		if ( deform.numDupVerts > 0 ) {
    738 			R_AllocStaticTriSurfDupVerts( &tri, deform.numDupVerts );
    739 			deform.dupVerts = tri.dupVerts;
    740 			file->ReadBigArray( deform.dupVerts, deform.numDupVerts * 2 );
    741 		}
    742 
    743 		if ( deform.numSilEdges > 0 ) {
    744 			R_AllocStaticTriSurfSilEdges( &tri, deform.numSilEdges );
    745 			deform.silEdges = tri.silEdges;
    746 			assert( deform.silEdges != NULL );
    747 			for ( int j = 0; j < deform.numSilEdges; j++ ) {
    748 				file->ReadBig( deform.silEdges[j].p1 );
    749 				file->ReadBig( deform.silEdges[j].p2 );
    750 				file->ReadBig( deform.silEdges[j].v1 );
    751 				file->ReadBig( deform.silEdges[j].v2 );
    752 			}
    753 		}
    754 
    755 		idShadowVertSkinned * shadowVerts = (idShadowVertSkinned *) Mem_Alloc( ALIGN( deform.numOutputVerts * 2 * sizeof( idShadowVertSkinned ), 16 ), TAG_MODEL );
    756 		idShadowVertSkinned::CreateShadowCache( shadowVerts, deform.verts, deform.numOutputVerts );
    757 
    758 		deform.staticAmbientCache = vertexCache.AllocStaticVertex( deform.verts, ALIGN( deform.numOutputVerts * sizeof( idDrawVert ), VERTEX_CACHE_ALIGN ) );
    759 		deform.staticIndexCache = vertexCache.AllocStaticIndex( deform.indexes, ALIGN( deform.numIndexes * sizeof( triIndex_t ), INDEX_CACHE_ALIGN ) );
    760 		deform.staticShadowCache = vertexCache.AllocStaticVertex( shadowVerts, ALIGN( deform.numOutputVerts * 2 * sizeof( idShadowVertSkinned ), VERTEX_CACHE_ALIGN ) );
    761 
    762 		Mem_Free( shadowVerts );
    763 
    764 		file->ReadBig( meshes[i].surfaceNum );
    765 	}
    766 
    767 	return true;
    768 }
    769 
    770 /*
    771 ========================
    772 idRenderModelMD5::WriteBinaryModel
    773 ========================
    774 */
    775 void idRenderModelMD5::WriteBinaryModel( idFile * file, ID_TIME_T *_timeStamp ) const {
    776 
    777 	idRenderModelStatic::WriteBinaryModel( file );
    778 
    779 	if ( file == NULL ) {
    780 		return;
    781 	}
    782 
    783 	file->WriteBig( MD5B_MAGIC );
    784 
    785 	file->WriteBig( joints.Num() );
    786 	for ( int i = 0; i < joints.Num(); i++ ) {
    787 		file->WriteString( joints[i].name );
    788 		int offset = -1;
    789 		if ( joints[i].parent != NULL ) {
    790 			offset = joints[i].parent - joints.Ptr();
    791 		}
    792 		file->WriteBig( offset );
    793 	}
    794 
    795 	file->WriteBig( defaultPose.Num() );
    796 	for ( int i = 0; i < defaultPose.Num(); i++ ) {
    797 		file->WriteBig( defaultPose[i].q.x );
    798 		file->WriteBig( defaultPose[i].q.y );
    799 		file->WriteBig( defaultPose[i].q.z );
    800 		file->WriteBig( defaultPose[i].q.w );
    801 		file->WriteVec3( defaultPose[i].t );
    802 	}
    803 
    804 	file->WriteBig( invertedDefaultPose.Num() );
    805 	for ( int i = 0; i < invertedDefaultPose.Num(); i++ ) {
    806 		file->WriteBigArray( invertedDefaultPose[ i ].ToFloatPtr(), JOINTMAT_TYPESIZE );
    807 	}
    808 
    809 	file->WriteBig( meshes.Num() );
    810 	for ( int i = 0; i < meshes.Num(); i++ ) {
    811 
    812 		if ( meshes[i].shader != NULL && meshes[i].shader->GetName() != NULL ) {
    813 			file->WriteString( meshes[i].shader->GetName() );
    814 		} else {
    815 			file->WriteString( "" );
    816 		}
    817 
    818 		file->WriteBig( meshes[i].numVerts );
    819 		file->WriteBig( meshes[i].numTris );
    820 
    821 		file->WriteBig( meshes[i].numMeshJoints );
    822 		file->WriteBigArray( meshes[i].meshJoints, meshes[i].numMeshJoints );
    823 		file->WriteBig( meshes[i].maxJointVertDist );
    824 
    825 		deformInfo_t & deform = *meshes[i].deformInfo;
    826 
    827 		file->WriteBig( deform.numSourceVerts );
    828 		file->WriteBig( deform.numOutputVerts );
    829 		file->WriteBig( deform.numIndexes );
    830 		file->WriteBig( deform.numMirroredVerts );
    831 		file->WriteBig( deform.numDupVerts );
    832 		file->WriteBig( deform.numSilEdges );
    833 
    834 		if ( deform.numOutputVerts > 0 ) {
    835 			file->WriteBigArray( deform.verts, deform.numOutputVerts );
    836 		}
    837 
    838 		if ( deform.numIndexes > 0 ) {
    839 			file->WriteBigArray( deform.indexes, deform.numIndexes );
    840 			file->WriteBigArray( deform.silIndexes, deform.numIndexes );
    841 		}
    842 
    843 		if ( deform.numMirroredVerts > 0 ) {
    844 			file->WriteBigArray( deform.mirroredVerts, deform.numMirroredVerts );
    845 		}
    846 
    847 		if ( deform.numDupVerts > 0 ) {
    848 			file->WriteBigArray( deform.dupVerts, deform.numDupVerts * 2 );
    849 		}
    850 
    851 		if ( deform.numSilEdges > 0 ) {
    852 			for ( int j = 0; j < deform.numSilEdges; j++ ) {
    853 				file->WriteBig( deform.silEdges[j].p1 );
    854 				file->WriteBig( deform.silEdges[j].p2 );
    855 				file->WriteBig( deform.silEdges[j].v1 );
    856 				file->WriteBig( deform.silEdges[j].v2 );
    857 			}
    858 		}
    859 
    860 		file->WriteBig( meshes[i].surfaceNum );
    861 	}
    862 }
    863 
    864 /*
    865 ====================
    866 idRenderModelMD5::LoadModel
    867 
    868 used for initial loads, reloadModel, and reloading the data of purged models
    869 Upon exit, the model will absolutely be valid, but possibly as a default model
    870 ====================
    871 */
    872 void idRenderModelMD5::LoadModel() {
    873 
    874 	int			version;
    875 	int			num;
    876 	int			parentNum;
    877 	idToken		token;
    878 	idLexer		parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS );
    879 
    880 	if ( !purged ) {
    881 		PurgeModel();
    882 	}
    883 	purged = false;
    884 
    885 	if ( !parser.LoadFile( name ) ) {
    886 		MakeDefaultModel();
    887 		return;
    888 	}
    889 
    890 	parser.ExpectTokenString( MD5_VERSION_STRING );
    891 	version = parser.ParseInt();
    892 
    893 	if ( version != MD5_VERSION ) {
    894 		parser.Error( "Invalid version %d.  Should be version %d\n", version, MD5_VERSION );
    895 	}
    896 
    897 	//
    898 	// skip commandline
    899 	//
    900 	parser.ExpectTokenString( "commandline" );
    901 	parser.ReadToken( &token );
    902 
    903 	// parse num joints
    904 	parser.ExpectTokenString( "numJoints" );
    905 	num  = parser.ParseInt();
    906 	joints.SetGranularity( 1 );
    907 	joints.SetNum( num );
    908 	defaultPose.SetGranularity( 1 );
    909 	defaultPose.SetNum( num );
    910 
    911 	// parse num meshes
    912 	parser.ExpectTokenString( "numMeshes" );
    913 	num = parser.ParseInt();
    914 	if ( num < 0 ) {
    915 		parser.Error( "Invalid size: %d", num );
    916 	}
    917 	meshes.SetGranularity( 1 );
    918 	meshes.SetNum( num );
    919 
    920 	//
    921 	// parse joints
    922 	//
    923 	parser.ExpectTokenString( "joints" );
    924 	parser.ExpectTokenString( "{" );
    925 	idJointMat *poseMat = ( idJointMat * )_alloca16( joints.Num() * sizeof( poseMat[0] ) );
    926 	for( int i = 0; i < joints.Num(); i++ ) {
    927 		idMD5Joint * joint = &joints[i];
    928 		idJointQuat	* pose = &defaultPose[i];
    929 
    930 		ParseJoint( parser, joint, pose );
    931 		poseMat[ i ].SetRotation( pose->q.ToMat3() );
    932 		poseMat[ i ].SetTranslation( pose->t );
    933 		if ( joint->parent ) {
    934 			parentNum = joint->parent - joints.Ptr();
    935 			pose->q = ( poseMat[ i ].ToMat3() * poseMat[ parentNum ].ToMat3().Transpose() ).ToQuat();
    936 			pose->t = ( poseMat[ i ].ToVec3() - poseMat[ parentNum ].ToVec3() ) * poseMat[ parentNum ].ToMat3().Transpose();
    937 		}
    938 	}
    939 	parser.ExpectTokenString( "}" );
    940 
    941 	//-----------------------------------------
    942 	// create the inverse of the base pose joints to support tech6 style deformation
    943 	// of base pose vertexes, normals, and tangents.
    944 	//
    945 	// vertex * joints * inverseJoints == vertex when joints is the base pose
    946 	// When the joints are in another pose, it gives the animated vertex position
    947 	//-----------------------------------------
    948 	invertedDefaultPose.SetNum( SIMD_ROUND_JOINTS( joints.Num() ) );
    949 	for ( int i = 0; i < joints.Num(); i++ ) {
    950 		invertedDefaultPose[i] = poseMat[i];
    951 		invertedDefaultPose[i].Invert();
    952 	}
    953 	SIMD_INIT_LAST_JOINT( invertedDefaultPose.Ptr(), joints.Num() );
    954 
    955 	for ( int i = 0; i < meshes.Num(); i++ ) {
    956 		parser.ExpectTokenString( "mesh" );
    957 		meshes[i].ParseMesh( parser, defaultPose.Num(), poseMat );
    958 	}
    959 
    960 	// calculate the bounds of the model
    961 	bounds.Clear();
    962 	for ( int i = 0; i < meshes.Num(); i++ ) {
    963 		idBounds meshBounds;
    964 		meshes[i].CalculateBounds( poseMat, meshBounds );
    965 		bounds.AddBounds( meshBounds );
    966 	}
    967 
    968 	// set the timestamp for reloadmodels
    969 	fileSystem->ReadFile( name, NULL, &timeStamp );
    970 
    971 	common->UpdateLevelLoadPacifier();
    972 }
    973 
    974 /*
    975 ==============
    976 idRenderModelMD5::Print
    977 ==============
    978 */
    979 void idRenderModelMD5::Print() const {
    980 	common->Printf( "%s\n", name.c_str() );
    981 	common->Printf( "Dynamic model.\n" );
    982 	common->Printf( "Generated smooth normals.\n" );
    983 	common->Printf( "    verts  tris weights material\n" );
    984 	int	totalVerts = 0;
    985 	int	totalTris = 0;
    986 	const idMD5Mesh * mesh = meshes.Ptr();
    987 	for ( int i = 0; i < meshes.Num(); i++, mesh++ ) {
    988 		totalVerts += mesh->NumVerts();
    989 		totalTris += mesh->NumTris();
    990 		common->Printf( "%2i: %5i %5i %s\n", i, mesh->NumVerts(), mesh->NumTris(), mesh->shader->GetName() );
    991 	}	
    992 	common->Printf( "-----\n" );
    993 	common->Printf( "%4i verts.\n", totalVerts );
    994 	common->Printf( "%4i tris.\n", totalTris );
    995 	common->Printf( "%4i joints.\n", joints.Num() );
    996 }
    997 
    998 /*
    999 ==============
   1000 idRenderModelMD5::List
   1001 ==============
   1002 */
   1003 void idRenderModelMD5::List() const {
   1004 	int			i;
   1005 	const idMD5Mesh	*mesh;
   1006 	int			totalTris = 0;
   1007 	int			totalVerts = 0;
   1008 
   1009 	for( mesh = meshes.Ptr(), i = 0; i < meshes.Num(); i++, mesh++ ) {
   1010 		totalTris += mesh->numTris;
   1011 		totalVerts += mesh->NumVerts();
   1012 	}
   1013 	common->Printf( " %4ik %3i %4i %4i %s(MD5)", Memory()/1024, meshes.Num(), totalVerts, totalTris, Name() );
   1014 
   1015 	if ( defaulted ) {
   1016 		common->Printf( " (DEFAULTED)" );
   1017 	}
   1018 
   1019 	common->Printf( "\n" );
   1020 }
   1021 
   1022 /*
   1023 ====================
   1024 idRenderModelMD5::Bounds
   1025 
   1026 This calculates a rough bounds by using the joint radii without
   1027 transforming all the points
   1028 ====================
   1029 */
   1030 idBounds idRenderModelMD5::Bounds( const renderEntity_t *ent ) const {
   1031 	if ( ent == NULL ) {
   1032 		// this is the bounds for the reference pose
   1033 		return bounds;
   1034 	}
   1035 
   1036 	return ent->bounds;
   1037 }
   1038 
   1039 /*
   1040 ====================
   1041 idRenderModelMD5::DrawJoints
   1042 ====================
   1043 */
   1044 void idRenderModelMD5::DrawJoints( const renderEntity_t *ent, const viewDef_t *view ) const {
   1045 	int					i;
   1046 	int					num;
   1047 	idVec3				pos;
   1048 	const idJointMat	*joint;
   1049 	const idMD5Joint	*md5Joint;
   1050 	int					parentNum;
   1051 
   1052 	num = ent->numJoints;
   1053 	joint = ent->joints;
   1054 	md5Joint = joints.Ptr();	
   1055 	for( i = 0; i < num; i++, joint++, md5Joint++ ) {
   1056 		pos = ent->origin + joint->ToVec3() * ent->axis;
   1057 		if ( md5Joint->parent ) {
   1058 			parentNum = md5Joint->parent - joints.Ptr();
   1059 			common->RW()->DebugLine( colorWhite, ent->origin + ent->joints[ parentNum ].ToVec3() * ent->axis, pos );
   1060 		}
   1061 
   1062 		common->RW()->DebugLine( colorRed,	pos, pos + joint->ToMat3()[ 0 ] * 2.0f * ent->axis );
   1063 		common->RW()->DebugLine( colorGreen,pos, pos + joint->ToMat3()[ 1 ] * 2.0f * ent->axis );
   1064 		common->RW()->DebugLine( colorBlue,	pos, pos + joint->ToMat3()[ 2 ] * 2.0f * ent->axis );
   1065 	}
   1066 
   1067 	idBounds bounds;
   1068 
   1069 	bounds.FromTransformedBounds( ent->bounds, vec3_zero, ent->axis );
   1070 	common->RW()->DebugBounds( colorMagenta, bounds, ent->origin );
   1071 
   1072 	if ( ( r_jointNameScale.GetFloat() != 0.0f ) && ( bounds.Expand( 128.0f ).ContainsPoint( view->renderView.vieworg - ent->origin ) ) ) {
   1073 		idVec3	offset( 0, 0, r_jointNameOffset.GetFloat() );
   1074 		float	scale;
   1075 
   1076 		scale = r_jointNameScale.GetFloat();
   1077 		joint = ent->joints;
   1078 		num = ent->numJoints;
   1079 		for( i = 0; i < num; i++, joint++ ) {
   1080 			pos = ent->origin + joint->ToVec3() * ent->axis;
   1081 			common->RW()->DrawText( joints[ i ].name, pos + offset, scale, colorWhite, view->renderView.viewaxis, 1 );
   1082 		}
   1083 	}
   1084 }
   1085 
   1086 /*
   1087 ====================
   1088 TransformJoints
   1089 ====================
   1090 */
   1091 static void TransformJoints( idJointMat *__restrict outJoints, const int numJoints, const idJointMat *__restrict inJoints1, const idJointMat *__restrict inJoints2 ) {
   1092 
   1093 	float * outFloats = outJoints->ToFloatPtr();
   1094 	const float * inFloats1 = inJoints1->ToFloatPtr();
   1095 	const float * inFloats2 = inJoints2->ToFloatPtr();
   1096 
   1097 	assert_16_byte_aligned( outFloats );
   1098 	assert_16_byte_aligned( inFloats1 );
   1099 	assert_16_byte_aligned( inFloats2 );
   1100 
   1101 #ifdef ID_WIN_X86_SSE2_INTRIN
   1102 
   1103 	const __m128 mask_keep_last = __m128c( _mm_set_epi32( 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000 ) );
   1104 
   1105 	for ( int i = 0; i < numJoints; i += 2, inFloats1 += 2 * 12, inFloats2 += 2 * 12, outFloats += 2 * 12 ) {
   1106 		__m128 m1a0 = _mm_load_ps( inFloats1 + 0 * 12 + 0 );
   1107 		__m128 m1b0 = _mm_load_ps( inFloats1 + 0 * 12 + 4 );
   1108 		__m128 m1c0 = _mm_load_ps( inFloats1 + 0 * 12 + 8 );
   1109 		__m128 m1a1 = _mm_load_ps( inFloats1 + 1 * 12 + 0 );
   1110 		__m128 m1b1 = _mm_load_ps( inFloats1 + 1 * 12 + 4 );
   1111 		__m128 m1c1 = _mm_load_ps( inFloats1 + 1 * 12 + 8 );
   1112 
   1113 		__m128 m2a0 = _mm_load_ps( inFloats2 + 0 * 12 + 0 );
   1114 		__m128 m2b0 = _mm_load_ps( inFloats2 + 0 * 12 + 4 );
   1115 		__m128 m2c0 = _mm_load_ps( inFloats2 + 0 * 12 + 8 );
   1116 		__m128 m2a1 = _mm_load_ps( inFloats2 + 1 * 12 + 0 );
   1117 		__m128 m2b1 = _mm_load_ps( inFloats2 + 1 * 12 + 4 );
   1118 		__m128 m2c1 = _mm_load_ps( inFloats2 + 1 * 12 + 8 );
   1119 
   1120 		__m128 tj0 = _mm_and_ps( m1a0, mask_keep_last );
   1121 		__m128 tk0 = _mm_and_ps( m1b0, mask_keep_last );
   1122 		__m128 tl0 = _mm_and_ps( m1c0, mask_keep_last );
   1123 		__m128 tj1 = _mm_and_ps( m1a1, mask_keep_last );
   1124 		__m128 tk1 = _mm_and_ps( m1b1, mask_keep_last );
   1125 		__m128 tl1 = _mm_and_ps( m1c1, mask_keep_last );
   1126 
   1127 		__m128 ta0 = _mm_splat_ps( m1a0, 0 );
   1128 		__m128 td0 = _mm_splat_ps( m1b0, 0 );
   1129 		__m128 tg0 = _mm_splat_ps( m1c0, 0 );
   1130 		__m128 ta1 = _mm_splat_ps( m1a1, 0 );
   1131 		__m128 td1 = _mm_splat_ps( m1b1, 0 );
   1132 		__m128 tg1 = _mm_splat_ps( m1c1, 0 );
   1133 
   1134 		__m128 ra0 = _mm_add_ps( tj0, _mm_mul_ps( ta0, m2a0 ) );
   1135 		__m128 rd0 = _mm_add_ps( tk0, _mm_mul_ps( td0, m2a0 ) );
   1136 		__m128 rg0 = _mm_add_ps( tl0, _mm_mul_ps( tg0, m2a0 ) );
   1137 		__m128 ra1 = _mm_add_ps( tj1, _mm_mul_ps( ta1, m2a1 ) );
   1138 		__m128 rd1 = _mm_add_ps( tk1, _mm_mul_ps( td1, m2a1 ) );
   1139 		__m128 rg1 = _mm_add_ps( tl1, _mm_mul_ps( tg1, m2a1 ) );
   1140 
   1141 		__m128 tb0 = _mm_splat_ps( m1a0, 1 );
   1142 		__m128 te0 = _mm_splat_ps( m1b0, 1 );
   1143 		__m128 th0 = _mm_splat_ps( m1c0, 1 );
   1144 		__m128 tb1 = _mm_splat_ps( m1a1, 1 );
   1145 		__m128 te1 = _mm_splat_ps( m1b1, 1 );
   1146 		__m128 th1 = _mm_splat_ps( m1c1, 1 );
   1147 
   1148 		__m128 rb0 = _mm_add_ps( ra0, _mm_mul_ps( tb0, m2b0 ) );
   1149 		__m128 re0 = _mm_add_ps( rd0, _mm_mul_ps( te0, m2b0 ) );
   1150 		__m128 rh0 = _mm_add_ps( rg0, _mm_mul_ps( th0, m2b0 ) );
   1151 		__m128 rb1 = _mm_add_ps( ra1, _mm_mul_ps( tb1, m2b1 ) );
   1152 		__m128 re1 = _mm_add_ps( rd1, _mm_mul_ps( te1, m2b1 ) );
   1153 		__m128 rh1 = _mm_add_ps( rg1, _mm_mul_ps( th1, m2b1 ) );
   1154 
   1155 		__m128 tc0 = _mm_splat_ps( m1a0, 2 );
   1156 		__m128 tf0 = _mm_splat_ps( m1b0, 2 );
   1157 		__m128 ti0 = _mm_splat_ps( m1c0, 2 );
   1158 		__m128 tf1 = _mm_splat_ps( m1b1, 2 );
   1159 		__m128 ti1 = _mm_splat_ps( m1c1, 2 );
   1160 		__m128 tc1 = _mm_splat_ps( m1a1, 2 );
   1161 
   1162 		__m128 rc0 = _mm_add_ps( rb0, _mm_mul_ps( tc0, m2c0 ) );
   1163 		__m128 rf0 = _mm_add_ps( re0, _mm_mul_ps( tf0, m2c0 ) );
   1164 		__m128 ri0 = _mm_add_ps( rh0, _mm_mul_ps( ti0, m2c0 ) );
   1165 		__m128 rc1 = _mm_add_ps( rb1, _mm_mul_ps( tc1, m2c1 ) );
   1166 		__m128 rf1 = _mm_add_ps( re1, _mm_mul_ps( tf1, m2c1 ) );
   1167 		__m128 ri1 = _mm_add_ps( rh1, _mm_mul_ps( ti1, m2c1 ) );
   1168 
   1169 		_mm_store_ps( outFloats + 0 * 12 + 0, rc0 );
   1170 		_mm_store_ps( outFloats + 0 * 12 + 4, rf0 );
   1171 		_mm_store_ps( outFloats + 0 * 12 + 8, ri0 );
   1172 		_mm_store_ps( outFloats + 1 * 12 + 0, rc1 );
   1173 		_mm_store_ps( outFloats + 1 * 12 + 4, rf1 );
   1174 		_mm_store_ps( outFloats + 1 * 12 + 8, ri1 );
   1175 	}
   1176 
   1177 #else
   1178 
   1179 	for ( int i = 0; i < numJoints; i++ ) {
   1180 		idJointMat::Multiply( outJoints[i], inJoints1[i], inJoints2[i] );
   1181 	}
   1182 
   1183 #endif
   1184 }
   1185 
   1186 /*
   1187 ====================
   1188 idRenderModelMD5::InstantiateDynamicModel
   1189 ====================
   1190 */
   1191 idRenderModel *idRenderModelMD5::InstantiateDynamicModel( const struct renderEntity_s *ent, const viewDef_t *view, idRenderModel *cachedModel ) {
   1192 	if ( cachedModel != NULL && !r_useCachedDynamicModels.GetBool() ) {
   1193 		delete cachedModel;
   1194 		cachedModel = NULL;
   1195 	}
   1196 
   1197 	if ( purged ) {
   1198 		common->DWarning( "model %s instantiated while purged", Name() );
   1199 		LoadModel();
   1200 	}
   1201 
   1202 	if ( !ent->joints ) {
   1203 		common->Printf( "idRenderModelMD5::InstantiateDynamicModel: NULL joints on renderEntity for '%s'\n", Name() );
   1204 		delete cachedModel;
   1205 		return NULL;
   1206 	} else if ( ent->numJoints != joints.Num() ) {
   1207 		common->Printf( "idRenderModelMD5::InstantiateDynamicModel: renderEntity has different number of joints than model for '%s'\n", Name() );
   1208 		delete cachedModel;
   1209 		return NULL;
   1210 	}
   1211 
   1212 	tr.pc.c_generateMd5++;
   1213 
   1214 	idRenderModelStatic * staticModel;
   1215 	if ( cachedModel != NULL ) {
   1216 		assert( dynamic_cast<idRenderModelStatic *>(cachedModel) != NULL );
   1217 		assert( idStr::Icmp( cachedModel->Name(), MD5_SnapshotName ) == 0 );
   1218 		staticModel = static_cast<idRenderModelStatic *>(cachedModel);
   1219 	} else {
   1220 		staticModel = new (TAG_MODEL) idRenderModelStatic;
   1221 		staticModel->InitEmpty( MD5_SnapshotName );
   1222 	}
   1223 
   1224 	staticModel->bounds.Clear();
   1225 
   1226 	if ( r_showSkel.GetInteger() ) {
   1227 		if ( ( view != NULL ) && ( !r_skipSuppress.GetBool() || !ent->suppressSurfaceInViewID || ( ent->suppressSurfaceInViewID != view->renderView.viewID ) ) ) {
   1228 			// only draw the skeleton
   1229 			DrawJoints( ent, view );
   1230 		}
   1231 
   1232 		if ( r_showSkel.GetInteger() > 1 ) {
   1233 			// turn off the model when showing the skeleton
   1234 			staticModel->InitEmpty( MD5_SnapshotName );
   1235 			return staticModel;
   1236 		}
   1237 	}
   1238 
   1239 	// update the GPU joints array
   1240 	const int numInvertedJoints = SIMD_ROUND_JOINTS( joints.Num() );
   1241 	if ( staticModel->jointsInverted == NULL ) {
   1242 		staticModel->numInvertedJoints = numInvertedJoints;
   1243 		const int alignment = glConfig.uniformBufferOffsetAlignment;
   1244 		staticModel->jointsInverted = (idJointMat *)Mem_ClearedAlloc( ALIGN( numInvertedJoints * sizeof( idJointMat ), alignment ), TAG_JOINTMAT );
   1245 		staticModel->jointsInvertedBuffer = 0;
   1246 	} else {
   1247 		assert( staticModel->numInvertedJoints == numInvertedJoints );
   1248 	}
   1249 
   1250 	TransformJoints( staticModel->jointsInverted, joints.Num(), ent->joints, invertedDefaultPose.Ptr() );
   1251 
   1252 	// create all the surfaces
   1253 	idMD5Mesh * mesh = meshes.Ptr();
   1254 	for ( int i = 0; i < meshes.Num(); i++, mesh++ ) {
   1255 		// avoid deforming the surface if it will be a nodraw due to a skin remapping
   1256 		const idMaterial *shader = mesh->shader;
   1257 		
   1258 		shader = R_RemapShaderBySkin( shader, ent->customSkin, ent->customShader );
   1259 		
   1260 		if ( !shader || ( !shader->IsDrawn() && !shader->SurfaceCastsShadow() ) ) {
   1261 			staticModel->DeleteSurfaceWithId( i );
   1262 			mesh->surfaceNum = -1;
   1263 			continue;
   1264 		}
   1265 
   1266 		modelSurface_t *surf;
   1267 
   1268 		int surfaceNum = 0;
   1269 		if ( staticModel->FindSurfaceWithId( i, surfaceNum ) ) {
   1270 			mesh->surfaceNum = surfaceNum;
   1271 			surf = &staticModel->surfaces[surfaceNum];
   1272 		} else {
   1273 			mesh->surfaceNum = staticModel->NumSurfaces();
   1274 			surf = &staticModel->surfaces.Alloc();
   1275 			surf->geometry = NULL;
   1276 			surf->shader = NULL;
   1277 			surf->id = i;
   1278 		}
   1279 
   1280 		mesh->UpdateSurface( ent, ent->joints, staticModel->jointsInverted, surf );
   1281 		assert( surf->geometry != NULL );	// to get around compiler warning
   1282 
   1283 		// the deformation of the tangents can be deferred until each surface is added to the view
   1284 		surf->geometry->staticModelWithJoints = staticModel;
   1285 	
   1286 		staticModel->bounds.AddBounds( surf->geometry->bounds );
   1287 	}
   1288 
   1289 	return staticModel;
   1290 }
   1291 
   1292 /*
   1293 ====================
   1294 idRenderModelMD5::IsDynamicModel
   1295 ====================
   1296 */
   1297 dynamicModel_t idRenderModelMD5::IsDynamicModel() const {
   1298 	return DM_CACHED;
   1299 }
   1300 
   1301 /*
   1302 ====================
   1303 idRenderModelMD5::NumJoints
   1304 ====================
   1305 */
   1306 int idRenderModelMD5::NumJoints() const {
   1307 	return joints.Num();
   1308 }
   1309 
   1310 /*
   1311 ====================
   1312 idRenderModelMD5::GetJoints
   1313 ====================
   1314 */
   1315 const idMD5Joint *idRenderModelMD5::GetJoints() const {
   1316 	return joints.Ptr();
   1317 }
   1318 
   1319 /*
   1320 ====================
   1321 idRenderModelMD5::GetDefaultPose
   1322 ====================
   1323 */
   1324 const idJointQuat *idRenderModelMD5::GetDefaultPose() const {
   1325 	return defaultPose.Ptr();
   1326 }
   1327 
   1328 /*
   1329 ====================
   1330 idRenderModelMD5::GetJointHandle
   1331 ====================
   1332 */
   1333 jointHandle_t idRenderModelMD5::GetJointHandle( const char *name ) const {
   1334 	const idMD5Joint *joint = joints.Ptr();
   1335 	for ( int i = 0; i < joints.Num(); i++, joint++ ) {
   1336 		if ( idStr::Icmp( joint->name.c_str(), name ) == 0 ) {
   1337 			return ( jointHandle_t )i;
   1338 		}
   1339 	}
   1340 
   1341 	return INVALID_JOINT;
   1342 }
   1343 
   1344 /*
   1345 =====================
   1346 idRenderModelMD5::GetJointName
   1347 =====================
   1348 */
   1349 const char *idRenderModelMD5::GetJointName( jointHandle_t handle ) const {
   1350 	if ( ( handle < 0 ) || ( handle >= joints.Num() ) ) {
   1351 		return "<invalid joint>";
   1352 	}
   1353 
   1354 	return joints[ handle ].name;
   1355 }
   1356 
   1357 /*
   1358 ====================
   1359 idRenderModelMD5::NearestJoint
   1360 ====================
   1361 */
   1362 int idRenderModelMD5::NearestJoint( int surfaceNum, int a, int b, int c ) const {
   1363 	if ( surfaceNum > meshes.Num() ) {
   1364 		common->Error( "idRenderModelMD5::NearestJoint: surfaceNum > meshes.Num()" );
   1365 	}
   1366 
   1367 	const idMD5Mesh *mesh = meshes.Ptr();
   1368 	for ( int i = 0; i < meshes.Num(); i++, mesh++ ) {
   1369 		if ( mesh->surfaceNum == surfaceNum ) {
   1370 			return mesh->NearestJoint( a, b, c );
   1371 		}
   1372 	}
   1373 	return 0;
   1374 }
   1375 
   1376 /*
   1377 ====================
   1378 idRenderModelMD5::TouchData
   1379 
   1380 models that are already loaded at level start time
   1381 will still touch their materials to make sure they
   1382 are kept loaded
   1383 ====================
   1384 */
   1385 void idRenderModelMD5::TouchData() {
   1386 	for ( int i = 0; i < meshes.Num(); i++ ) {
   1387 		declManager->FindMaterial( meshes[i].shader->GetName() );
   1388 	}
   1389 }
   1390 
   1391 /*
   1392 ===================
   1393 idRenderModelMD5::PurgeModel
   1394 
   1395 frees all the data, but leaves the class around for dangling references,
   1396 which can regenerate the data with LoadModel()
   1397 ===================
   1398 */
   1399 void idRenderModelMD5::PurgeModel() {
   1400 	purged = true;
   1401 	joints.Clear();
   1402 	defaultPose.Clear();
   1403 	meshes.Clear();
   1404 }
   1405 
   1406 /*
   1407 ===================
   1408 idRenderModelMD5::Memory
   1409 ===================
   1410 */
   1411 int	idRenderModelMD5::Memory() const {
   1412 	int total = sizeof( *this );
   1413 	total += joints.MemoryUsed() + defaultPose.MemoryUsed() + meshes.MemoryUsed();
   1414 
   1415 	// count up strings
   1416 	for ( int i = 0; i < joints.Num(); i++ ) {
   1417 		total += joints[i].name.DynamicMemoryUsed();
   1418 	}
   1419 
   1420 	// count up meshes
   1421 	for ( int i = 0; i < meshes.Num(); i++ ) {
   1422 		const idMD5Mesh *mesh = &meshes[i];
   1423 
   1424 		total += mesh->numMeshJoints * sizeof( mesh->meshJoints[0] );
   1425 
   1426 		// sum up deform info
   1427 		total += sizeof( mesh->deformInfo );
   1428 		total += R_DeformInfoMemoryUsed( mesh->deformInfo );
   1429 	}
   1430 	return total;
   1431 }