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

tr_mesh.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_mesh.c: triangle model functions
00023 
00024 #include "tr_local.h"
00025 
00026 static float ProjectRadius( float r, vec3_t location )
00027 {
00028     float pr;
00029     float dist;
00030     float c;
00031     vec3_t  p;
00032     float   projected[4];
00033 
00034     c = DotProduct( tr.viewParms.or.axis[0], tr.viewParms.or.origin );
00035     dist = DotProduct( tr.viewParms.or.axis[0], location ) - c;
00036 
00037     if ( dist <= 0 )
00038         return 0;
00039 
00040     p[0] = 0;
00041     p[1] = fabs( r );
00042     p[2] = -dist;
00043 
00044     projected[0] = p[0] * tr.viewParms.projectionMatrix[0] + 
00045                    p[1] * tr.viewParms.projectionMatrix[4] +
00046                    p[2] * tr.viewParms.projectionMatrix[8] +
00047                    tr.viewParms.projectionMatrix[12];
00048 
00049     projected[1] = p[0] * tr.viewParms.projectionMatrix[1] + 
00050                    p[1] * tr.viewParms.projectionMatrix[5] +
00051                    p[2] * tr.viewParms.projectionMatrix[9] +
00052                    tr.viewParms.projectionMatrix[13];
00053 
00054     projected[2] = p[0] * tr.viewParms.projectionMatrix[2] + 
00055                    p[1] * tr.viewParms.projectionMatrix[6] +
00056                    p[2] * tr.viewParms.projectionMatrix[10] +
00057                    tr.viewParms.projectionMatrix[14];
00058 
00059     projected[3] = p[0] * tr.viewParms.projectionMatrix[3] + 
00060                    p[1] * tr.viewParms.projectionMatrix[7] +
00061                    p[2] * tr.viewParms.projectionMatrix[11] +
00062                    tr.viewParms.projectionMatrix[15];
00063 
00064 
00065     pr = projected[1] / projected[3];
00066 
00067     if ( pr > 1.0f )
00068         pr = 1.0f;
00069 
00070     return pr;
00071 }
00072 
00073 /*
00074 =============
00075 R_CullModel
00076 =============
00077 */
00078 static int R_CullModel( md3Header_t *header, trRefEntity_t *ent ) {
00079     vec3_t      bounds[2];
00080     md3Frame_t  *oldFrame, *newFrame;
00081     int         i;
00082 
00083     // compute frame pointers
00084     newFrame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.frame;
00085     oldFrame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.oldframe;
00086 
00087     // cull bounding sphere ONLY if this is not an upscaled entity
00088     if ( !ent->e.nonNormalizedAxes )
00089     {
00090         if ( ent->e.frame == ent->e.oldframe )
00091         {
00092             switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) )
00093             {
00094             case CULL_OUT:
00095                 tr.pc.c_sphere_cull_md3_out++;
00096                 return CULL_OUT;
00097 
00098             case CULL_IN:
00099                 tr.pc.c_sphere_cull_md3_in++;
00100                 return CULL_IN;
00101 
00102             case CULL_CLIP:
00103                 tr.pc.c_sphere_cull_md3_clip++;
00104                 break;
00105             }
00106         }
00107         else
00108         {
00109             int sphereCull, sphereCullB;
00110 
00111             sphereCull  = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius );
00112             if ( newFrame == oldFrame ) {
00113                 sphereCullB = sphereCull;
00114             } else {
00115                 sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius );
00116             }
00117 
00118             if ( sphereCull == sphereCullB )
00119             {
00120                 if ( sphereCull == CULL_OUT )
00121                 {
00122                     tr.pc.c_sphere_cull_md3_out++;
00123                     return CULL_OUT;
00124                 }
00125                 else if ( sphereCull == CULL_IN )
00126                 {
00127                     tr.pc.c_sphere_cull_md3_in++;
00128                     return CULL_IN;
00129                 }
00130                 else
00131                 {
00132                     tr.pc.c_sphere_cull_md3_clip++;
00133                 }
00134             }
00135         }
00136     }
00137     
00138     // calculate a bounding box in the current coordinate system
00139     for (i = 0 ; i < 3 ; i++) {
00140         bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i];
00141         bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i];
00142     }
00143 
00144     switch ( R_CullLocalBox( bounds ) )
00145     {
00146     case CULL_IN:
00147         tr.pc.c_box_cull_md3_in++;
00148         return CULL_IN;
00149     case CULL_CLIP:
00150         tr.pc.c_box_cull_md3_clip++;
00151         return CULL_CLIP;
00152     case CULL_OUT:
00153     default:
00154         tr.pc.c_box_cull_md3_out++;
00155         return CULL_OUT;
00156     }
00157 }
00158 
00159 
00160 /*
00161 =================
00162 R_ComputeLOD
00163 
00164 =================
00165 */
00166 int R_ComputeLOD( trRefEntity_t *ent ) {
00167     float radius;
00168     float flod, lodscale;
00169     float projectedRadius;
00170     md3Frame_t *frame;
00171     int lod;
00172 
00173     if ( tr.currentModel->numLods < 2 )
00174     {
00175         // model has only 1 LOD level, skip computations and bias
00176         lod = 0;
00177     }
00178     else
00179     {
00180         // multiple LODs exist, so compute projected bounding sphere
00181         // and use that as a criteria for selecting LOD
00182 
00183         frame = ( md3Frame_t * ) ( ( ( unsigned char * ) tr.currentModel->md3[0] ) + tr.currentModel->md3[0]->ofsFrames );
00184 
00185         frame += ent->e.frame;
00186 
00187         radius = RadiusFromBounds( frame->bounds[0], frame->bounds[1] );
00188 
00189         if ( ( projectedRadius = ProjectRadius( radius, ent->e.origin ) ) != 0 )
00190         {
00191             lodscale = r_lodscale->value;
00192             if (lodscale > 20) lodscale = 20;
00193             flod = 1.0f - projectedRadius * lodscale;
00194         }
00195         else
00196         {
00197             // object intersects near view plane, e.g. view weapon
00198             flod = 0;
00199         }
00200 
00201         flod *= tr.currentModel->numLods;
00202         lod = myftol( flod );
00203 
00204         if ( lod < 0 )
00205         {
00206             lod = 0;
00207         }
00208         else if ( lod >= tr.currentModel->numLods )
00209         {
00210             lod = tr.currentModel->numLods - 1;
00211         }
00212     }
00213 
00214     lod += r_lodbias->integer;
00215     
00216     if ( lod >= tr.currentModel->numLods )
00217         lod = tr.currentModel->numLods - 1;
00218     if ( lod < 0 )
00219         lod = 0;
00220 
00221     return lod;
00222 }
00223 
00224 /*
00225 =================
00226 R_ComputeFogNum
00227 
00228 =================
00229 */
00230 int R_ComputeFogNum( md3Header_t *header, trRefEntity_t *ent ) {
00231     int             i, j;
00232     fog_t           *fog;
00233     md3Frame_t      *md3Frame;
00234     vec3_t          localOrigin;
00235 
00236     if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
00237         return 0;
00238     }
00239 
00240     // FIXME: non-normalized axis issues
00241     md3Frame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.frame;
00242     VectorAdd( ent->e.origin, md3Frame->localOrigin, localOrigin );
00243     for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
00244         fog = &tr.world->fogs[i];
00245         for ( j = 0 ; j < 3 ; j++ ) {
00246             if ( localOrigin[j] - md3Frame->radius >= fog->bounds[1][j] ) {
00247                 break;
00248             }
00249             if ( localOrigin[j] + md3Frame->radius <= fog->bounds[0][j] ) {
00250                 break;
00251             }
00252         }
00253         if ( j == 3 ) {
00254             return i;
00255         }
00256     }
00257 
00258     return 0;
00259 }
00260 
00261 /*
00262 =================
00263 R_AddMD3Surfaces
00264 
00265 =================
00266 */
00267 void R_AddMD3Surfaces( trRefEntity_t *ent ) {
00268     int             i;
00269     md3Header_t     *header = 0;
00270     md3Surface_t    *surface = 0;
00271     md3Shader_t     *md3Shader = 0;
00272     shader_t        *shader = 0;
00273     int             cull;
00274     int             lod;
00275     int             fogNum;
00276     qboolean        personalModel;
00277 
00278     // don't add third_person objects if not in a portal
00279     personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal;
00280 
00281     if ( ent->e.renderfx & RF_WRAP_FRAMES ) {
00282         ent->e.frame %= tr.currentModel->md3[0]->numFrames;
00283         ent->e.oldframe %= tr.currentModel->md3[0]->numFrames;
00284     }
00285 
00286     //
00287     // Validate the frames so there is no chance of a crash.
00288     // This will write directly into the entity structure, so
00289     // when the surfaces are rendered, they don't need to be
00290     // range checked again.
00291     //
00292     if ( (ent->e.frame >= tr.currentModel->md3[0]->numFrames) 
00293         || (ent->e.frame < 0)
00294         || (ent->e.oldframe >= tr.currentModel->md3[0]->numFrames)
00295         || (ent->e.oldframe < 0) ) {
00296             ri.Printf( PRINT_DEVELOPER, "R_AddMD3Surfaces: no such frame %d to %d for '%s'\n",
00297                 ent->e.oldframe, ent->e.frame,
00298                 tr.currentModel->name );
00299             ent->e.frame = 0;
00300             ent->e.oldframe = 0;
00301     }
00302 
00303     //
00304     // compute LOD
00305     //
00306     lod = R_ComputeLOD( ent );
00307 
00308     header = tr.currentModel->md3[lod];
00309 
00310     //
00311     // cull the entire model if merged bounding box of both frames
00312     // is outside the view frustum.
00313     //
00314     cull = R_CullModel ( header, ent );
00315     if ( cull == CULL_OUT ) {
00316         return;
00317     }
00318 
00319     //
00320     // set up lighting now that we know we aren't culled
00321     //
00322     if ( !personalModel || r_shadows->integer > 1 ) {
00323         R_SetupEntityLighting( &tr.refdef, ent );
00324     }
00325 
00326     //
00327     // see if we are in a fog volume
00328     //
00329     fogNum = R_ComputeFogNum( header, ent );
00330 
00331     //
00332     // draw all surfaces
00333     //
00334     surface = (md3Surface_t *)( (byte *)header + header->ofsSurfaces );
00335     for ( i = 0 ; i < header->numSurfaces ; i++ ) {
00336 
00337         if ( ent->e.customShader ) {
00338             shader = R_GetShaderByHandle( ent->e.customShader );
00339         } else if ( ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins ) {
00340             skin_t *skin;
00341             int     j;
00342 
00343             skin = R_GetSkinByHandle( ent->e.customSkin );
00344 
00345             // match the surface name to something in the skin file
00346             shader = tr.defaultShader;
00347             for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
00348                 // the names have both been lowercased
00349                 if ( !strcmp( skin->surfaces[j]->name, surface->name ) ) {
00350                     shader = skin->surfaces[j]->shader;
00351                     break;
00352                 }
00353             }
00354             if (shader == tr.defaultShader) {
00355                 ri.Printf( PRINT_DEVELOPER, "WARNING: no shader for surface %s in skin %s\n", surface->name, skin->name);
00356             }
00357             else if (shader->defaultShader) {
00358                 ri.Printf( PRINT_DEVELOPER, "WARNING: shader %s in skin %s not found\n", shader->name, skin->name);
00359             }
00360         } else if ( surface->numShaders <= 0 ) {
00361             shader = tr.defaultShader;
00362         } else {
00363             md3Shader = (md3Shader_t *) ( (byte *)surface + surface->ofsShaders );
00364             md3Shader += ent->e.skinNum % surface->numShaders;
00365             shader = tr.shaders[ md3Shader->shaderIndex ];
00366         }
00367 
00368 
00369         // we will add shadows even if the main object isn't visible in the view
00370 
00371         // stencil shadows can't do personal models unless I polyhedron clip
00372         if ( !personalModel
00373             && r_shadows->integer == 2 
00374             && fogNum == 0
00375             && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) ) 
00376             && shader->sort == SS_OPAQUE ) {
00377             R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, qfalse );
00378         }
00379 
00380         // projection shadows work fine with personal models
00381         if ( r_shadows->integer == 3
00382             && fogNum == 0
00383             && (ent->e.renderfx & RF_SHADOW_PLANE )
00384             && shader->sort == SS_OPAQUE ) {
00385             R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse );
00386         }
00387 
00388         // don't add third_person objects if not viewing through a portal
00389         if ( !personalModel ) {
00390             R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse );
00391         }
00392 
00393         surface = (md3Surface_t *)( (byte *)surface + surface->ofsEnd );
00394     }
00395 
00396 }
00397 

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