Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

tr_model.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 // tr_models.c -- model loading and caching
00023 
00024 #include "tr_local.h"
00025 
00026 #define LL(x) x=LittleLong(x)
00027 
00028 static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *name );
00029 static qboolean R_LoadMD4 (model_t *mod, void *buffer, const char *name );
00030 
00031 model_t *loadmodel;
00032 
00033 /*
00034 ** R_GetModelByHandle
00035 */
00036 model_t *R_GetModelByHandle( qhandle_t index ) {
00037     model_t     *mod;
00038 
00039     // out of range gets the defualt model
00040     if ( index < 1 || index >= tr.numModels ) {
00041         return tr.models[0];
00042     }
00043 
00044     mod = tr.models[index];
00045 
00046     return mod;
00047 }
00048 
00049 //===============================================================================
00050 
00051 /*
00052 ** R_AllocModel
00053 */
00054 model_t *R_AllocModel( void ) {
00055     model_t     *mod;
00056 
00057     if ( tr.numModels == MAX_MOD_KNOWN ) {
00058         return NULL;
00059     }
00060 
00061     mod = ri.Hunk_Alloc( sizeof( *tr.models[tr.numModels] ), h_low );
00062     mod->index = tr.numModels;
00063     tr.models[tr.numModels] = mod;
00064     tr.numModels++;
00065 
00066     return mod;
00067 }
00068 
00069 /*
00070 ====================
00071 RE_RegisterModel
00072 
00073 Loads in a model for the given name
00074 
00075 Zero will be returned if the model fails to load.
00076 An entry will be retained for failed models as an
00077 optimization to prevent disk rescanning if they are
00078 asked for again.
00079 ====================
00080 */
00081 qhandle_t RE_RegisterModel( const char *name ) {
00082     model_t     *mod;
00083     unsigned    *buf;
00084     int         lod;
00085     int         ident;
00086     qboolean    loaded;
00087     qhandle_t   hModel;
00088     int         numLoaded;
00089 
00090     if ( !name || !name[0] ) {
00091         ri.Printf( PRINT_ALL, "RE_RegisterModel: NULL name\n" );
00092         return 0;
00093     }
00094 
00095     if ( strlen( name ) >= MAX_QPATH ) {
00096         Com_Printf( "Model name exceeds MAX_QPATH\n" );
00097         return 0;
00098     }
00099 
00100     //
00101     // search the currently loaded models
00102     //
00103     for ( hModel = 1 ; hModel < tr.numModels; hModel++ ) {
00104         mod = tr.models[hModel];
00105         if ( !strcmp( mod->name, name ) ) {
00106             if( mod->type == MOD_BAD ) {
00107                 return 0;
00108             }
00109             return hModel;
00110         }
00111     }
00112 
00113     // allocate a new model_t
00114 
00115     if ( ( mod = R_AllocModel() ) == NULL ) {
00116         ri.Printf( PRINT_WARNING, "RE_RegisterModel: R_AllocModel() failed for '%s'\n", name);
00117         return 0;
00118     }
00119 
00120     // only set the name after the model has been successfully loaded
00121     Q_strncpyz( mod->name, name, sizeof( mod->name ) );
00122 
00123 
00124     // make sure the render thread is stopped
00125     R_SyncRenderThread();
00126 
00127     mod->numLods = 0;
00128 
00129     //
00130     // load the files
00131     //
00132     numLoaded = 0;
00133 
00134     for ( lod = MD3_MAX_LODS - 1 ; lod >= 0 ; lod-- ) {
00135         char filename[1024];
00136 
00137         strcpy( filename, name );
00138 
00139         if ( lod != 0 ) {
00140             char namebuf[80];
00141 
00142             if ( strrchr( filename, '.' ) ) {
00143                 *strrchr( filename, '.' ) = 0;
00144             }
00145             sprintf( namebuf, "_%d.md3", lod );
00146             strcat( filename, namebuf );
00147         }
00148 
00149         ri.FS_ReadFile( filename, (void **)&buf );
00150         if ( !buf ) {
00151             continue;
00152         }
00153         
00154         loadmodel = mod;
00155         
00156         ident = LittleLong(*(unsigned *)buf);
00157         if ( ident == MD4_IDENT ) {
00158             loaded = R_LoadMD4( mod, buf, name );
00159         } else {
00160             if ( ident != MD3_IDENT ) {
00161                 ri.Printf (PRINT_WARNING,"RE_RegisterModel: unknown fileid for %s\n", name);
00162                 goto fail;
00163             }
00164 
00165             loaded = R_LoadMD3( mod, lod, buf, name );
00166         }
00167         
00168         ri.FS_FreeFile (buf);
00169 
00170         if ( !loaded ) {
00171             if ( lod == 0 ) {
00172                 goto fail;
00173             } else {
00174                 break;
00175             }
00176         } else {
00177             mod->numLods++;
00178             numLoaded++;
00179             // if we have a valid model and are biased
00180             // so that we won't see any higher detail ones,
00181             // stop loading them
00182 //          if ( lod <= r_lodbias->integer ) {
00183 //              break;
00184 //          }
00185         }
00186     }
00187 
00188     if ( numLoaded ) {
00189         // duplicate into higher lod spots that weren't
00190         // loaded, in case the user changes r_lodbias on the fly
00191         for ( lod-- ; lod >= 0 ; lod-- ) {
00192             mod->numLods++;
00193             mod->md3[lod] = mod->md3[lod+1];
00194         }
00195 
00196         return mod->index;
00197     }
00198 #ifdef _DEBUG
00199     else {
00200         ri.Printf (PRINT_WARNING,"RE_RegisterModel: couldn't load %s\n", name);
00201     }
00202 #endif
00203 
00204 fail:
00205     // we still keep the model_t around, so if the model name is asked for
00206     // again, we won't bother scanning the filesystem
00207     mod->type = MOD_BAD;
00208     return 0;
00209 }
00210 
00211 
00212 /*
00213 =================
00214 R_LoadMD3
00215 =================
00216 */
00217 static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_name ) {
00218     int                 i, j;
00219     md3Header_t         *pinmodel;
00220     md3Frame_t          *frame;
00221     md3Surface_t        *surf;
00222     md3Shader_t         *shader;
00223     md3Triangle_t       *tri;
00224     md3St_t             *st;
00225     md3XyzNormal_t      *xyz;
00226     md3Tag_t            *tag;
00227     int                 version;
00228     int                 size;
00229 
00230     pinmodel = (md3Header_t *)buffer;
00231 
00232     version = LittleLong (pinmodel->version);
00233     if (version != MD3_VERSION) {
00234         ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has wrong version (%i should be %i)\n",
00235                  mod_name, version, MD3_VERSION);
00236         return qfalse;
00237     }
00238 
00239     mod->type = MOD_MESH;
00240     size = LittleLong(pinmodel->ofsEnd);
00241     mod->dataSize += size;
00242     mod->md3[lod] = ri.Hunk_Alloc( size, h_low );
00243 
00244     Com_Memcpy (mod->md3[lod], buffer, LittleLong(pinmodel->ofsEnd) );
00245 
00246     LL(mod->md3[lod]->ident);
00247     LL(mod->md3[lod]->version);
00248     LL(mod->md3[lod]->numFrames);
00249     LL(mod->md3[lod]->numTags);
00250     LL(mod->md3[lod]->numSurfaces);
00251     LL(mod->md3[lod]->ofsFrames);
00252     LL(mod->md3[lod]->ofsTags);
00253     LL(mod->md3[lod]->ofsSurfaces);
00254     LL(mod->md3[lod]->ofsEnd);
00255 
00256     if ( mod->md3[lod]->numFrames < 1 ) {
00257         ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has no frames\n", mod_name );
00258         return qfalse;
00259     }
00260     
00261     // swap all the frames
00262     frame = (md3Frame_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsFrames );
00263     for ( i = 0 ; i < mod->md3[lod]->numFrames ; i++, frame++) {
00264         frame->radius = LittleFloat( frame->radius );
00265         for ( j = 0 ; j < 3 ; j++ ) {
00266             frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] );
00267             frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] );
00268             frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] );
00269         }
00270     }
00271 
00272     // swap all the tags
00273     tag = (md3Tag_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsTags );
00274     for ( i = 0 ; i < mod->md3[lod]->numTags * mod->md3[lod]->numFrames ; i++, tag++) {
00275         for ( j = 0 ; j < 3 ; j++ ) {
00276             tag->origin[j] = LittleFloat( tag->origin[j] );
00277             tag->axis[0][j] = LittleFloat( tag->axis[0][j] );
00278             tag->axis[1][j] = LittleFloat( tag->axis[1][j] );
00279             tag->axis[2][j] = LittleFloat( tag->axis[2][j] );
00280         }
00281     }
00282 
00283     // swap all the surfaces
00284     surf = (md3Surface_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsSurfaces );
00285     for ( i = 0 ; i < mod->md3[lod]->numSurfaces ; i++) {
00286 
00287         LL(surf->ident);
00288         LL(surf->flags);
00289         LL(surf->numFrames);
00290         LL(surf->numShaders);
00291         LL(surf->numTriangles);
00292         LL(surf->ofsTriangles);
00293         LL(surf->numVerts);
00294         LL(surf->ofsShaders);
00295         LL(surf->ofsSt);
00296         LL(surf->ofsXyzNormals);
00297         LL(surf->ofsEnd);
00298         
00299         if ( surf->numVerts > SHADER_MAX_VERTEXES ) {
00300             ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i verts on a surface (%i)",
00301                 mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
00302         }
00303         if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) {
00304             ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i triangles on a surface (%i)",
00305                 mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
00306         }
00307     
00308         // change to surface identifier
00309         surf->ident = SF_MD3;
00310 
00311         // lowercase the surface name so skin compares are faster
00312         Q_strlwr( surf->name );
00313 
00314         // strip off a trailing _1 or _2
00315         // this is a crutch for q3data being a mess
00316         j = strlen( surf->name );
00317         if ( j > 2 && surf->name[j-2] == '_' ) {
00318             surf->name[j-2] = 0;
00319         }
00320 
00321         // register the shaders
00322         shader = (md3Shader_t *) ( (byte *)surf + surf->ofsShaders );
00323         for ( j = 0 ; j < surf->numShaders ; j++, shader++ ) {
00324             shader_t    *sh;
00325 
00326             sh = R_FindShader( shader->name, LIGHTMAP_NONE, qtrue );
00327             if ( sh->defaultShader ) {
00328                 shader->shaderIndex = 0;
00329             } else {
00330                 shader->shaderIndex = sh->index;
00331             }
00332         }
00333 
00334         // swap all the triangles
00335         tri = (md3Triangle_t *) ( (byte *)surf + surf->ofsTriangles );
00336         for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
00337             LL(tri->indexes[0]);
00338             LL(tri->indexes[1]);
00339             LL(tri->indexes[2]);
00340         }
00341 
00342         // swap all the ST
00343         st = (md3St_t *) ( (byte *)surf + surf->ofsSt );
00344         for ( j = 0 ; j < surf->numVerts ; j++, st++ ) {
00345             st->st[0] = LittleFloat( st->st[0] );
00346             st->st[1] = LittleFloat( st->st[1] );
00347         }
00348 
00349         // swap all the XyzNormals
00350         xyz = (md3XyzNormal_t *) ( (byte *)surf + surf->ofsXyzNormals );
00351         for ( j = 0 ; j < surf->numVerts * surf->numFrames ; j++, xyz++ ) 
00352         {
00353             xyz->xyz[0] = LittleShort( xyz->xyz[0] );
00354             xyz->xyz[1] = LittleShort( xyz->xyz[1] );
00355             xyz->xyz[2] = LittleShort( xyz->xyz[2] );
00356 
00357             xyz->normal = LittleShort( xyz->normal );
00358         }
00359 
00360 
00361         // find the next surface
00362         surf = (md3Surface_t *)( (byte *)surf + surf->ofsEnd );
00363     }
00364     
00365     return qtrue;
00366 }
00367 
00368 
00369 
00370 /*
00371 =================
00372 R_LoadMD4
00373 =================
00374 */
00375 static qboolean R_LoadMD4( model_t *mod, void *buffer, const char *mod_name ) {
00376     int                 i, j, k, lodindex;
00377     md4Header_t         *pinmodel, *md4;
00378     md4Frame_t          *frame;
00379     md4LOD_t            *lod;
00380     md4Surface_t        *surf;
00381     md4Triangle_t       *tri;
00382     md4Vertex_t         *v;
00383     int                 version;
00384     int                 size;
00385     shader_t            *sh;
00386     int                 frameSize;
00387 
00388     pinmodel = (md4Header_t *)buffer;
00389 
00390     version = LittleLong (pinmodel->version);
00391     if (version != MD4_VERSION) {
00392         ri.Printf( PRINT_WARNING, "R_LoadMD4: %s has wrong version (%i should be %i)\n",
00393                  mod_name, version, MD4_VERSION);
00394         return qfalse;
00395     }
00396 
00397     mod->type = MOD_MD4;
00398     size = LittleLong(pinmodel->ofsEnd);
00399     mod->dataSize += size;
00400     md4 = mod->md4 = ri.Hunk_Alloc( size, h_low );
00401 
00402     Com_Memcpy( md4, buffer, LittleLong(pinmodel->ofsEnd) );
00403 
00404     LL(md4->ident);
00405     LL(md4->version);
00406     LL(md4->numFrames);
00407     LL(md4->numBones);
00408     LL(md4->numLODs);
00409     LL(md4->ofsFrames);
00410     LL(md4->ofsLODs);
00411     LL(md4->ofsEnd);
00412 
00413     if ( md4->numFrames < 1 ) {
00414         ri.Printf( PRINT_WARNING, "R_LoadMD4: %s has no frames\n", mod_name );
00415         return qfalse;
00416     }
00417 
00418     // we don't need to swap tags in the renderer, they aren't used
00419     
00420     // swap all the frames
00421     frameSize = (int)( &((md4Frame_t *)0)->bones[ md4->numBones ] );
00422     for ( i = 0 ; i < md4->numFrames ; i++, frame++) {
00423         frame = (md4Frame_t *) ( (byte *)md4 + md4->ofsFrames + i * frameSize );
00424         frame->radius = LittleFloat( frame->radius );
00425         for ( j = 0 ; j < 3 ; j++ ) {
00426             frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] );
00427             frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] );
00428             frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] );
00429         }
00430         for ( j = 0 ; j < md4->numBones * sizeof( md4Bone_t ) / 4 ; j++ ) {
00431             ((float *)frame->bones)[j] = LittleFloat( ((float *)frame->bones)[j] );
00432         }
00433     }
00434 
00435     // swap all the LOD's
00436     lod = (md4LOD_t *) ( (byte *)md4 + md4->ofsLODs );
00437     for ( lodindex = 0 ; lodindex < md4->numLODs ; lodindex++ ) {
00438 
00439         // swap all the surfaces
00440         surf = (md4Surface_t *) ( (byte *)lod + lod->ofsSurfaces );
00441         for ( i = 0 ; i < lod->numSurfaces ; i++) {
00442             LL(surf->ident);
00443             LL(surf->numTriangles);
00444             LL(surf->ofsTriangles);
00445             LL(surf->numVerts);
00446             LL(surf->ofsVerts);
00447             LL(surf->ofsEnd);
00448             
00449             if ( surf->numVerts > SHADER_MAX_VERTEXES ) {
00450                 ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i verts on a surface (%i)",
00451                     mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
00452             }
00453             if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) {
00454                 ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i triangles on a surface (%i)",
00455                     mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
00456             }
00457 
00458             // change to surface identifier
00459             surf->ident = SF_MD4;
00460 
00461             // lowercase the surface name so skin compares are faster
00462             Q_strlwr( surf->name );
00463         
00464             // register the shaders
00465             sh = R_FindShader( surf->shader, LIGHTMAP_NONE, qtrue );
00466             if ( sh->defaultShader ) {
00467                 surf->shaderIndex = 0;
00468             } else {
00469                 surf->shaderIndex = sh->index;
00470             }
00471 
00472             // swap all the triangles
00473             tri = (md4Triangle_t *) ( (byte *)surf + surf->ofsTriangles );
00474             for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
00475                 LL(tri->indexes[0]);
00476                 LL(tri->indexes[1]);
00477                 LL(tri->indexes[2]);
00478             }
00479 
00480             // swap all the vertexes
00481             // FIXME
00482             // This makes TFC's skeletons work.  Shouldn't be necessary anymore, but left
00483             // in for reference.
00484             //v = (md4Vertex_t *) ( (byte *)surf + surf->ofsVerts + 12);
00485             v = (md4Vertex_t *) ( (byte *)surf + surf->ofsVerts);
00486             for ( j = 0 ; j < surf->numVerts ; j++ ) {
00487                 v->normal[0] = LittleFloat( v->normal[0] );
00488                 v->normal[1] = LittleFloat( v->normal[1] );
00489                 v->normal[2] = LittleFloat( v->normal[2] );
00490 
00491                 v->texCoords[0] = LittleFloat( v->texCoords[0] );
00492                 v->texCoords[1] = LittleFloat( v->texCoords[1] );
00493 
00494                 v->numWeights = LittleLong( v->numWeights );
00495 
00496                 for ( k = 0 ; k < v->numWeights ; k++ ) {
00497                     v->weights[k].boneIndex = LittleLong( v->weights[k].boneIndex );
00498                     v->weights[k].boneWeight = LittleFloat( v->weights[k].boneWeight );
00499                    v->weights[k].offset[0] = LittleFloat( v->weights[k].offset[0] );
00500                    v->weights[k].offset[1] = LittleFloat( v->weights[k].offset[1] );
00501                    v->weights[k].offset[2] = LittleFloat( v->weights[k].offset[2] );
00502                 }
00503                 // FIXME
00504                 // This makes TFC's skeletons work.  Shouldn't be necessary anymore, but left
00505                 // in for reference.
00506                 //v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights] + 12 );
00507                 v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights]);
00508             }
00509 
00510             // find the next surface
00511             surf = (md4Surface_t *)( (byte *)surf + surf->ofsEnd );
00512         }
00513 
00514         // find the next LOD
00515         lod = (md4LOD_t *)( (byte *)lod + lod->ofsEnd );
00516     }
00517 
00518     return qtrue;
00519 }
00520 
00521 
00522 
00523 
00524 //=============================================================================
00525 
00526 /*
00527 ** RE_BeginRegistration
00528 */
00529 void RE_BeginRegistration( glconfig_t *glconfigOut ) {
00530 
00531     R_Init();
00532 
00533     *glconfigOut = glConfig;
00534 
00535     R_SyncRenderThread();
00536 
00537     tr.viewCluster = -1;        // force markleafs to regenerate
00538     R_ClearFlares();
00539     RE_ClearScene();
00540 
00541     tr.registered = qtrue;
00542 
00543     // NOTE: this sucks, for some reason the first stretch pic is never drawn
00544     // without this we'd see a white flash on a level load because the very
00545     // first time the level shot would not be drawn
00546     RE_StretchPic(0, 0, 0, 0, 0, 0, 1, 1, 0);
00547 }
00548 
00549 //=============================================================================
00550 
00551 /*
00552 ===============
00553 R_ModelInit
00554 ===============
00555 */
00556 void R_ModelInit( void ) {
00557     model_t     *mod;
00558 
00559     // leave a space for NULL model
00560     tr.numModels = 0;
00561 
00562     mod = R_AllocModel();
00563     mod->type = MOD_BAD;
00564 }
00565 
00566 
00567 /*
00568 ================
00569 R_Modellist_f
00570 ================
00571 */
00572 void R_Modellist_f( void ) {
00573     int     i, j;
00574     model_t *mod;
00575     int     total;
00576     int     lods;
00577 
00578     total = 0;
00579     for ( i = 1 ; i < tr.numModels; i++ ) {
00580         mod = tr.models[i];
00581         lods = 1;
00582         for ( j = 1 ; j < MD3_MAX_LODS ; j++ ) {
00583             if ( mod->md3[j] && mod->md3[j] != mod->md3[j-1] ) {
00584                 lods++;
00585             }
00586         }
00587         ri.Printf( PRINT_ALL, "%8i : (%i) %s\n",mod->dataSize, lods, mod->name );
00588         total += mod->dataSize;
00589     }
00590     ri.Printf( PRINT_ALL, "%8i : Total models\n", total );
00591 
00592 #if 0       // not working right with new hunk
00593     if ( tr.world ) {
00594         ri.Printf( PRINT_ALL, "\n%8i : %s\n", tr.world->dataSize, tr.world->name );
00595     }
00596 #endif
00597 }
00598 
00599 
00600 //=============================================================================
00601 
00602 
00603 /*
00604 ================
00605 R_GetTag
00606 ================
00607 */
00608 static md3Tag_t *R_GetTag( md3Header_t *mod, int frame, const char *tagName ) {
00609     md3Tag_t        *tag;
00610     int             i;
00611 
00612     if ( frame >= mod->numFrames ) {
00613         // it is possible to have a bad frame while changing models, so don't error
00614         frame = mod->numFrames - 1;
00615     }
00616 
00617     tag = (md3Tag_t *)((byte *)mod + mod->ofsTags) + frame * mod->numTags;
00618     for ( i = 0 ; i < mod->numTags ; i++, tag++ ) {
00619         if ( !strcmp( tag->name, tagName ) ) {
00620             return tag; // found it
00621         }
00622     }
00623 
00624     return NULL;
00625 }
00626 
00627 /*
00628 ================
00629 R_LerpTag
00630 ================
00631 */
00632 int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame, 
00633                      float frac, const char *tagName ) {
00634     md3Tag_t    *start, *end;
00635     int     i;
00636     float       frontLerp, backLerp;
00637     model_t     *model;
00638 
00639     model = R_GetModelByHandle( handle );
00640     if ( !model->md3[0] ) {
00641         AxisClear( tag->axis );
00642         VectorClear( tag->origin );
00643         return qfalse;
00644     }
00645 
00646     start = R_GetTag( model->md3[0], startFrame, tagName );
00647     end = R_GetTag( model->md3[0], endFrame, tagName );
00648     if ( !start || !end ) {
00649         AxisClear( tag->axis );
00650         VectorClear( tag->origin );
00651         return qfalse;
00652     }
00653 
00654     frontLerp = frac;
00655     backLerp = 1.0f - frac;
00656 
00657     for ( i = 0 ; i < 3 ; i++ ) {
00658         tag->origin[i] = start->origin[i] * backLerp +  end->origin[i] * frontLerp;
00659         tag->axis[0][i] = start->axis[0][i] * backLerp +  end->axis[0][i] * frontLerp;
00660         tag->axis[1][i] = start->axis[1][i] * backLerp +  end->axis[1][i] * frontLerp;
00661         tag->axis[2][i] = start->axis[2][i] * backLerp +  end->axis[2][i] * frontLerp;
00662     }
00663     VectorNormalize( tag->axis[0] );
00664     VectorNormalize( tag->axis[1] );
00665     VectorNormalize( tag->axis[2] );
00666     return qtrue;
00667 }
00668 
00669 
00670 /*
00671 ====================
00672 R_ModelBounds
00673 ====================
00674 */
00675 void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) {
00676     model_t     *model;
00677     md3Header_t *header;
00678     md3Frame_t  *frame;
00679 
00680     model = R_GetModelByHandle( handle );
00681 
00682     if ( model->bmodel ) {
00683         VectorCopy( model->bmodel->bounds[0], mins );
00684         VectorCopy( model->bmodel->bounds[1], maxs );
00685         return;
00686     }
00687 
00688     if ( !model->md3[0] ) {
00689         VectorClear( mins );
00690         VectorClear( maxs );
00691         return;
00692     }
00693 
00694     header = model->md3[0];
00695 
00696     frame = (md3Frame_t *)( (byte *)header + header->ofsFrames );
00697 
00698     VectorCopy( frame->bounds[0], mins );
00699     VectorCopy( frame->bounds[1], maxs );
00700 }

Generated on Thu Aug 25 12:37:53 2005 for Quake III Arena by  doxygen 1.3.9.1