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

tr_world.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 #include "tr_local.h"
00023 
00024 
00025 
00026 /*
00027 =================
00028 R_CullTriSurf
00029 
00030 Returns true if the grid is completely culled away.
00031 Also sets the clipped hint bit in tess
00032 =================
00033 */
00034 static qboolean R_CullTriSurf( srfTriangles_t *cv ) {
00035     int     boxCull;
00036 
00037     boxCull = R_CullLocalBox( cv->bounds );
00038 
00039     if ( boxCull == CULL_OUT ) {
00040         return qtrue;
00041     }
00042     return qfalse;
00043 }
00044 
00045 /*
00046 =================
00047 R_CullGrid
00048 
00049 Returns true if the grid is completely culled away.
00050 Also sets the clipped hint bit in tess
00051 =================
00052 */
00053 static qboolean R_CullGrid( srfGridMesh_t *cv ) {
00054     int     boxCull;
00055     int     sphereCull;
00056 
00057     if ( r_nocurves->integer ) {
00058         return qtrue;
00059     }
00060 
00061     if ( tr.currentEntityNum != ENTITYNUM_WORLD ) {
00062         sphereCull = R_CullLocalPointAndRadius( cv->localOrigin, cv->meshRadius );
00063     } else {
00064         sphereCull = R_CullPointAndRadius( cv->localOrigin, cv->meshRadius );
00065     }
00066     boxCull = CULL_OUT;
00067     
00068     // check for trivial reject
00069     if ( sphereCull == CULL_OUT )
00070     {
00071         tr.pc.c_sphere_cull_patch_out++;
00072         return qtrue;
00073     }
00074     // check bounding box if necessary
00075     else if ( sphereCull == CULL_CLIP )
00076     {
00077         tr.pc.c_sphere_cull_patch_clip++;
00078 
00079         boxCull = R_CullLocalBox( cv->meshBounds );
00080 
00081         if ( boxCull == CULL_OUT ) 
00082         {
00083             tr.pc.c_box_cull_patch_out++;
00084             return qtrue;
00085         }
00086         else if ( boxCull == CULL_IN )
00087         {
00088             tr.pc.c_box_cull_patch_in++;
00089         }
00090         else
00091         {
00092             tr.pc.c_box_cull_patch_clip++;
00093         }
00094     }
00095     else
00096     {
00097         tr.pc.c_sphere_cull_patch_in++;
00098     }
00099 
00100     return qfalse;
00101 }
00102 
00103 
00104 /*
00105 ================
00106 R_CullSurface
00107 
00108 Tries to back face cull surfaces before they are lighted or
00109 added to the sorting list.
00110 
00111 This will also allow mirrors on both sides of a model without recursion.
00112 ================
00113 */
00114 static qboolean R_CullSurface( surfaceType_t *surface, shader_t *shader ) {
00115     srfSurfaceFace_t *sface;
00116     float           d;
00117 
00118     if ( r_nocull->integer ) {
00119         return qfalse;
00120     }
00121 
00122     if ( *surface == SF_GRID ) {
00123         return R_CullGrid( (srfGridMesh_t *)surface );
00124     }
00125 
00126     if ( *surface == SF_TRIANGLES ) {
00127         return R_CullTriSurf( (srfTriangles_t *)surface );
00128     }
00129 
00130     if ( *surface != SF_FACE ) {
00131         return qfalse;
00132     }
00133 
00134     if ( shader->cullType == CT_TWO_SIDED ) {
00135         return qfalse;
00136     }
00137 
00138     // face culling
00139     if ( !r_facePlaneCull->integer ) {
00140         return qfalse;
00141     }
00142 
00143     sface = ( srfSurfaceFace_t * ) surface;
00144     d = DotProduct (tr.or.viewOrigin, sface->plane.normal);
00145 
00146     // don't cull exactly on the plane, because there are levels of rounding
00147     // through the BSP, ICD, and hardware that may cause pixel gaps if an
00148     // epsilon isn't allowed here 
00149     if ( shader->cullType == CT_FRONT_SIDED ) {
00150         if ( d < sface->plane.dist - 8 ) {
00151             return qtrue;
00152         }
00153     } else {
00154         if ( d > sface->plane.dist + 8 ) {
00155             return qtrue;
00156         }
00157     }
00158 
00159     return qfalse;
00160 }
00161 
00162 
00163 static int R_DlightFace( srfSurfaceFace_t *face, int dlightBits ) {
00164     float       d;
00165     int         i;
00166     dlight_t    *dl;
00167 
00168     for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
00169         if ( ! ( dlightBits & ( 1 << i ) ) ) {
00170             continue;
00171         }
00172         dl = &tr.refdef.dlights[i];
00173         d = DotProduct( dl->origin, face->plane.normal ) - face->plane.dist;
00174         if ( d < -dl->radius || d > dl->radius ) {
00175             // dlight doesn't reach the plane
00176             dlightBits &= ~( 1 << i );
00177         }
00178     }
00179 
00180     if ( !dlightBits ) {
00181         tr.pc.c_dlightSurfacesCulled++;
00182     }
00183 
00184     face->dlightBits[ tr.smpFrame ] = dlightBits;
00185     return dlightBits;
00186 }
00187 
00188 static int R_DlightGrid( srfGridMesh_t *grid, int dlightBits ) {
00189     int         i;
00190     dlight_t    *dl;
00191 
00192     for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
00193         if ( ! ( dlightBits & ( 1 << i ) ) ) {
00194             continue;
00195         }
00196         dl = &tr.refdef.dlights[i];
00197         if ( dl->origin[0] - dl->radius > grid->meshBounds[1][0]
00198             || dl->origin[0] + dl->radius < grid->meshBounds[0][0]
00199             || dl->origin[1] - dl->radius > grid->meshBounds[1][1]
00200             || dl->origin[1] + dl->radius < grid->meshBounds[0][1]
00201             || dl->origin[2] - dl->radius > grid->meshBounds[1][2]
00202             || dl->origin[2] + dl->radius < grid->meshBounds[0][2] ) {
00203             // dlight doesn't reach the bounds
00204             dlightBits &= ~( 1 << i );
00205         }
00206     }
00207 
00208     if ( !dlightBits ) {
00209         tr.pc.c_dlightSurfacesCulled++;
00210     }
00211 
00212     grid->dlightBits[ tr.smpFrame ] = dlightBits;
00213     return dlightBits;
00214 }
00215 
00216 
00217 static int R_DlightTrisurf( srfTriangles_t *surf, int dlightBits ) {
00218     // FIXME: more dlight culling to trisurfs...
00219     surf->dlightBits[ tr.smpFrame ] = dlightBits;
00220     return dlightBits;
00221 #if 0
00222     int         i;
00223     dlight_t    *dl;
00224 
00225     for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
00226         if ( ! ( dlightBits & ( 1 << i ) ) ) {
00227             continue;
00228         }
00229         dl = &tr.refdef.dlights[i];
00230         if ( dl->origin[0] - dl->radius > grid->meshBounds[1][0]
00231             || dl->origin[0] + dl->radius < grid->meshBounds[0][0]
00232             || dl->origin[1] - dl->radius > grid->meshBounds[1][1]
00233             || dl->origin[1] + dl->radius < grid->meshBounds[0][1]
00234             || dl->origin[2] - dl->radius > grid->meshBounds[1][2]
00235             || dl->origin[2] + dl->radius < grid->meshBounds[0][2] ) {
00236             // dlight doesn't reach the bounds
00237             dlightBits &= ~( 1 << i );
00238         }
00239     }
00240 
00241     if ( !dlightBits ) {
00242         tr.pc.c_dlightSurfacesCulled++;
00243     }
00244 
00245     grid->dlightBits[ tr.smpFrame ] = dlightBits;
00246     return dlightBits;
00247 #endif
00248 }
00249 
00250 /*
00251 ====================
00252 R_DlightSurface
00253 
00254 The given surface is going to be drawn, and it touches a leaf
00255 that is touched by one or more dlights, so try to throw out
00256 more dlights if possible.
00257 ====================
00258 */
00259 static int R_DlightSurface( msurface_t *surf, int dlightBits ) {
00260     if ( *surf->data == SF_FACE ) {
00261         dlightBits = R_DlightFace( (srfSurfaceFace_t *)surf->data, dlightBits );
00262     } else if ( *surf->data == SF_GRID ) {
00263         dlightBits = R_DlightGrid( (srfGridMesh_t *)surf->data, dlightBits );
00264     } else if ( *surf->data == SF_TRIANGLES ) {
00265         dlightBits = R_DlightTrisurf( (srfTriangles_t *)surf->data, dlightBits );
00266     } else {
00267         dlightBits = 0;
00268     }
00269 
00270     if ( dlightBits ) {
00271         tr.pc.c_dlightSurfaces++;
00272     }
00273 
00274     return dlightBits;
00275 }
00276 
00277 
00278 
00279 /*
00280 ======================
00281 R_AddWorldSurface
00282 ======================
00283 */
00284 static void R_AddWorldSurface( msurface_t *surf, int dlightBits ) {
00285     if ( surf->viewCount == tr.viewCount ) {
00286         return;     // already in this view
00287     }
00288 
00289     surf->viewCount = tr.viewCount;
00290     // FIXME: bmodel fog?
00291 
00292     // try to cull before dlighting or adding
00293     if ( R_CullSurface( surf->data, surf->shader ) ) {
00294         return;
00295     }
00296 
00297     // check for dlighting
00298     if ( dlightBits ) {
00299         dlightBits = R_DlightSurface( surf, dlightBits );
00300         dlightBits = ( dlightBits != 0 );
00301     }
00302 
00303     R_AddDrawSurf( surf->data, surf->shader, surf->fogIndex, dlightBits );
00304 }
00305 
00306 /*
00307 =============================================================
00308 
00309     BRUSH MODELS
00310 
00311 =============================================================
00312 */
00313 
00314 /*
00315 =================
00316 R_AddBrushModelSurfaces
00317 =================
00318 */
00319 void R_AddBrushModelSurfaces ( trRefEntity_t *ent ) {
00320     bmodel_t    *bmodel;
00321     int         clip;
00322     model_t     *pModel;
00323     int         i;
00324 
00325     pModel = R_GetModelByHandle( ent->e.hModel );
00326 
00327     bmodel = pModel->bmodel;
00328 
00329     clip = R_CullLocalBox( bmodel->bounds );
00330     if ( clip == CULL_OUT ) {
00331         return;
00332     }
00333     
00334     R_DlightBmodel( bmodel );
00335 
00336     for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) {
00337         R_AddWorldSurface( bmodel->firstSurface + i, tr.currentEntity->needDlights );
00338     }
00339 }
00340 
00341 
00342 /*
00343 =============================================================
00344 
00345     WORLD MODEL
00346 
00347 =============================================================
00348 */
00349 
00350 
00351 /*
00352 ================
00353 R_RecursiveWorldNode
00354 ================
00355 */
00356 static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits ) {
00357 
00358     do {
00359         int         newDlights[2];
00360 
00361         // if the node wasn't marked as potentially visible, exit
00362         if (node->visframe != tr.visCount) {
00363             return;
00364         }
00365 
00366         // if the bounding volume is outside the frustum, nothing
00367         // inside can be visible OPTIMIZE: don't do this all the way to leafs?
00368 
00369         if ( !r_nocull->integer ) {
00370             int     r;
00371 
00372             if ( planeBits & 1 ) {
00373                 r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[0]);
00374                 if (r == 2) {
00375                     return;                     // culled
00376                 }
00377                 if ( r == 1 ) {
00378                     planeBits &= ~1;            // all descendants will also be in front
00379                 }
00380             }
00381 
00382             if ( planeBits & 2 ) {
00383                 r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[1]);
00384                 if (r == 2) {
00385                     return;                     // culled
00386                 }
00387                 if ( r == 1 ) {
00388                     planeBits &= ~2;            // all descendants will also be in front
00389                 }
00390             }
00391 
00392             if ( planeBits & 4 ) {
00393                 r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[2]);
00394                 if (r == 2) {
00395                     return;                     // culled
00396                 }
00397                 if ( r == 1 ) {
00398                     planeBits &= ~4;            // all descendants will also be in front
00399                 }
00400             }
00401 
00402             if ( planeBits & 8 ) {
00403                 r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[3]);
00404                 if (r == 2) {
00405                     return;                     // culled
00406                 }
00407                 if ( r == 1 ) {
00408                     planeBits &= ~8;            // all descendants will also be in front
00409                 }
00410             }
00411 
00412         }
00413 
00414         if ( node->contents != -1 ) {
00415             break;
00416         }
00417 
00418         // node is just a decision point, so go down both sides
00419         // since we don't care about sort orders, just go positive to negative
00420 
00421         // determine which dlights are needed
00422         newDlights[0] = 0;
00423         newDlights[1] = 0;
00424         if ( dlightBits ) {
00425             int i;
00426 
00427             for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
00428                 dlight_t    *dl;
00429                 float       dist;
00430 
00431                 if ( dlightBits & ( 1 << i ) ) {
00432                     dl = &tr.refdef.dlights[i];
00433                     dist = DotProduct( dl->origin, node->plane->normal ) - node->plane->dist;
00434                     
00435                     if ( dist > -dl->radius ) {
00436                         newDlights[0] |= ( 1 << i );
00437                     }
00438                     if ( dist < dl->radius ) {
00439                         newDlights[1] |= ( 1 << i );
00440                     }
00441                 }
00442             }
00443         }
00444 
00445         // recurse down the children, front side first
00446         R_RecursiveWorldNode (node->children[0], planeBits, newDlights[0] );
00447 
00448         // tail recurse
00449         node = node->children[1];
00450         dlightBits = newDlights[1];
00451     } while ( 1 );
00452 
00453     {
00454         // leaf node, so add mark surfaces
00455         int         c;
00456         msurface_t  *surf, **mark;
00457 
00458         tr.pc.c_leafs++;
00459 
00460         // add to z buffer bounds
00461         if ( node->mins[0] < tr.viewParms.visBounds[0][0] ) {
00462             tr.viewParms.visBounds[0][0] = node->mins[0];
00463         }
00464         if ( node->mins[1] < tr.viewParms.visBounds[0][1] ) {
00465             tr.viewParms.visBounds[0][1] = node->mins[1];
00466         }
00467         if ( node->mins[2] < tr.viewParms.visBounds[0][2] ) {
00468             tr.viewParms.visBounds[0][2] = node->mins[2];
00469         }
00470 
00471         if ( node->maxs[0] > tr.viewParms.visBounds[1][0] ) {
00472             tr.viewParms.visBounds[1][0] = node->maxs[0];
00473         }
00474         if ( node->maxs[1] > tr.viewParms.visBounds[1][1] ) {
00475             tr.viewParms.visBounds[1][1] = node->maxs[1];
00476         }
00477         if ( node->maxs[2] > tr.viewParms.visBounds[1][2] ) {
00478             tr.viewParms.visBounds[1][2] = node->maxs[2];
00479         }
00480 
00481         // add the individual surfaces
00482         mark = node->firstmarksurface;
00483         c = node->nummarksurfaces;
00484         while (c--) {
00485             // the surface may have already been added if it
00486             // spans multiple leafs
00487             surf = *mark;
00488             R_AddWorldSurface( surf, dlightBits );
00489             mark++;
00490         }
00491     }
00492 
00493 }
00494 
00495 
00496 /*
00497 ===============
00498 R_PointInLeaf
00499 ===============
00500 */
00501 static mnode_t *R_PointInLeaf( const vec3_t p ) {
00502     mnode_t     *node;
00503     float       d;
00504     cplane_t    *plane;
00505     
00506     if ( !tr.world ) {
00507         ri.Error (ERR_DROP, "R_PointInLeaf: bad model");
00508     }
00509 
00510     node = tr.world->nodes;
00511     while( 1 ) {
00512         if (node->contents != -1) {
00513             break;
00514         }
00515         plane = node->plane;
00516         d = DotProduct (p,plane->normal) - plane->dist;
00517         if (d > 0) {
00518             node = node->children[0];
00519         } else {
00520             node = node->children[1];
00521         }
00522     }
00523     
00524     return node;
00525 }
00526 
00527 /*
00528 ==============
00529 R_ClusterPVS
00530 ==============
00531 */
00532 static const byte *R_ClusterPVS (int cluster) {
00533     if (!tr.world || !tr.world->vis || cluster < 0 || cluster >= tr.world->numClusters ) {
00534         return tr.world->novis;
00535     }
00536 
00537     return tr.world->vis + cluster * tr.world->clusterBytes;
00538 }
00539 
00540 /*
00541 =================
00542 R_inPVS
00543 =================
00544 */
00545 qboolean R_inPVS( const vec3_t p1, const vec3_t p2 ) {
00546     mnode_t *leaf;
00547     byte    *vis;
00548 
00549     leaf = R_PointInLeaf( p1 );
00550     vis = CM_ClusterPVS( leaf->cluster );
00551     leaf = R_PointInLeaf( p2 );
00552 
00553     if ( !(vis[leaf->cluster>>3] & (1<<(leaf->cluster&7))) ) {
00554         return qfalse;
00555     }
00556     return qtrue;
00557 }
00558 
00559 /*
00560 ===============
00561 R_MarkLeaves
00562 
00563 Mark the leaves and nodes that are in the PVS for the current
00564 cluster
00565 ===============
00566 */
00567 static void R_MarkLeaves (void) {
00568     const byte  *vis;
00569     mnode_t *leaf, *parent;
00570     int     i;
00571     int     cluster;
00572 
00573     // lockpvs lets designers walk around to determine the
00574     // extent of the current pvs
00575     if ( r_lockpvs->integer ) {
00576         return;
00577     }
00578 
00579     // current viewcluster
00580     leaf = R_PointInLeaf( tr.viewParms.pvsOrigin );
00581     cluster = leaf->cluster;
00582 
00583     // if the cluster is the same and the area visibility matrix
00584     // hasn't changed, we don't need to mark everything again
00585 
00586     // if r_showcluster was just turned on, remark everything 
00587     if ( tr.viewCluster == cluster && !tr.refdef.areamaskModified 
00588         && !r_showcluster->modified ) {
00589         return;
00590     }
00591 
00592     if ( r_showcluster->modified || r_showcluster->integer ) {
00593         r_showcluster->modified = qfalse;
00594         if ( r_showcluster->integer ) {
00595             ri.Printf( PRINT_ALL, "cluster:%i  area:%i\n", cluster, leaf->area );
00596         }
00597     }
00598 
00599     tr.visCount++;
00600     tr.viewCluster = cluster;
00601 
00602     if ( r_novis->integer || tr.viewCluster == -1 ) {
00603         for (i=0 ; i<tr.world->numnodes ; i++) {
00604             if (tr.world->nodes[i].contents != CONTENTS_SOLID) {
00605                 tr.world->nodes[i].visframe = tr.visCount;
00606             }
00607         }
00608         return;
00609     }
00610 
00611     vis = R_ClusterPVS (tr.viewCluster);
00612     
00613     for (i=0,leaf=tr.world->nodes ; i<tr.world->numnodes ; i++, leaf++) {
00614         cluster = leaf->cluster;
00615         if ( cluster < 0 || cluster >= tr.world->numClusters ) {
00616             continue;
00617         }
00618 
00619         // check general pvs
00620         if ( !(vis[cluster>>3] & (1<<(cluster&7))) ) {
00621             continue;
00622         }
00623 
00624         // check for door connection
00625         if ( (tr.refdef.areamask[leaf->area>>3] & (1<<(leaf->area&7)) ) ) {
00626             continue;       // not visible
00627         }
00628 
00629         parent = leaf;
00630         do {
00631             if (parent->visframe == tr.visCount)
00632                 break;
00633             parent->visframe = tr.visCount;
00634             parent = parent->parent;
00635         } while (parent);
00636     }
00637 }
00638 
00639 
00640 /*
00641 =============
00642 R_AddWorldSurfaces
00643 =============
00644 */
00645 void R_AddWorldSurfaces (void) {
00646     if ( !r_drawworld->integer ) {
00647         return;
00648     }
00649 
00650     if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
00651         return;
00652     }
00653 
00654     tr.currentEntityNum = ENTITYNUM_WORLD;
00655     tr.shiftedEntityNum = tr.currentEntityNum << QSORT_ENTITYNUM_SHIFT;
00656 
00657     // determine which leaves are in the PVS / areamask
00658     R_MarkLeaves ();
00659 
00660     // clear out the visible min/max
00661     ClearBounds( tr.viewParms.visBounds[0], tr.viewParms.visBounds[1] );
00662 
00663     // perform frustum culling and add all the potentially visible surfaces
00664     if ( tr.refdef.num_dlights > 32 ) {
00665         tr.refdef.num_dlights = 32 ;
00666     }
00667     R_RecursiveWorldNode( tr.world->nodes, 15, ( 1 << tr.refdef.num_dlights ) - 1 );
00668 }

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