1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
8 
9 Doom 3 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 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 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 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 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 #include "sys/platform.h"
30 #include "framework/Session.h"
31 #include "renderer/tr_local.h"
32 
33 #include "renderer/Model_local.h"
34 
35 static const char *MD5_SnapshotName = "_MD5_Snapshot_";
36 
37 /***********************************************************************
38 
39 	idMD5Mesh
40 
41 ***********************************************************************/
42 
43 static int c_numVerts = 0;
44 static int c_numWeights = 0;
45 static int c_numWeightJoints = 0;
46 
47 typedef struct vertexWeight_s {
48 	int							vert;
49 	int							joint;
50 	idVec3						offset;
51 	float						jointWeight;
52 } vertexWeight_t;
53 
54 /*
55 ====================
56 idMD5Mesh::idMD5Mesh
57 ====================
58 */
idMD5Mesh()59 idMD5Mesh::idMD5Mesh() {
60 	scaledWeights	= NULL;
61 	weightIndex		= NULL;
62 	shader			= NULL;
63 	numTris			= 0;
64 	deformInfo		= NULL;
65 	surfaceNum		= 0;
66 }
67 
68 /*
69 ====================
70 idMD5Mesh::~idMD5Mesh
71 ====================
72 */
~idMD5Mesh()73 idMD5Mesh::~idMD5Mesh() {
74 	Mem_Free16( scaledWeights );
75 	Mem_Free16( weightIndex );
76 	if ( deformInfo ) {
77 		R_FreeDeformInfo( deformInfo );
78 		deformInfo = NULL;
79 	}
80 }
81 
82 /*
83 ====================
84 idMD5Mesh::ParseMesh
85 ====================
86 */
ParseMesh(idLexer & parser,int numJoints,const idJointMat * joints)87 void idMD5Mesh::ParseMesh( idLexer &parser, int numJoints, const idJointMat *joints ) {
88 	idToken		token;
89 	idToken		name;
90 	int			num;
91 	int			count;
92 	int			jointnum;
93 	idStr		shaderName;
94 	int			i, j;
95 	idList<int>	tris;
96 	idList<int>	firstWeightForVertex;
97 	idList<int>	numWeightsForVertex;
98 	int			maxweight;
99 	idList<vertexWeight_t> tempWeights;
100 
101 	parser.ExpectTokenString( "{" );
102 
103 	//
104 	// parse name
105 	//
106 	if ( parser.CheckTokenString( "name" ) ) {
107 		parser.ReadToken( &name );
108 	}
109 
110 	//
111 	// parse shader
112 	//
113 	parser.ExpectTokenString( "shader" );
114 
115 	parser.ReadToken( &token );
116 	shaderName = token;
117 
118 	shader = declManager->FindMaterial( shaderName );
119 
120 	//
121 	// parse texture coordinates
122 	//
123 	parser.ExpectTokenString( "numverts" );
124 	count = parser.ParseInt();
125 	if ( count < 0 ) {
126 		parser.Error( "Invalid size: %s", token.c_str() );
127 	}
128 
129 	texCoords.SetNum( count );
130 	firstWeightForVertex.SetNum( count );
131 	numWeightsForVertex.SetNum( count );
132 
133 	numWeights = 0;
134 	maxweight = 0;
135 	for( i = 0; i < texCoords.Num(); i++ ) {
136 		parser.ExpectTokenString( "vert" );
137 		parser.ParseInt();
138 
139 		parser.Parse1DMatrix( 2, texCoords[ i ].ToFloatPtr() );
140 
141 		firstWeightForVertex[ i ]	= parser.ParseInt();
142 		numWeightsForVertex[ i ]	= parser.ParseInt();
143 
144 		if ( !numWeightsForVertex[ i ] ) {
145 			parser.Error( "Vertex without any joint weights." );
146 		}
147 
148 		numWeights += numWeightsForVertex[ i ];
149 		if ( numWeightsForVertex[ i ] + firstWeightForVertex[ i ] > maxweight ) {
150 			maxweight = numWeightsForVertex[ i ] + firstWeightForVertex[ i ];
151 		}
152 	}
153 
154 	//
155 	// parse tris
156 	//
157 	parser.ExpectTokenString( "numtris" );
158 	count = parser.ParseInt();
159 	if ( count < 0 ) {
160 		parser.Error( "Invalid size: %d", count );
161 	}
162 
163 	tris.SetNum( count * 3 );
164 	numTris = count;
165 	for( i = 0; i < count; i++ ) {
166 		parser.ExpectTokenString( "tri" );
167 		parser.ParseInt();
168 
169 		tris[ i * 3 + 0 ] = parser.ParseInt();
170 		tris[ i * 3 + 1 ] = parser.ParseInt();
171 		tris[ i * 3 + 2 ] = parser.ParseInt();
172 	}
173 
174 	//
175 	// parse weights
176 	//
177 	parser.ExpectTokenString( "numweights" );
178 	count = parser.ParseInt();
179 	if ( count < 0 ) {
180 		parser.Error( "Invalid size: %d", count );
181 	}
182 
183 	if ( maxweight > count ) {
184 		parser.Warning( "Vertices reference out of range weights in model (%d of %d weights).", maxweight, count );
185 	}
186 
187 	tempWeights.SetNum( count );
188 
189 	for( i = 0; i < count; i++ ) {
190 		parser.ExpectTokenString( "weight" );
191 		parser.ParseInt();
192 
193 		jointnum = parser.ParseInt();
194 		if ( ( jointnum < 0 ) || ( jointnum >= numJoints ) ) {
195 			parser.Error( "Joint Index out of range(%d): %d", numJoints, jointnum );
196 		}
197 
198 		tempWeights[ i ].joint			= jointnum;
199 		tempWeights[ i ].jointWeight	= parser.ParseFloat();
200 
201 		parser.Parse1DMatrix( 3, tempWeights[ i ].offset.ToFloatPtr() );
202 	}
203 
204 	// create pre-scaled weights and an index for the vertex/joint lookup
205 	scaledWeights = (idVec4 *) Mem_Alloc16( numWeights * sizeof( scaledWeights[0] ) );
206 	weightIndex = (int *) Mem_Alloc16( numWeights * 2 * sizeof( weightIndex[0] ) );
207 	memset( weightIndex, 0, numWeights * 2 * sizeof( weightIndex[0] ) );
208 
209 	count = 0;
210 	for( i = 0; i < texCoords.Num(); i++ ) {
211 		num = firstWeightForVertex[i];
212 		for( j = 0; j < numWeightsForVertex[i]; j++, num++, count++ ) {
213 			scaledWeights[count].ToVec3() = tempWeights[num].offset * tempWeights[num].jointWeight;
214 			scaledWeights[count].w = tempWeights[num].jointWeight;
215 			weightIndex[count * 2 + 0] = tempWeights[num].joint * sizeof( idJointMat );
216 		}
217 		weightIndex[count * 2 - 1] = 1;
218 	}
219 
220 	tempWeights.Clear();
221 	numWeightsForVertex.Clear();
222 	firstWeightForVertex.Clear();
223 
224 	parser.ExpectTokenString( "}" );
225 
226 	// update counters
227 	c_numVerts += texCoords.Num();
228 	c_numWeights += numWeights;
229 	c_numWeightJoints++;
230 	for ( i = 0; i < numWeights; i++ ) {
231 		c_numWeightJoints += weightIndex[i*2+1];
232 	}
233 
234 	//
235 	// build the information that will be common to all animations of this mesh:
236 	// silhouette edge connectivity and normal / tangent generation information
237 	//
238 	idDrawVert *verts = (idDrawVert *) _alloca16( texCoords.Num() * sizeof( idDrawVert ) );
239 	for ( i = 0; i < texCoords.Num(); i++ ) {
240 		verts[i].Clear();
241 		verts[i].st = texCoords[i];
242 	}
243 	TransformVerts( verts, joints );
244 	deformInfo = R_BuildDeformInfo( texCoords.Num(), verts, tris.Num(), tris.Ptr(), shader->UseUnsmoothedTangents() );
245 }
246 
247 /*
248 ====================
249 idMD5Mesh::TransformVerts
250 ====================
251 */
TransformVerts(idDrawVert * verts,const idJointMat * entJoints)252 void idMD5Mesh::TransformVerts( idDrawVert *verts, const idJointMat *entJoints ) {
253 	SIMDProcessor->TransformVerts( verts, texCoords.Num(), entJoints, scaledWeights, weightIndex, numWeights );
254 }
255 
256 /*
257 ====================
258 idMD5Mesh::TransformScaledVerts
259 
260 Special transform to make the mesh seem fat or skinny.  May be used for zombie deaths
261 ====================
262 */
TransformScaledVerts(idDrawVert * verts,const idJointMat * entJoints,float scale)263 void idMD5Mesh::TransformScaledVerts( idDrawVert *verts, const idJointMat *entJoints, float scale ) {
264 	idVec4 *scaledWeights = (idVec4 *) _alloca16( numWeights * sizeof( scaledWeights[0] ) );
265 	SIMDProcessor->Mul( scaledWeights[0].ToFloatPtr(), scale, scaledWeights[0].ToFloatPtr(), numWeights * 4 );
266 	SIMDProcessor->TransformVerts( verts, texCoords.Num(), entJoints, scaledWeights, weightIndex, numWeights );
267 }
268 
269 /*
270 ====================
271 idMD5Mesh::UpdateSurface
272 ====================
273 */
UpdateSurface(const struct renderEntity_s * ent,const idJointMat * entJoints,modelSurface_t * surf)274 void idMD5Mesh::UpdateSurface( const struct renderEntity_s *ent, const idJointMat *entJoints, modelSurface_t *surf ) {
275 	int i, base;
276 	srfTriangles_t *tri;
277 
278 	tr.pc.c_deformedSurfaces++;
279 	tr.pc.c_deformedVerts += deformInfo->numOutputVerts;
280 	tr.pc.c_deformedIndexes += deformInfo->numIndexes;
281 
282 	surf->shader = shader;
283 
284 	if ( surf->geometry ) {
285 		// if the number of verts and indexes are the same we can re-use the triangle surface
286 		// the number of indexes must be the same to assure the correct amount of memory is allocated for the facePlanes
287 		if ( surf->geometry->numVerts == deformInfo->numOutputVerts && surf->geometry->numIndexes == deformInfo->numIndexes ) {
288 			R_FreeStaticTriSurfVertexCaches( surf->geometry );
289 		} else {
290 			R_FreeStaticTriSurf( surf->geometry );
291 			surf->geometry = R_AllocStaticTriSurf();
292 		}
293 	} else {
294 		surf->geometry = R_AllocStaticTriSurf();
295 	}
296 
297 	tri = surf->geometry;
298 
299 	// note that some of the data is references, and should not be freed
300 	tri->deformedSurface = true;
301 	tri->tangentsCalculated = false;
302 	tri->facePlanesCalculated = false;
303 
304 	tri->numIndexes = deformInfo->numIndexes;
305 	tri->indexes = deformInfo->indexes;
306 	tri->silIndexes = deformInfo->silIndexes;
307 	tri->numMirroredVerts = deformInfo->numMirroredVerts;
308 	tri->mirroredVerts = deformInfo->mirroredVerts;
309 	tri->numDupVerts = deformInfo->numDupVerts;
310 	tri->dupVerts = deformInfo->dupVerts;
311 	tri->numSilEdges = deformInfo->numSilEdges;
312 	tri->silEdges = deformInfo->silEdges;
313 	tri->dominantTris = deformInfo->dominantTris;
314 	tri->numVerts = deformInfo->numOutputVerts;
315 
316 	if ( tri->verts == NULL ) {
317 		R_AllocStaticTriSurfVerts( tri, tri->numVerts );
318 		for ( i = 0; i < deformInfo->numSourceVerts; i++ ) {
319 			tri->verts[i].Clear();
320 			tri->verts[i].st = texCoords[i];
321 		}
322 	}
323 
324 	if ( ent->shaderParms[ SHADERPARM_MD5_SKINSCALE ] != 0.0f ) {
325 		TransformScaledVerts( tri->verts, entJoints, ent->shaderParms[ SHADERPARM_MD5_SKINSCALE ] );
326 	} else {
327 		TransformVerts( tri->verts, entJoints );
328 	}
329 
330 	// replicate the mirror seam vertexes
331 	base = deformInfo->numOutputVerts - deformInfo->numMirroredVerts;
332 	for ( i = 0; i < deformInfo->numMirroredVerts; i++ ) {
333 		tri->verts[base + i] = tri->verts[deformInfo->mirroredVerts[i]];
334 	}
335 
336 	R_BoundTriSurf( tri );
337 
338 	// If a surface is going to be have a lighting interaction generated, it will also have to call
339 	// R_DeriveTangents() to get normals, tangents, and face planes.  If it only
340 	// needs shadows generated, it will only have to generate face planes.  If it only
341 	// has ambient drawing, or is culled, no additional work will be necessary
342 	if ( !r_useDeferredTangents.GetBool() ) {
343 		// set face planes, vertex normals, tangents
344 		R_DeriveTangents( tri );
345 	}
346 }
347 
348 /*
349 ====================
350 idMD5Mesh::CalcBounds
351 ====================
352 */
CalcBounds(const idJointMat * entJoints)353 idBounds idMD5Mesh::CalcBounds( const idJointMat *entJoints ) {
354 	idBounds	bounds;
355 	idDrawVert *verts = (idDrawVert *) _alloca16( texCoords.Num() * sizeof( idDrawVert ) );
356 
357 	TransformVerts( verts, entJoints );
358 
359 	SIMDProcessor->MinMax( bounds[0], bounds[1], verts, texCoords.Num() );
360 
361 	return bounds;
362 }
363 
364 /*
365 ====================
366 idMD5Mesh::NearestJoint
367 ====================
368 */
NearestJoint(int a,int b,int c) const369 int idMD5Mesh::NearestJoint( int a, int b, int c ) const {
370 	int i, bestJoint, vertNum, weightVertNum;
371 	float bestWeight;
372 
373 	// duplicated vertices might not have weights
374 	if ( a >= 0 && a < texCoords.Num() ) {
375 		vertNum = a;
376 	} else if ( b >= 0 && b < texCoords.Num() ) {
377 		vertNum = b;
378 	} else if ( c >= 0 && c < texCoords.Num() ) {
379 		vertNum = c;
380 	} else {
381 		// all vertices are duplicates which shouldn't happen
382 		return 0;
383 	}
384 
385 	// find the first weight for this vertex
386 	weightVertNum = 0;
387 	for( i = 0; weightVertNum < vertNum; i++ ) {
388 		weightVertNum += weightIndex[i*2+1];
389 	}
390 
391 	// get the joint for the largest weight
392 	bestWeight = scaledWeights[i].w;
393 	bestJoint = weightIndex[i*2+0] / sizeof( idJointMat );
394 	for( ; weightIndex[i*2+1] == 0; i++ ) {
395 		if ( scaledWeights[i].w > bestWeight ) {
396 			bestWeight = scaledWeights[i].w;
397 			bestJoint = weightIndex[i*2+0] / sizeof( idJointMat );
398 		}
399 	}
400 	return bestJoint;
401 }
402 
403 /*
404 ====================
405 idMD5Mesh::NumVerts
406 ====================
407 */
NumVerts(void) const408 int idMD5Mesh::NumVerts( void ) const {
409 	return texCoords.Num();
410 }
411 
412 /*
413 ====================
414 idMD5Mesh::NumTris
415 ====================
416 */
NumTris(void) const417 int	idMD5Mesh::NumTris( void ) const {
418 	return numTris;
419 }
420 
421 /*
422 ====================
423 idMD5Mesh::NumWeights
424 ====================
425 */
NumWeights(void) const426 int	idMD5Mesh::NumWeights( void ) const {
427 	return numWeights;
428 }
429 
430 /***********************************************************************
431 
432 	idRenderModelMD5
433 
434 ***********************************************************************/
435 
436 /*
437 ====================
438 idRenderModelMD5::ParseJoint
439 ====================
440 */
ParseJoint(idLexer & parser,idMD5Joint * joint,idJointQuat * defaultPose)441 void idRenderModelMD5::ParseJoint( idLexer &parser, idMD5Joint *joint, idJointQuat *defaultPose ) {
442 	idToken	token;
443 	int		num;
444 
445 	//
446 	// parse name
447 	//
448 	parser.ReadToken( &token );
449 	joint->name = token;
450 
451 	//
452 	// parse parent
453 	//
454 	num = parser.ParseInt();
455 	if ( num < 0 ) {
456 		joint->parent = NULL;
457 	} else {
458 		if ( num >= joints.Num() - 1 ) {
459 			parser.Error( "Invalid parent for joint '%s'", joint->name.c_str() );
460 		}
461 		joint->parent = &joints[ num ];
462 	}
463 
464 	//
465 	// parse default pose
466 	//
467 	parser.Parse1DMatrix( 3, defaultPose->t.ToFloatPtr() );
468 	parser.Parse1DMatrix( 3, defaultPose->q.ToFloatPtr() );
469 	defaultPose->q.w = defaultPose->q.CalcW();
470 }
471 
472 /*
473 ====================
474 idRenderModelMD5::InitFromFile
475 ====================
476 */
InitFromFile(const char * fileName)477 void idRenderModelMD5::InitFromFile( const char *fileName ) {
478 	name = fileName;
479 	LoadModel();
480 }
481 
482 /*
483 ====================
484 idRenderModelMD5::LoadModel
485 
486 used for initial loads, reloadModel, and reloading the data of purged models
487 Upon exit, the model will absolutely be valid, but possibly as a default model
488 ====================
489 */
LoadModel()490 void idRenderModelMD5::LoadModel() {
491 	int			version;
492 	int			i;
493 	int			num;
494 	int			parentNum;
495 	idToken		token;
496 	idLexer		parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS );
497 	idJointQuat	*pose;
498 	idMD5Joint	*joint;
499 	idJointMat *poseMat3;
500 
501 	if ( !purged ) {
502 		PurgeModel();
503 	}
504 	purged = false;
505 
506 	if ( !parser.LoadFile( name ) ) {
507 		MakeDefaultModel();
508 		return;
509 	}
510 
511 	parser.ExpectTokenString( MD5_VERSION_STRING );
512 	version = parser.ParseInt();
513 
514 	if ( version != MD5_VERSION ) {
515 		parser.Error( "Invalid version %d.  Should be version %d\n", version, MD5_VERSION );
516 	}
517 
518 	//
519 	// skip commandline
520 	//
521 	parser.ExpectTokenString( "commandline" );
522 	parser.ReadToken( &token );
523 
524 	// parse num joints
525 	parser.ExpectTokenString( "numJoints" );
526 	num  = parser.ParseInt();
527 	joints.SetGranularity( 1 );
528 	joints.SetNum( num );
529 	defaultPose.SetGranularity( 1 );
530 	defaultPose.SetNum( num );
531 	poseMat3 = ( idJointMat * )_alloca16( num * sizeof( *poseMat3 ) );
532 
533 	// parse num meshes
534 	parser.ExpectTokenString( "numMeshes" );
535 	num = parser.ParseInt();
536 	if ( num < 0 ) {
537 		parser.Error( "Invalid size: %d", num );
538 	}
539 	meshes.SetGranularity( 1 );
540 	meshes.SetNum( num );
541 
542 	//
543 	// parse joints
544 	//
545 	parser.ExpectTokenString( "joints" );
546 	parser.ExpectTokenString( "{" );
547 	pose = defaultPose.Ptr();
548 	joint = joints.Ptr();
549 	for( i = 0; i < joints.Num(); i++, joint++, pose++ ) {
550 		ParseJoint( parser, joint, pose );
551 		poseMat3[ i ].SetRotation( pose->q.ToMat3() );
552 		poseMat3[ i ].SetTranslation( pose->t );
553 		if ( joint->parent ) {
554 			parentNum = joint->parent - joints.Ptr();
555 			pose->q = ( poseMat3[ i ].ToMat3() * poseMat3[ parentNum ].ToMat3().Transpose() ).ToQuat();
556 			pose->t = ( poseMat3[ i ].ToVec3() - poseMat3[ parentNum ].ToVec3() ) * poseMat3[ parentNum ].ToMat3().Transpose();
557 		}
558 	}
559 	parser.ExpectTokenString( "}" );
560 
561 	for( i = 0; i < meshes.Num(); i++ ) {
562 		parser.ExpectTokenString( "mesh" );
563 		meshes[ i ].ParseMesh( parser, defaultPose.Num(), poseMat3 );
564 	}
565 
566 	//
567 	// calculate the bounds of the model
568 	//
569 	CalculateBounds( poseMat3 );
570 
571 	// set the timestamp for reloadmodels
572 	fileSystem->ReadFile( name, NULL, &timeStamp );
573 }
574 
575 /*
576 ==============
577 idRenderModelMD5::Print
578 ==============
579 */
Print() const580 void idRenderModelMD5::Print() const {
581 	const idMD5Mesh	*mesh;
582 	int			i;
583 
584 	common->Printf( "%s\n", name.c_str() );
585 	common->Printf( "Dynamic model.\n" );
586 	common->Printf( "Generated smooth normals.\n" );
587 	common->Printf( "    verts  tris weights material\n" );
588 	int	totalVerts = 0;
589 	int	totalTris = 0;
590 	int	totalWeights = 0;
591 	for( mesh = meshes.Ptr(), i = 0; i < meshes.Num(); i++, mesh++ ) {
592 		totalVerts += mesh->NumVerts();
593 		totalTris += mesh->NumTris();
594 		totalWeights += mesh->NumWeights();
595 		common->Printf( "%2i: %5i %5i %7i %s\n", i, mesh->NumVerts(), mesh->NumTris(), mesh->NumWeights(), mesh->shader->GetName() );
596 	}
597 	common->Printf( "-----\n" );
598 	common->Printf( "%4i verts.\n", totalVerts );
599 	common->Printf( "%4i tris.\n", totalTris );
600 	common->Printf( "%4i weights.\n", totalWeights );
601 	common->Printf( "%4i joints.\n", joints.Num() );
602 }
603 
604 /*
605 ==============
606 idRenderModelMD5::List
607 ==============
608 */
List() const609 void idRenderModelMD5::List() const {
610 	int			i;
611 	const idMD5Mesh	*mesh;
612 	int			totalTris = 0;
613 	int			totalVerts = 0;
614 
615 	for( mesh = meshes.Ptr(), i = 0; i < meshes.Num(); i++, mesh++ ) {
616 		totalTris += mesh->numTris;
617 		totalVerts += mesh->NumVerts();
618 	}
619 	common->Printf( " %4ik %3i %4i %4i %s(MD5)", Memory()/1024, meshes.Num(), totalVerts, totalTris, Name() );
620 
621 	if ( defaulted ) {
622 		common->Printf( " (DEFAULTED)" );
623 	}
624 
625 	common->Printf( "\n" );
626 }
627 
628 /*
629 ====================
630 idRenderModelMD5::CalculateBounds
631 ====================
632 */
CalculateBounds(const idJointMat * entJoints)633 void idRenderModelMD5::CalculateBounds( const idJointMat *entJoints ) {
634 	int			i;
635 	idMD5Mesh	*mesh;
636 
637 	bounds.Clear();
638 	for( mesh = meshes.Ptr(), i = 0; i < meshes.Num(); i++, mesh++ ) {
639 		bounds.AddBounds( mesh->CalcBounds( entJoints ) );
640 	}
641 }
642 
643 /*
644 ====================
645 idRenderModelMD5::Bounds
646 
647 This calculates a rough bounds by using the joint radii without
648 transforming all the points
649 ====================
650 */
Bounds(const renderEntity_t * ent) const651 idBounds idRenderModelMD5::Bounds( const renderEntity_t *ent ) const {
652 #if 0
653 	// we can't calculate a rational bounds without an entity,
654 	// because joints could be positioned to deform it into an
655 	// arbitrarily large shape
656 	if ( !ent ) {
657 		common->Error( "idRenderModelMD5::Bounds: called without entity" );
658 	}
659 #endif
660 
661 	if ( !ent ) {
662 		// this is the bounds for the reference pose
663 		return bounds;
664 	}
665 
666 	return ent->bounds;
667 }
668 
669 /*
670 ====================
671 idRenderModelMD5::DrawJoints
672 ====================
673 */
DrawJoints(const renderEntity_t * ent,const struct viewDef_s * view) const674 void idRenderModelMD5::DrawJoints( const renderEntity_t *ent, const struct viewDef_s *view ) const {
675 	int					i;
676 	int					num;
677 	idVec3				pos;
678 	const idJointMat	*joint;
679 	const idMD5Joint	*md5Joint;
680 	int					parentNum;
681 
682 	num = ent->numJoints;
683 	joint = ent->joints;
684 	md5Joint = joints.Ptr();
685 	for( i = 0; i < num; i++, joint++, md5Joint++ ) {
686 		pos = ent->origin + joint->ToVec3() * ent->axis;
687 		if ( md5Joint->parent ) {
688 			parentNum = md5Joint->parent - joints.Ptr();
689 			session->rw->DebugLine( colorWhite, ent->origin + ent->joints[ parentNum ].ToVec3() * ent->axis, pos );
690 		}
691 
692 		session->rw->DebugLine( colorRed,	pos, pos + joint->ToMat3()[ 0 ] * 2.0f * ent->axis );
693 		session->rw->DebugLine( colorGreen,	pos, pos + joint->ToMat3()[ 1 ] * 2.0f * ent->axis );
694 		session->rw->DebugLine( colorBlue,	pos, pos + joint->ToMat3()[ 2 ] * 2.0f * ent->axis );
695 	}
696 
697 	idBounds bounds;
698 
699 	bounds.FromTransformedBounds( ent->bounds, vec3_zero, ent->axis );
700 	session->rw->DebugBounds( colorMagenta, bounds, ent->origin );
701 
702 	if ( ( r_jointNameScale.GetFloat() != 0.0f ) && ( bounds.Expand( 128.0f ).ContainsPoint( view->renderView.vieworg - ent->origin ) ) ) {
703 		idVec3	offset( 0, 0, r_jointNameOffset.GetFloat() );
704 		float	scale;
705 
706 		scale = r_jointNameScale.GetFloat();
707 		joint = ent->joints;
708 		num = ent->numJoints;
709 		for( i = 0; i < num; i++, joint++ ) {
710 			pos = ent->origin + joint->ToVec3() * ent->axis;
711 			session->rw->DrawText( joints[ i ].name, pos + offset, scale, colorWhite, view->renderView.viewaxis, 1 );
712 		}
713 	}
714 }
715 
716 /*
717 ====================
718 idRenderModelMD5::InstantiateDynamicModel
719 ====================
720 */
InstantiateDynamicModel(const struct renderEntity_s * ent,const struct viewDef_s * view,idRenderModel * cachedModel)721 idRenderModel *idRenderModelMD5::InstantiateDynamicModel( const struct renderEntity_s *ent, const struct viewDef_s *view, idRenderModel *cachedModel ) {
722 	int					i, surfaceNum;
723 	idMD5Mesh			*mesh;
724 	idRenderModelStatic	*staticModel;
725 
726 	if ( cachedModel && !r_useCachedDynamicModels.GetBool() ) {
727 		delete cachedModel;
728 		cachedModel = NULL;
729 	}
730 
731 	if ( purged ) {
732 		common->DWarning( "model %s instantiated while purged", Name() );
733 		LoadModel();
734 	}
735 
736 	if ( !ent->joints ) {
737 		common->Printf( "idRenderModelMD5::InstantiateDynamicModel: NULL joints on renderEntity for '%s'\n", Name() );
738 		delete cachedModel;
739 		return NULL;
740 	} else if ( ent->numJoints != joints.Num() ) {
741 		common->Printf( "idRenderModelMD5::InstantiateDynamicModel: renderEntity has different number of joints than model for '%s'\n", Name() );
742 		delete cachedModel;
743 		return NULL;
744 	}
745 
746 	tr.pc.c_generateMd5++;
747 
748 	if ( cachedModel ) {
749 		assert( dynamic_cast<idRenderModelStatic *>(cachedModel) != NULL );
750 		assert( idStr::Icmp( cachedModel->Name(), MD5_SnapshotName ) == 0 );
751 		staticModel = static_cast<idRenderModelStatic *>(cachedModel);
752 	} else {
753 		staticModel = new idRenderModelStatic;
754 		staticModel->InitEmpty( MD5_SnapshotName );
755 	}
756 
757 	staticModel->bounds.Clear();
758 
759 	if ( r_showSkel.GetInteger() ) {
760 		if ( ( view != NULL ) && ( !r_skipSuppress.GetBool() || !ent->suppressSurfaceInViewID || ( ent->suppressSurfaceInViewID != view->renderView.viewID ) ) ) {
761 			// only draw the skeleton
762 			DrawJoints( ent, view );
763 		}
764 
765 		if ( r_showSkel.GetInteger() > 1 ) {
766 			// turn off the model when showing the skeleton
767 			staticModel->InitEmpty( MD5_SnapshotName );
768 			return staticModel;
769 		}
770 	}
771 
772 	// create all the surfaces
773 	for( mesh = meshes.Ptr(), i = 0; i < meshes.Num(); i++, mesh++ ) {
774 		// avoid deforming the surface if it will be a nodraw due to a skin remapping
775 		// FIXME: may have to still deform clipping hulls
776 		const idMaterial *shader = mesh->shader;
777 
778 		shader = R_RemapShaderBySkin( shader, ent->customSkin, ent->customShader );
779 
780 		if ( !shader || ( !shader->IsDrawn() && !shader->SurfaceCastsShadow() ) ) {
781 			staticModel->DeleteSurfaceWithId( i );
782 			mesh->surfaceNum = -1;
783 			continue;
784 		}
785 
786 		modelSurface_t *surf;
787 
788 		if ( staticModel->FindSurfaceWithId( i, surfaceNum ) ) {
789 			mesh->surfaceNum = surfaceNum;
790 			surf = &staticModel->surfaces[surfaceNum];
791 		} else {
792 
793 			// Remove Overlays before adding new surfaces
794 			idRenderModelOverlay::RemoveOverlaySurfacesFromModel( staticModel );
795 
796 			mesh->surfaceNum = staticModel->NumSurfaces();
797 			surf = &staticModel->surfaces.Alloc();
798 			surf->geometry = NULL;
799 			surf->shader = NULL;
800 			surf->id = i;
801 		}
802 
803 		mesh->UpdateSurface( ent, ent->joints, surf );
804 
805 		staticModel->bounds.AddPoint( surf->geometry->bounds[0] );
806 		staticModel->bounds.AddPoint( surf->geometry->bounds[1] );
807 	}
808 
809 	return staticModel;
810 }
811 
812 /*
813 ====================
814 idRenderModelMD5::IsDynamicModel
815 ====================
816 */
IsDynamicModel() const817 dynamicModel_t idRenderModelMD5::IsDynamicModel() const {
818 	return DM_CACHED;
819 }
820 
821 /*
822 ====================
823 idRenderModelMD5::NumJoints
824 ====================
825 */
NumJoints(void) const826 int idRenderModelMD5::NumJoints( void ) const {
827 	return joints.Num();
828 }
829 
830 /*
831 ====================
832 idRenderModelMD5::GetJoints
833 ====================
834 */
GetJoints(void) const835 const idMD5Joint *idRenderModelMD5::GetJoints( void ) const {
836 	return joints.Ptr();
837 }
838 
839 /*
840 ====================
841 idRenderModelMD5::GetDefaultPose
842 ====================
843 */
GetDefaultPose(void) const844 const idJointQuat *idRenderModelMD5::GetDefaultPose( void ) const {
845 	return defaultPose.Ptr();
846 }
847 
848 /*
849 ====================
850 idRenderModelMD5::GetJointHandle
851 ====================
852 */
GetJointHandle(const char * name) const853 jointHandle_t idRenderModelMD5::GetJointHandle( const char *name ) const {
854 	const idMD5Joint *joint;
855 	int	i;
856 
857 	joint = joints.Ptr();
858 	for( i = 0; i < joints.Num(); i++, joint++ ) {
859 		if ( idStr::Icmp( joint->name.c_str(), name ) == 0 ) {
860 			return ( jointHandle_t )i;
861 		}
862 	}
863 
864 	return INVALID_JOINT;
865 }
866 
867 /*
868 =====================
869 idRenderModelMD5::GetJointName
870 =====================
871 */
GetJointName(jointHandle_t handle) const872 const char *idRenderModelMD5::GetJointName( jointHandle_t handle ) const {
873 	if ( ( handle < 0 ) || ( handle >= joints.Num() ) ) {
874 		return "<invalid joint>";
875 	}
876 
877 	return joints[ handle ].name;
878 }
879 
880 /*
881 ====================
882 idRenderModelMD5::NearestJoint
883 ====================
884 */
NearestJoint(int surfaceNum,int a,int b,int c) const885 int idRenderModelMD5::NearestJoint( int surfaceNum, int a, int b, int c ) const {
886 	int i;
887 	const idMD5Mesh *mesh;
888 
889 	if ( surfaceNum > meshes.Num() ) {
890 		common->Error( "idRenderModelMD5::NearestJoint: surfaceNum > meshes.Num()" );
891 	}
892 
893 	for ( mesh = meshes.Ptr(), i = 0; i < meshes.Num(); i++, mesh++ ) {
894 		if ( mesh->surfaceNum == surfaceNum ) {
895 			return mesh->NearestJoint( a, b, c );
896 		}
897 	}
898 	return 0;
899 }
900 
901 /*
902 ====================
903 idRenderModelMD5::TouchData
904 
905 models that are already loaded at level start time
906 will still touch their materials to make sure they
907 are kept loaded
908 ====================
909 */
TouchData()910 void idRenderModelMD5::TouchData() {
911 	idMD5Mesh	*mesh;
912 	int			i;
913 
914 	for( mesh = meshes.Ptr(), i = 0; i < meshes.Num(); i++, mesh++ ) {
915 		declManager->FindMaterial( mesh->shader->GetName() );
916 	}
917 }
918 
919 /*
920 ===================
921 idRenderModelMD5::PurgeModel
922 
923 frees all the data, but leaves the class around for dangling references,
924 which can regenerate the data with LoadModel()
925 ===================
926 */
PurgeModel()927 void idRenderModelMD5::PurgeModel() {
928 	purged = true;
929 	joints.Clear();
930 	defaultPose.Clear();
931 	meshes.Clear();
932 }
933 
934 /*
935 ===================
936 idRenderModelMD5::Memory
937 ===================
938 */
Memory() const939 int	idRenderModelMD5::Memory() const {
940 	int		total, i;
941 
942 	total = sizeof( *this );
943 	total += joints.MemoryUsed() + defaultPose.MemoryUsed() + meshes.MemoryUsed();
944 
945 	// count up strings
946 	for ( i = 0; i < joints.Num(); i++ ) {
947 		total += joints[i].name.DynamicMemoryUsed();
948 	}
949 
950 	// count up meshes
951 	for ( i = 0 ; i < meshes.Num() ; i++ ) {
952 		const idMD5Mesh *mesh = &meshes[i];
953 
954 		total += mesh->texCoords.MemoryUsed() + mesh->numWeights * ( sizeof( mesh->scaledWeights[0] ) + sizeof( mesh->weightIndex[0] ) * 2 );
955 
956 		// sum up deform info
957 		total += sizeof( mesh->deformInfo );
958 		total += R_DeformInfoMemoryUsed( mesh->deformInfo );
959 	}
960 	return total;
961 }
962