1 /*
2 ===========================================================================
3 
4 Return to Castle Wolfenstein multiplayer GPL Source Code
5 Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
8 
9 RTCW MP 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 RTCW MP 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 RTCW MP Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the RTCW MP 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 RTCW MP 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 
30 #include "tr_local.h"
31 
32 /*
33 
34 All bones should be an identity orientation to display the mesh exactly
35 as it is specified.
36 
37 For all other frames, the bones represent the transformation from the
38 orientation of the bone in the base frame to the orientation in this
39 frame.
40 
41 */
42 
43 //#define HIGH_PRECISION_BONES	// enable this for 32bit precision bones
44 //#define DBG_PROFILE_BONES
45 
46 //-----------------------------------------------------------------------------
47 // Static Vars, ugly but easiest (and fastest) means of separating RB_SurfaceAnim
48 // and R_CalcBones
49 
50 static float frontlerp, backlerp;
51 static float torsoFrontlerp, torsoBacklerp;
52 static int             *triangles;
53 static glIndex_t *pIndexes;
54 static int indexes;
55 static int baseIndex, baseVertex, oldIndexes;
56 static int numVerts;
57 static mdsVertex_t     *v;
58 static mdsBoneFrame_t bones[MDS_MAX_BONES], rawBones[MDS_MAX_BONES], oldBones[MDS_MAX_BONES];
59 static char validBones[MDS_MAX_BONES];
60 static char newBones[ MDS_MAX_BONES ];
61 static mdsBoneFrame_t  *bonePtr, *bone, *parentBone;
62 static mdsBoneFrameCompressed_t    *cBonePtr, *cTBonePtr, *cOldBonePtr, *cOldTBonePtr, *cBoneList, *cOldBoneList, *cBoneListTorso, *cOldBoneListTorso;
63 static mdsBoneInfo_t   *boneInfo, *thisBoneInfo, *parentBoneInfo;
64 static mdsFrame_t      *frame, *torsoFrame;
65 static mdsFrame_t      *oldFrame, *oldTorsoFrame;
66 static int frameSize;
67 static short           *sh, *sh2;
68 static float           *pf;
69 static vec3_t angles, tangles, torsoParentOffset, torsoAxis[3], tmpAxis[3];
70 static float           *tempVert;
71 static int16_t         *tempNormal;
72 static vec3_t vec, v2, dir;
73 static float diff, a1, a2;
74 static int render_count;
75 static float lodRadius, lodScale;
76 static int             *collapse_map, *pCollapseMap;
77 static int collapse[ MDS_MAX_VERTS ], *pCollapse;
78 static int p0, p1, p2;
79 static qboolean isTorso, fullTorso;
80 static vec4_t m1[4], m2[4];
81 // static  vec4_t m3[4], m4[4]; // TTimo unused
82 // static  vec4_t tmp1[4], tmp2[4]; // TTimo unused
83 static vec3_t t;
84 static refEntity_t lastBoneEntity;
85 
86 static int totalrv, totalrt, totalv, totalt;    //----(SA)
87 
88 //-----------------------------------------------------------------------------
89 
RB_ProjectRadius(float r,vec3_t location)90 static float RB_ProjectRadius( float r, vec3_t location ) {
91 	float pr;
92 	float dist;
93 	float c;
94 	vec3_t p;
95 	float projected[4];
96 
97 	c = DotProduct( backEnd.viewParms.or.axis[0], backEnd.viewParms.or.origin );
98 	dist = DotProduct( backEnd.viewParms.or.axis[0], location ) - c;
99 
100 	if ( dist <= 0 ) {
101 		return 0;
102 	}
103 
104 	p[0] = 0;
105 	p[1] = fabs( r );
106 	p[2] = -dist;
107 
108 	projected[0] = p[0] * backEnd.viewParms.projectionMatrix[0] +
109 				   p[1] * backEnd.viewParms.projectionMatrix[4] +
110 				   p[2] * backEnd.viewParms.projectionMatrix[8] +
111 				   backEnd.viewParms.projectionMatrix[12];
112 
113 	projected[1] = p[0] * backEnd.viewParms.projectionMatrix[1] +
114 				   p[1] * backEnd.viewParms.projectionMatrix[5] +
115 				   p[2] * backEnd.viewParms.projectionMatrix[9] +
116 				   backEnd.viewParms.projectionMatrix[13];
117 
118 	projected[2] = p[0] * backEnd.viewParms.projectionMatrix[2] +
119 				   p[1] * backEnd.viewParms.projectionMatrix[6] +
120 				   p[2] * backEnd.viewParms.projectionMatrix[10] +
121 				   backEnd.viewParms.projectionMatrix[14];
122 
123 	projected[3] = p[0] * backEnd.viewParms.projectionMatrix[3] +
124 				   p[1] * backEnd.viewParms.projectionMatrix[7] +
125 				   p[2] * backEnd.viewParms.projectionMatrix[11] +
126 				   backEnd.viewParms.projectionMatrix[15];
127 
128 
129 	pr = projected[1] / projected[3];
130 
131 	if ( pr > 1.0f ) {
132 		pr = 1.0f;
133 	}
134 
135 	return pr;
136 }
137 
138 /*
139 =============
140 R_CullModel
141 =============
142 */
R_CullModel(mdsHeader_t * header,trRefEntity_t * ent)143 static int R_CullModel( mdsHeader_t *header, trRefEntity_t *ent ) {
144 	vec3_t bounds[2];
145 	mdsFrame_t  *oldFrame, *newFrame;
146 	int i, frameSize;
147 
148 	frameSize = (int) ( sizeof( mdsFrame_t ) - sizeof( mdsBoneFrameCompressed_t ) + header->numBones * sizeof( mdsBoneFrameCompressed_t ) );
149 
150 	// compute frame pointers
151 	newFrame = ( mdsFrame_t * )( ( byte * ) header + header->ofsFrames + ent->e.frame * frameSize );
152 	oldFrame = ( mdsFrame_t * )( ( byte * ) header + header->ofsFrames + ent->e.oldframe * frameSize );
153 
154 	// cull bounding sphere ONLY if this is not an upscaled entity
155 	if ( !ent->e.nonNormalizedAxes ) {
156 		if ( ent->e.frame == ent->e.oldframe ) {
157 			switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) )
158 			{
159 			case CULL_OUT:
160 				tr.pc.c_sphere_cull_md3_out++;
161 				return CULL_OUT;
162 
163 			case CULL_IN:
164 				tr.pc.c_sphere_cull_md3_in++;
165 				return CULL_IN;
166 
167 			case CULL_CLIP:
168 				tr.pc.c_sphere_cull_md3_clip++;
169 				break;
170 			}
171 		} else
172 		{
173 			int sphereCull, sphereCullB;
174 
175 			sphereCull  = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius );
176 			if ( newFrame == oldFrame ) {
177 				sphereCullB = sphereCull;
178 			} else {
179 				sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius );
180 			}
181 
182 			if ( sphereCull == sphereCullB ) {
183 				if ( sphereCull == CULL_OUT ) {
184 					tr.pc.c_sphere_cull_md3_out++;
185 					return CULL_OUT;
186 				} else if ( sphereCull == CULL_IN )   {
187 					tr.pc.c_sphere_cull_md3_in++;
188 					return CULL_IN;
189 				} else
190 				{
191 					tr.pc.c_sphere_cull_md3_clip++;
192 				}
193 			}
194 		}
195 	}
196 
197 	// calculate a bounding box in the current coordinate system
198 	for ( i = 0 ; i < 3 ; i++ ) {
199 		bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i];
200 		bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i];
201 	}
202 
203 	switch ( R_CullLocalBox( bounds ) )
204 	{
205 	case CULL_IN:
206 		tr.pc.c_box_cull_md3_in++;
207 		return CULL_IN;
208 	case CULL_CLIP:
209 		tr.pc.c_box_cull_md3_clip++;
210 		return CULL_CLIP;
211 	case CULL_OUT:
212 	default:
213 		tr.pc.c_box_cull_md3_out++;
214 		return CULL_OUT;
215 	}
216 }
217 
218 /*
219 =================
220 RB_CalcMDSLod
221 
222 =================
223 */
RB_CalcMDSLod(refEntity_t * refent,vec3_t origin,float radius,float modelBias,float modelScale)224 float RB_CalcMDSLod( refEntity_t *refent, vec3_t origin, float radius, float modelBias, float modelScale ) {
225 	float flod, lodScale;
226 	float projectedRadius;
227 
228 	// compute projected bounding sphere and use that as a criteria for selecting LOD
229 
230 	projectedRadius = RB_ProjectRadius( radius, origin );
231 	if ( projectedRadius != 0 ) {
232 
233 //		ri.Printf (PRINT_ALL, "projected radius: %f\n", projectedRadius);
234 
235 		lodScale = r_lodscale->value;   // fudge factor since MDS uses a much smoother method of LOD
236 		flod = projectedRadius * lodScale * modelScale;
237 	} else
238 	{
239 		// object intersects near view plane, e.g. view weapon
240 		flod = 1.0f;
241 	}
242 
243 	if ( refent->reFlags & REFLAG_FORCE_LOD ) {
244 		flod *= 0.5;
245 	}
246 //----(SA)	like reflag_force_lod, but separate for the moment
247 	if ( refent->reFlags & REFLAG_DEAD_LOD ) {
248 		flod *= 0.8;
249 	}
250 
251 	flod -= 0.25 * ( r_lodbias->value ) + modelBias;
252 
253 	if ( flod < 0.0 ) {
254 		flod = 0.0;
255 	} else if ( flod > 1.0f ) {
256 		flod = 1.0f;
257 	}
258 
259 	return flod;
260 }
261 
262 /*
263 =================
264 R_ComputeFogNum
265 
266 =================
267 */
R_ComputeFogNum(mdsHeader_t * header,trRefEntity_t * ent)268 static int R_ComputeFogNum( mdsHeader_t *header, trRefEntity_t *ent ) {
269 	int i, j;
270 	fog_t           *fog;
271 	mdsFrame_t      *mdsFrame;
272 	vec3_t localOrigin;
273 
274 	if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
275 		return 0;
276 	}
277 
278 	// FIXME: non-normalized axis issues
279 	mdsFrame = ( mdsFrame_t * )( ( byte * ) header + header->ofsFrames + ( sizeof( mdsFrame_t ) + sizeof( mdsBoneFrameCompressed_t ) * ( header->numBones - 1 ) ) * ent->e.frame );
280 	VectorAdd( ent->e.origin, mdsFrame->localOrigin, localOrigin );
281 	for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
282 		fog = &tr.world->fogs[i];
283 		for ( j = 0 ; j < 3 ; j++ ) {
284 			if ( localOrigin[j] - mdsFrame->radius >= fog->bounds[1][j] ) {
285 				break;
286 			}
287 			if ( localOrigin[j] + mdsFrame->radius <= fog->bounds[0][j] ) {
288 				break;
289 			}
290 		}
291 		if ( j == 3 ) {
292 			return i;
293 		}
294 	}
295 
296 	return 0;
297 }
298 
299 /*
300 ==============
301 R_AddAnimSurfaces
302 ==============
303 */
R_AddAnimSurfaces(trRefEntity_t * ent)304 void R_AddAnimSurfaces( trRefEntity_t *ent ) {
305 	mdsHeader_t     *header;
306 	mdsSurface_t    *surface;
307 	shader_t        *shader = 0;
308 	int             cubemapIndex;
309 	int i, fogNum, cull;
310 	qboolean personalModel;
311 
312 	// don't add third_person objects if not in a portal
313 	personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !(tr.viewParms.isPortal
314 	                 || (tr.viewParms.flags & (VPF_SHADOWMAP | VPF_DEPTHSHADOW)));
315 
316 	header = tr.currentModel->mds;
317 
318 	//
319 	// cull the entire model if merged bounding box of both frames
320 	// is outside the view frustum.
321 	//
322 	cull = R_CullModel( header, ent );
323 	if ( cull == CULL_OUT ) {
324 		return;
325 	}
326 
327 	//
328 	// set up lighting now that we know we aren't culled
329 	//
330 	if ( !personalModel || r_shadows->integer > 1 ) {
331 		R_SetupEntityLighting( &tr.refdef, ent );
332 	}
333 
334 	//
335 	// see if we are in a fog volume
336 	//
337 	fogNum = R_ComputeFogNum( header, ent );
338 
339 	cubemapIndex = R_CubemapForPoint(ent->e.origin);
340 
341 	surface = ( mdsSurface_t * )( (byte *)header + header->ofsSurfaces );
342 	for ( i = 0 ; i < header->numSurfaces ; i++ ) {
343 
344 		if ( ent->e.customShader ) {
345 			shader = R_GetShaderByHandle( ent->e.customShader );
346 		} else if ( ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins ) {
347 			skin_t *skin;
348 			int j;
349 
350 			skin = R_GetSkinByHandle( ent->e.customSkin );
351 
352 			// match the surface name to something in the skin file
353 			shader = tr.defaultShader;
354 
355 			if ( ent->e.renderfx & RF_BLINK ) {
356 				const char *s = va( "%s_b", surface->name );   // append '_b' for 'blink'
357 				for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
358 					if ( !strcmp( skin->surfaces[j].name, s ) ) {
359 						shader = skin->surfaces[j].shader;
360 						break;
361 					}
362 				}
363 			}
364 
365 			if ( shader == tr.defaultShader ) {    // blink reference in skin was not found
366 				for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
367 					// the names have both been lowercased
368 					if ( !strcmp( skin->surfaces[j].name, surface->name ) ) {
369 						shader = skin->surfaces[j].shader;
370 						break;
371 					}
372 				}
373 			}
374 
375 			if ( shader == tr.defaultShader ) {
376 				ri.Printf( PRINT_DEVELOPER, "WARNING: no shader for surface %s in skin %s\n", surface->name, skin->name );
377 			} else if ( shader->defaultShader )     {
378 				ri.Printf( PRINT_DEVELOPER, "WARNING: shader %s in skin %s not found\n", shader->name, skin->name );
379 			}
380 		} else {
381 			shader = R_GetShaderByHandle( surface->shaderIndex );
382 		}
383 
384 		// don't add third_person objects if not viewing through a portal
385 		if ( !personalModel ) {
386 			R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse, qfalse, cubemapIndex );
387 		}
388 
389 		surface = ( mdsSurface_t * )( (byte *)surface + surface->ofsEnd );
390 	}
391 }
392 
LocalMatrixTransformVector(vec3_t in,vec3_t mat[3],vec3_t out)393 static ID_INLINE void LocalMatrixTransformVector( vec3_t in, vec3_t mat[ 3 ], vec3_t out ) {
394 	out[ 0 ] = in[ 0 ] * mat[ 0 ][ 0 ] + in[ 1 ] * mat[ 0 ][ 1 ] + in[ 2 ] * mat[ 0 ][ 2 ];
395 	out[ 1 ] = in[ 0 ] * mat[ 1 ][ 0 ] + in[ 1 ] * mat[ 1 ][ 1 ] + in[ 2 ] * mat[ 1 ][ 2 ];
396 	out[ 2 ] = in[ 0 ] * mat[ 2 ][ 0 ] + in[ 1 ] * mat[ 2 ][ 1 ] + in[ 2 ] * mat[ 2 ][ 2 ];
397 }
398 
LocalScaledMatrixTransformVector(vec3_t in,float s,vec3_t mat[3],vec3_t out)399 static ID_INLINE void LocalScaledMatrixTransformVector( vec3_t in, float s, vec3_t mat[ 3 ], vec3_t out ) {
400 	out[ 0 ] = ( 1.0f - s ) * in[ 0 ] + s * ( in[ 0 ] * mat[ 0 ][ 0 ] + in[ 1 ] * mat[ 0 ][ 1 ] + in[ 2 ] * mat[ 0 ][ 2 ] );
401 	out[ 1 ] = ( 1.0f - s ) * in[ 1 ] + s * ( in[ 0 ] * mat[ 1 ][ 0 ] + in[ 1 ] * mat[ 1 ][ 1 ] + in[ 2 ] * mat[ 1 ][ 2 ] );
402 	out[ 2 ] = ( 1.0f - s ) * in[ 2 ] + s * ( in[ 0 ] * mat[ 2 ][ 0 ] + in[ 1 ] * mat[ 2 ][ 1 ] + in[ 2 ] * mat[ 2 ][ 2 ] );
403 }
404 
LocalAddScaledMatrixTransformVectorTranslate(vec3_t in,float s,vec3_t mat[3],vec3_t tr,vec3_t out)405 static ID_INLINE void LocalAddScaledMatrixTransformVectorTranslate( vec3_t in, float s, vec3_t mat[ 3 ], vec3_t tr, vec3_t out ) {
406 	out[ 0 ] += s * ( in[ 0 ] * mat[ 0 ][ 0 ] + in[ 1 ] * mat[ 0 ][ 1 ] + in[ 2 ] * mat[ 0 ][ 2 ] + tr[ 0 ] );
407 	out[ 1 ] += s * ( in[ 0 ] * mat[ 1 ][ 0 ] + in[ 1 ] * mat[ 1 ][ 1 ] + in[ 2 ] * mat[ 1 ][ 2 ] + tr[ 1 ] );
408 	out[ 2 ] += s * ( in[ 0 ] * mat[ 2 ][ 0 ] + in[ 1 ] * mat[ 2 ][ 1 ] + in[ 2 ] * mat[ 2 ][ 2 ] + tr[ 2 ] );
409 }
410 
411 static float LAVangle;
412 static float sp, sy, cp, cy;
413 //static float    sr, cr;// TTimo: unused
414 
LocalAngleVector(vec3_t angles,vec3_t forward)415 static ID_INLINE void LocalAngleVector( vec3_t angles, vec3_t forward ) {
416 	LAVangle = angles[YAW] * ( M_PI * 2 / 360 );
417 	sy = sin( LAVangle );
418 	cy = cos( LAVangle );
419 	LAVangle = angles[PITCH] * ( M_PI * 2 / 360 );
420 	sp = sin( LAVangle );
421 	cp = cos( LAVangle );
422 
423 	forward[0] = cp * cy;
424 	forward[1] = cp * sy;
425 	forward[2] = -sp;
426 }
427 
LocalVectorMA(vec3_t org,float dist,vec3_t vec,vec3_t out)428 static ID_INLINE void LocalVectorMA( vec3_t org, float dist, vec3_t vec, vec3_t out ) {
429 	out[0] = org[0] + dist * vec[0];
430 	out[1] = org[1] + dist * vec[1];
431 	out[2] = org[2] + dist * vec[2];
432 }
433 
434 #define ANGLES_SHORT_TO_FLOAT( pf, sh )     { *( pf++ ) = SHORT2ANGLE( *( sh++ ) ); *( pf++ ) = SHORT2ANGLE( *( sh++ ) ); *( pf++ ) = SHORT2ANGLE( *( sh++ ) ); }
435 
SLerp_Normal(vec3_t from,vec3_t to,float tt,vec3_t out)436 static ID_INLINE void SLerp_Normal( vec3_t from, vec3_t to, float tt, vec3_t out ) {
437 	float ft = 1.0 - tt;
438 
439 	out[0] = from[0] * ft + to[0] * tt;
440 	out[1] = from[1] * ft + to[1] * tt;
441 	out[2] = from[2] * ft + to[2] * tt;
442 
443 	VectorNormalize( out );
444 }
445 
446 /*
447 ===============================================================================
448 
449 4x4 Matrices
450 
451 ===============================================================================
452 */
453 
454 // TTimo: const usage would require an explicit cast, non ANSI C
455 // see unix/const-arg.c
Matrix4MultiplyInto3x3AndTranslation(vec4_t a[4],vec4_t b[4],vec3_t dst[3],vec3_t t)456 static ID_INLINE void Matrix4MultiplyInto3x3AndTranslation( /*const*/ vec4_t a[4], /*const*/ vec4_t b[4], vec3_t dst[3], vec3_t t ) {
457 	dst[0][0] = a[0][0] * b[0][0] + a[0][1] * b[1][0] + a[0][2] * b[2][0] + a[0][3] * b[3][0];
458 	dst[0][1] = a[0][0] * b[0][1] + a[0][1] * b[1][1] + a[0][2] * b[2][1] + a[0][3] * b[3][1];
459 	dst[0][2] = a[0][0] * b[0][2] + a[0][1] * b[1][2] + a[0][2] * b[2][2] + a[0][3] * b[3][2];
460 	t[0]      = a[0][0] * b[0][3] + a[0][1] * b[1][3] + a[0][2] * b[2][3] + a[0][3] * b[3][3];
461 
462 	dst[1][0] = a[1][0] * b[0][0] + a[1][1] * b[1][0] + a[1][2] * b[2][0] + a[1][3] * b[3][0];
463 	dst[1][1] = a[1][0] * b[0][1] + a[1][1] * b[1][1] + a[1][2] * b[2][1] + a[1][3] * b[3][1];
464 	dst[1][2] = a[1][0] * b[0][2] + a[1][1] * b[1][2] + a[1][2] * b[2][2] + a[1][3] * b[3][2];
465 	t[1]      = a[1][0] * b[0][3] + a[1][1] * b[1][3] + a[1][2] * b[2][3] + a[1][3] * b[3][3];
466 
467 	dst[2][0] = a[2][0] * b[0][0] + a[2][1] * b[1][0] + a[2][2] * b[2][0] + a[2][3] * b[3][0];
468 	dst[2][1] = a[2][0] * b[0][1] + a[2][1] * b[1][1] + a[2][2] * b[2][1] + a[2][3] * b[3][1];
469 	dst[2][2] = a[2][0] * b[0][2] + a[2][1] * b[1][2] + a[2][2] * b[2][2] + a[2][3] * b[3][2];
470 	t[2]      = a[2][0] * b[0][3] + a[2][1] * b[1][3] + a[2][2] * b[2][3] + a[2][3] * b[3][3];
471 }
472 
473 // can put an axis rotation followed by a translation directly into one matrix
474 // TTimo: const usage would require an explicit cast, non ANSI C
475 // see unix/const-arg.c
Matrix4FromAxisPlusTranslation(vec3_t axis[3],const vec3_t t,vec4_t dst[4])476 static ID_INLINE void Matrix4FromAxisPlusTranslation( /*const*/ vec3_t axis[3], const vec3_t t, vec4_t dst[4] ) {
477 	int i, j;
478 	for ( i = 0; i < 3; i++ ) {
479 		for ( j = 0; j < 3; j++ ) {
480 			dst[i][j] = axis[i][j];
481 		}
482 		dst[3][i] = 0;
483 		dst[i][3] = t[i];
484 	}
485 	dst[3][3] = 1;
486 }
487 
488 // can put a scaled axis rotation followed by a translation directly into one matrix
489 // TTimo: const usage would require an explicit cast, non ANSI C
490 // see unix/const-arg.c
Matrix4FromScaledAxisPlusTranslation(vec3_t axis[3],const float scale,const vec3_t t,vec4_t dst[4])491 static ID_INLINE void Matrix4FromScaledAxisPlusTranslation( /*const*/ vec3_t axis[3], const float scale, const vec3_t t, vec4_t dst[4] ) {
492 	int i, j;
493 
494 	for ( i = 0; i < 3; i++ ) {
495 		for ( j = 0; j < 3; j++ ) {
496 			dst[i][j] = scale * axis[i][j];
497 			if ( i == j ) {
498 				dst[i][j] += 1.0f - scale;
499 			}
500 		}
501 		dst[3][i] = 0;
502 		dst[i][3] = t[i];
503 	}
504 	dst[3][3] = 1;
505 }
506 
507 /*
508 ===============================================================================
509 
510 3x3 Matrices
511 
512 ===============================================================================
513 */
514 
Matrix3Transpose(const vec3_t matrix[3],vec3_t transpose[3])515 static ID_INLINE void Matrix3Transpose( const vec3_t matrix[3], vec3_t transpose[3] ) {
516 	int i, j;
517 	for ( i = 0; i < 3; i++ ) {
518 		for ( j = 0; j < 3; j++ ) {
519 			transpose[i][j] = matrix[j][i];
520 		}
521 	}
522 }
523 
524 
525 /*
526 ==============
527 R_CalcBone
528 ==============
529 */
R_CalcBone(mdsHeader_t * header,const refEntity_t * refent,int boneNum)530 void R_CalcBone( mdsHeader_t *header, const refEntity_t *refent, int boneNum ) {
531 	int j;
532 
533 	thisBoneInfo = &boneInfo[boneNum];
534 	if ( thisBoneInfo->torsoWeight ) {
535 		cTBonePtr = &cBoneListTorso[boneNum];
536 		isTorso = qtrue;
537 		if ( thisBoneInfo->torsoWeight == 1.0f ) {
538 			fullTorso = qtrue;
539 		}
540 	} else {
541 		isTorso = qfalse;
542 		fullTorso = qfalse;
543 	}
544 	cBonePtr = &cBoneList[boneNum];
545 
546 	bonePtr = &bones[ boneNum ];
547 
548 	// we can assume the parent has already been uncompressed for this frame + lerp
549 	if ( thisBoneInfo->parent >= 0 ) {
550 		parentBone = &bones[ thisBoneInfo->parent ];
551 		parentBoneInfo = &boneInfo[ thisBoneInfo->parent ];
552 	} else {
553 		parentBone = NULL;
554 		parentBoneInfo = NULL;
555 	}
556 
557 #ifdef HIGH_PRECISION_BONES
558 	// rotation
559 	if ( fullTorso ) {
560 		VectorCopy( cTBonePtr->angles, angles );
561 	} else {
562 		VectorCopy( cBonePtr->angles, angles );
563 		if ( isTorso ) {
564 			VectorCopy( cTBonePtr->angles, tangles );
565 			// blend the angles together
566 			for ( j = 0; j < 3; j++ ) {
567 				diff = tangles[j] - angles[j];
568 				if ( fabs( diff ) > 180 ) {
569 					diff = AngleNormalize180( diff );
570 				}
571 				angles[j] = angles[j] + thisBoneInfo->torsoWeight * diff;
572 			}
573 		}
574 	}
575 #else
576 	// rotation
577 	if ( fullTorso ) {
578 		sh = (short *)cTBonePtr->angles;
579 		pf = angles;
580 		ANGLES_SHORT_TO_FLOAT( pf, sh );
581 	} else {
582 		sh = (short *)cBonePtr->angles;
583 		pf = angles;
584 		ANGLES_SHORT_TO_FLOAT( pf, sh );
585 		if ( isTorso ) {
586 			sh = (short *)cTBonePtr->angles;
587 			pf = tangles;
588 			ANGLES_SHORT_TO_FLOAT( pf, sh );
589 			// blend the angles together
590 			for ( j = 0; j < 3; j++ ) {
591 				diff = tangles[j] - angles[j];
592 				if ( fabs( diff ) > 180 ) {
593 					diff = AngleNormalize180( diff );
594 				}
595 				angles[j] = angles[j] + thisBoneInfo->torsoWeight * diff;
596 			}
597 		}
598 	}
599 #endif
600 	AnglesToAxis( angles, bonePtr->matrix );
601 
602 	// translation
603 	if ( parentBone ) {
604 
605 #ifdef HIGH_PRECISION_BONES
606 		if ( fullTorso ) {
607 			angles[0] = cTBonePtr->ofsAngles[0];
608 			angles[1] = cTBonePtr->ofsAngles[1];
609 			angles[2] = 0;
610 			LocalAngleVector( angles, vec );
611 			LocalVectorMA( parentBone->translation, thisBoneInfo->parentDist, vec, bonePtr->translation );
612 		} else {
613 
614 			angles[0] = cBonePtr->ofsAngles[0];
615 			angles[1] = cBonePtr->ofsAngles[1];
616 			angles[2] = 0;
617 			LocalAngleVector( angles, vec );
618 
619 			if ( isTorso ) {
620 				tangles[0] = cTBonePtr->ofsAngles[0];
621 				tangles[1] = cTBonePtr->ofsAngles[1];
622 				tangles[2] = 0;
623 				LocalAngleVector( tangles, v2 );
624 
625 				// blend the angles together
626 				SLerp_Normal( vec, v2, thisBoneInfo->torsoWeight, vec );
627 				LocalVectorMA( parentBone->translation, thisBoneInfo->parentDist, vec, bonePtr->translation );
628 
629 			} else {    // legs bone
630 				LocalVectorMA( parentBone->translation, thisBoneInfo->parentDist, vec, bonePtr->translation );
631 			}
632 		}
633 #else
634 		if ( fullTorso ) {
635 			sh = (short *)cTBonePtr->ofsAngles; pf = angles;
636 			*( pf++ ) = SHORT2ANGLE( *( sh++ ) ); *( pf++ ) = SHORT2ANGLE( *( sh++ ) ); *( pf++ ) = 0;
637 			LocalAngleVector( angles, vec );
638 			LocalVectorMA( parentBone->translation, thisBoneInfo->parentDist, vec, bonePtr->translation );
639 		} else {
640 
641 			sh = (short *)cBonePtr->ofsAngles; pf = angles;
642 			*( pf++ ) = SHORT2ANGLE( *( sh++ ) ); *( pf++ ) = SHORT2ANGLE( *( sh++ ) ); *( pf++ ) = 0;
643 			LocalAngleVector( angles, vec );
644 
645 			if ( isTorso ) {
646 				sh = (short *)cTBonePtr->ofsAngles;
647 				pf = tangles;
648 				*( pf++ ) = SHORT2ANGLE( *( sh++ ) ); *( pf++ ) = SHORT2ANGLE( *( sh++ ) ); *( pf++ ) = 0;
649 				LocalAngleVector( tangles, v2 );
650 
651 				// blend the angles together
652 				SLerp_Normal( vec, v2, thisBoneInfo->torsoWeight, vec );
653 				LocalVectorMA( parentBone->translation, thisBoneInfo->parentDist, vec, bonePtr->translation );
654 
655 			} else {    // legs bone
656 				LocalVectorMA( parentBone->translation, thisBoneInfo->parentDist, vec, bonePtr->translation );
657 			}
658 		}
659 #endif
660 	} else {    // just use the frame position
661 		bonePtr->translation[0] = frame->parentOffset[0];
662 		bonePtr->translation[1] = frame->parentOffset[1];
663 		bonePtr->translation[2] = frame->parentOffset[2];
664 	}
665 	//
666 	if ( boneNum == header->torsoParent ) { // this is the torsoParent
667 		VectorCopy( bonePtr->translation, torsoParentOffset );
668 	}
669 	//
670 	validBones[boneNum] = 1;
671 	//
672 	rawBones[boneNum] = *bonePtr;
673 	newBones[boneNum] = 1;
674 
675 }
676 
677 /*
678 ==============
679 R_CalcBoneLerp
680 ==============
681 */
R_CalcBoneLerp(mdsHeader_t * header,const refEntity_t * refent,int boneNum)682 void R_CalcBoneLerp( mdsHeader_t *header, const refEntity_t *refent, int boneNum ) {
683 	int j;
684 
685 	if ( !refent || !header || boneNum < 0 || boneNum >= MDS_MAX_BONES ) {
686 		return;
687 	}
688 
689 
690 	thisBoneInfo = &boneInfo[boneNum];
691 
692 	if ( !thisBoneInfo ) {
693 		return;
694 	}
695 
696 	if ( thisBoneInfo->parent >= 0 ) {
697 		parentBone = &bones[ thisBoneInfo->parent ];
698 		parentBoneInfo = &boneInfo[ thisBoneInfo->parent ];
699 	} else {
700 		parentBone = NULL;
701 		parentBoneInfo = NULL;
702 	}
703 
704 	if ( thisBoneInfo->torsoWeight ) {
705 		cTBonePtr = &cBoneListTorso[boneNum];
706 		cOldTBonePtr = &cOldBoneListTorso[boneNum];
707 		isTorso = qtrue;
708 		if ( thisBoneInfo->torsoWeight == 1.0f ) {
709 			fullTorso = qtrue;
710 		}
711 	} else {
712 		isTorso = qfalse;
713 		fullTorso = qfalse;
714 	}
715 	cBonePtr = &cBoneList[boneNum];
716 	cOldBonePtr = &cOldBoneList[boneNum];
717 
718 	bonePtr = &bones[boneNum];
719 
720 	newBones[ boneNum ] = 1;
721 
722 	// rotation (take into account 170 to -170 lerps, which need to take the shortest route)
723 	if ( fullTorso ) {
724 
725 		sh = (short *)cTBonePtr->angles;
726 		sh2 = (short *)cOldTBonePtr->angles;
727 		pf = angles;
728 
729 		a1 = SHORT2ANGLE( *( sh++ ) ); a2 = SHORT2ANGLE( *( sh2++ ) ); diff = AngleNormalize180( a1 - a2 );
730 		*( pf++ ) = a1 - torsoBacklerp * diff;
731 		a1 = SHORT2ANGLE( *( sh++ ) ); a2 = SHORT2ANGLE( *( sh2++ ) ); diff = AngleNormalize180( a1 - a2 );
732 		*( pf++ ) = a1 - torsoBacklerp * diff;
733 		a1 = SHORT2ANGLE( *( sh++ ) ); a2 = SHORT2ANGLE( *( sh2++ ) ); diff = AngleNormalize180( a1 - a2 );
734 		*( pf++ ) = a1 - torsoBacklerp * diff;
735 
736 	} else {
737 
738 		sh = (short *)cBonePtr->angles;
739 		sh2 = (short *)cOldBonePtr->angles;
740 		pf = angles;
741 
742 		a1 = SHORT2ANGLE( *( sh++ ) ); a2 = SHORT2ANGLE( *( sh2++ ) ); diff = AngleNormalize180( a1 - a2 );
743 		*( pf++ ) = a1 - backlerp * diff;
744 		a1 = SHORT2ANGLE( *( sh++ ) ); a2 = SHORT2ANGLE( *( sh2++ ) ); diff = AngleNormalize180( a1 - a2 );
745 		*( pf++ ) = a1 - backlerp * diff;
746 		a1 = SHORT2ANGLE( *( sh++ ) ); a2 = SHORT2ANGLE( *( sh2++ ) ); diff = AngleNormalize180( a1 - a2 );
747 		*( pf++ ) = a1 - backlerp * diff;
748 
749 		if ( isTorso ) {
750 
751 			sh = (short *)cTBonePtr->angles;
752 			sh2 = (short *)cOldTBonePtr->angles;
753 			pf = tangles;
754 
755 			a1 = SHORT2ANGLE( *( sh++ ) ); a2 = SHORT2ANGLE( *( sh2++ ) ); diff = AngleNormalize180( a1 - a2 );
756 			*( pf++ ) = a1 - torsoBacklerp * diff;
757 			a1 = SHORT2ANGLE( *( sh++ ) ); a2 = SHORT2ANGLE( *( sh2++ ) ); diff = AngleNormalize180( a1 - a2 );
758 			*( pf++ ) = a1 - torsoBacklerp * diff;
759 			a1 = SHORT2ANGLE( *( sh++ ) ); a2 = SHORT2ANGLE( *( sh2++ ) ); diff = AngleNormalize180( a1 - a2 );
760 			*( pf++ ) = a1 - torsoBacklerp * diff;
761 
762 			// blend the angles together
763 			for ( j = 0; j < 3; j++ ) {
764 				diff = tangles[j] - angles[j];
765 				if ( fabs( diff ) > 180 ) {
766 					diff = AngleNormalize180( diff );
767 				}
768 				angles[j] = angles[j] + thisBoneInfo->torsoWeight * diff;
769 			}
770 
771 		}
772 
773 	}
774 	AnglesToAxis( angles, bonePtr->matrix );
775 
776 	if ( parentBone ) {
777 
778 		if ( fullTorso ) {
779 			sh = (short *)cTBonePtr->ofsAngles;
780 			sh2 = (short *)cOldTBonePtr->ofsAngles;
781 		} else {
782 			sh = (short *)cBonePtr->ofsAngles;
783 			sh2 = (short *)cOldBonePtr->ofsAngles;
784 		}
785 
786 		pf = angles;
787 		*( pf++ ) = SHORT2ANGLE( *( sh++ ) );
788 		*( pf++ ) = SHORT2ANGLE( *( sh++ ) );
789 		*( pf++ ) = 0;
790 		LocalAngleVector( angles, v2 );     // new
791 
792 		pf = angles;
793 		*( pf++ ) = SHORT2ANGLE( *( sh2++ ) );
794 		*( pf++ ) = SHORT2ANGLE( *( sh2++ ) );
795 		*( pf++ ) = 0;
796 		LocalAngleVector( angles, vec );    // old
797 
798 		// blend the angles together
799 		if ( fullTorso ) {
800 			SLerp_Normal( vec, v2, torsoFrontlerp, dir );
801 		} else {
802 			SLerp_Normal( vec, v2, frontlerp, dir );
803 		}
804 
805 		// translation
806 		if ( !fullTorso && isTorso ) {    // partial legs/torso, need to lerp according to torsoWeight
807 
808 			// calc the torso frame
809 			sh = (short *)cTBonePtr->ofsAngles;
810 			sh2 = (short *)cOldTBonePtr->ofsAngles;
811 
812 			pf = angles;
813 			*( pf++ ) = SHORT2ANGLE( *( sh++ ) );
814 			*( pf++ ) = SHORT2ANGLE( *( sh++ ) );
815 			*( pf++ ) = 0;
816 			LocalAngleVector( angles, v2 );     // new
817 
818 			pf = angles;
819 			*( pf++ ) = SHORT2ANGLE( *( sh2++ ) );
820 			*( pf++ ) = SHORT2ANGLE( *( sh2++ ) );
821 			*( pf++ ) = 0;
822 			LocalAngleVector( angles, vec );    // old
823 
824 			// blend the angles together
825 			SLerp_Normal( vec, v2, torsoFrontlerp, v2 );
826 
827 			// blend the torso/legs together
828 			SLerp_Normal( dir, v2, thisBoneInfo->torsoWeight, dir );
829 
830 		}
831 
832 		LocalVectorMA( parentBone->translation, thisBoneInfo->parentDist, dir, bonePtr->translation );
833 
834 	} else {    // just interpolate the frame positions
835 
836 		bonePtr->translation[0] = frontlerp * frame->parentOffset[0] + backlerp * oldFrame->parentOffset[0];
837 		bonePtr->translation[1] = frontlerp * frame->parentOffset[1] + backlerp * oldFrame->parentOffset[1];
838 		bonePtr->translation[2] = frontlerp * frame->parentOffset[2] + backlerp * oldFrame->parentOffset[2];
839 
840 	}
841 	//
842 	if ( boneNum == header->torsoParent ) { // this is the torsoParent
843 		VectorCopy( bonePtr->translation, torsoParentOffset );
844 	}
845 	validBones[boneNum] = 1;
846 	//
847 	rawBones[boneNum] = *bonePtr;
848 	newBones[boneNum] = 1;
849 
850 }
851 
852 
853 /*
854 ==============
855 R_CalcBones
856 
857 	The list of bones[] should only be built and modified from within here
858 ==============
859 */
R_CalcBones(mdsHeader_t * header,const refEntity_t * refent,int * boneList,int numBones)860 void R_CalcBones( mdsHeader_t *header, const refEntity_t *refent, int *boneList, int numBones ) {
861 
862 	int i;
863 	int     *boneRefs;
864 	float torsoWeight;
865 
866 	//
867 	// if the entity has changed since the last time the bones were built, reset them
868 	//
869 	if ( memcmp( &lastBoneEntity, refent, sizeof( refEntity_t ) ) ) {
870 		// different, cached bones are not valid
871 		memset( validBones, 0, header->numBones );
872 		lastBoneEntity = *refent;
873 
874 		// (SA) also reset these counter statics
875 //----(SA)	print stats for the complete model (not per-surface)
876 		if ( r_bonesDebug->integer == 4 && totalrt ) {
877 			ri.Printf( PRINT_ALL, "Lod %.2f  verts %4d/%4d  tris %4d/%4d  (%.2f%%)\n",
878 					   lodScale,
879 					   totalrv,
880 					   totalv,
881 					   totalrt,
882 					   totalt,
883 					   ( float )( 100.0 * totalrt ) / (float) totalt );
884 		}
885 //----(SA)	end
886 		totalrv = totalrt = totalv = totalt = 0;
887 
888 	}
889 
890 	memset( newBones, 0, header->numBones );
891 
892 	if ( refent->oldframe == refent->frame ) {
893 		backlerp = 0;
894 		frontlerp = 1;
895 	} else  {
896 		backlerp = refent->backlerp;
897 		frontlerp = 1.0f - backlerp;
898 	}
899 
900 	if ( refent->oldTorsoFrame == refent->torsoFrame ) {
901 		torsoBacklerp = 0;
902 		torsoFrontlerp = 1;
903 	} else {
904 		torsoBacklerp = refent->torsoBacklerp;
905 		torsoFrontlerp = 1.0f - torsoBacklerp;
906 	}
907 
908 	frameSize = (int) ( sizeof( mdsFrame_t ) + ( header->numBones - 1 ) * sizeof( mdsBoneFrameCompressed_t ) );
909 
910 	frame = ( mdsFrame_t * )( (byte *)header + header->ofsFrames +
911 							  refent->frame * frameSize );
912 	torsoFrame = ( mdsFrame_t * )( (byte *)header + header->ofsFrames +
913 								   refent->torsoFrame * frameSize );
914 	oldFrame = ( mdsFrame_t * )( (byte *)header + header->ofsFrames +
915 								 refent->oldframe * frameSize );
916 	oldTorsoFrame = ( mdsFrame_t * )( (byte *)header + header->ofsFrames +
917 									  refent->oldTorsoFrame * frameSize );
918 
919 	//
920 	// lerp all the needed bones (torsoParent is always the first bone in the list)
921 	//
922 	cBoneList = frame->bones;
923 	cBoneListTorso = torsoFrame->bones;
924 
925 	boneInfo = ( mdsBoneInfo_t * )( (byte *)header + header->ofsBones );
926 	boneRefs = boneList;
927 	//
928 	Matrix3Transpose( refent->torsoAxis, torsoAxis );
929 
930 #ifdef HIGH_PRECISION_BONES
931 	if ( qtrue ) {
932 #else
933 	if ( !backlerp && !torsoBacklerp ) {
934 #endif
935 
936 		for ( i = 0; i < numBones; i++, boneRefs++ ) {
937 
938 			if ( validBones[*boneRefs] ) {
939 				// this bone is still in the cache
940 				bones[*boneRefs] = rawBones[*boneRefs];
941 				continue;
942 			}
943 
944 			// find our parent, and make sure it has been calculated
945 			if ( ( boneInfo[*boneRefs].parent >= 0 ) && ( !validBones[boneInfo[*boneRefs].parent] && !newBones[boneInfo[*boneRefs].parent] ) ) {
946 				R_CalcBone( header, refent, boneInfo[*boneRefs].parent );
947 			}
948 
949 			R_CalcBone( header, refent, *boneRefs );
950 
951 		}
952 
953 	} else {    // interpolated
954 
955 		cOldBoneList = oldFrame->bones;
956 		cOldBoneListTorso = oldTorsoFrame->bones;
957 
958 		for ( i = 0; i < numBones; i++, boneRefs++ ) {
959 
960 			if ( validBones[*boneRefs] ) {
961 				// this bone is still in the cache
962 				bones[*boneRefs] = rawBones[*boneRefs];
963 				continue;
964 			}
965 
966 			// find our parent, and make sure it has been calculated
967 			if ( ( boneInfo[*boneRefs].parent >= 0 ) && ( !validBones[boneInfo[*boneRefs].parent] && !newBones[boneInfo[*boneRefs].parent] ) ) {
968 				R_CalcBoneLerp( header, refent, boneInfo[*boneRefs].parent );
969 			}
970 
971 			R_CalcBoneLerp( header, refent, *boneRefs );
972 
973 		}
974 
975 	}
976 
977 	// adjust for torso rotations
978 	torsoWeight = 0;
979 	boneRefs = boneList;
980 	for ( i = 0; i < numBones; i++, boneRefs++ ) {
981 
982 		thisBoneInfo = &boneInfo[ *boneRefs ];
983 		bonePtr = &bones[ *boneRefs ];
984 		// add torso rotation
985 		if ( thisBoneInfo->torsoWeight > 0 ) {
986 
987 			if ( !newBones[ *boneRefs ] ) {
988 				// just copy it back from the previous calc
989 				bones[ *boneRefs ] = oldBones[ *boneRefs ];
990 				continue;
991 			}
992 
993 			if ( !( thisBoneInfo->flags & BONEFLAG_TAG ) ) {
994 
995 				// 1st multiply with the bone->matrix
996 				// 2nd translation for rotation relative to bone around torso parent offset
997 				VectorSubtract( bonePtr->translation, torsoParentOffset, t );
998 				Matrix4FromAxisPlusTranslation( bonePtr->matrix, t, m1 );
999 				// 3rd scaled rotation
1000 				// 4th translate back to torso parent offset
1001 				// use previously created matrix if available for the same weight
1002 				if ( torsoWeight != thisBoneInfo->torsoWeight ) {
1003 					Matrix4FromScaledAxisPlusTranslation( torsoAxis, thisBoneInfo->torsoWeight, torsoParentOffset, m2 );
1004 					torsoWeight = thisBoneInfo->torsoWeight;
1005 				}
1006 				// multiply matrices to create one matrix to do all calculations
1007 				Matrix4MultiplyInto3x3AndTranslation( m2, m1, bonePtr->matrix, bonePtr->translation );
1008 
1009 			} else {    // tag's require special handling
1010 
1011 				// rotate each of the axis by the torsoAngles
1012 				LocalScaledMatrixTransformVector( bonePtr->matrix[0], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[0] );
1013 				LocalScaledMatrixTransformVector( bonePtr->matrix[1], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[1] );
1014 				LocalScaledMatrixTransformVector( bonePtr->matrix[2], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[2] );
1015 				memcpy( bonePtr->matrix, tmpAxis, sizeof( tmpAxis ) );
1016 
1017 				// rotate the translation around the torsoParent
1018 				VectorSubtract( bonePtr->translation, torsoParentOffset, t );
1019 				LocalScaledMatrixTransformVector( t, thisBoneInfo->torsoWeight, torsoAxis, bonePtr->translation );
1020 				VectorAdd( bonePtr->translation, torsoParentOffset, bonePtr->translation );
1021 
1022 			}
1023 		}
1024 	}
1025 
1026 	// backup the final bones
1027 	memcpy( oldBones, bones, sizeof( bones[0] ) * header->numBones );
1028 }
1029 
1030 #ifdef DBG_PROFILE_BONES
1031 #define DBG_SHOWTIME    Com_Printf( "%i: %i, ", di++, ( dt = ri.Milliseconds() ) - ldt ); ldt = dt;
1032 #else
1033 #define DBG_SHOWTIME    ;
1034 #endif
1035 
1036 /*
1037 ==============
1038 RB_SurfaceAnim
1039 ==============
1040 */
1041 void RB_SurfaceAnim( mdsSurface_t *surface ) {
1042 	int j, k;
1043 	refEntity_t *refent;
1044 	int             *boneList;
1045 	mdsHeader_t     *header;
1046 
1047 #ifdef DBG_PROFILE_BONES
1048 	int di = 0, dt, ldt;
1049 
1050 	dt = ri.Milliseconds();
1051 	ldt = dt;
1052 #endif
1053 
1054 	refent = &backEnd.currentEntity->e;
1055 	boneList = ( int * )( (byte *)surface + surface->ofsBoneReferences );
1056 	header = ( mdsHeader_t * )( (byte *)surface + surface->ofsHeader );
1057 
1058 	R_CalcBones( header, (const refEntity_t *)refent, boneList, surface->numBoneReferences );
1059 
1060 	DBG_SHOWTIME
1061 
1062 	//
1063 	// calculate LOD
1064 	//
1065 	// TODO: lerp the radius and origin
1066 	VectorAdd( refent->origin, frame->localOrigin, vec );
1067 	lodRadius = frame->radius;
1068 	lodScale = RB_CalcMDSLod( refent, vec, lodRadius, header->lodBias, header->lodScale );
1069 
1070 
1071 //DBG_SHOWTIME
1072 
1073 //----(SA)	modification to allow dead skeletal bodies to go below minlod (experiment)
1074 	if ( refent->reFlags & REFLAG_DEAD_LOD ) {
1075 		if ( lodScale < 0.35 ) {   // allow dead to lod down to 35% (even if below surf->minLod) (%35 is arbitrary and probably not good generally.  worked for the blackguard/infantry as a test though)
1076 			lodScale = 0.35;
1077 		}
1078 		render_count = (int)( (float) surface->numVerts * lodScale );
1079 
1080 	} else {
1081 		render_count = (int)( (float) surface->numVerts * lodScale );
1082 		if ( render_count < surface->minLod ) {
1083 			if ( !( refent->reFlags & REFLAG_DEAD_LOD ) ) {
1084 				render_count = surface->minLod;
1085 			}
1086 		}
1087 	}
1088 //----(SA)	end
1089 
1090 
1091 	if ( render_count > surface->numVerts ) {
1092 		render_count = surface->numVerts;
1093 	}
1094 
1095 //DBG_SHOWTIME
1096 
1097 	//
1098 	// setup triangle list
1099 	//
1100 	RB_CHECKOVERFLOW( render_count, surface->numTriangles * 3 );
1101 
1102 //DBG_SHOWTIME
1103 
1104 	collapse_map   = ( int * )( ( byte * )surface + surface->ofsCollapseMap );
1105 	triangles = ( int * )( (byte *)surface + surface->ofsTriangles );
1106 	indexes = surface->numTriangles * 3;
1107 	baseIndex = tess.numIndexes;
1108 	baseVertex = tess.numVertexes;
1109 	oldIndexes = baseIndex;
1110 
1111 	tess.numVertexes += render_count;
1112 
1113 	pIndexes = (glIndex_t *)&tess.indexes[baseIndex];
1114 
1115 //DBG_SHOWTIME
1116 
1117 	if ( render_count == surface->numVerts ) {
1118 		for ( j = 0; j < indexes; j++ )
1119 			pIndexes[j] = triangles[j] + baseVertex;
1120 		tess.numIndexes += indexes;
1121 	} else
1122 	{
1123 		int *collapseEnd;
1124 
1125 		pCollapse = collapse;
1126 		for ( j = 0; j < render_count; pCollapse++, j++ )
1127 		{
1128 			*pCollapse = j;
1129 		}
1130 
1131 		pCollapseMap = &collapse_map[render_count];
1132 		for ( collapseEnd = collapse + surface->numVerts ; pCollapse < collapseEnd; pCollapse++, pCollapseMap++ )
1133 		{
1134 			*pCollapse = collapse[ *pCollapseMap ];
1135 		}
1136 
1137 		for ( j = 0 ; j < indexes ; j += 3 )
1138 		{
1139 			p0 = collapse[ *( triangles++ ) ];
1140 			p1 = collapse[ *( triangles++ ) ];
1141 			p2 = collapse[ *( triangles++ ) ];
1142 
1143 			// FIXME
1144 			// note:  serious optimization opportunity here,
1145 			//  by sorting the triangles the following "continue"
1146 			//  could have been made into a "break" statement.
1147 			if ( p0 == p1 || p1 == p2 || p2 == p0 ) {
1148 				continue;
1149 			}
1150 
1151 			*( pIndexes++ ) = baseVertex + p0;
1152 			*( pIndexes++ ) = baseVertex + p1;
1153 			*( pIndexes++ ) = baseVertex + p2;
1154 			tess.numIndexes += 3;
1155 		}
1156 
1157 		baseIndex = tess.numIndexes;
1158 	}
1159 
1160 //DBG_SHOWTIME
1161 
1162 	//
1163 	// deform the vertexes by the lerped bones
1164 	//
1165 	numVerts = surface->numVerts;
1166 	v = ( mdsVertex_t * )( (byte *)surface + surface->ofsVerts );
1167 	tempVert = ( float * )( tess.xyz + baseVertex );
1168 	tempNormal = ( int16_t * )( tess.normal + baseVertex );
1169 	for ( j = 0; j < render_count; j++, tempVert += 4, tempNormal += 4 ) {
1170 		mdsWeight_t *w;
1171 		vec3_t newNormal;
1172 
1173 		VectorClear( tempVert );
1174 
1175 		w = v->weights;
1176 		for ( k = 0 ; k < v->numWeights ; k++, w++ ) {
1177 			bone = &bones[w->boneIndex];
1178 			LocalAddScaledMatrixTransformVectorTranslate( w->offset, w->boneWeight, bone->matrix, bone->translation, tempVert );
1179 		}
1180 
1181 		LocalMatrixTransformVector( v->normal, bones[v->weights[0].boneIndex].matrix, newNormal );
1182 
1183 		R_VaoPackNormal(tempNormal, newNormal);
1184 
1185 		tess.texCoords[baseVertex + j][0] = v->texCoords[0];
1186 		tess.texCoords[baseVertex + j][1] = v->texCoords[1];
1187 
1188 		v = (mdsVertex_t *)&v->weights[v->numWeights];
1189 	}
1190 
1191 	DBG_SHOWTIME
1192 
1193 #if 0 // FIXME: implement this
1194 	if ( r_bonesDebug->integer ) {
1195 		if ( r_bonesDebug->integer < 3 ) {
1196 			// DEBUG: show the bones as a stick figure with axis at each bone
1197 			int i, *boneRefs = ( int * )( (byte *)surface + surface->ofsBoneReferences );
1198 			for ( i = 0; i < surface->numBoneReferences; i++, boneRefs++ ) {
1199 				bonePtr = &bones[*boneRefs];
1200 
1201 				GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
1202 				qglLineWidth( 1 );
1203 				qglBegin( GL_LINES );
1204 				for ( j = 0; j < 3; j++ ) {
1205 					VectorClear( vec );
1206 					vec[j] = 1;
1207 					qglColor3fv( vec );
1208 					qglVertex3fv( bonePtr->translation );
1209 					VectorMA( bonePtr->translation, 5, bonePtr->matrix[j], vec );
1210 					qglVertex3fv( vec );
1211 				}
1212 				qglEnd();
1213 
1214 				// connect to our parent if it's valid
1215 				if ( validBones[boneInfo[*boneRefs].parent] ) {
1216 					qglLineWidth( 2 );
1217 					qglBegin( GL_LINES );
1218 					qglColor3f( .6,.6,.6 );
1219 					qglVertex3fv( bonePtr->translation );
1220 					qglVertex3fv( bones[boneInfo[*boneRefs].parent].translation );
1221 					qglEnd();
1222 				}
1223 
1224 				qglLineWidth( 1 );
1225 			}
1226 		}
1227 
1228 		if ( r_bonesDebug->integer == 3 || r_bonesDebug->integer == 4 ) {
1229 			int render_indexes = ( tess.numIndexes - oldIndexes );
1230 
1231 			// show mesh edges
1232 			tempVert = ( float * )( tess.xyz + baseVertex );
1233 			tempNormal = ( int16_t * )( tess.normal + baseVertex );
1234 
1235 			GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
1236 			qglLineWidth( 1 );
1237 			qglBegin( GL_LINES );
1238 			qglColor3f( .0,.0,.8 );
1239 
1240 			pIndexes = (glIndex_t *)&tess.indexes[oldIndexes];
1241 			for ( j = 0; j < render_indexes / 3; j++, pIndexes += 3 ) {
1242 				qglVertex3fv( tempVert + 4 * pIndexes[0] );
1243 				qglVertex3fv( tempVert + 4 * pIndexes[1] );
1244 
1245 				qglVertex3fv( tempVert + 4 * pIndexes[1] );
1246 				qglVertex3fv( tempVert + 4 * pIndexes[2] );
1247 
1248 				qglVertex3fv( tempVert + 4 * pIndexes[2] );
1249 				qglVertex3fv( tempVert + 4 * pIndexes[0] );
1250 			}
1251 
1252 			qglEnd();
1253 
1254 //----(SA)	track debug stats
1255 			if ( r_bonesDebug->integer == 4 ) {
1256 				totalrv += render_count;
1257 				totalrt += render_indexes / 3;
1258 				totalv += surface->numVerts;
1259 				totalt += surface->numTriangles;
1260 			}
1261 //----(SA)	end
1262 
1263 			if ( r_bonesDebug->integer == 3 ) {
1264 				ri.Printf( PRINT_ALL, "Lod %.2f  verts %4d/%4d  tris %4d/%4d  (%.2f%%)\n", lodScale, render_count, surface->numVerts, render_indexes / 3, surface->numTriangles,
1265 						   ( float )( 100.0 * render_indexes / 3 ) / (float) surface->numTriangles );
1266 			}
1267 		}
1268 	}
1269 #endif
1270 
1271 	if ( r_bonesDebug->integer > 1 ) {
1272 		// dont draw the actual surface
1273 		tess.numIndexes = oldIndexes;
1274 		tess.numVertexes = baseVertex;
1275 		return;
1276 	}
1277 
1278 #ifdef DBG_PROFILE_BONES
1279 	Com_Printf( "\n" );
1280 #endif
1281 
1282 }
1283 
1284 /*
1285 ===============
1286 R_RecursiveBoneListAdd
1287 ===============
1288 */
1289 void R_RecursiveBoneListAdd( int bi, int *boneList, int *numBones, mdsBoneInfo_t *boneInfoList ) {
1290 
1291 	if ( boneInfoList[ bi ].parent >= 0 ) {
1292 
1293 		R_RecursiveBoneListAdd( boneInfoList[ bi ].parent, boneList, numBones, boneInfoList );
1294 
1295 	}
1296 
1297 	boneList[ ( *numBones )++ ] = bi;
1298 
1299 }
1300 
1301 /*
1302 ===============
1303 R_GetBoneTag
1304 ===============
1305 */
1306 int R_GetBoneTag( orientation_t *outTag, mdsHeader_t *mds, int startTagIndex, const refEntity_t *refent, const char *tagName ) {
1307 
1308 	int i;
1309 	mdsTag_t    *pTag;
1310 	mdsBoneInfo_t *boneInfoList;
1311 	int boneList[ MDS_MAX_BONES ];
1312 	int numBones;
1313 
1314 	if ( startTagIndex > mds->numTags ) {
1315 		memset( outTag, 0, sizeof( *outTag ) );
1316 		return -1;
1317 	}
1318 
1319 	// find the correct tag
1320 
1321 	pTag = ( mdsTag_t * )( (byte *)mds + mds->ofsTags );
1322 
1323 	pTag += startTagIndex;
1324 
1325 	for ( i = startTagIndex; i < mds->numTags; i++, pTag++ ) {
1326 		if ( !strcmp( pTag->name, tagName ) ) {
1327 			break;
1328 		}
1329 	}
1330 
1331 	if ( i >= mds->numTags ) {
1332 		memset( outTag, 0, sizeof( *outTag ) );
1333 		return -1;
1334 	}
1335 
1336 	// now build the list of bones we need to calc to get this tag's bone information
1337 
1338 	boneInfoList = ( mdsBoneInfo_t * )( (byte *)mds + mds->ofsBones );
1339 	numBones = 0;
1340 
1341 	R_RecursiveBoneListAdd( pTag->boneIndex, boneList, &numBones, boneInfoList );
1342 
1343 	// calc the bones
1344 
1345 	R_CalcBones( (mdsHeader_t *)mds, refent, boneList, numBones );
1346 
1347 	// now extract the orientation for the bone that represents our tag
1348 
1349 	memcpy( outTag->axis, bones[ pTag->boneIndex ].matrix, sizeof( outTag->axis ) );
1350 	VectorCopy( bones[ pTag->boneIndex ].translation, outTag->origin );
1351 
1352 /* code not functional, not in backend
1353 	if (r_bonesDebug->integer == 4) {
1354 		int j;
1355 		// DEBUG: show the tag position/axis
1356 		GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
1357 		qglLineWidth( 2 );
1358 		qglBegin( GL_LINES );
1359 		for (j=0; j<3; j++) {
1360 			VectorClear(vec);
1361 			vec[j] = 1;
1362 			qglColor3fv( vec );
1363 			qglVertex3fv( outTag->origin );
1364 			VectorMA( outTag->origin, 8, outTag->axis[j], vec );
1365 			qglVertex3fv( vec );
1366 		}
1367 		qglEnd();
1368 
1369 		qglLineWidth( 1 );
1370 	}
1371 */
1372 
1373 	return i;
1374 }
1375 
1376 // copied and adapted from tr_mesh.c
1377 
1378 /*
1379 =============
1380 R_MDRCullModel
1381 =============
1382 */
1383 
1384 static int R_MDRCullModel( mdrHeader_t *header, trRefEntity_t *ent ) {
1385 	vec3_t		bounds[2];
1386 	mdrFrame_t	*oldFrame, *newFrame;
1387 	int			i, frameSize;
1388 
1389 	frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] );
1390 
1391 	// compute frame pointers
1392 	newFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame);
1393 	oldFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.oldframe);
1394 
1395 	// cull bounding sphere ONLY if this is not an upscaled entity
1396 	if ( !ent->e.nonNormalizedAxes )
1397 	{
1398 		if ( ent->e.frame == ent->e.oldframe )
1399 		{
1400 			switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) )
1401 			{
1402 				// Ummm... yeah yeah I know we don't really have an md3 here.. but we pretend
1403 				// we do. After all, the purpose of mdrs are not that different, are they?
1404 
1405 				case CULL_OUT:
1406 					tr.pc.c_sphere_cull_md3_out++;
1407 					return CULL_OUT;
1408 
1409 				case CULL_IN:
1410 					tr.pc.c_sphere_cull_md3_in++;
1411 					return CULL_IN;
1412 
1413 				case CULL_CLIP:
1414 					tr.pc.c_sphere_cull_md3_clip++;
1415 					break;
1416 			}
1417 		}
1418 		else
1419 		{
1420 			int sphereCull, sphereCullB;
1421 
1422 			sphereCull  = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius );
1423 			if ( newFrame == oldFrame ) {
1424 				sphereCullB = sphereCull;
1425 			} else {
1426 				sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius );
1427 			}
1428 
1429 			if ( sphereCull == sphereCullB )
1430 			{
1431 				if ( sphereCull == CULL_OUT )
1432 				{
1433 					tr.pc.c_sphere_cull_md3_out++;
1434 					return CULL_OUT;
1435 				}
1436 				else if ( sphereCull == CULL_IN )
1437 				{
1438 					tr.pc.c_sphere_cull_md3_in++;
1439 					return CULL_IN;
1440 				}
1441 				else
1442 				{
1443 					tr.pc.c_sphere_cull_md3_clip++;
1444 				}
1445 			}
1446 		}
1447 	}
1448 
1449 	// calculate a bounding box in the current coordinate system
1450 	for (i = 0 ; i < 3 ; i++) {
1451 		bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i];
1452 		bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i];
1453 	}
1454 
1455 	switch ( R_CullLocalBox( bounds ) )
1456 	{
1457 		case CULL_IN:
1458 			tr.pc.c_box_cull_md3_in++;
1459 			return CULL_IN;
1460 		case CULL_CLIP:
1461 			tr.pc.c_box_cull_md3_clip++;
1462 			return CULL_CLIP;
1463 		case CULL_OUT:
1464 		default:
1465 			tr.pc.c_box_cull_md3_out++;
1466 			return CULL_OUT;
1467 	}
1468 }
1469 
1470 /*
1471 =================
1472 R_MDRComputeFogNum
1473 
1474 =================
1475 */
1476 
1477 int R_MDRComputeFogNum( mdrHeader_t *header, trRefEntity_t *ent ) {
1478 	int				i, j;
1479 	fog_t			*fog;
1480 	mdrFrame_t		*mdrFrame;
1481 	vec3_t			localOrigin;
1482 	int frameSize;
1483 
1484 	if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
1485 		return 0;
1486 	}
1487 
1488 	frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] );
1489 
1490 	// FIXME: non-normalized axis issues
1491 	mdrFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame);
1492 	VectorAdd( ent->e.origin, mdrFrame->localOrigin, localOrigin );
1493 	for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
1494 		fog = &tr.world->fogs[i];
1495 		for ( j = 0 ; j < 3 ; j++ ) {
1496 			if ( localOrigin[j] - mdrFrame->radius >= fog->bounds[1][j] ) {
1497 				break;
1498 			}
1499 			if ( localOrigin[j] + mdrFrame->radius <= fog->bounds[0][j] ) {
1500 				break;
1501 			}
1502 		}
1503 		if ( j == 3 ) {
1504 			return i;
1505 		}
1506 	}
1507 
1508 	return 0;
1509 }
1510 
1511 
1512 /*
1513 ==============
1514 R_MDRAddAnimSurfaces
1515 ==============
1516 */
1517 
1518 // much stuff in there is just copied from R_AddMd3Surfaces in tr_mesh.c
1519 
1520 void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) {
1521 	mdrHeader_t		*header;
1522 	mdrSurface_t	*surface;
1523 	mdrLOD_t		*lod;
1524 	shader_t		*shader;
1525 	skin_t		*skin;
1526 	int				i, j;
1527 	int				lodnum = 0;
1528 	int				fogNum = 0;
1529 	int				cull;
1530 	int             cubemapIndex;
1531 	qboolean	personalModel;
1532 
1533 	header = (mdrHeader_t *) tr.currentModel->modelData;
1534 
1535 	personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !(tr.viewParms.isPortal
1536 	                 || (tr.viewParms.flags & (VPF_SHADOWMAP | VPF_DEPTHSHADOW)));
1537 
1538 	if ( ent->e.renderfx & RF_WRAP_FRAMES )
1539 	{
1540 		ent->e.frame %= header->numFrames;
1541 		ent->e.oldframe %= header->numFrames;
1542 	}
1543 
1544 	//
1545 	// Validate the frames so there is no chance of a crash.
1546 	// This will write directly into the entity structure, so
1547 	// when the surfaces are rendered, they don't need to be
1548 	// range checked again.
1549 	//
1550 	if ((ent->e.frame >= header->numFrames)
1551 		|| (ent->e.frame < 0)
1552 		|| (ent->e.oldframe >= header->numFrames)
1553 		|| (ent->e.oldframe < 0) )
1554 	{
1555 		ri.Printf( PRINT_DEVELOPER, "R_MDRAddAnimSurfaces: no such frame %d to %d for '%s'\n",
1556 			   ent->e.oldframe, ent->e.frame, tr.currentModel->name );
1557 		ent->e.frame = 0;
1558 		ent->e.oldframe = 0;
1559 	}
1560 
1561 	//
1562 	// cull the entire model if merged bounding box of both frames
1563 	// is outside the view frustum.
1564 	//
1565 	cull = R_MDRCullModel (header, ent);
1566 	if ( cull == CULL_OUT ) {
1567 		return;
1568 	}
1569 
1570 	// figure out the current LOD of the model we're rendering, and set the lod pointer respectively.
1571 	lodnum = R_ComputeLOD(ent);
1572 	// check whether this model has as that many LODs at all. If not, try the closest thing we got.
1573 	if(header->numLODs <= 0)
1574 		return;
1575 	if(header->numLODs <= lodnum)
1576 		lodnum = header->numLODs - 1;
1577 
1578 	lod = (mdrLOD_t *)( (byte *)header + header->ofsLODs);
1579 	for(i = 0; i < lodnum; i++)
1580 	{
1581 		lod = (mdrLOD_t *) ((byte *) lod + lod->ofsEnd);
1582 	}
1583 
1584 	// set up lighting
1585 	if ( !personalModel || r_shadows->integer > 1 )
1586 	{
1587 		R_SetupEntityLighting( &tr.refdef, ent );
1588 	}
1589 
1590 	// fogNum?
1591 	fogNum = R_MDRComputeFogNum( header, ent );
1592 
1593 	cubemapIndex = R_CubemapForPoint(ent->e.origin);
1594 
1595 	surface = (mdrSurface_t *)( (byte *)lod + lod->ofsSurfaces );
1596 
1597 	for ( i = 0 ; i < lod->numSurfaces ; i++ )
1598 	{
1599 
1600 		if(ent->e.customShader)
1601 			shader = R_GetShaderByHandle(ent->e.customShader);
1602 		else if(ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins)
1603 		{
1604 			skin = R_GetSkinByHandle(ent->e.customSkin);
1605 			shader = tr.defaultShader;
1606 
1607 			for(j = 0; j < skin->numSurfaces; j++)
1608 			{
1609 				if (!strcmp(skin->surfaces[j].name, surface->name))
1610 				{
1611 					shader = skin->surfaces[j].shader;
1612 					break;
1613 				}
1614 			}
1615 		}
1616 		else if(surface->shaderIndex > 0)
1617 			shader = R_GetShaderByHandle( surface->shaderIndex );
1618 		else
1619 			shader = tr.defaultShader;
1620 
1621 		// we will add shadows even if the main object isn't visible in the view
1622 
1623 		// stencil shadows can't do personal models unless I polyhedron clip
1624 		if ( !personalModel
1625 		        && r_shadows->integer == 2
1626 			&& fogNum == 0
1627 			&& !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) )
1628 			&& shader->sort == SS_OPAQUE )
1629 		{
1630 			R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, qfalse, qfalse, 0 );
1631 		}
1632 
1633 		// projection shadows work fine with personal models
1634 		if ( r_shadows->integer == 3
1635 			&& fogNum == 0
1636 			&& (ent->e.renderfx & RF_SHADOW_PLANE )
1637 			&& shader->sort == SS_OPAQUE )
1638 		{
1639 			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse, qfalse, 0 );
1640 		}
1641 
1642 		if ( !personalModel )
1643 			R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse, qfalse, cubemapIndex );
1644 
1645 		surface = (mdrSurface_t *)( (byte *)surface + surface->ofsEnd );
1646 	}
1647 }
1648 
1649 /*
1650 ==============
1651 RB_MDRSurfaceAnim
1652 ==============
1653 */
1654 void RB_MDRSurfaceAnim( mdrSurface_t *surface )
1655 {
1656 	int				i, j, k;
1657 	float			frontlerp, backlerp;
1658 	int				*triangles;
1659 	int				indexes;
1660 	int				baseIndex, baseVertex;
1661 	int				numVerts;
1662 	mdrVertex_t		*v;
1663 	mdrHeader_t		*header;
1664 	mdrFrame_t		*frame;
1665 	mdrFrame_t		*oldFrame;
1666 	mdrBone_t		bones[MDR_MAX_BONES], *bonePtr, *bone;
1667 
1668 	int			frameSize;
1669 
1670 	// don't lerp if lerping off, or this is the only frame, or the last frame...
1671 	//
1672 	if (backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame)
1673 	{
1674 		backlerp	= 0;	// if backlerp is 0, lerping is off and frontlerp is never used
1675 		frontlerp	= 1;
1676 	}
1677 	else
1678 	{
1679 		backlerp	= backEnd.currentEntity->e.backlerp;
1680 		frontlerp	= 1.0f - backlerp;
1681 	}
1682 
1683 	header = (mdrHeader_t *)((byte *)surface + surface->ofsHeader);
1684 
1685 	frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] );
1686 
1687 	frame = (mdrFrame_t *)((byte *)header + header->ofsFrames +
1688 		backEnd.currentEntity->e.frame * frameSize );
1689 	oldFrame = (mdrFrame_t *)((byte *)header + header->ofsFrames +
1690 		backEnd.currentEntity->e.oldframe * frameSize );
1691 
1692 	RB_CHECKOVERFLOW( surface->numVerts, surface->numTriangles * 3 );
1693 
1694 	triangles	= (int *) ((byte *)surface + surface->ofsTriangles);
1695 	indexes		= surface->numTriangles * 3;
1696 	baseIndex	= tess.numIndexes;
1697 	baseVertex	= tess.numVertexes;
1698 
1699 	// Set up all triangles.
1700 	for (j = 0 ; j < indexes ; j++)
1701 	{
1702 		tess.indexes[baseIndex + j] = baseVertex + triangles[j];
1703 	}
1704 	tess.numIndexes += indexes;
1705 
1706 	//
1707 	// lerp all the needed bones
1708 	//
1709 	if ( !backlerp )
1710 	{
1711 		// no lerping needed
1712 		bonePtr = frame->bones;
1713 	}
1714 	else
1715 	{
1716 		bonePtr = bones;
1717 
1718 		for ( i = 0 ; i < header->numBones*12 ; i++ )
1719 		{
1720 			((float *)bonePtr)[i] = frontlerp * ((float *)frame->bones)[i] + backlerp * ((float *)oldFrame->bones)[i];
1721 		}
1722 	}
1723 
1724 	//
1725 	// deform the vertexes by the lerped bones
1726 	//
1727 	numVerts = surface->numVerts;
1728 	v = (mdrVertex_t *) ((byte *)surface + surface->ofsVerts);
1729 	for ( j = 0; j < numVerts; j++ )
1730 	{
1731 		vec3_t	tempVert, tempNormal;
1732 		mdrWeight_t	*w;
1733 
1734 		VectorClear( tempVert );
1735 		VectorClear( tempNormal );
1736 		w = v->weights;
1737 		for ( k = 0 ; k < v->numWeights ; k++, w++ )
1738 		{
1739 			bone = bonePtr + w->boneIndex;
1740 
1741 			tempVert[0] += w->boneWeight * ( DotProduct( bone->matrix[0], w->offset ) + bone->matrix[0][3] );
1742 			tempVert[1] += w->boneWeight * ( DotProduct( bone->matrix[1], w->offset ) + bone->matrix[1][3] );
1743 			tempVert[2] += w->boneWeight * ( DotProduct( bone->matrix[2], w->offset ) + bone->matrix[2][3] );
1744 
1745 			tempNormal[0] += w->boneWeight * DotProduct( bone->matrix[0], v->normal );
1746 			tempNormal[1] += w->boneWeight * DotProduct( bone->matrix[1], v->normal );
1747 			tempNormal[2] += w->boneWeight * DotProduct( bone->matrix[2], v->normal );
1748 		}
1749 
1750 		tess.xyz[baseVertex + j][0] = tempVert[0];
1751 		tess.xyz[baseVertex + j][1] = tempVert[1];
1752 		tess.xyz[baseVertex + j][2] = tempVert[2];
1753 
1754 		R_VaoPackNormal(tess.normal[baseVertex + j], tempNormal);
1755 
1756 		tess.texCoords[baseVertex + j][0] = v->texCoords[0];
1757 		tess.texCoords[baseVertex + j][1] = v->texCoords[1];
1758 
1759 		v = (mdrVertex_t *)&v->weights[v->numWeights];
1760 	}
1761 
1762 	tess.numVertexes += surface->numVerts;
1763 }
1764 
1765 
1766 #define MC_MASK_X ((1<<(MC_BITS_X))-1)
1767 #define MC_MASK_Y ((1<<(MC_BITS_Y))-1)
1768 #define MC_MASK_Z ((1<<(MC_BITS_Z))-1)
1769 #define MC_MASK_VECT ((1<<(MC_BITS_VECT))-1)
1770 
1771 #define MC_SCALE_VECT (1.0f/(float)((1<<(MC_BITS_VECT-1))-2))
1772 
1773 #define MC_POS_X (0)
1774 #define MC_SHIFT_X (0)
1775 
1776 #define MC_POS_Y ((((MC_BITS_X))/8))
1777 #define MC_SHIFT_Y ((((MC_BITS_X)%8)))
1778 
1779 #define MC_POS_Z ((((MC_BITS_X+MC_BITS_Y))/8))
1780 #define MC_SHIFT_Z ((((MC_BITS_X+MC_BITS_Y)%8)))
1781 
1782 #define MC_POS_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z))/8))
1783 #define MC_SHIFT_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z)%8)))
1784 
1785 #define MC_POS_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT))/8))
1786 #define MC_SHIFT_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT)%8)))
1787 
1788 #define MC_POS_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2))/8))
1789 #define MC_SHIFT_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2)%8)))
1790 
1791 #define MC_POS_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3))/8))
1792 #define MC_SHIFT_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3)%8)))
1793 
1794 #define MC_POS_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4))/8))
1795 #define MC_SHIFT_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4)%8)))
1796 
1797 #define MC_POS_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5))/8))
1798 #define MC_SHIFT_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5)%8)))
1799 
1800 #define MC_POS_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6))/8))
1801 #define MC_SHIFT_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6)%8)))
1802 
1803 #define MC_POS_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7))/8))
1804 #define MC_SHIFT_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7)%8)))
1805 
1806 #define MC_POS_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8))/8))
1807 #define MC_SHIFT_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8)%8)))
1808 
1809 void MC_UnCompress(float mat[3][4],const unsigned char * comp)
1810 {
1811 	int val;
1812 
1813 	val=(int)((unsigned short *)(comp))[0];
1814 	val-=1<<(MC_BITS_X-1);
1815 	mat[0][3]=((float)(val))*MC_SCALE_X;
1816 
1817 	val=(int)((unsigned short *)(comp))[1];
1818 	val-=1<<(MC_BITS_Y-1);
1819 	mat[1][3]=((float)(val))*MC_SCALE_Y;
1820 
1821 	val=(int)((unsigned short *)(comp))[2];
1822 	val-=1<<(MC_BITS_Z-1);
1823 	mat[2][3]=((float)(val))*MC_SCALE_Z;
1824 
1825 	val=(int)((unsigned short *)(comp))[3];
1826 	val-=1<<(MC_BITS_VECT-1);
1827 	mat[0][0]=((float)(val))*MC_SCALE_VECT;
1828 
1829 	val=(int)((unsigned short *)(comp))[4];
1830 	val-=1<<(MC_BITS_VECT-1);
1831 	mat[0][1]=((float)(val))*MC_SCALE_VECT;
1832 
1833 	val=(int)((unsigned short *)(comp))[5];
1834 	val-=1<<(MC_BITS_VECT-1);
1835 	mat[0][2]=((float)(val))*MC_SCALE_VECT;
1836 
1837 
1838 	val=(int)((unsigned short *)(comp))[6];
1839 	val-=1<<(MC_BITS_VECT-1);
1840 	mat[1][0]=((float)(val))*MC_SCALE_VECT;
1841 
1842 	val=(int)((unsigned short *)(comp))[7];
1843 	val-=1<<(MC_BITS_VECT-1);
1844 	mat[1][1]=((float)(val))*MC_SCALE_VECT;
1845 
1846 	val=(int)((unsigned short *)(comp))[8];
1847 	val-=1<<(MC_BITS_VECT-1);
1848 	mat[1][2]=((float)(val))*MC_SCALE_VECT;
1849 
1850 
1851 	val=(int)((unsigned short *)(comp))[9];
1852 	val-=1<<(MC_BITS_VECT-1);
1853 	mat[2][0]=((float)(val))*MC_SCALE_VECT;
1854 
1855 	val=(int)((unsigned short *)(comp))[10];
1856 	val-=1<<(MC_BITS_VECT-1);
1857 	mat[2][1]=((float)(val))*MC_SCALE_VECT;
1858 
1859 	val=(int)((unsigned short *)(comp))[11];
1860 	val-=1<<(MC_BITS_VECT-1);
1861 	mat[2][2]=((float)(val))*MC_SCALE_VECT;
1862 }
1863