1 /*
2 ===========================================================================
3
4 Return to Castle Wolfenstein single player 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 single player GPL Source Code (RTCW SP Source Code).
8
9 RTCW SP 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 SP 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 SP Source Code. If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the RTCW SP 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 SP 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 // tr_models.c -- model loading and caching
30
31 #include "tr_local.h"
32
33 #define LL( x ) x = LittleLong( x )
34
35 // Ridah
36 static qboolean R_LoadMDC( model_t *mod, int lod, void *buffer, const char *modName );
37 // done.
38 static qboolean R_LoadMD3( model_t *mod, int lod, void *buffer, const char *modName );
39 static qboolean R_LoadMDS( model_t *mod, void *buffer, const char *mod_name );
40 static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char *mod_name );
41
42 extern cvar_t *r_compressModels;
43 extern cvar_t *r_exportCompressedModels;
44 extern cvar_t *r_buildScript;
45
46 /*
47 ====================
48 R_RegisterMD3
49 ====================
50 */
R_RegisterMD3(const char * name,model_t * mod)51 qhandle_t R_RegisterMD3(const char *name, model_t *mod)
52 {
53 union {
54 unsigned *u;
55 void *v;
56 } buf;
57 int lod;
58 int ident = 0;
59 qboolean loaded = qfalse;
60 int numLoaded;
61 char filename[MAX_QPATH], namebuf[MAX_QPATH+20];
62 char *fext, defex[] = "md3";
63
64 numLoaded = 0;
65
66 strcpy(filename, name);
67
68 fext = strchr(filename, '.');
69 if(!fext)
70 fext = defex;
71 else
72 {
73 *fext = '\0';
74 fext++;
75 }
76
77 for (lod = MD3_MAX_LODS - 1 ; lod >= 0 ; lod--)
78 {
79 if(lod)
80 Com_sprintf(namebuf, sizeof(namebuf), "%s_%d.%s", filename, lod, fext);
81 else
82 Com_sprintf(namebuf, sizeof(namebuf), "%s.%s", filename, fext);
83
84
85 if ( r_compressModels->integer ) {
86 namebuf[strlen( namebuf ) - 1] = '3'; // try MD3 first
87 } else {
88 namebuf[strlen( namebuf ) - 1] = 'c'; // try MDC first
89 }
90
91 ri.FS_ReadFile( namebuf, &buf.v );
92 if ( !buf.u ) {
93 if ( r_compressModels->integer ) {
94 namebuf[strlen( namebuf ) - 1] = 'c'; // try MDC second
95 } else {
96 namebuf[strlen( namebuf ) - 1] = '3'; // try MD3 second
97 }
98 ri.FS_ReadFile( namebuf, (void **)&buf );
99 if ( !buf.u ) {
100 continue;
101 }
102 }
103
104 ident = LittleLong(* (unsigned *) buf.u);
105 // Ridah, mesh compression
106 if ( ident != MD3_IDENT && ident != MDC_IDENT ) {
107 ri.Printf( PRINT_WARNING,"RE_RegisterModel: unknown fileid for %s\n", name );
108 goto fail;
109 }
110
111 if (ident == MD3_IDENT) {
112 loaded = R_LoadMD3(mod, lod, buf.u, name);
113 } else if (ident == MDC_IDENT) {
114 loaded = R_LoadMDC( mod, lod, buf.u, name );
115 }
116 // done.
117
118 ri.FS_FreeFile(buf.v);
119
120 if(loaded)
121 {
122 mod->numLods++;
123 numLoaded++;
124 }
125 else
126 break;
127 }
128
129 if(numLoaded)
130 {
131 // duplicate into higher lod spots that weren't
132 // loaded, in case the user changes r_lodbias on the fly
133 for(lod--; lod >= 0; lod--)
134 {
135 mod->numLods++;
136 mod->mdv[lod] = mod->mdv[lod + 1];
137 }
138
139 return mod->index;
140 }
141
142 #ifdef _DEBUG
143 ri.Printf(PRINT_WARNING,"R_RegisterMD3: couldn't load %s\n", name);
144 #endif
145
146 fail:
147 // we still keep the model_t around, so if the model name is asked for
148 // again, we won't bother scanning the filesystem
149 mod->type = MOD_BAD;
150 return 0;
151 }
152
153 /*
154 ====================
155 R_RegisterMDS
156 ====================
157 */
R_RegisterMDS(const char * name,model_t * mod)158 qhandle_t R_RegisterMDS(const char *name, model_t *mod)
159 {
160 union {
161 unsigned *u;
162 void *v;
163 } buf;
164 int ident;
165 qboolean loaded = qfalse;
166
167 ri.FS_ReadFile(name, (void **) &buf.v);
168 if(!buf.u)
169 {
170 mod->type = MOD_BAD;
171 return 0;
172 }
173
174 ident = LittleLong(*(unsigned *)buf.u);
175 if(ident == MDS_IDENT)
176 loaded = R_LoadMDS(mod, buf.u, name);
177
178 ri.FS_FreeFile (buf.v);
179
180 if(!loaded)
181 {
182 ri.Printf(PRINT_WARNING,"R_RegisterMDS: couldn't load mds file %s\n", name);
183 mod->type = MOD_BAD;
184 return 0;
185 }
186
187 return mod->index;
188 }
189
190 /*
191 ====================
192 R_RegisterMDR
193 ====================
194 */
R_RegisterMDR(const char * name,model_t * mod)195 qhandle_t R_RegisterMDR(const char *name, model_t *mod)
196 {
197 union {
198 unsigned *u;
199 void *v;
200 } buf;
201 int ident;
202 qboolean loaded = qfalse;
203 int filesize;
204
205 filesize = ri.FS_ReadFile(name, (void **) &buf.v);
206 if(!buf.u)
207 {
208 mod->type = MOD_BAD;
209 return 0;
210 }
211
212 ident = LittleLong(*(unsigned *)buf.u);
213 if(ident == MDR_IDENT)
214 loaded = R_LoadMDR(mod, buf.u, filesize, name);
215
216 ri.FS_FreeFile (buf.v);
217
218 if(!loaded)
219 {
220 ri.Printf(PRINT_WARNING,"R_RegisterMDR: couldn't load mdr file %s\n", name);
221 mod->type = MOD_BAD;
222 return 0;
223 }
224
225 return mod->index;
226 }
227
228 /*
229 ====================
230 R_RegisterIQM
231 ====================
232 */
R_RegisterIQM(const char * name,model_t * mod)233 qhandle_t R_RegisterIQM(const char *name, model_t *mod)
234 {
235 union {
236 unsigned *u;
237 void *v;
238 } buf;
239 qboolean loaded = qfalse;
240 int filesize;
241
242 filesize = ri.FS_ReadFile(name, (void **) &buf.v);
243 if(!buf.u)
244 {
245 mod->type = MOD_BAD;
246 return 0;
247 }
248
249 loaded = R_LoadIQM(mod, buf.u, filesize, name);
250
251 ri.FS_FreeFile (buf.v);
252
253 if(!loaded)
254 {
255 ri.Printf(PRINT_WARNING,"R_RegisterIQM: couldn't load iqm file %s\n", name);
256 mod->type = MOD_BAD;
257 return 0;
258 }
259
260 return mod->index;
261 }
262
263
264 typedef struct
265 {
266 char *ext;
267 qhandle_t (*ModelLoader)( const char *, model_t * );
268 } modelExtToLoaderMap_t;
269
270 // Note that the ordering indicates the order of preference used
271 // when there are multiple models of different formats available
272 static modelExtToLoaderMap_t modelLoaders[ ] =
273 {
274 { "iqm", R_RegisterIQM },
275 { "mdr", R_RegisterMDR },
276 { "mds", R_RegisterMDS },
277 { "md3", R_RegisterMD3 },
278 { "mdc", R_RegisterMD3 }
279 };
280
281 static int numModelLoaders = ARRAY_LEN(modelLoaders);
282
283 /*
284 ** R_GetModelByHandle
285 */
R_GetModelByHandle(qhandle_t index)286 model_t *R_GetModelByHandle( qhandle_t index ) {
287 model_t *mod;
288
289 // out of range gets the defualt model
290 if ( index < 1 || index >= tr.numModels ) {
291 return tr.models[0];
292 }
293
294 mod = tr.models[index];
295
296 return mod;
297 }
298
299 //===============================================================================
300
301 /*
302 ** R_AllocModel
303 */
R_AllocModel(void)304 model_t *R_AllocModel( void ) {
305 model_t *mod;
306
307 if ( tr.numModels == MAX_MOD_KNOWN ) {
308 return NULL;
309 }
310
311 mod = ri.Hunk_Alloc( sizeof( *tr.models[tr.numModels] ), h_low );
312 mod->index = tr.numModels;
313 tr.models[tr.numModels] = mod;
314 tr.numModels++;
315
316 return mod;
317 }
318
319 /*
320 ====================
321 RE_RegisterModel
322
323 Loads in a model for the given name
324
325 Zero will be returned if the model fails to load.
326 An entry will be retained for failed models as an
327 optimization to prevent disk rescanning if they are
328 asked for again.
329 ====================
330 */
RE_RegisterModel(const char * name)331 qhandle_t RE_RegisterModel( const char *name ) {
332 model_t *mod;
333 qhandle_t hModel;
334 qboolean orgNameFailed = qfalse;
335 int orgLoader = -1;
336 int i;
337 char localName[ MAX_QPATH ];
338 const char *ext;
339 char altName[ MAX_QPATH ];
340
341 if ( !name || !name[0] ) {
342 // Ridah, disabled this, we can see models that can't be found because they won't be there
343 //ri.Printf( PRINT_ALL, "RE_RegisterModel: NULL name\n" );
344 return 0;
345 }
346
347 if ( strlen( name ) >= MAX_QPATH ) {
348 ri.Printf( PRINT_ALL, "Model name exceeds MAX_QPATH\n" );
349 return 0;
350 }
351
352 //
353 // search the currently loaded models
354 //
355 for ( hModel = 1 ; hModel < tr.numModels; hModel++ ) {
356 mod = tr.models[hModel];
357 if ( !strcmp( mod->name, name ) ) {
358 if( mod->type == MOD_BAD ) {
359 return 0;
360 }
361 return hModel;
362 }
363 }
364
365 // allocate a new model_t
366
367 if ( ( mod = R_AllocModel() ) == NULL ) {
368 ri.Printf( PRINT_WARNING, "RE_RegisterModel: R_AllocModel() failed for '%s'\n", name );
369 return 0;
370 }
371
372 // only set the name after the model has been successfully loaded
373 Q_strncpyz( mod->name, name, sizeof( mod->name ) );
374
375 // GR - by default models are not tessellated
376 mod->ATI_tess = qfalse;
377 // GR - check if can be tessellated...
378 // make sure to tessellate model heads
379 if ( strstr( name, "head" ) ) {
380 mod->ATI_tess = qtrue;
381 }
382
383 R_IssuePendingRenderCommands();
384
385 mod->type = MOD_BAD;
386 mod->numLods = 0;
387
388 //
389 // load the files
390 //
391 Q_strncpyz( localName, name, MAX_QPATH );
392
393 ext = COM_GetExtension( localName );
394 if( *ext )
395 {
396 // Look for the correct loader and use it
397 for( i = 0; i < numModelLoaders; i++ )
398 {
399 if( !Q_stricmp( ext, modelLoaders[ i ].ext ) )
400 {
401 // Load
402 hModel = modelLoaders[ i ].ModelLoader( localName, mod );
403 break;
404 }
405 }
406 // A loader was found
407 if( i < numModelLoaders )
408 {
409 if( !hModel )
410 {
411 // Loader failed, most likely because the file isn't there;
412 // try again without the extension
413 orgNameFailed = qtrue;
414 orgLoader = i;
415 COM_StripExtension( name, localName, MAX_QPATH );
416 }
417 else
418 {
419 // Something loaded
420 return mod->index;
421 }
422 }
423 }
424
425 // Try and find a suitable match using all
426 // the model formats supported
427 for( i = 0; i < numModelLoaders; i++ )
428 {
429 if (i == orgLoader)
430 continue;
431
432 Com_sprintf( altName, sizeof (altName), "%s.%s", localName, modelLoaders[ i ].ext );
433
434 // Load
435 hModel = modelLoaders[ i ].ModelLoader( altName, mod );
436
437 if( hModel )
438 {
439 if( orgNameFailed )
440 {
441 ri.Printf( PRINT_DEVELOPER, "WARNING: %s not present, using %s instead\n",
442 name, altName );
443 }
444
445 break;
446 }
447 }
448
449 return hModel;
450 }
451
452 //-------------------------------------------------------------------------------
453 // Ridah, mesh compression
454 float r_anormals[NUMMDCVERTEXNORMALS][3] = {
455 #include "anorms256.h"
456 };
457
458 /*
459 =============
460 R_MDC_GetVec
461 =============
462 */
R_MDC_GetVec(unsigned char anorm,vec3_t dir)463 void R_MDC_GetVec( unsigned char anorm, vec3_t dir ) {
464 VectorCopy( r_anormals[anorm], dir );
465 }
466
467 /*
468 =============
469 R_MDC_GetAnorm
470 =============
471 */
R_MDC_GetAnorm(const vec3_t dir)472 unsigned char R_MDC_GetAnorm( const vec3_t dir ) {
473 int i, best_start_i[3] = { 0 }, next_start, next_end, best = 0; // TTimo: init
474 float best_diff, group_val, this_val, diff;
475 float *this_norm;
476
477 // find best Z match
478
479 if ( dir[2] > 0.097545f ) {
480 next_start = 144;
481 next_end = NUMMDCVERTEXNORMALS;
482 } else
483 {
484 next_start = 0;
485 next_end = 144;
486 }
487
488 best_diff = 999;
489 this_val = -999;
490
491 for ( i = next_start ; i < next_end ; i++ )
492 {
493 if ( r_anormals[i][2] == this_val ) {
494 continue;
495 } else {
496 this_val = r_anormals[i][2];
497 }
498
499 if ( ( diff = fabs( dir[2] - r_anormals[i][2] ) ) < best_diff ) {
500 best_diff = diff;
501 best_start_i[2] = i;
502
503 }
504
505 if ( next_start ) {
506 if ( r_anormals[i][2] > dir[2] ) {
507 break; // we've gone passed the dir[2], so we can't possibly find a better match now
508 }
509 } else {
510 if ( r_anormals[i][2] < dir[2] ) {
511 break; // we've gone passed the dir[2], so we can't possibly find a better match now
512 }
513 }
514 }
515
516 best_diff = -999;
517
518 // find best match within the Z group
519
520 for ( i = best_start_i[2], group_val = r_anormals[i][2]; i < NUMMDCVERTEXNORMALS; i++ )
521 {
522 this_norm = r_anormals[i];
523
524 if ( this_norm[2] != group_val ) {
525 break; // done checking the group
526 }
527 diff = DotProduct( dir, this_norm );
528
529 if ( diff > best_diff ) {
530 best_diff = diff;
531 best = i;
532 }
533 }
534
535 return (unsigned char)best;
536 }
537
538 /*
539 =================
540 R_MDC_EncodeOfsVec
541 =================
542 */
R_MDC_EncodeXyzCompressed(const vec3_t vec,const vec3_t normal,mdcXyzCompressed_t * out)543 qboolean R_MDC_EncodeXyzCompressed( const vec3_t vec, const vec3_t normal, mdcXyzCompressed_t *out ) {
544 mdcXyzCompressed_t retval;
545 int i;
546 unsigned char anorm;
547
548 retval.ofsVec = 0;
549 for ( i = 0; i < 3; i++ ) {
550 if ( fabs( vec[i] ) >= MDC_MAX_DIST ) {
551 return qfalse;
552 }
553 retval.ofsVec += ( ( (int)fabs( ( vec[i] + MDC_DIST_SCALE * 0.5 ) * ( 1.0 / MDC_DIST_SCALE ) + MDC_MAX_OFS ) ) << ( i * MDC_BITS_PER_AXIS ) );
554 }
555 anorm = R_MDC_GetAnorm( normal );
556 retval.ofsVec |= ( (int)anorm ) << 24;
557
558 *out = retval;
559 return qtrue;
560 }
561
562 /*
563 =================
564 R_LoadMDC
565 =================
566 */
R_LoadMDC(model_t * mod,int lod,void * buffer,const char * modName)567 static qboolean R_LoadMDC( model_t *mod, int lod, void *buffer, const char *modName )
568 {
569 int f, i, j, k;
570
571 mdcHeader_t *mdcModel;
572 md3Frame_t *md3Frame;
573 mdcSurface_t *mdcSurf;
574 md3Shader_t *md3Shader;
575 md3Triangle_t *md3Tri;
576 md3St_t *md3st;
577 md3XyzNormal_t *md3xyz;
578 mdcXyzCompressed_t *mdcxyzComp;
579 short *mdcBaseFrame, *mdcCompFrame;
580 mdcTag_t *mdcTag;
581 mdcTagName_t *mdcTagName;
582
583 mdvModel_t *mdvModel;
584 mdvFrame_t *frame;
585 mdvSurface_t *surf;//, *surface;
586 int *shaderIndex;
587 glIndex_t *tri;
588 mdvVertex_t *v;
589 mdvSt_t *st;
590 mdvTag_t *tag;
591 mdvTagName_t *tagName;
592
593 int version;
594 int size;
595
596 mdcModel = (mdcHeader_t *) buffer;
597
598 version = LittleLong(mdcModel->version);
599 if(version != MDC_VERSION)
600 {
601 ri.Printf(PRINT_WARNING, "R_LoadMDC: %s has wrong version (%i should be %i)\n", modName, version, MDC_VERSION);
602 return qfalse;
603 }
604
605 mod->type = MOD_MESH;
606 size = LittleLong(mdcModel->ofsEnd);
607 mod->dataSize += size;
608 mdvModel = mod->mdv[lod] = ri.Hunk_Alloc(sizeof(mdvModel_t), h_low);
609
610 LL( mdcModel->ident );
611 LL( mdcModel->version );
612 LL( mdcModel->numFrames );
613 LL( mdcModel->numTags );
614 LL( mdcModel->numSurfaces );
615 LL( mdcModel->ofsFrames );
616 LL( mdcModel->ofsTagNames );
617 LL( mdcModel->ofsTags );
618 LL( mdcModel->ofsSurfaces );
619 LL( mdcModel->ofsEnd );
620 LL( mdcModel->flags );
621 LL( mdcModel->numSkins );
622
623 if( mdcModel->numFrames < 1 )
624 {
625 ri.Printf(PRINT_WARNING, "R_LoadMDC: %s has no frames\n", modName);
626 return qfalse;
627 }
628
629 // swap all the frames
630 mdvModel->numFrames = mdcModel->numFrames;
631 mdvModel->frames = frame = ri.Hunk_Alloc(sizeof(*frame) * mdcModel->numFrames, h_low);
632
633 md3Frame = (md3Frame_t *) ((byte *) mdcModel + mdcModel->ofsFrames);
634 for(i = 0; i < mdcModel->numFrames; i++, frame++, md3Frame++)
635 {
636 frame->radius = LittleFloat(md3Frame->radius);
637 if ( strstr( mod->name, "sherman" ) || strstr( mod->name, "mg42" ) )
638 {
639 frame->radius = 256;
640 for ( j = 0 ; j < 3 ; j++ )
641 {
642 frame->bounds[0][j] = 128;
643 frame->bounds[1][j] = -128;
644 frame->localOrigin[j] = LittleFloat( md3Frame->localOrigin[j] );
645 }
646 }
647 else
648 {
649 for(j = 0; j < 3; j++)
650 {
651 frame->bounds[0][j] = LittleFloat(md3Frame->bounds[0][j]);
652 frame->bounds[1][j] = LittleFloat(md3Frame->bounds[1][j]);
653 frame->localOrigin[j] = LittleFloat(md3Frame->localOrigin[j]);
654 }
655 }
656 }
657
658 // swap all the tags
659 mdvModel->numTags = mdcModel->numTags;
660 mdvModel->tags = tag = ri.Hunk_Alloc(sizeof(*tag) * (mdcModel->numTags * mdcModel->numFrames), h_low);
661
662 mdcTag = (mdcTag_t *) ((byte *) mdcModel + mdcModel->ofsTags);
663 for(i = 0; i < mdcModel->numTags * mdcModel->numFrames; i++, tag++, mdcTag++)
664 {
665 vec3_t angles;
666 for(j = 0; j < 3; j++)
667 {
668 tag->origin[j] = LittleShort(mdcTag->xyz[j]) * MD3_XYZ_SCALE;
669 angles[j] = LittleShort(mdcTag->angles[j]) * MDC_TAG_ANGLE_SCALE;
670 }
671 AnglesToAxis(angles, tag->axis);
672 }
673
674
675 mdvModel->tagNames = tagName = ri.Hunk_Alloc(sizeof(*tagName) * (mdcModel->numTags), h_low);
676
677 mdcTagName = (mdcTagName_t *) ((byte *) mdcModel + mdcModel->ofsTagNames);
678 for(i = 0; i < mdcModel->numTags; i++, tagName++, mdcTagName++)
679 {
680 Q_strncpyz(tagName->name, mdcTagName->name, sizeof(tagName->name));
681 }
682
683 // swap all the surfaces
684 mdvModel->numSurfaces = mdcModel->numSurfaces;
685 mdvModel->surfaces = surf = ri.Hunk_Alloc(sizeof(*surf) * mdcModel->numSurfaces, h_low);
686
687 mdcSurf = (mdcSurface_t *) ((byte *) mdcModel + mdcModel->ofsSurfaces);
688 for(i = 0; i < mdcModel->numSurfaces; i++)
689 {
690 LL( mdcSurf->ident );
691 LL( mdcSurf->flags );
692 LL( mdcSurf->numBaseFrames );
693 LL( mdcSurf->numCompFrames );
694 LL( mdcSurf->numShaders );
695 LL( mdcSurf->numTriangles );
696 LL( mdcSurf->ofsTriangles );
697 LL( mdcSurf->numVerts );
698 LL( mdcSurf->ofsShaders );
699 LL( mdcSurf->ofsSt );
700 LL( mdcSurf->ofsXyzNormals );
701 LL( mdcSurf->ofsXyzCompressed );
702 LL( mdcSurf->ofsFrameBaseFrames );
703 LL( mdcSurf->ofsFrameCompFrames );
704 LL( mdcSurf->ofsEnd );
705
706 if(mdcSurf->numVerts >= SHADER_MAX_VERTEXES)
707 {
708 ri.Printf(PRINT_WARNING, "R_LoadMDC: %s has more than %i verts on %s (%i).\n",
709 modName, SHADER_MAX_VERTEXES - 1, mdcSurf->name[0] ? mdcSurf->name : "a surface",
710 mdcSurf->numVerts );
711 return qfalse;
712 }
713 if(mdcSurf->numTriangles * 3 >= SHADER_MAX_INDEXES)
714 {
715 ri.Printf(PRINT_WARNING, "R_LoadMDC: %s has more than %i triangles on %s (%i).\n",
716 modName, ( SHADER_MAX_INDEXES / 3 ) - 1, mdcSurf->name[0] ? mdcSurf->name : "a surface",
717 mdcSurf->numTriangles );
718 return qfalse;
719 }
720
721 // change to surface identifier
722 surf->surfaceType = SF_MDV;
723
724 // give pointer to model for Tess_SurfaceMDX
725 surf->model = mdvModel;
726
727 // copy surface name
728 Q_strncpyz(surf->name, mdcSurf->name, sizeof(surf->name));
729
730 // lowercase the surface name so skin compares are faster
731 Q_strlwr(surf->name);
732
733 // strip off a trailing _1 or _2
734 // this is a crutch for q3data being a mess
735 j = strlen(surf->name);
736 if(j > 2 && surf->name[j - 2] == '_')
737 {
738 surf->name[j - 2] = 0;
739 }
740
741 // register the shaders
742 surf->numShaderIndexes = mdcSurf->numShaders;
743 surf->shaderIndexes = shaderIndex = ri.Hunk_Alloc(sizeof(*shaderIndex) * mdcSurf->numShaders, h_low);
744
745 md3Shader = (md3Shader_t *) ((byte *) mdcSurf + mdcSurf->ofsShaders);
746 for(j = 0; j < mdcSurf->numShaders; j++, shaderIndex++, md3Shader++)
747 {
748 shader_t *sh;
749
750 sh = R_FindShader(md3Shader->name, LIGHTMAP_NONE, qtrue);
751 if(sh->defaultShader)
752 {
753 *shaderIndex = 0;
754 }
755 else
756 {
757 *shaderIndex = sh->index;
758 }
759 }
760
761 // swap all the triangles
762 surf->numIndexes = mdcSurf->numTriangles * 3;
763 surf->indexes = tri = ri.Hunk_Alloc(sizeof(*tri) * 3 * mdcSurf->numTriangles, h_low);
764
765 md3Tri = (md3Triangle_t *) ((byte *) mdcSurf + mdcSurf->ofsTriangles);
766 for(j = 0; j < mdcSurf->numTriangles; j++, tri += 3, md3Tri++)
767 {
768 tri[0] = LittleLong(md3Tri->indexes[0]);
769 tri[1] = LittleLong(md3Tri->indexes[1]);
770 tri[2] = LittleLong(md3Tri->indexes[2]);
771 }
772
773 // swap all the ST
774 surf->st = st = ri.Hunk_Alloc(sizeof(*st) * mdcSurf->numVerts, h_low);
775
776 md3st = (md3St_t *) ((byte *) mdcSurf + mdcSurf->ofsSt);
777 for(j = 0; j < mdcSurf->numVerts; j++, md3st++, st++)
778 {
779 st->st[0] = LittleFloat(md3st->st[0]);
780 st->st[1] = LittleFloat(md3st->st[1]);
781 }
782
783 // swap all the XyzNormals
784 md3xyz = ( md3XyzNormal_t * )( (byte *)mdcSurf + mdcSurf->ofsXyzNormals );
785 for ( j = 0 ; j < mdcSurf->numVerts * mdcSurf->numBaseFrames ; j++, md3xyz++ )
786 {
787 md3xyz->xyz[0] = LittleShort( md3xyz->xyz[0] );
788 md3xyz->xyz[1] = LittleShort( md3xyz->xyz[1] );
789 md3xyz->xyz[2] = LittleShort( md3xyz->xyz[2] );
790
791 md3xyz->normal = LittleShort( md3xyz->normal );
792 }
793
794 // swap all the XyzCompressed
795 mdcxyzComp = ( mdcXyzCompressed_t * )( (byte *)mdcSurf + mdcSurf->ofsXyzCompressed );
796 for ( j = 0 ; j < mdcSurf->numVerts * mdcSurf->numCompFrames ; j++, mdcxyzComp++ )
797 {
798 LL( mdcxyzComp->ofsVec );
799 }
800
801 // swap the frameBaseFrames
802 mdcBaseFrame = ( short * )( (byte *)mdcSurf + mdcSurf->ofsFrameBaseFrames );
803 for ( j = 0; j < mdcModel->numFrames; j++, mdcBaseFrame++ )
804 {
805 *mdcBaseFrame = LittleShort( *mdcBaseFrame );
806 }
807
808 // swap the frameCompFrames
809 mdcCompFrame = ( short * )( (byte *)mdcSurf + mdcSurf->ofsFrameCompFrames );
810 for ( j = 0; j < mdcModel->numFrames; j++, mdcCompFrame++ )
811 {
812 *mdcCompFrame = LittleShort( *mdcCompFrame );
813 }
814
815 // expand the base frames
816 surf->numVerts = mdcSurf->numVerts;
817 surf->verts = v = ri.Hunk_Alloc(sizeof(*v) * (mdcSurf->numVerts * mdcModel->numFrames), h_low);
818
819 mdcBaseFrame = ( short * )( (byte *)mdcSurf + mdcSurf->ofsFrameBaseFrames );
820 for(j = 0; j < mdcModel->numFrames; j++, mdcBaseFrame++)
821 {
822 md3xyz = ( md3XyzNormal_t * )( (byte *)mdcSurf + mdcSurf->ofsXyzNormals ) + ( *mdcBaseFrame * surf->numVerts );
823 for(k = 0; k < mdcSurf->numVerts; k++, md3xyz++, v++)
824 {
825 unsigned lat, lng;
826 unsigned short normal;
827 vec3_t fNormal;
828
829 v->xyz[0] = md3xyz->xyz[0] * MD3_XYZ_SCALE;
830 v->xyz[1] = md3xyz->xyz[1] * MD3_XYZ_SCALE;
831 v->xyz[2] = md3xyz->xyz[2] * MD3_XYZ_SCALE;
832
833 normal = md3xyz->normal;
834
835 lat = ( normal >> 8 ) & 0xff;
836 lng = ( normal & 0xff );
837 lat *= (FUNCTABLE_SIZE/256);
838 lng *= (FUNCTABLE_SIZE/256);
839
840 // decode X as cos( lat ) * sin( long )
841 // decode Y as sin( lat ) * sin( long )
842 // decode Z as cos( long )
843
844 fNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
845 fNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
846 fNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
847
848 R_VaoPackNormal(v->normal, fNormal);
849 }
850 }
851
852 // expand the compressed frames
853 if (mdcSurf->numCompFrames > 0)
854 {
855 mdcCompFrame = ( short * )( (byte *)mdcSurf + mdcSurf->ofsFrameCompFrames );
856 for(j = 0; j < mdcModel->numFrames; j++, mdcCompFrame++)
857 {
858 if (*mdcCompFrame < 0)
859 continue;
860
861 v = surf->verts + j * surf->numVerts;
862 mdcxyzComp = ( mdcXyzCompressed_t * )( (byte *)mdcSurf + mdcSurf->ofsXyzCompressed ) + ( *mdcCompFrame * surf->numVerts );
863
864 for(k = 0; k < mdcSurf->numVerts; k++, mdcxyzComp++, v++)
865 {
866 vec3_t ofsVec;
867 vec3_t fNormal;
868
869 R_MDC_DecodeXyzCompressed(mdcxyzComp->ofsVec, ofsVec, fNormal);
870 VectorAdd( v->xyz, ofsVec, v->xyz );
871
872 R_VaoPackNormal(v->normal, fNormal);
873 }
874 }
875 }
876
877 // calc tangent spaces
878 {
879 vec3_t *sdirs = ri.Z_Malloc(sizeof(*sdirs) * surf->numVerts * mdvModel->numFrames);
880 vec3_t *tdirs = ri.Z_Malloc(sizeof(*tdirs) * surf->numVerts * mdvModel->numFrames);
881
882 for(j = 0, v = surf->verts; j < (surf->numVerts * mdvModel->numFrames); j++, v++)
883 {
884 VectorClear(sdirs[j]);
885 VectorClear(tdirs[j]);
886 }
887
888 for(f = 0; f < mdvModel->numFrames; f++)
889 {
890 for(j = 0, tri = surf->indexes; j < surf->numIndexes; j += 3, tri += 3)
891 {
892 vec3_t sdir, tdir;
893 const float *v0, *v1, *v2, *t0, *t1, *t2;
894 glIndex_t index0, index1, index2;
895
896 index0 = surf->numVerts * f + tri[0];
897 index1 = surf->numVerts * f + tri[1];
898 index2 = surf->numVerts * f + tri[2];
899
900 v0 = surf->verts[index0].xyz;
901 v1 = surf->verts[index1].xyz;
902 v2 = surf->verts[index2].xyz;
903
904 t0 = surf->st[tri[0]].st;
905 t1 = surf->st[tri[1]].st;
906 t2 = surf->st[tri[2]].st;
907
908 R_CalcTexDirs(sdir, tdir, v0, v1, v2, t0, t1, t2);
909
910 VectorAdd(sdir, sdirs[index0], sdirs[index0]);
911 VectorAdd(sdir, sdirs[index1], sdirs[index1]);
912 VectorAdd(sdir, sdirs[index2], sdirs[index2]);
913 VectorAdd(tdir, tdirs[index0], tdirs[index0]);
914 VectorAdd(tdir, tdirs[index1], tdirs[index1]);
915 VectorAdd(tdir, tdirs[index2], tdirs[index2]);
916 }
917 }
918
919 for(j = 0, v = surf->verts; j < (surf->numVerts * mdvModel->numFrames); j++, v++)
920 {
921 vec3_t normal;
922 vec4_t tangent;
923
924 VectorNormalize(sdirs[j]);
925 VectorNormalize(tdirs[j]);
926
927 R_VaoUnpackNormal(normal, v->normal);
928
929 tangent[3] = R_CalcTangentSpace(tangent, NULL, normal, sdirs[j], tdirs[j]);
930
931 R_VaoPackTangent(v->tangent, tangent);
932 }
933
934 ri.Free(sdirs);
935 ri.Free(tdirs);
936 }
937
938 // find the next surface
939 mdcSurf = (mdcSurface_t *) ((byte *) mdcSurf + mdcSurf->ofsEnd);
940 surf++;
941 }
942
943 {
944 srfVaoMdvMesh_t *vaoSurf;
945
946 mdvModel->numVaoSurfaces = mdvModel->numSurfaces;
947 mdvModel->vaoSurfaces = ri.Hunk_Alloc(sizeof(*mdvModel->vaoSurfaces) * mdvModel->numSurfaces, h_low);
948
949 vaoSurf = mdvModel->vaoSurfaces;
950 surf = mdvModel->surfaces;
951 for (i = 0; i < mdvModel->numSurfaces; i++, vaoSurf++, surf++)
952 {
953 uint32_t offset_xyz, offset_st, offset_normal, offset_tangent;
954 uint32_t stride_xyz, stride_st, stride_normal, stride_tangent;
955 uint32_t dataSize, dataOfs;
956 uint8_t *data;
957
958 if (mdvModel->numFrames > 1)
959 {
960 // vertex animation, store texcoords first, then position/normal/tangents
961 offset_st = 0;
962 offset_xyz = surf->numVerts * sizeof(vec2_t);
963 offset_normal = offset_xyz + sizeof(vec3_t);
964 offset_tangent = offset_normal + sizeof(int16_t) * 4;
965 stride_st = sizeof(vec2_t);
966 stride_xyz = sizeof(vec3_t) + sizeof(int16_t) * 4;
967 stride_xyz += sizeof(int16_t) * 4;
968 stride_normal = stride_tangent = stride_xyz;
969
970 dataSize = offset_xyz + surf->numVerts * mdvModel->numFrames * stride_xyz;
971 }
972 else
973 {
974 // no animation, interleave everything
975 offset_xyz = 0;
976 offset_st = offset_xyz + sizeof(vec3_t);
977 offset_normal = offset_st + sizeof(vec2_t);
978 offset_tangent = offset_normal + sizeof(int16_t) * 4;
979 stride_xyz = offset_tangent + sizeof(int16_t) * 4;
980 stride_st = stride_normal = stride_tangent = stride_xyz;
981
982 dataSize = surf->numVerts * stride_xyz;
983 }
984
985
986 data = ri.Z_Malloc(dataSize);
987 dataOfs = 0;
988
989 if (mdvModel->numFrames > 1)
990 {
991 st = surf->st;
992 for ( j = 0 ; j < surf->numVerts ; j++, st++ ) {
993 memcpy(data + dataOfs, &st->st, sizeof(vec2_t));
994 dataOfs += sizeof(st->st);
995 }
996
997 v = surf->verts;
998 for ( j = 0; j < surf->numVerts * mdvModel->numFrames ; j++, v++ )
999 {
1000 // xyz
1001 memcpy(data + dataOfs, &v->xyz, sizeof(vec3_t));
1002 dataOfs += sizeof(vec3_t);
1003
1004 // normal
1005 memcpy(data + dataOfs, &v->normal, sizeof(int16_t) * 4);
1006 dataOfs += sizeof(int16_t) * 4;
1007
1008 // tangent
1009 memcpy(data + dataOfs, &v->tangent, sizeof(int16_t) * 4);
1010 dataOfs += sizeof(int16_t) * 4;
1011 }
1012 }
1013 else
1014 {
1015 v = surf->verts;
1016 st = surf->st;
1017 for ( j = 0; j < surf->numVerts; j++, v++, st++ )
1018 {
1019 // xyz
1020 memcpy(data + dataOfs, &v->xyz, sizeof(vec3_t));
1021 dataOfs += sizeof(v->xyz);
1022
1023 // st
1024 memcpy(data + dataOfs, &st->st, sizeof(vec2_t));
1025 dataOfs += sizeof(st->st);
1026
1027 // normal
1028 memcpy(data + dataOfs, &v->normal, sizeof(int16_t) * 4);
1029 dataOfs += sizeof(int16_t) * 4;
1030
1031 // tangent
1032 memcpy(data + dataOfs, &v->tangent, sizeof(int16_t) * 4);
1033 dataOfs += sizeof(int16_t) * 4;
1034 }
1035 }
1036
1037 vaoSurf->surfaceType = SF_VAO_MDVMESH;
1038 vaoSurf->mdvModel = mdvModel;
1039 vaoSurf->mdvSurface = surf;
1040 vaoSurf->numIndexes = surf->numIndexes;
1041 vaoSurf->numVerts = surf->numVerts;
1042
1043 vaoSurf->vao = R_CreateVao(va("staticMD3Mesh_VAO '%s'", surf->name), data, dataSize, (byte *)surf->indexes, surf->numIndexes * sizeof(*surf->indexes), VAO_USAGE_STATIC);
1044
1045 vaoSurf->vao->attribs[ATTR_INDEX_POSITION].enabled = 1;
1046 vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].enabled = 1;
1047 vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].enabled = 1;
1048 vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].enabled = 1;
1049 vaoSurf->vao->attribs[ATTR_INDEX_POSITION].count = 3;
1050 vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].count = 2;
1051 vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].count = 4;
1052 vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].count = 4;
1053
1054 vaoSurf->vao->attribs[ATTR_INDEX_POSITION].type = GL_FLOAT;
1055 vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].type = GL_FLOAT;
1056 vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].type = GL_SHORT;
1057 vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].type = GL_SHORT;
1058
1059 vaoSurf->vao->attribs[ATTR_INDEX_POSITION].normalized = GL_FALSE;
1060 vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].normalized = GL_FALSE;
1061 vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].normalized = GL_TRUE;
1062 vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].normalized = GL_TRUE;
1063
1064 vaoSurf->vao->attribs[ATTR_INDEX_POSITION].offset = offset_xyz;
1065 vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].offset = offset_st;
1066 vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].offset = offset_normal;
1067 vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].offset = offset_tangent;
1068
1069 vaoSurf->vao->attribs[ATTR_INDEX_POSITION].stride = stride_xyz;
1070 vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].stride = stride_st;
1071 vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].stride = stride_normal;
1072 vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].stride = stride_tangent;
1073
1074 if (mdvModel->numFrames > 1)
1075 {
1076 vaoSurf->vao->attribs[ATTR_INDEX_POSITION2] = vaoSurf->vao->attribs[ATTR_INDEX_POSITION];
1077 vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2 ] = vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ];
1078 vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2 ] = vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ];
1079
1080 vaoSurf->vao->frameSize = stride_xyz * surf->numVerts;
1081 }
1082
1083 Vao_SetVertexPointers(vaoSurf->vao);
1084
1085 ri.Free(data);
1086 }
1087 }
1088
1089 return qtrue;
1090 }
1091 // done.
1092 //-------------------------------------------------------------------------------
1093
1094 /*
1095 =================
1096 R_LoadMD3
1097 =================
1098 */
R_LoadMD3(model_t * mod,int lod,void * buffer,const char * modName)1099 static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, const char *modName)
1100 {
1101 int f, i, j;
1102
1103 md3Header_t *md3Model;
1104 md3Frame_t *md3Frame;
1105 md3Surface_t *md3Surf;
1106 md3Shader_t *md3Shader;
1107 md3Triangle_t *md3Tri;
1108 md3St_t *md3st;
1109 md3XyzNormal_t *md3xyz;
1110 md3Tag_t *md3Tag;
1111
1112 mdvModel_t *mdvModel;
1113 mdvFrame_t *frame;
1114 mdvSurface_t *surf;//, *surface;
1115 int *shaderIndex;
1116 glIndex_t *tri;
1117 mdvVertex_t *v;
1118 mdvSt_t *st;
1119 mdvTag_t *tag;
1120 mdvTagName_t *tagName;
1121
1122 int version;
1123 int size;
1124
1125 qboolean fixRadius = qfalse;
1126
1127 md3Model = (md3Header_t *) buffer;
1128
1129 version = LittleLong(md3Model->version);
1130 if(version != MD3_VERSION)
1131 {
1132 ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has wrong version (%i should be %i)\n", modName, version, MD3_VERSION);
1133 return qfalse;
1134 }
1135
1136 mod->type = MOD_MESH;
1137 size = LittleLong(md3Model->ofsEnd);
1138 mod->dataSize += size;
1139 // Ridah, convert to compressed format
1140 if ( !r_compressModels->integer ) {
1141 mdvModel = mod->mdv[lod] = ri.Hunk_Alloc(sizeof(mdvModel_t), h_low);
1142 } else {
1143 mdvModel = mod->mdv[lod] = ri.Hunk_AllocateTempMemory( size );
1144 }
1145 // done.
1146
1147 //memcpy( mod->md3[lod], buffer, LittleLong( pinmodel->ofsEnd ) );
1148
1149 LL(md3Model->ident);
1150 LL(md3Model->version);
1151 LL(md3Model->numFrames);
1152 LL(md3Model->numTags);
1153 LL(md3Model->numSurfaces);
1154 LL(md3Model->ofsFrames);
1155 LL(md3Model->ofsTags);
1156 LL(md3Model->ofsSurfaces);
1157 LL(md3Model->ofsEnd);
1158
1159 if(md3Model->numFrames < 1)
1160 {
1161 ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has no frames\n", modName);
1162 return qfalse;
1163 }
1164
1165 if ( strstr( mod->name,"sherman" ) || strstr( mod->name, "mg42" ) ) {
1166 fixRadius = qtrue;
1167 }
1168
1169 // swap all the frames
1170 mdvModel->numFrames = md3Model->numFrames;
1171 mdvModel->frames = frame = ri.Hunk_Alloc(sizeof(*frame) * md3Model->numFrames, h_low);
1172
1173 md3Frame = (md3Frame_t *) ((byte *) md3Model + md3Model->ofsFrames);
1174 for(i = 0; i < md3Model->numFrames; i++, frame++, md3Frame++)
1175 {
1176 frame->radius = LittleFloat( md3Frame->radius );
1177 if ( fixRadius ) {
1178 frame->radius = 256;
1179 for ( j = 0 ; j < 3 ; j++ ) {
1180 frame->bounds[0][j] = 128;
1181 frame->bounds[1][j] = -128;
1182 frame->localOrigin[j] = LittleFloat( md3Frame->localOrigin[j] );
1183 }
1184 }
1185 // Hack for Bug using plugin generated model
1186 else if ( frame->radius == 1 ) {
1187 frame->radius = 256;
1188 for ( j = 0 ; j < 3 ; j++ ) {
1189 frame->bounds[0][j] = 128;
1190 frame->bounds[1][j] = -128;
1191 frame->localOrigin[j] = LittleFloat( md3Frame->localOrigin[j] );
1192 }
1193 } else
1194 {
1195 for ( j = 0 ; j < 3 ; j++ ) {
1196 frame->bounds[0][j] = LittleFloat( md3Frame->bounds[0][j] );
1197 frame->bounds[1][j] = LittleFloat( md3Frame->bounds[1][j] );
1198 frame->localOrigin[j] = LittleFloat( md3Frame->localOrigin[j] );
1199 }
1200 }
1201 }
1202
1203 // swap all the tags
1204 mdvModel->numTags = md3Model->numTags;
1205 mdvModel->tags = tag = ri.Hunk_Alloc(sizeof(*tag) * (md3Model->numTags * md3Model->numFrames), h_low);
1206
1207 md3Tag = (md3Tag_t *) ((byte *) md3Model + md3Model->ofsTags);
1208 for(i = 0; i < md3Model->numTags * md3Model->numFrames; i++, tag++, md3Tag++)
1209 {
1210 for(j = 0; j < 3; j++)
1211 {
1212 tag->origin[j] = LittleFloat(md3Tag->origin[j]);
1213 tag->axis[0][j] = LittleFloat(md3Tag->axis[0][j]);
1214 tag->axis[1][j] = LittleFloat(md3Tag->axis[1][j]);
1215 tag->axis[2][j] = LittleFloat(md3Tag->axis[2][j]);
1216 }
1217 }
1218
1219
1220 mdvModel->tagNames = tagName = ri.Hunk_Alloc(sizeof(*tagName) * (md3Model->numTags), h_low);
1221
1222 md3Tag = (md3Tag_t *) ((byte *) md3Model + md3Model->ofsTags);
1223 for(i = 0; i < md3Model->numTags; i++, tagName++, md3Tag++)
1224 {
1225 Q_strncpyz(tagName->name, md3Tag->name, sizeof(tagName->name));
1226 }
1227
1228 // swap all the surfaces
1229 mdvModel->numSurfaces = md3Model->numSurfaces;
1230 mdvModel->surfaces = surf = ri.Hunk_Alloc(sizeof(*surf) * md3Model->numSurfaces, h_low);
1231
1232 md3Surf = (md3Surface_t *) ((byte *) md3Model + md3Model->ofsSurfaces);
1233 for(i = 0; i < md3Model->numSurfaces; i++)
1234 {
1235 LL(md3Surf->ident);
1236 LL(md3Surf->flags);
1237 LL(md3Surf->numFrames);
1238 LL(md3Surf->numShaders);
1239 LL(md3Surf->numTriangles);
1240 LL(md3Surf->ofsTriangles);
1241 LL(md3Surf->numVerts);
1242 LL(md3Surf->ofsShaders);
1243 LL(md3Surf->ofsSt);
1244 LL(md3Surf->ofsXyzNormals);
1245 LL(md3Surf->ofsEnd);
1246
1247 if(md3Surf->numVerts >= SHADER_MAX_VERTEXES)
1248 {
1249 ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has more than %i verts on %s (%i).\n",
1250 modName, SHADER_MAX_VERTEXES - 1, md3Surf->name[0] ? md3Surf->name : "a surface",
1251 md3Surf->numVerts );
1252 return qfalse;
1253 }
1254 if(md3Surf->numTriangles * 3 >= SHADER_MAX_INDEXES)
1255 {
1256 ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has more than %i triangles on %s (%i).\n",
1257 modName, ( SHADER_MAX_INDEXES / 3 ) - 1, md3Surf->name[0] ? md3Surf->name : "a surface",
1258 md3Surf->numTriangles );
1259 return qfalse;
1260 }
1261
1262 // change to surface identifier
1263 surf->surfaceType = SF_MDV;
1264
1265 // give pointer to model for Tess_SurfaceMDX
1266 surf->model = mdvModel;
1267
1268 // copy surface name
1269 Q_strncpyz(surf->name, md3Surf->name, sizeof(surf->name));
1270
1271 // lowercase the surface name so skin compares are faster
1272 Q_strlwr(surf->name);
1273
1274 // strip off a trailing _1 or _2
1275 // this is a crutch for q3data being a mess
1276 j = strlen(surf->name);
1277 if(j > 2 && surf->name[j - 2] == '_')
1278 {
1279 surf->name[j - 2] = 0;
1280 }
1281
1282 // register the shaders
1283 surf->numShaderIndexes = md3Surf->numShaders;
1284 surf->shaderIndexes = shaderIndex = ri.Hunk_Alloc(sizeof(*shaderIndex) * md3Surf->numShaders, h_low);
1285 md3Shader = (md3Shader_t *) ((byte *) md3Surf + md3Surf->ofsShaders);
1286 for(j = 0; j < md3Surf->numShaders; j++, shaderIndex++, md3Shader++)
1287 {
1288 shader_t *sh;
1289
1290 sh = R_FindShader(md3Shader->name, LIGHTMAP_NONE, qtrue);
1291 if(sh->defaultShader)
1292 {
1293 *shaderIndex = 0;
1294 }
1295
1296 else
1297 {
1298 *shaderIndex = sh->index;
1299 }
1300 }
1301
1302 // swap all the triangles
1303 surf->numIndexes = md3Surf->numTriangles * 3;
1304 surf->indexes = tri = ri.Hunk_Alloc(sizeof(*tri) * 3 * md3Surf->numTriangles, h_low);
1305
1306 md3Tri = (md3Triangle_t *) ((byte *) md3Surf + md3Surf->ofsTriangles);
1307 for(j = 0; j < md3Surf->numTriangles; j++, tri += 3, md3Tri++)
1308 {
1309 tri[0] = LittleLong(md3Tri->indexes[0]);
1310 tri[1] = LittleLong(md3Tri->indexes[1]);
1311 tri[2] = LittleLong(md3Tri->indexes[2]);
1312 }
1313
1314 // swap all the XyzNormals
1315 surf->numVerts = md3Surf->numVerts;
1316 surf->verts = v = ri.Hunk_Alloc(sizeof(*v) * (md3Surf->numVerts * md3Surf->numFrames), h_low);
1317
1318 md3xyz = (md3XyzNormal_t *) ((byte *) md3Surf + md3Surf->ofsXyzNormals);
1319 for(j = 0; j < md3Surf->numVerts * md3Surf->numFrames; j++, md3xyz++, v++)
1320 {
1321 unsigned lat, lng;
1322 unsigned short normal;
1323 vec3_t fNormal;
1324
1325 v->xyz[0] = LittleShort(md3xyz->xyz[0]) * MD3_XYZ_SCALE;
1326 v->xyz[1] = LittleShort(md3xyz->xyz[1]) * MD3_XYZ_SCALE;
1327 v->xyz[2] = LittleShort(md3xyz->xyz[2]) * MD3_XYZ_SCALE;
1328
1329 normal = LittleShort(md3xyz->normal);
1330
1331 lat = ( normal >> 8 ) & 0xff;
1332 lng = ( normal & 0xff );
1333 lat *= (FUNCTABLE_SIZE/256);
1334 lng *= (FUNCTABLE_SIZE/256);
1335
1336 // decode X as cos( lat ) * sin( long )
1337 // decode Y as sin( lat ) * sin( long )
1338 // decode Z as cos( long )
1339
1340 fNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
1341 fNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
1342 fNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
1343
1344 R_VaoPackNormal(v->normal, fNormal);
1345 }
1346
1347 // swap all the ST
1348 surf->st = st = ri.Hunk_Alloc(sizeof(*st) * md3Surf->numVerts, h_low);
1349
1350 md3st = (md3St_t *) ((byte *) md3Surf + md3Surf->ofsSt);
1351 for(j = 0; j < md3Surf->numVerts; j++, md3st++, st++)
1352 {
1353 st->st[0] = LittleFloat(md3st->st[0]);
1354 st->st[1] = LittleFloat(md3st->st[1]);
1355 }
1356
1357 // calc tangent spaces
1358 {
1359 vec3_t *sdirs = ri.Z_Malloc(sizeof(*sdirs) * surf->numVerts * mdvModel->numFrames);
1360 vec3_t *tdirs = ri.Z_Malloc(sizeof(*tdirs) * surf->numVerts * mdvModel->numFrames);
1361
1362 for(j = 0, v = surf->verts; j < (surf->numVerts * mdvModel->numFrames); j++, v++)
1363 {
1364 VectorClear(sdirs[j]);
1365 VectorClear(tdirs[j]);
1366 }
1367
1368 for(f = 0; f < mdvModel->numFrames; f++)
1369 {
1370 for(j = 0, tri = surf->indexes; j < surf->numIndexes; j += 3, tri += 3)
1371 {
1372 vec3_t sdir, tdir;
1373 const float *v0, *v1, *v2, *t0, *t1, *t2;
1374 glIndex_t index0, index1, index2;
1375
1376 index0 = surf->numVerts * f + tri[0];
1377 index1 = surf->numVerts * f + tri[1];
1378 index2 = surf->numVerts * f + tri[2];
1379
1380 v0 = surf->verts[index0].xyz;
1381 v1 = surf->verts[index1].xyz;
1382 v2 = surf->verts[index2].xyz;
1383
1384 t0 = surf->st[tri[0]].st;
1385 t1 = surf->st[tri[1]].st;
1386 t2 = surf->st[tri[2]].st;
1387
1388 R_CalcTexDirs(sdir, tdir, v0, v1, v2, t0, t1, t2);
1389
1390 VectorAdd(sdir, sdirs[index0], sdirs[index0]);
1391 VectorAdd(sdir, sdirs[index1], sdirs[index1]);
1392 VectorAdd(sdir, sdirs[index2], sdirs[index2]);
1393 VectorAdd(tdir, tdirs[index0], tdirs[index0]);
1394 VectorAdd(tdir, tdirs[index1], tdirs[index1]);
1395 VectorAdd(tdir, tdirs[index2], tdirs[index2]);
1396 }
1397 }
1398
1399 for(j = 0, v = surf->verts; j < (surf->numVerts * mdvModel->numFrames); j++, v++)
1400 {
1401 vec3_t normal;
1402 vec4_t tangent;
1403
1404 VectorNormalize(sdirs[j]);
1405 VectorNormalize(tdirs[j]);
1406
1407 R_VaoUnpackNormal(normal, v->normal);
1408
1409 tangent[3] = R_CalcTangentSpace(tangent, NULL, normal, sdirs[j], tdirs[j]);
1410
1411 R_VaoPackTangent(v->tangent, tangent);
1412 }
1413
1414 ri.Free(sdirs);
1415 ri.Free(tdirs);
1416 }
1417
1418 // find the next surface
1419 md3Surf = (md3Surface_t *) ((byte *) md3Surf + md3Surf->ofsEnd);
1420 surf++;
1421 }
1422
1423 {
1424 srfVaoMdvMesh_t *vaoSurf;
1425
1426 mdvModel->numVaoSurfaces = mdvModel->numSurfaces;
1427 mdvModel->vaoSurfaces = ri.Hunk_Alloc(sizeof(*mdvModel->vaoSurfaces) * mdvModel->numSurfaces, h_low);
1428
1429 vaoSurf = mdvModel->vaoSurfaces;
1430 surf = mdvModel->surfaces;
1431 for (i = 0; i < mdvModel->numSurfaces; i++, vaoSurf++, surf++)
1432 {
1433 uint32_t offset_xyz, offset_st, offset_normal, offset_tangent;
1434 uint32_t stride_xyz, stride_st, stride_normal, stride_tangent;
1435 uint32_t dataSize, dataOfs;
1436 uint8_t *data;
1437
1438 if (mdvModel->numFrames > 1)
1439 {
1440 // vertex animation, store texcoords first, then position/normal/tangents
1441 offset_st = 0;
1442 offset_xyz = surf->numVerts * sizeof(vec2_t);
1443 offset_normal = offset_xyz + sizeof(vec3_t);
1444 offset_tangent = offset_normal + sizeof(int16_t) * 4;
1445 stride_st = sizeof(vec2_t);
1446 stride_xyz = sizeof(vec3_t) + sizeof(int16_t) * 4;
1447 stride_xyz += sizeof(int16_t) * 4;
1448 stride_normal = stride_tangent = stride_xyz;
1449
1450 dataSize = offset_xyz + surf->numVerts * mdvModel->numFrames * stride_xyz;
1451 }
1452 else
1453 {
1454 // no animation, interleave everything
1455 offset_xyz = 0;
1456 offset_st = offset_xyz + sizeof(vec3_t);
1457 offset_normal = offset_st + sizeof(vec2_t);
1458 offset_tangent = offset_normal + sizeof(int16_t) * 4;
1459 stride_xyz = offset_tangent + sizeof(int16_t) * 4;
1460 stride_st = stride_normal = stride_tangent = stride_xyz;
1461
1462 dataSize = surf->numVerts * stride_xyz;
1463 }
1464
1465
1466 data = ri.Z_Malloc(dataSize);
1467 dataOfs = 0;
1468
1469 if (mdvModel->numFrames > 1)
1470 {
1471 st = surf->st;
1472 for ( j = 0 ; j < surf->numVerts ; j++, st++ ) {
1473 memcpy(data + dataOfs, &st->st, sizeof(vec2_t));
1474 dataOfs += sizeof(st->st);
1475 }
1476
1477 v = surf->verts;
1478 for ( j = 0; j < surf->numVerts * mdvModel->numFrames ; j++, v++ )
1479 {
1480 // xyz
1481 memcpy(data + dataOfs, &v->xyz, sizeof(vec3_t));
1482 dataOfs += sizeof(vec3_t);
1483
1484 // normal
1485 memcpy(data + dataOfs, &v->normal, sizeof(int16_t) * 4);
1486 dataOfs += sizeof(int16_t) * 4;
1487
1488 // tangent
1489 memcpy(data + dataOfs, &v->tangent, sizeof(int16_t) * 4);
1490 dataOfs += sizeof(int16_t) * 4;
1491 }
1492 }
1493 else
1494 {
1495 v = surf->verts;
1496 st = surf->st;
1497 for ( j = 0; j < surf->numVerts; j++, v++, st++ )
1498 {
1499 // xyz
1500 memcpy(data + dataOfs, &v->xyz, sizeof(vec3_t));
1501 dataOfs += sizeof(v->xyz);
1502
1503 // st
1504 memcpy(data + dataOfs, &st->st, sizeof(vec2_t));
1505 dataOfs += sizeof(st->st);
1506
1507 // normal
1508 memcpy(data + dataOfs, &v->normal, sizeof(int16_t) * 4);
1509 dataOfs += sizeof(int16_t) * 4;
1510
1511 // tangent
1512 memcpy(data + dataOfs, &v->tangent, sizeof(int16_t) * 4);
1513 dataOfs += sizeof(int16_t) * 4;
1514 }
1515 }
1516
1517 vaoSurf->surfaceType = SF_VAO_MDVMESH;
1518 vaoSurf->mdvModel = mdvModel;
1519 vaoSurf->mdvSurface = surf;
1520 vaoSurf->numIndexes = surf->numIndexes;
1521 vaoSurf->numVerts = surf->numVerts;
1522
1523 vaoSurf->vao = R_CreateVao(va("staticMD3Mesh_VAO '%s'", surf->name), data, dataSize, (byte *)surf->indexes, surf->numIndexes * sizeof(*surf->indexes), VAO_USAGE_STATIC);
1524
1525 vaoSurf->vao->attribs[ATTR_INDEX_POSITION].enabled = 1;
1526 vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].enabled = 1;
1527 vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].enabled = 1;
1528 vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].enabled = 1;
1529 vaoSurf->vao->attribs[ATTR_INDEX_POSITION].count = 3;
1530 vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].count = 2;
1531 vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].count = 4;
1532 vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].count = 4;
1533
1534 vaoSurf->vao->attribs[ATTR_INDEX_POSITION].type = GL_FLOAT;
1535 vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].type = GL_FLOAT;
1536 vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].type = GL_SHORT;
1537 vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].type = GL_SHORT;
1538
1539 vaoSurf->vao->attribs[ATTR_INDEX_POSITION].normalized = GL_FALSE;
1540 vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].normalized = GL_FALSE;
1541 vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].normalized = GL_TRUE;
1542 vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].normalized = GL_TRUE;
1543
1544 vaoSurf->vao->attribs[ATTR_INDEX_POSITION].offset = offset_xyz;
1545 vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].offset = offset_st;
1546 vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].offset = offset_normal;
1547 vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].offset = offset_tangent;
1548
1549 vaoSurf->vao->attribs[ATTR_INDEX_POSITION].stride = stride_xyz;
1550 vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].stride = stride_st;
1551 vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].stride = stride_normal;
1552 vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].stride = stride_tangent;
1553
1554 if (mdvModel->numFrames > 1)
1555 {
1556 vaoSurf->vao->attribs[ATTR_INDEX_POSITION2] = vaoSurf->vao->attribs[ATTR_INDEX_POSITION];
1557 vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2 ] = vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ];
1558 vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2 ] = vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ];
1559
1560 vaoSurf->vao->frameSize = stride_xyz * surf->numVerts;
1561 }
1562
1563 Vao_SetVertexPointers(vaoSurf->vao);
1564
1565 ri.Free(data);
1566 }
1567 }
1568
1569 return qtrue;
1570 }
1571
1572 /*
1573 =================
1574 R_LoadMDR
1575 =================
1576 */
R_LoadMDR(model_t * mod,void * buffer,int filesize,const char * mod_name)1577 static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char *mod_name )
1578 {
1579 int i, j, k, l;
1580 mdrHeader_t *pinmodel, *mdr;
1581 mdrFrame_t *frame;
1582 mdrLOD_t *lod, *curlod;
1583 mdrSurface_t *surf, *cursurf;
1584 mdrTriangle_t *tri, *curtri;
1585 mdrVertex_t *v, *curv;
1586 mdrWeight_t *weight, *curweight;
1587 mdrTag_t *tag, *curtag;
1588 int size;
1589 shader_t *sh;
1590
1591 pinmodel = (mdrHeader_t *)buffer;
1592
1593 pinmodel->version = LittleLong(pinmodel->version);
1594 if (pinmodel->version != MDR_VERSION)
1595 {
1596 ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has wrong version (%i should be %i)\n", mod_name, pinmodel->version, MDR_VERSION);
1597 return qfalse;
1598 }
1599
1600 size = LittleLong(pinmodel->ofsEnd);
1601
1602 if(size > filesize)
1603 {
1604 ri.Printf(PRINT_WARNING, "R_LoadMDR: Header of %s is broken. Wrong filesize declared!\n", mod_name);
1605 return qfalse;
1606 }
1607
1608 mod->type = MOD_MDR;
1609
1610 LL(pinmodel->numFrames);
1611 LL(pinmodel->numBones);
1612 LL(pinmodel->ofsFrames);
1613
1614 // This is a model that uses some type of compressed Bones. We don't want to uncompress every bone for each rendered frame
1615 // over and over again, we'll uncompress it in this function already, so we must adjust the size of the target mdr.
1616 if(pinmodel->ofsFrames < 0)
1617 {
1618 // mdrFrame_t is larger than mdrCompFrame_t:
1619 size += pinmodel->numFrames * sizeof(frame->name);
1620 // now add enough space for the uncompressed bones.
1621 size += pinmodel->numFrames * pinmodel->numBones * ((sizeof(mdrBone_t) - sizeof(mdrCompBone_t)));
1622 }
1623
1624 // simple bounds check
1625 if(pinmodel->numBones < 0 ||
1626 sizeof(*mdr) + pinmodel->numFrames * (sizeof(*frame) + (pinmodel->numBones - 1) * sizeof(*frame->bones)) > size)
1627 {
1628 ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
1629 return qfalse;
1630 }
1631
1632 mod->dataSize += size;
1633 mod->modelData = mdr = ri.Hunk_Alloc( size, h_low );
1634
1635 // Copy all the values over from the file and fix endian issues in the process, if necessary.
1636
1637 mdr->ident = LittleLong(pinmodel->ident);
1638 mdr->version = pinmodel->version; // Don't need to swap byte order on this one, we already did above.
1639 Q_strncpyz(mdr->name, pinmodel->name, sizeof(mdr->name));
1640 mdr->numFrames = pinmodel->numFrames;
1641 mdr->numBones = pinmodel->numBones;
1642 mdr->numLODs = LittleLong(pinmodel->numLODs);
1643 mdr->numTags = LittleLong(pinmodel->numTags);
1644 // We don't care about the other offset values, we'll generate them ourselves while loading.
1645
1646 mod->numLods = mdr->numLODs;
1647
1648 if ( mdr->numFrames < 1 )
1649 {
1650 ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has no frames\n", mod_name);
1651 return qfalse;
1652 }
1653
1654 /* The first frame will be put into the first free space after the header */
1655 frame = (mdrFrame_t *)(mdr + 1);
1656 mdr->ofsFrames = (int)((byte *) frame - (byte *) mdr);
1657
1658 if (pinmodel->ofsFrames < 0)
1659 {
1660 mdrCompFrame_t *cframe;
1661
1662 // compressed model...
1663 cframe = (mdrCompFrame_t *)((byte *) pinmodel - pinmodel->ofsFrames);
1664
1665 for(i = 0; i < mdr->numFrames; i++)
1666 {
1667 for(j = 0; j < 3; j++)
1668 {
1669 frame->bounds[0][j] = LittleFloat(cframe->bounds[0][j]);
1670 frame->bounds[1][j] = LittleFloat(cframe->bounds[1][j]);
1671 frame->localOrigin[j] = LittleFloat(cframe->localOrigin[j]);
1672 }
1673
1674 frame->radius = LittleFloat(cframe->radius);
1675 frame->name[0] = '\0'; // No name supplied in the compressed version.
1676
1677 for(j = 0; j < mdr->numBones; j++)
1678 {
1679 for(k = 0; k < (sizeof(cframe->bones[j].Comp) / 2); k++)
1680 {
1681 // Do swapping for the uncompressing functions. They seem to use shorts
1682 // values only, so I assume this will work. Never tested it on other
1683 // platforms, though.
1684
1685 ((unsigned short *)(cframe->bones[j].Comp))[k] =
1686 LittleShort( ((unsigned short *)(cframe->bones[j].Comp))[k] );
1687 }
1688
1689 /* Now do the actual uncompressing */
1690 MC_UnCompress(frame->bones[j].matrix, cframe->bones[j].Comp);
1691 }
1692
1693 // Next Frame...
1694 cframe = (mdrCompFrame_t *) &cframe->bones[j];
1695 frame = (mdrFrame_t *) &frame->bones[j];
1696 }
1697 }
1698 else
1699 {
1700 mdrFrame_t *curframe;
1701
1702 // uncompressed model...
1703 //
1704
1705 curframe = (mdrFrame_t *)((byte *) pinmodel + pinmodel->ofsFrames);
1706
1707 // swap all the frames
1708 for ( i = 0 ; i < mdr->numFrames ; i++)
1709 {
1710 for(j = 0; j < 3; j++)
1711 {
1712 frame->bounds[0][j] = LittleFloat(curframe->bounds[0][j]);
1713 frame->bounds[1][j] = LittleFloat(curframe->bounds[1][j]);
1714 frame->localOrigin[j] = LittleFloat(curframe->localOrigin[j]);
1715 }
1716
1717 frame->radius = LittleFloat(curframe->radius);
1718 Q_strncpyz(frame->name, curframe->name, sizeof(frame->name));
1719
1720 for (j = 0; j < (int) (mdr->numBones * sizeof(mdrBone_t) / 4); j++)
1721 {
1722 ((float *)frame->bones)[j] = LittleFloat( ((float *)curframe->bones)[j] );
1723 }
1724
1725 curframe = (mdrFrame_t *) &curframe->bones[mdr->numBones];
1726 frame = (mdrFrame_t *) &frame->bones[mdr->numBones];
1727 }
1728 }
1729
1730 // frame should now point to the first free address after all frames.
1731 lod = (mdrLOD_t *) frame;
1732 mdr->ofsLODs = (int) ((byte *) lod - (byte *)mdr);
1733
1734 curlod = (mdrLOD_t *)((byte *) pinmodel + LittleLong(pinmodel->ofsLODs));
1735
1736 // swap all the LOD's
1737 for ( l = 0 ; l < mdr->numLODs ; l++)
1738 {
1739 // simple bounds check
1740 if((byte *) (lod + 1) > (byte *) mdr + size)
1741 {
1742 ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
1743 return qfalse;
1744 }
1745
1746 lod->numSurfaces = LittleLong(curlod->numSurfaces);
1747
1748 // swap all the surfaces
1749 surf = (mdrSurface_t *) (lod + 1);
1750 lod->ofsSurfaces = (int)((byte *) surf - (byte *) lod);
1751 cursurf = (mdrSurface_t *) ((byte *)curlod + LittleLong(curlod->ofsSurfaces));
1752
1753 for ( i = 0 ; i < lod->numSurfaces ; i++)
1754 {
1755 // simple bounds check
1756 if((byte *) (surf + 1) > (byte *) mdr + size)
1757 {
1758 ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
1759 return qfalse;
1760 }
1761
1762 // first do some copying stuff
1763
1764 surf->ident = SF_MDR;
1765 Q_strncpyz(surf->name, cursurf->name, sizeof(surf->name));
1766 Q_strncpyz(surf->shader, cursurf->shader, sizeof(surf->shader));
1767
1768 surf->ofsHeader = (byte *) mdr - (byte *) surf;
1769
1770 surf->numVerts = LittleLong(cursurf->numVerts);
1771 surf->numTriangles = LittleLong(cursurf->numTriangles);
1772 // numBoneReferences and BoneReferences generally seem to be unused
1773
1774 // now do the checks that may fail.
1775 if ( surf->numVerts >= SHADER_MAX_VERTEXES )
1776 {
1777 ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i verts on %s (%i).\n",
1778 mod_name, SHADER_MAX_VERTEXES - 1, surf->name[0] ? surf->name : "a surface",
1779 surf->numVerts );
1780 return qfalse;
1781 }
1782 if ( surf->numTriangles*3 >= SHADER_MAX_INDEXES )
1783 {
1784 ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i triangles on %s (%i).\n",
1785 mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, surf->name[0] ? surf->name : "a surface",
1786 surf->numTriangles );
1787 return qfalse;
1788 }
1789 // lowercase the surface name so skin compares are faster
1790 Q_strlwr( surf->name );
1791
1792 // register the shaders
1793 sh = R_FindShader(surf->shader, LIGHTMAP_NONE, qtrue);
1794 if ( sh->defaultShader ) {
1795 surf->shaderIndex = 0;
1796 } else {
1797 surf->shaderIndex = sh->index;
1798 }
1799
1800 // now copy the vertexes.
1801 v = (mdrVertex_t *) (surf + 1);
1802 surf->ofsVerts = (int)((byte *) v - (byte *) surf);
1803 curv = (mdrVertex_t *) ((byte *)cursurf + LittleLong(cursurf->ofsVerts));
1804
1805 for(j = 0; j < surf->numVerts; j++)
1806 {
1807 LL(curv->numWeights);
1808
1809 // simple bounds check
1810 if(curv->numWeights < 0 || (byte *) (v + 1) + (curv->numWeights - 1) * sizeof(*weight) > (byte *) mdr + size)
1811 {
1812 ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
1813 return qfalse;
1814 }
1815
1816 v->normal[0] = LittleFloat(curv->normal[0]);
1817 v->normal[1] = LittleFloat(curv->normal[1]);
1818 v->normal[2] = LittleFloat(curv->normal[2]);
1819
1820 v->texCoords[0] = LittleFloat(curv->texCoords[0]);
1821 v->texCoords[1] = LittleFloat(curv->texCoords[1]);
1822
1823 v->numWeights = curv->numWeights;
1824 weight = &v->weights[0];
1825 curweight = &curv->weights[0];
1826
1827 // Now copy all the weights
1828 for(k = 0; k < v->numWeights; k++)
1829 {
1830 weight->boneIndex = LittleLong(curweight->boneIndex);
1831 weight->boneWeight = LittleFloat(curweight->boneWeight);
1832
1833 weight->offset[0] = LittleFloat(curweight->offset[0]);
1834 weight->offset[1] = LittleFloat(curweight->offset[1]);
1835 weight->offset[2] = LittleFloat(curweight->offset[2]);
1836
1837 weight++;
1838 curweight++;
1839 }
1840
1841 v = (mdrVertex_t *) weight;
1842 curv = (mdrVertex_t *) curweight;
1843 }
1844
1845 // we know the offset to the triangles now:
1846 tri = (mdrTriangle_t *) v;
1847 surf->ofsTriangles = (int)((byte *) tri - (byte *) surf);
1848 curtri = (mdrTriangle_t *)((byte *) cursurf + LittleLong(cursurf->ofsTriangles));
1849
1850 // simple bounds check
1851 if(surf->numTriangles < 0 || (byte *) (tri + surf->numTriangles) > (byte *) mdr + size)
1852 {
1853 ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
1854 return qfalse;
1855 }
1856
1857 for(j = 0; j < surf->numTriangles; j++)
1858 {
1859 tri->indexes[0] = LittleLong(curtri->indexes[0]);
1860 tri->indexes[1] = LittleLong(curtri->indexes[1]);
1861 tri->indexes[2] = LittleLong(curtri->indexes[2]);
1862
1863 tri++;
1864 curtri++;
1865 }
1866
1867 // tri now points to the end of the surface.
1868 surf->ofsEnd = (byte *) tri - (byte *) surf;
1869 surf = (mdrSurface_t *) tri;
1870
1871 // find the next surface.
1872 cursurf = (mdrSurface_t *) ((byte *) cursurf + LittleLong(cursurf->ofsEnd));
1873 }
1874
1875 // surf points to the next lod now.
1876 lod->ofsEnd = (int)((byte *) surf - (byte *) lod);
1877 lod = (mdrLOD_t *) surf;
1878
1879 // find the next LOD.
1880 curlod = (mdrLOD_t *)((byte *) curlod + LittleLong(curlod->ofsEnd));
1881 }
1882
1883 // lod points to the first tag now, so update the offset too.
1884 tag = (mdrTag_t *) lod;
1885 mdr->ofsTags = (int)((byte *) tag - (byte *) mdr);
1886 curtag = (mdrTag_t *) ((byte *)pinmodel + LittleLong(pinmodel->ofsTags));
1887
1888 // simple bounds check
1889 if(mdr->numTags < 0 || (byte *) (tag + mdr->numTags) > (byte *) mdr + size)
1890 {
1891 ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
1892 return qfalse;
1893 }
1894
1895 for (i = 0 ; i < mdr->numTags ; i++)
1896 {
1897 tag->boneIndex = LittleLong(curtag->boneIndex);
1898 Q_strncpyz(tag->name, curtag->name, sizeof(tag->name));
1899
1900 tag++;
1901 curtag++;
1902 }
1903
1904 // And finally we know the real offset to the end.
1905 mdr->ofsEnd = (int)((byte *) tag - (byte *) mdr);
1906
1907 // phew! we're done.
1908
1909 return qtrue;
1910 }
1911
1912
1913 /*
1914 =================
1915 R_LoadMDS
1916 =================
1917 */
R_LoadMDS(model_t * mod,void * buffer,const char * mod_name)1918 static qboolean R_LoadMDS( model_t *mod, void *buffer, const char *mod_name ) {
1919 int i, j, k;
1920 mdsHeader_t *pinmodel, *mds;
1921 mdsFrame_t *frame;
1922 mdsSurface_t *surf;
1923 mdsTriangle_t *tri;
1924 mdsVertex_t *v;
1925 mdsBoneInfo_t *bi;
1926 mdsTag_t *tag;
1927 int version;
1928 int size;
1929 shader_t *sh;
1930 int frameSize;
1931 int *collapseMap, *boneref;
1932
1933 pinmodel = (mdsHeader_t *)buffer;
1934
1935 version = LittleLong( pinmodel->version );
1936 if ( version != MDS_VERSION ) {
1937 ri.Printf( PRINT_WARNING, "R_LoadMDS: %s has wrong version (%i should be %i)\n",
1938 mod_name, version, MDS_VERSION );
1939 return qfalse;
1940 }
1941
1942 mod->type = MOD_MDS;
1943 size = LittleLong( pinmodel->ofsEnd );
1944 mod->dataSize += size;
1945 mds = mod->mds = ri.Hunk_Alloc( size, h_low );
1946
1947 memcpy( mds, buffer, LittleLong( pinmodel->ofsEnd ) );
1948
1949 LL( mds->ident );
1950 LL( mds->version );
1951 LL( mds->numFrames );
1952 LL( mds->numBones );
1953 LL( mds->numTags );
1954 LL( mds->numSurfaces );
1955 LL( mds->ofsFrames );
1956 LL( mds->ofsBones );
1957 LL( mds->ofsTags );
1958 LL( mds->ofsEnd );
1959 LL( mds->ofsSurfaces );
1960 mds->lodBias = LittleFloat( mds->lodBias );
1961 mds->lodScale = LittleFloat( mds->lodScale );
1962 LL( mds->torsoParent );
1963
1964 if ( mds->numFrames < 1 ) {
1965 ri.Printf( PRINT_WARNING, "R_LoadMDS: %s has no frames\n", mod_name );
1966 return qfalse;
1967 }
1968
1969 if ( LittleLong( 1 ) != 1 ) {
1970 // swap all the frames
1971 //frameSize = (int)( &((mdsFrame_t *)0)->bones[ mds->numBones ] );
1972 frameSize = (int) ( sizeof( mdsFrame_t ) - sizeof( mdsBoneFrameCompressed_t ) + mds->numBones * sizeof( mdsBoneFrameCompressed_t ) );
1973 for ( i = 0 ; i < mds->numFrames ; i++, frame++ ) {
1974 frame = ( mdsFrame_t * )( (byte *)mds + mds->ofsFrames + i * frameSize );
1975 frame->radius = LittleFloat( frame->radius );
1976 for ( j = 0 ; j < 3 ; j++ ) {
1977 frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] );
1978 frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] );
1979 frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] );
1980 frame->parentOffset[j] = LittleFloat( frame->parentOffset[j] );
1981 }
1982 for ( j = 0 ; j < mds->numBones * sizeof( mdsBoneFrameCompressed_t ) / sizeof( short ) ; j++ ) {
1983 ( (short *)frame->bones )[j] = LittleShort( ( (short *)frame->bones )[j] );
1984 }
1985 }
1986
1987 // swap all the tags
1988 tag = ( mdsTag_t * )( (byte *)mds + mds->ofsTags );
1989 for ( i = 0 ; i < mds->numTags ; i++, tag++ ) {
1990 LL( tag->boneIndex );
1991 tag->torsoWeight = LittleFloat( tag->torsoWeight );
1992 }
1993
1994 // swap all the bones
1995 for ( i = 0 ; i < mds->numBones ; i++, bi++ ) {
1996 bi = ( mdsBoneInfo_t * )( (byte *)mds + mds->ofsBones + i * sizeof( mdsBoneInfo_t ) );
1997 LL( bi->parent );
1998 bi->torsoWeight = LittleFloat( bi->torsoWeight );
1999 bi->parentDist = LittleFloat( bi->parentDist );
2000 LL( bi->flags );
2001 }
2002 }
2003
2004 // swap all the surfaces
2005 surf = ( mdsSurface_t * )( (byte *)mds + mds->ofsSurfaces );
2006 for ( i = 0 ; i < mds->numSurfaces ; i++ ) {
2007 if ( LittleLong( 1 ) != 1 ) {
2008 LL( surf->ident );
2009 LL( surf->shaderIndex );
2010 LL( surf->minLod );
2011 LL( surf->ofsHeader );
2012 LL( surf->ofsCollapseMap );
2013 LL( surf->numTriangles );
2014 LL( surf->ofsTriangles );
2015 LL( surf->numVerts );
2016 LL( surf->ofsVerts );
2017 LL( surf->numBoneReferences );
2018 LL( surf->ofsBoneReferences );
2019 LL( surf->ofsEnd );
2020 }
2021
2022 // change to surface identifier
2023 surf->ident = SF_MDS;
2024
2025 if ( surf->numVerts >= SHADER_MAX_VERTEXES ) {
2026 ri.Printf(PRINT_WARNING, "R_LoadMDS: %s has more than %i verts on %s (%i).\n",
2027 mod_name, SHADER_MAX_VERTEXES - 1, surf->name[0] ? surf->name : "a surface",
2028 surf->numVerts );
2029 return qfalse;
2030 }
2031 if ( surf->numTriangles*3 >= SHADER_MAX_INDEXES ) {
2032 ri.Printf(PRINT_WARNING, "R_LoadMDS: %s has more than %i triangles on %s (%i).\n",
2033 mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, surf->name[0] ? surf->name : "a surface",
2034 surf->numTriangles );
2035 return qfalse;
2036 }
2037
2038 // register the shaders
2039 if ( surf->shader[0] ) {
2040 sh = R_FindShader( surf->shader, LIGHTMAP_NONE, qtrue );
2041 if ( sh->defaultShader ) {
2042 surf->shaderIndex = 0;
2043 } else {
2044 surf->shaderIndex = sh->index;
2045 }
2046 } else {
2047 surf->shaderIndex = 0;
2048 }
2049
2050 if ( LittleLong( 1 ) != 1 ) {
2051 // swap all the triangles
2052 tri = ( mdsTriangle_t * )( (byte *)surf + surf->ofsTriangles );
2053 for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
2054 LL( tri->indexes[0] );
2055 LL( tri->indexes[1] );
2056 LL( tri->indexes[2] );
2057 }
2058
2059 // swap all the vertexes
2060 v = ( mdsVertex_t * )( (byte *)surf + surf->ofsVerts );
2061 for ( j = 0 ; j < surf->numVerts ; j++ ) {
2062 v->normal[0] = LittleFloat( v->normal[0] );
2063 v->normal[1] = LittleFloat( v->normal[1] );
2064 v->normal[2] = LittleFloat( v->normal[2] );
2065
2066 v->texCoords[0] = LittleFloat( v->texCoords[0] );
2067 v->texCoords[1] = LittleFloat( v->texCoords[1] );
2068
2069 v->numWeights = LittleLong( v->numWeights );
2070
2071 for ( k = 0 ; k < v->numWeights ; k++ ) {
2072 v->weights[k].boneIndex = LittleLong( v->weights[k].boneIndex );
2073 v->weights[k].boneWeight = LittleFloat( v->weights[k].boneWeight );
2074 v->weights[k].offset[0] = LittleFloat( v->weights[k].offset[0] );
2075 v->weights[k].offset[1] = LittleFloat( v->weights[k].offset[1] );
2076 v->weights[k].offset[2] = LittleFloat( v->weights[k].offset[2] );
2077 }
2078
2079 v = (mdsVertex_t *)&v->weights[v->numWeights];
2080 }
2081
2082 // swap the collapse map
2083 collapseMap = ( int * )( (byte *)surf + surf->ofsCollapseMap );
2084 for ( j = 0; j < surf->numVerts; j++, collapseMap++ ) {
2085 *collapseMap = LittleLong( *collapseMap );
2086 }
2087
2088 // swap the bone references
2089 boneref = ( int * )( ( byte *)surf + surf->ofsBoneReferences );
2090 for ( j = 0; j < surf->numBoneReferences; j++, boneref++ ) {
2091 *boneref = LittleLong( *boneref );
2092 }
2093 }
2094
2095 // find the next surface
2096 surf = ( mdsSurface_t * )( (byte *)surf + surf->ofsEnd );
2097 }
2098
2099 return qtrue;
2100 }
2101
2102
2103
2104
2105 //=============================================================================
2106
2107 /*
2108 ** RE_BeginRegistration
2109 */
RE_BeginRegistration(glconfig_t * glconfigOut)2110 void RE_BeginRegistration( glconfig_t *glconfigOut ) {
2111 int i;
2112
2113 ri.Hunk_Clear(); // (SA) MEM NOTE: not in missionpack
2114
2115 R_Init();
2116 *glconfigOut = glConfig;
2117
2118 R_IssuePendingRenderCommands();
2119
2120 tr.visIndex = 0;
2121 // force markleafs to regenerate
2122 for(i = 0; i < MAX_VISCOUNTS; i++) {
2123 tr.visClusters[i] = -2;
2124 }
2125
2126 R_ClearFlares();
2127 RE_ClearScene();
2128
2129 tr.registered = qtrue;
2130 }
2131
2132 /*
2133 ===============
2134 R_ModelInit
2135 ===============
2136 */
R_ModelInit(void)2137 void R_ModelInit( void ) {
2138 model_t *mod;
2139
2140 // leave a space for NULL model
2141 tr.numModels = 0;
2142
2143 mod = R_AllocModel();
2144 mod->type = MOD_BAD;
2145 }
2146
2147
2148 /*
2149 ================
2150 R_Modellist_f
2151 ================
2152 */
2153
R_Modellist_f(void)2154 void R_Modellist_f( void ) {
2155 int i, j;
2156 model_t *mod;
2157 int total;
2158 int lods;
2159
2160 total = 0;
2161 for ( i = 1 ; i < tr.numModels; i++ ) {
2162 mod = tr.models[i];
2163 lods = 1;
2164 for ( j = 1 ; j < MD3_MAX_LODS ; j++ ) {
2165 if ( mod->mdv[j] && mod->mdv[j] != mod->mdv[j - 1] ) {
2166 lods++;
2167 }
2168 }
2169 ri.Printf( PRINT_ALL, "%8i : (%i) %s\n",mod->dataSize, lods, mod->name );
2170 total += mod->dataSize;
2171 }
2172 ri.Printf( PRINT_ALL, "%8i : Total models\n", total );
2173 }
2174
2175
2176 //=============================================================================
2177
2178
2179 /*
2180 ================
2181 R_GetTag
2182 ================
2183 */
R_GetTag(mdvModel_t * model,int frame,const char * _tagName,int startTagIndex,mdvTag_t ** outTag)2184 static int R_GetTag(mdvModel_t * model, int frame, const char *_tagName, int startTagIndex, mdvTag_t ** outTag)
2185 {
2186 int i;
2187 mdvTag_t *tag;
2188 mdvTagName_t *tagName;
2189
2190 if ( frame >= model->numFrames ) {
2191 // it is possible to have a bad frame while changing models, so don't error
2192 frame = model->numFrames - 1;
2193 }
2194
2195 if(startTagIndex > model->numTags)
2196 {
2197 *outTag = NULL;
2198 return -1;
2199 }
2200
2201 #if 1
2202 tag = model->tags + frame * model->numTags;
2203 tagName = model->tagNames;
2204 for(i = 0; i < model->numTags; i++, tag++, tagName++)
2205 {
2206 if((i >= startTagIndex) && !strcmp(tagName->name, _tagName))
2207 {
2208 *outTag = tag;
2209 return i;
2210 }
2211 }
2212 #endif
2213
2214 *outTag = NULL;
2215 return -1;
2216 }
2217
R_GetAnimTag(mdrHeader_t * mod,int framenum,const char * tagName,int startTagIndex,mdvTag_t ** outTag)2218 static int R_GetAnimTag( mdrHeader_t *mod, int framenum, const char *tagName, int startTagIndex, mdvTag_t **outTag)
2219 {
2220 int i, j, k;
2221 int frameSize;
2222 mdrFrame_t *frame;
2223 mdrTag_t *tag;
2224 mdvTag_t *dest = *outTag;
2225
2226 if ( framenum >= mod->numFrames )
2227 {
2228 // it is possible to have a bad frame while changing models, so don't error
2229 framenum = mod->numFrames - 1;
2230 }
2231
2232 if ( startTagIndex > mod->numTags )
2233 {
2234 *outTag = NULL;
2235 return -1;
2236 }
2237
2238 tag = (mdrTag_t *)((byte *)mod + mod->ofsTags);
2239 for ( i = 0 ; i < mod->numTags ; i++, tag++ )
2240 {
2241 if ( ( i >= startTagIndex ) && !strcmp( tag->name, tagName ) )
2242 {
2243 // uncompressed model...
2244 //
2245 frameSize = (intptr_t)( &((mdrFrame_t *)0)->bones[ mod->numBones ] );
2246 frame = (mdrFrame_t *)((byte *)mod + mod->ofsFrames + framenum * frameSize );
2247
2248 for (j = 0; j < 3; j++)
2249 {
2250 for (k = 0; k < 3; k++)
2251 dest->axis[j][k]=frame->bones[tag->boneIndex].matrix[k][j];
2252 }
2253
2254 dest->origin[0]=frame->bones[tag->boneIndex].matrix[0][3];
2255 dest->origin[1]=frame->bones[tag->boneIndex].matrix[1][3];
2256 dest->origin[2]=frame->bones[tag->boneIndex].matrix[2][3];
2257
2258 return i;
2259 }
2260 }
2261
2262 *outTag = NULL;
2263 return -1;
2264 }
2265
2266
2267 /*
2268 ================
2269 R_LerpTag
2270
2271 returns the index of the tag it found, for cycling through tags with the same name
2272 ================
2273 */
R_LerpTag(orientation_t * tag,const refEntity_t * refent,const char * tagNameIn,int startIndex)2274 int R_LerpTag( orientation_t *tag, const refEntity_t *refent, const char *tagNameIn, int startIndex ) {
2275 mdvTag_t *start, *end;
2276 mdvTag_t start_space, end_space;
2277 int i;
2278 float frontLerp, backLerp;
2279 model_t *model;
2280 char tagName[MAX_QPATH]; //, *ch;
2281 int retval = 0;
2282 qhandle_t handle;
2283 int startFrame, endFrame;
2284 float frac;
2285
2286 handle = refent->hModel;
2287 startFrame = refent->oldframe;
2288 endFrame = refent->frame;
2289 frac = 1.0 - refent->backlerp;
2290
2291 Q_strncpyz( tagName, tagNameIn, MAX_QPATH );
2292
2293 model = R_GetModelByHandle( handle );
2294 if ( !model->mdv[0] /*&& !model->mdc[0]*/ && !model->mds ) {
2295 if(model->type == MOD_MDR)
2296 {
2297 start = &start_space;
2298 end = &end_space;
2299 retval = R_GetAnimTag((mdrHeader_t *) model->modelData, startFrame, tagName, startIndex, &start);
2300 R_GetAnimTag((mdrHeader_t *) model->modelData, endFrame, tagName, startIndex, &end);
2301 }
2302 else if ( model->type == MOD_IQM ) {
2303 return R_IQMLerpTag( tag, model->modelData,
2304 startFrame, endFrame,
2305 frac, tagName, startIndex );
2306 } else {
2307 start = end = NULL;
2308 }
2309 } else if ( model->type == MOD_MESH ) {
2310 // old MD3 style
2311 retval = R_GetTag(model->mdv[0], startFrame, tagName, startIndex, &start);
2312 R_GetTag(model->mdv[0], endFrame, tagName, startIndex, &end);
2313 } else if ( model->type == MOD_MDS ) { // use bone lerping
2314
2315 retval = R_GetBoneTag( tag, model->mds, startIndex, refent, tagNameIn );
2316
2317 if ( retval >= 0 ) {
2318 return retval;
2319 }
2320
2321 // failed
2322 return -1;
2323 } else {
2324 // failed
2325 return -1;
2326 }
2327
2328 if ( !start || !end ) {
2329 AxisClear( tag->axis );
2330 VectorClear( tag->origin );
2331 return -1;
2332 }
2333
2334 frontLerp = frac;
2335 backLerp = 1.0f - frac;
2336
2337 for ( i = 0 ; i < 3 ; i++ ) {
2338 tag->origin[i] = start->origin[i] * backLerp + end->origin[i] * frontLerp;
2339 tag->axis[0][i] = start->axis[0][i] * backLerp + end->axis[0][i] * frontLerp;
2340 tag->axis[1][i] = start->axis[1][i] * backLerp + end->axis[1][i] * frontLerp;
2341 tag->axis[2][i] = start->axis[2][i] * backLerp + end->axis[2][i] * frontLerp;
2342 }
2343
2344 VectorNormalize( tag->axis[0] );
2345 VectorNormalize( tag->axis[1] );
2346 VectorNormalize( tag->axis[2] );
2347
2348 return retval;
2349 }
2350
2351 /*
2352 ===============
2353 R_TagInfo_f
2354 ===============
2355 */
R_TagInfo_f(void)2356 void R_TagInfo_f( void ) {
2357 Com_Printf( "command not functional\n" );
2358 }
2359
2360
2361 /*
2362 ====================
2363 R_ModelBounds
2364 ====================
2365 */
R_ModelBounds(qhandle_t handle,vec3_t mins,vec3_t maxs)2366 void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) {
2367 model_t *model;
2368
2369 model = R_GetModelByHandle( handle );
2370
2371 if ( model->bmodel ) {
2372 VectorCopy( model->bmodel->bounds[0], mins );
2373 VectorCopy( model->bmodel->bounds[1], maxs );
2374 return;
2375 }
2376
2377 // Ridah
2378 if ( model->mdv[0] ) {
2379 mdvModel_t *header;
2380 mdvFrame_t *frame;
2381
2382 header = model->mdv[0];
2383 frame = header->frames;
2384
2385 VectorCopy( frame->bounds[0], mins );
2386 VectorCopy( frame->bounds[1], maxs );
2387 return;
2388 } else if (model->type == MOD_MDR) {
2389 mdrHeader_t *header;
2390 mdrFrame_t *frame;
2391
2392 header = (mdrHeader_t *)model->modelData;
2393 frame = (mdrFrame_t *) ((byte *)header + header->ofsFrames);
2394
2395 VectorCopy( frame->bounds[0], mins );
2396 VectorCopy( frame->bounds[1], maxs );
2397
2398 return;
2399 } else if(model->type == MOD_IQM) {
2400 iqmData_t *iqmData;
2401
2402 iqmData = model->modelData;
2403
2404 if(iqmData->bounds)
2405 {
2406 VectorCopy(iqmData->bounds, mins);
2407 VectorCopy(iqmData->bounds + 3, maxs);
2408 return;
2409 }
2410 }
2411
2412 VectorClear( mins );
2413 VectorClear( maxs );
2414 // done.
2415 }
2416
2417
R_Hunk_Begin(void)2418 void *R_Hunk_Begin( void ) {
2419 return NULL;
2420 }
2421
R_Hunk_Alloc(int size)2422 void *R_Hunk_Alloc( int size ) {
2423 return NULL;
2424 }
2425
2426 // this is only called when we shutdown GL
R_Hunk_End(void)2427 void R_Hunk_End( void ) {
2428 return;
2429 }
2430
R_Hunk_Reset(void)2431 void R_Hunk_Reset( void ) {
2432 return;
2433 }
2434
2435