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