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

fog.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 "qbsp.h"
00023 
00024 
00025 int         c_fogFragment;
00026 int         c_fogPatchFragments;
00027 
00028 /*
00029 ====================
00030 DrawSurfToMesh
00031 ====================
00032 */
00033 mesh_t  *DrawSurfToMesh( mapDrawSurface_t *ds ) {
00034     mesh_t      *m;
00035 
00036     m = malloc( sizeof( *m ) );
00037     m->width = ds->patchWidth;
00038     m->height = ds->patchHeight;
00039     m->verts = malloc( sizeof(m->verts[0]) * m->width * m->height );
00040     memcpy( m->verts, ds->verts, sizeof(m->verts[0]) * m->width * m->height );
00041 
00042     return m;
00043 }
00044 
00045 
00046 /*
00047 ====================
00048 SplitMeshByPlane
00049 ====================
00050 */
00051 void SplitMeshByPlane( mesh_t *in, vec3_t normal, float dist, mesh_t **front, mesh_t **back ) {
00052     int     w, h, split;
00053     float   d[MAX_PATCH_SIZE][MAX_PATCH_SIZE];
00054     drawVert_t  *dv, *v1, *v2;
00055     int     c_front, c_back, c_on;
00056     mesh_t  *f, *b;
00057     int     i;
00058     float   frac;
00059     int     frontAprox, backAprox;
00060 
00061     for ( i = 0 ; i < 2 ; i++ ) {
00062         dv = in->verts;
00063         c_front = 0;
00064         c_back = 0;
00065         c_on = 0;
00066         for ( h = 0 ; h < in->height ; h++ ) {
00067             for ( w = 0 ; w < in->width ; w++, dv++ ) {
00068                 d[h][w] = DotProduct( dv->xyz, normal ) - dist;
00069                 if ( d[h][w] > ON_EPSILON ) {
00070                     c_front++;
00071                 } else if ( d[h][w] < -ON_EPSILON ) {
00072                     c_back++;
00073                 } else {
00074                     c_on++;
00075                 }
00076             }
00077         }
00078 
00079         *front = NULL;
00080         *back = NULL;
00081 
00082         if ( !c_front ) {
00083             *back = in;
00084             return;
00085         }
00086         if ( !c_back ) {
00087             *front = in;
00088             return;
00089         }
00090 
00091         // find a split point
00092         split = -1;
00093         for ( w = 0 ; w < in->width -1 ; w++ ) {
00094             if ( ( d[0][w] < 0 ) != ( d[0][w+1] < 0 ) ) {
00095                 if ( split == -1 ) {
00096                     split = w;
00097                     break;
00098                 }
00099             }
00100         }
00101 
00102         if ( split == -1 ) {
00103             if ( i == 1 ) {
00104                 qprintf( "No crossing points in patch\n");
00105                 *front = in;
00106                 return;
00107             }
00108 
00109             in = TransposeMesh( in );
00110             InvertMesh( in );
00111             continue;
00112         }
00113 
00114         // make sure the split point stays the same for all other rows
00115         for ( h = 1 ; h < in->height ; h++ ) {
00116             for ( w = 0 ; w < in->width -1 ; w++ ) {
00117                 if ( ( d[h][w] < 0 ) != ( d[h][w+1] < 0 ) ) {
00118                     if ( w != split ) {
00119                         _printf( "multiple crossing points for patch -- can't clip\n");
00120                         *front = in;
00121                         return;
00122                     }
00123                 }
00124             }
00125             if ( ( d[h][split] < 0 ) == ( d[h][split+1] < 0 ) ) {
00126                 _printf( "differing crossing points for patch -- can't clip\n");
00127                 *front = in;
00128                 return;
00129             }
00130         }
00131 
00132         break;
00133     }
00134 
00135 
00136     // create two new meshes
00137     f = malloc( sizeof( *f ) );
00138     f->width = split + 2;
00139     if ( ! (f->width & 1) ) {
00140         f->width++;
00141         frontAprox = 1;
00142     } else {
00143         frontAprox = 0;
00144     }
00145     if ( f->width > MAX_PATCH_SIZE ) {
00146         Error( "MAX_PATCH_SIZE after split");
00147     }
00148     f->height = in->height;
00149     f->verts = malloc( sizeof(f->verts[0]) * f->width * f->height );
00150 
00151     b = malloc( sizeof( *b ) );
00152     b->width = in->width - split;
00153     if ( ! (b->width & 1) ) {
00154         b->width++;
00155         backAprox = 1;
00156     } else {
00157         backAprox = 0;
00158     }
00159     if ( b->width > MAX_PATCH_SIZE ) {
00160         Error( "MAX_PATCH_SIZE after split");
00161     }
00162     b->height = in->height;
00163     b->verts = malloc( sizeof(b->verts[0]) * b->width * b->height );
00164 
00165     if ( d[0][0] > 0 ) {
00166         *front = f;
00167         *back = b;
00168     } else {
00169         *front = b;
00170         *back = f;
00171     }
00172 
00173     // distribute the points
00174     for ( w = 0 ; w < in->width ; w++ ) {
00175         for ( h = 0 ; h < in->height ; h++ ) {
00176             if ( w <= split ) {
00177                 f->verts[ h * f->width + w ] = in->verts[ h * in->width + w ];
00178             } else {
00179                 b->verts[ h * b->width + w - split + backAprox ] = in->verts[ h * in->width + w ];
00180             }
00181         }
00182     }
00183 
00184     // clip the crossing line
00185     for ( h = 0 ; h < in->height ; h++ ) {
00186         dv = &f->verts[ h * f->width + split + 1 ];
00187         v1 = &in->verts[ h * in->width + split ];
00188         v2 = &in->verts[ h * in->width + split + 1 ];
00189         frac = d[h][split] / ( d[h][split] - d[h][split+1] );
00190         for ( i = 0 ; i < 10 ; i++ ) {
00191             dv->xyz[i] = v1->xyz[i] + frac * ( v2->xyz[i] - v1->xyz[i] );
00192         }
00193         dv->xyz[10] = 0;//set all 4 colors to 0 
00194         if ( frontAprox ) {
00195             f->verts[ h * f->width + split + 2 ] = *dv;
00196         }
00197         b->verts[ h * b->width ] = *dv;
00198         if ( backAprox ) {
00199             b->verts[ h * b->width + 1 ] = *dv;
00200         }
00201     }
00202 
00203     /*
00204 PrintMesh( in );
00205 _printf("\n");
00206 PrintMesh( f );
00207 _printf("\n");
00208 PrintMesh( b );
00209 _printf("\n");
00210     */
00211 
00212     FreeMesh( in );
00213 }
00214 
00215 
00216 /*
00217 ====================
00218 ChopPatchByBrush
00219 ====================
00220 */
00221 qboolean ChopPatchByBrush( mapDrawSurface_t *ds, bspbrush_t *b ) {
00222     int         i, j;
00223     side_t      *s;
00224     plane_t     *plane;
00225     mesh_t      *outside[MAX_BRUSH_SIDES];
00226     int         numOutside;
00227     mesh_t      *m, *front, *back;
00228     mapDrawSurface_t    *newds;
00229 
00230     m = DrawSurfToMesh( ds );
00231     numOutside = 0;
00232 
00233     // only split by the top and bottom planes to avoid
00234     // some messy patch clipping issues
00235 
00236     for ( i = 4 ; i <= 5 ; i++ ) {
00237         s = &b->sides[ i ];
00238         plane = &mapplanes[ s->planenum ];
00239 
00240         SplitMeshByPlane( m, plane->normal, plane->dist, &front, &back );
00241 
00242         if ( !back ) {
00243             // nothing actually contained inside
00244             for ( j = 0 ; j < numOutside ; j++ ) {
00245                 FreeMesh( outside[j] );
00246             }
00247             return qfalse;
00248         }
00249         m = back;
00250 
00251         if ( front ) {
00252             if ( numOutside == MAX_BRUSH_SIDES ) {
00253                 Error( "MAX_BRUSH_SIDES" );
00254             }
00255             outside[ numOutside ] = front;
00256             numOutside++;
00257         }
00258     }
00259 
00260     // all of outside fragments become seperate drawsurfs
00261     c_fogPatchFragments += numOutside;
00262     for ( i = 0 ; i < numOutside ; i++ ) {
00263         newds = DrawSurfaceForMesh( outside[ i ] );
00264         newds->shaderInfo = ds->shaderInfo;
00265         FreeMesh( outside[ i ] );
00266     }
00267 
00268     // replace ds with m
00269     ds->patchWidth = m->width;
00270     ds->patchHeight = m->height;
00271     ds->numVerts = m->width * m->height;
00272     free( ds->verts );
00273     ds->verts = malloc( ds->numVerts * sizeof( *ds->verts ) );
00274     memcpy( ds->verts, m->verts, ds->numVerts * sizeof( *ds->verts ) );
00275 
00276     FreeMesh( m );
00277 
00278     return qtrue;
00279 }
00280 
00281 //===============================================================================
00282 
00283 /*
00284 ====================
00285 WindingFromDrawSurf
00286 ====================
00287 */
00288 winding_t   *WindingFromDrawSurf( mapDrawSurface_t *ds ) {
00289     winding_t   *w;
00290     int         i;
00291 
00292     w = AllocWinding( ds->numVerts );
00293     w->numpoints = ds->numVerts;
00294     for ( i = 0 ; i < ds->numVerts ; i++ ) {
00295         VectorCopy( ds->verts[i].xyz, w->p[i] );
00296     }
00297     return w;
00298 }
00299 
00300 /*
00301 ====================
00302 ChopFaceByBrush
00303 
00304 There may be a fragment contained in the brush
00305 ====================
00306 */
00307 qboolean ChopFaceByBrush( mapDrawSurface_t *ds, bspbrush_t *b ) {
00308     int         i, j;
00309     side_t      *s;
00310     plane_t     *plane;
00311     winding_t   *w;
00312     winding_t   *front, *back;
00313     winding_t   *outside[MAX_BRUSH_SIDES];
00314     int         numOutside;
00315     mapDrawSurface_t    *newds;
00316     drawVert_t      *dv;
00317     shaderInfo_t    *si;
00318     float       mins[2];
00319 
00320     // brush primitive :
00321     // axis base
00322     vec3_t      texX,texY;
00323     vec_t       x,y;
00324 
00325     w = WindingFromDrawSurf( ds );
00326     numOutside = 0;
00327 
00328     for ( i = 0 ; i < b->numsides ; i++ ) {
00329         s = &b->sides[ i ];
00330         if ( s->backSide ) {
00331             continue;
00332         }
00333         plane = &mapplanes[ s->planenum ];
00334 
00335         // handle coplanar outfacing (don't fog)
00336         if ( ds->side->planenum == s->planenum ) {
00337             return qfalse;
00338         }
00339 
00340         // handle coplanar infacing (keep inside)
00341         if ( ( ds->side->planenum ^ 1 ) == s->planenum ) {
00342             continue;
00343         }
00344 
00345         // general case
00346         ClipWindingEpsilon( w, plane->normal, plane->dist, ON_EPSILON,
00347             &front, &back );
00348         FreeWinding( w );
00349         if ( !back ) {
00350             // nothing actually contained inside
00351             for ( j = 0 ; j < numOutside ; j++ ) {
00352                 FreeWinding( outside[j] );
00353             }
00354             return qfalse;
00355         }
00356         if ( front ) {
00357             if ( numOutside == MAX_BRUSH_SIDES ) {
00358                 Error( "MAX_BRUSH_SIDES" );
00359             }
00360             outside[ numOutside ] = front;
00361             numOutside++;
00362         }
00363         w = back;
00364     }
00365 
00366     // all of outside fragments become seperate drawsurfs
00367     // linked to the same side
00368     c_fogFragment += numOutside;
00369     s = ds->side;
00370 
00371     for ( i = 0 ; i < numOutside ; i++ ) {
00372         newds = DrawSurfaceForSide( ds->mapBrush, s, outside[i] );
00373         FreeWinding( outside[i] );
00374     }
00375 
00376 
00377     // replace ds->verts with the verts for w
00378     ds->numVerts = w->numpoints;
00379     free( ds->verts );
00380 
00381     ds->verts = malloc( ds->numVerts * sizeof( *ds->verts ) );
00382     memset( ds->verts, 0, ds->numVerts * sizeof( *ds->verts ) );
00383 
00384     si = s->shaderInfo;
00385 
00386     mins[0] = 9999;
00387     mins[1] = 9999;
00388 
00389     // compute s/t coordinates from brush primitive texture matrix
00390     // compute axis base
00391     ComputeAxisBase( mapplanes[s->planenum].normal, texX, texY );
00392 
00393     for ( j = 0 ; j < w->numpoints ; j++ ) {
00394         dv = ds->verts + j;
00395         VectorCopy( w->p[j], dv->xyz );
00396     
00397         if (g_bBrushPrimit==BPRIMIT_OLDBRUSHES)
00398         {
00399             // calculate texture s/t
00400             dv->st[0] = s->vecs[0][3] + DotProduct( s->vecs[0], dv->xyz );
00401             dv->st[1] = s->vecs[1][3] + DotProduct( s->vecs[1], dv->xyz );  
00402             dv->st[0] /= si->width;
00403             dv->st[1] /= si->height;
00404         }
00405         else
00406         {
00407             // calculate texture s/t from brush primitive texture matrix
00408             x = DotProduct( dv->xyz, texX );
00409             y = DotProduct( dv->xyz, texY );
00410             dv->st[0]=s->texMat[0][0]*x+s->texMat[0][1]*y+s->texMat[0][2];
00411             dv->st[1]=s->texMat[1][0]*x+s->texMat[1][1]*y+s->texMat[1][2];
00412         }
00413 
00414         if ( dv->st[0] < mins[0] ) {
00415             mins[0] = dv->st[0];
00416         }
00417         if ( dv->st[1] < mins[1] ) {
00418             mins[1] = dv->st[1];
00419         }
00420 
00421         // copy normal
00422         VectorCopy ( mapplanes[s->planenum].normal, dv->normal );
00423     }
00424 
00425     // adjust the texture coordinates to be as close to 0 as possible
00426     if ( !si->globalTexture ) {
00427         mins[0] = floor( mins[0] );
00428         mins[1] = floor( mins[1] );
00429         for ( i = 0 ; i < w->numpoints ; i++ ) {
00430             dv = ds->verts + i;
00431             dv->st[0] -= mins[0];
00432             dv->st[1] -= mins[1];
00433         }
00434     }
00435 
00436     return qtrue;
00437 }
00438 
00439 //===============================================================================
00440 
00441 
00442 /*
00443 =====================
00444 FogDrawSurfs
00445 
00446 Call after the surface list has been pruned, 
00447 before tjunction fixing
00448 before lightmap allocation
00449 =====================
00450 */
00451 void FogDrawSurfs( void ) {
00452     int                 i, j, k;
00453     mapDrawSurface_t    *ds;
00454     bspbrush_t          *b;
00455     vec3_t              mins, maxs;
00456     int                 c_fogged;
00457     int                 numBaseDrawSurfs;
00458     dfog_t              *fog;
00459 
00460     qprintf("----- FogDrawsurfs -----\n");
00461 
00462     c_fogged = 0;
00463     c_fogFragment = 0;
00464 
00465     // find all fog brushes
00466     for ( b = entities[0].brushes ; b ; b = b->next ) {
00467         if ( !(b->contents & CONTENTS_FOG) ) {
00468             continue;
00469         }
00470 
00471         if ( numFogs == MAX_MAP_FOGS ) {
00472             Error( "MAX_MAP_FOGS" );
00473         }
00474         fog = &dfogs[numFogs];
00475         numFogs++;
00476         fog->brushNum = b->outputNumber;
00477 
00478         // find a side with a valid shaderInfo
00479         // non-axial fog columns may have bevel planes that need to be skipped
00480         for ( i = 0 ; i < b->numsides ; i++ ) {
00481             if ( b->sides[i].shaderInfo && (b->sides[i].shaderInfo->contents & CONTENTS_FOG) ) {
00482                 strcpy( fog->shader, b->sides[i].shaderInfo->shader );
00483                 break;
00484             }
00485         }
00486         if ( i == b->numsides ) {
00487             continue;       // shouldn't happen
00488         }
00489 
00490         fog->visibleSide = -1;
00491 
00492         // clip each surface into this, but don't clip any of
00493         // the resulting fragments to the same brush
00494         numBaseDrawSurfs = numMapDrawSurfs;
00495         for ( i = 0 ; i < numBaseDrawSurfs ; i++ ) {
00496             ds = &mapDrawSurfs[i];
00497 
00498             // bound the drawsurf
00499             ClearBounds( mins, maxs );
00500             for ( j = 0 ; j < ds->numVerts ; j++ ) {
00501                 AddPointToBounds( ds->verts[j].xyz, mins, maxs );
00502             }
00503 
00504             // check against the fog brush
00505             for ( k = 0 ; k < 3 ; k++ ) {
00506                 if ( mins[k] > b->maxs[k] ) {
00507                     break;
00508                 }
00509                 if ( maxs[k] < b->mins[k] ) {
00510                     break;
00511                 }
00512             }
00513             if ( k < 3 ) {
00514                 continue;       // bboxes don't intersect
00515             }
00516 
00517             if ( ds->mapBrush == b ) {
00518                 int     s;
00519 
00520                 s = ds->side - b->sides;
00521                 if ( s <= 6 ) { // not one of the reversed inside faces
00522                     // this is a visible fog plane
00523                     if ( fog->visibleSide != -1 ) {
00524                         _printf( "WARNING: fog brush %i has multiple visible sides\n", b->brushnum );
00525                     }
00526                     fog->visibleSide = s;
00527                 }
00528             }
00529 
00530             if ( ds->miscModel ) {
00531                 // we could write splitting code for trimodels if we wanted to...
00532                 c_fogged++;
00533                 ds->fogNum = numFogs - 1;
00534             } else if ( ds->patch ) {
00535                 if ( ChopPatchByBrush( ds, b ) ) {
00536                     c_fogged++;
00537                     ds->fogNum = numFogs - 1;
00538                 }
00539             } else {
00540                 if ( ChopFaceByBrush( ds, b ) ) {
00541                     c_fogged++;
00542                     ds->fogNum = numFogs - 1;
00543                 }
00544             }
00545         }
00546     }
00547 
00548     // split the drawsurfs by the fog brushes
00549 
00550     qprintf( "%5i fogs\n", numFogs );
00551     qprintf( "%5i fog polygon fragments\n", c_fogFragment );
00552     qprintf( "%5i fog patch fragments\n", c_fogPatchFragments );
00553     qprintf( "%5i fogged drawsurfs\n", c_fogged );
00554 }

Generated on Thu Aug 25 12:38:20 2005 for Quake III Arena by  doxygen 1.3.9.1