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

light_trace.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 "light.h"
00023 
00024 
00025 
00026 #define CURVE_FACET_ERROR   8
00027 
00028 int             c_totalTrace;
00029 int             c_cullTrace, c_testTrace;
00030 int             c_testFacets;
00031 
00032 surfaceTest_t   *surfaceTest[MAX_MAP_DRAW_SURFS];
00033 
00034 /*
00035 =====================
00036 CM_GenerateBoundaryForPoints
00037 =====================
00038 */
00039 void CM_GenerateBoundaryForPoints( float boundary[4], float plane[4], vec3_t a, vec3_t b ) {
00040     vec3_t  d1;
00041 
00042     // amke a perpendicular vector to the edge and the surface
00043     VectorSubtract( b, a, d1 );
00044     CrossProduct( plane, d1, boundary );
00045     VectorNormalize( boundary, boundary );
00046     boundary[3] = DotProduct( a, boundary );
00047 }
00048 
00049 /*
00050 =====================
00051 TextureMatrixFromPoints
00052 =====================
00053 */
00054 void TextureMatrixFromPoints( cFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
00055     int         i, j;
00056     float       t;
00057     float       m[3][4];
00058     float       s;
00059 
00060     // This is an incredibly stupid way of solving a three variable equation
00061     for ( i = 0 ; i < 2 ; i++ ) {
00062 
00063         m[0][0] = a->xyz[0];
00064         m[0][1] = a->xyz[1];
00065         m[0][2] = a->xyz[2];
00066         m[0][3] = a->st[i];
00067 
00068         m[1][0] = b->xyz[0];
00069         m[1][1] = b->xyz[1];
00070         m[1][2] = b->xyz[2];
00071         m[1][3] = b->st[i];
00072 
00073         m[2][0] = c->xyz[0];
00074         m[2][1] = c->xyz[1];
00075         m[2][2] = c->xyz[2];
00076         m[2][3] = c->st[i];
00077 
00078         if ( fabs(m[1][0]) > fabs(m[0][0]) && fabs(m[1][0]) > fabs(m[2][0]) ) {
00079             for ( j = 0 ; j < 4 ; j ++ ) {
00080                 t = m[0][j];
00081                 m[0][j] = m[1][j];
00082                 m[1][j] = t;
00083             }
00084         } else if ( fabs(m[2][0]) > fabs(m[0][0]) && fabs(m[2][0]) > fabs(m[1][0]) ) {
00085             for ( j = 0 ; j < 4 ; j ++ ) {
00086                 t = m[0][j];
00087                 m[0][j] = m[2][j];
00088                 m[2][j] = t;
00089             }
00090         }
00091 
00092         s = 1.0 / m[0][0];
00093         m[0][0] *= s;
00094         m[0][1] *= s;
00095         m[0][2] *= s;
00096         m[0][3] *= s;
00097 
00098         s = m[1][0];
00099         m[1][0] -= m[0][0] * s;
00100         m[1][1] -= m[0][1] * s;
00101         m[1][2] -= m[0][2] * s;
00102         m[1][3] -= m[0][3] * s;
00103 
00104         s = m[2][0];
00105         m[2][0] -= m[0][0] * s;
00106         m[2][1] -= m[0][1] * s;
00107         m[2][2] -= m[0][2] * s;
00108         m[2][3] -= m[0][3] * s;
00109 
00110         if ( fabs(m[2][1]) > fabs(m[1][1]) ) {
00111             for ( j = 0 ; j < 4 ; j ++ ) {
00112                 t = m[1][j];
00113                 m[1][j] = m[2][j];
00114                 m[2][j] = t;
00115             }
00116         }
00117 
00118         s = 1.0 / m[1][1];
00119         m[1][0] *= s;
00120         m[1][1] *= s;
00121         m[1][2] *= s;
00122         m[1][3] *= s;
00123 
00124         s = m[2][1];
00125         m[2][0] -= m[1][0] * s;
00126         m[2][1] -= m[1][1] * s;
00127         m[2][2] -= m[1][2] * s;
00128         m[2][3] -= m[1][3] * s;
00129 
00130         s = 1.0 / m[2][2];
00131         m[2][0] *= s;
00132         m[2][1] *= s;
00133         m[2][2] *= s;
00134         m[2][3] *= s;
00135 
00136         f->textureMatrix[i][2] = m[2][3];
00137         f->textureMatrix[i][1] = m[1][3] - f->textureMatrix[i][2] * m[1][2];
00138         f->textureMatrix[i][0] = m[0][3] - f->textureMatrix[i][2] * m[0][2] - f->textureMatrix[i][1] * m[0][1];
00139 
00140         f->textureMatrix[i][3] = 0;
00141 /*
00142         s = fabs( DotProduct( a->xyz, f->textureMatrix[i] ) - a->st[i] );
00143         if ( s > 0.01 ) {
00144             Error( "Bad textureMatrix" );
00145         }
00146         s = fabs( DotProduct( b->xyz, f->textureMatrix[i] ) - b->st[i] );
00147         if ( s > 0.01 ) {
00148             Error( "Bad textureMatrix" );
00149         }
00150         s = fabs( DotProduct( c->xyz, f->textureMatrix[i] ) - c->st[i] );
00151         if ( s > 0.01 ) {
00152             Error( "Bad textureMatrix" );
00153         }
00154 */
00155     }
00156 }
00157 
00158 /*
00159 =====================
00160 CM_GenerateFacetFor3Points
00161 =====================
00162 */
00163 qboolean CM_GenerateFacetFor3Points( cFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
00164     // if we can't generate a valid plane for the points, ignore the facet
00165     if ( !PlaneFromPoints( f->surface, a->xyz, b->xyz, c->xyz ) ) {
00166         f->numBoundaries = 0;
00167         return qfalse;
00168     }
00169 
00170     // make boundaries
00171     f->numBoundaries = 3;
00172 
00173     CM_GenerateBoundaryForPoints( f->boundaries[0], f->surface, a->xyz, b->xyz );
00174     CM_GenerateBoundaryForPoints( f->boundaries[1], f->surface, b->xyz, c->xyz );
00175     CM_GenerateBoundaryForPoints( f->boundaries[2], f->surface, c->xyz, a->xyz );
00176 
00177     VectorCopy( a->xyz, f->points[0] );
00178     VectorCopy( b->xyz, f->points[1] );
00179     VectorCopy( c->xyz, f->points[2] );
00180 
00181     TextureMatrixFromPoints( f, a, b, c );
00182 
00183     return qtrue;
00184 }
00185 
00186 /*
00187 =====================
00188 CM_GenerateFacetFor4Points
00189 
00190 Attempts to use four points as a planar quad
00191 =====================
00192 */
00193 #define PLANAR_EPSILON  0.1
00194 qboolean CM_GenerateFacetFor4Points( cFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c, drawVert_t *d ) {
00195     float   dist;
00196     int     i;
00197     vec4_t  plane;
00198 
00199     // if we can't generate a valid plane for the points, ignore the facet
00200     if ( !PlaneFromPoints( f->surface, a->xyz, b->xyz, c->xyz ) ) {
00201         f->numBoundaries = 0;
00202         return qfalse;
00203     }
00204 
00205     // if the fourth point is also on the plane, we can make a quad facet
00206     dist = DotProduct( d->xyz, f->surface ) - f->surface[3];
00207     if ( fabs( dist ) > PLANAR_EPSILON ) {
00208         f->numBoundaries = 0;
00209         return qfalse;
00210     }
00211 
00212     // make boundaries
00213     f->numBoundaries = 4;
00214 
00215     CM_GenerateBoundaryForPoints( f->boundaries[0], f->surface, a->xyz, b->xyz );
00216     CM_GenerateBoundaryForPoints( f->boundaries[1], f->surface, b->xyz, c->xyz );
00217     CM_GenerateBoundaryForPoints( f->boundaries[2], f->surface, c->xyz, d->xyz );
00218     CM_GenerateBoundaryForPoints( f->boundaries[3], f->surface, d->xyz, a->xyz );
00219 
00220     VectorCopy( a->xyz, f->points[0] );
00221     VectorCopy( b->xyz, f->points[1] );
00222     VectorCopy( c->xyz, f->points[2] );
00223     VectorCopy( d->xyz, f->points[3] );
00224 
00225     for (i = 1; i < 4; i++)
00226     {
00227         if ( !PlaneFromPoints( plane, f->points[i], f->points[(i+1) % 4], f->points[(i+2) % 4]) ) {
00228             f->numBoundaries = 0;
00229             return qfalse;
00230         }
00231 
00232         if (DotProduct(f->surface, plane) < 0.9) {
00233             f->numBoundaries = 0;
00234             return qfalse;
00235         }
00236     }
00237 
00238     TextureMatrixFromPoints( f, a, b, c );
00239 
00240     return qtrue;
00241 }
00242 
00243 
00244 
00245 
00246 /*
00247 ===============
00248 SphereFromBounds
00249 ===============
00250 */
00251 void SphereFromBounds( vec3_t mins, vec3_t maxs, vec3_t origin, float *radius ) {
00252     vec3_t      temp;
00253 
00254     VectorAdd( mins, maxs, origin );
00255     VectorScale( origin, 0.5, origin );
00256     VectorSubtract( maxs, origin, temp );
00257     *radius = VectorLength( temp );
00258 }
00259 
00260 
00261 /*
00262 ====================
00263 FacetsForTriangleSurface
00264 ====================
00265 */
00266 void FacetsForTriangleSurface( dsurface_t *dsurf, shaderInfo_t *si, surfaceTest_t *test ) {
00267     int         i;
00268     drawVert_t  *v1, *v2, *v3, *v4;
00269     int         count;
00270     int         i1, i2, i3, i4, i5, i6;
00271 
00272     test->patch = qfalse;
00273     test->numFacets = dsurf->numIndexes / 3;
00274     test->facets = malloc( sizeof( test->facets[0] ) * test->numFacets );
00275     test->shader = si;
00276 
00277     count = 0;
00278     for ( i = 0 ; i < test->numFacets ; i++ ) {
00279         i1 = drawIndexes[ dsurf->firstIndex + i*3 ];
00280         i2 = drawIndexes[ dsurf->firstIndex + i*3 + 1 ];
00281         i3 = drawIndexes[ dsurf->firstIndex + i*3 + 2 ];
00282 
00283         v1 = &drawVerts[ dsurf->firstVert + i1 ];
00284         v2 = &drawVerts[ dsurf->firstVert + i2 ];
00285         v3 = &drawVerts[ dsurf->firstVert + i3 ];
00286 
00287         // try and make a quad out of two triangles
00288         if ( i != test->numFacets - 1 ) {
00289             i4 = drawIndexes[ dsurf->firstIndex + i*3 + 3 ];
00290             i5 = drawIndexes[ dsurf->firstIndex + i*3 + 4 ];
00291             i6 = drawIndexes[ dsurf->firstIndex + i*3 + 5 ];
00292             if ( i4 == i3 && i5 == i2 ) {
00293                 v4 = &drawVerts[ dsurf->firstVert + i6 ];
00294                 if ( CM_GenerateFacetFor4Points( &test->facets[count], v1, v2, v4, v3 ) ) {
00295                     count++;
00296                     i++;        // skip next tri
00297                     continue;
00298                 }
00299             }
00300         }
00301 
00302         if (CM_GenerateFacetFor3Points( &test->facets[count], v1, v2, v3 ))
00303             count++;
00304     }       
00305 
00306     // we may have turned some pairs into quads
00307     test->numFacets = count;
00308 }
00309 
00310 /*
00311 ====================
00312 FacetsForPatch
00313 ====================
00314 */
00315 void FacetsForPatch( dsurface_t *dsurf, shaderInfo_t *si, surfaceTest_t *test ) {
00316     int         i, j;
00317     drawVert_t  *v1, *v2, *v3, *v4;
00318     int         count;
00319     mesh_t      srcMesh, *subdivided, *mesh;
00320 
00321     srcMesh.width = dsurf->patchWidth;
00322     srcMesh.height = dsurf->patchHeight;
00323     srcMesh.verts = &drawVerts[ dsurf->firstVert ];
00324 
00325     //subdivided = SubdivideMesh( mesh, CURVE_FACET_ERROR, 9999 );
00326     mesh = SubdivideMesh( srcMesh, 8, 999 );
00327     PutMeshOnCurve( *mesh );
00328     MakeMeshNormals( *mesh );
00329 
00330     subdivided = RemoveLinearMeshColumnsRows( mesh );
00331     FreeMesh(mesh);
00332 
00333     test->patch = qtrue;
00334     test->numFacets = ( subdivided->width - 1 ) * ( subdivided->height - 1 ) * 2;
00335     test->facets = malloc( sizeof( test->facets[0] ) * test->numFacets );
00336     test->shader = si;
00337 
00338     count = 0;
00339     for ( i = 0 ; i < subdivided->width - 1 ; i++ ) {
00340         for ( j = 0 ; j < subdivided->height - 1 ; j++ ) {
00341 
00342             v1 = subdivided->verts + j * subdivided->width + i;
00343             v2 = v1 + 1;
00344             v3 = v1 + subdivided->width + 1;
00345             v4 = v1 + subdivided->width;
00346 
00347             if ( CM_GenerateFacetFor4Points( &test->facets[count], v1, v4, v3, v2 ) ) {
00348                 count++;
00349             } else {
00350                 if (CM_GenerateFacetFor3Points( &test->facets[count], v1, v4, v3 ))
00351                     count++;
00352                 if (CM_GenerateFacetFor3Points( &test->facets[count], v1, v3, v2 ))
00353                     count++;
00354             }
00355         }
00356     }
00357     test->numFacets = count;
00358     FreeMesh(subdivided);
00359 }
00360 
00361 
00362 /*
00363 =====================
00364 InitSurfacesForTesting
00365 
00366 Builds structures to speed the ray tracing against surfaces
00367 =====================
00368 */
00369 void InitSurfacesForTesting( void ) {
00370 
00371     int             i, j;
00372     dsurface_t      *dsurf;
00373     surfaceTest_t   *test;
00374     drawVert_t      *dvert;
00375     shaderInfo_t    *si;
00376 
00377     for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
00378         dsurf = &drawSurfaces[ i ];
00379         if ( !dsurf->numIndexes && !dsurf->patchWidth ) {
00380             continue;
00381         }
00382 
00383         // don't make surfaces for transparent objects
00384         // because we want light to pass through them
00385         si = ShaderInfoForShader( dshaders[ dsurf->shaderNum].shader );
00386         if ( (si->contents & CONTENTS_TRANSLUCENT) && !(si->surfaceFlags & SURF_ALPHASHADOW) ) {
00387             continue;
00388         }
00389 
00390         test = malloc( sizeof( *test ) );
00391         surfaceTest[i] = test;
00392         ClearBounds( test->mins, test->maxs );
00393 
00394         dvert = &drawVerts[ dsurf->firstVert ];
00395         for ( j = 0 ; j < dsurf->numVerts ; j++, dvert++ ) {
00396             AddPointToBounds( dvert->xyz, test->mins, test->maxs );
00397         }
00398 
00399         SphereFromBounds( test->mins, test->maxs, test->origin, &test->radius );
00400 
00401         if ( dsurf->surfaceType == MST_TRIANGLE_SOUP || dsurf->surfaceType == MST_PLANAR ) {
00402             FacetsForTriangleSurface( dsurf, si, test );
00403         } else if ( dsurf->surfaceType == MST_PATCH ) {
00404             FacetsForPatch( dsurf, si, test );
00405         }
00406     }
00407 }
00408 
00409 
00410 /*
00411 =====================
00412 GenerateBoundaryForPoints
00413 =====================
00414 */
00415 void GenerateBoundaryForPoints( float boundary[4], float plane[4], vec3_t a, vec3_t b ) {
00416     vec3_t  d1;
00417 
00418     // amke a perpendicular vector to the edge and the surface
00419     VectorSubtract( b, a, d1 );
00420     CrossProduct( plane, d1, boundary );
00421     VectorNormalize( boundary, boundary );
00422     boundary[3] = DotProduct( a, boundary );
00423 }
00424 
00425 
00426 /*
00427 =================
00428 SetFacetFilter
00429 
00430 Given a point on a facet, determine the color filter
00431 for light passing through
00432 =================
00433 */
00434 void SetFacetFilter( traceWork_t *tr, shaderInfo_t *shader, cFacet_t *facet, vec3_t point ) {
00435     float   s, t;
00436     int     is, it;
00437     byte    *image;
00438     int     b;
00439 
00440     // most surfaces are completely opaque
00441     if ( !(shader->surfaceFlags & SURF_ALPHASHADOW) ) {
00442         VectorClear( tr->trace->filter );
00443         return;
00444     }
00445 
00446     s = DotProduct( point, facet->textureMatrix[0] ) + facet->textureMatrix[0][3];
00447     t = DotProduct( point, facet->textureMatrix[1] ) + facet->textureMatrix[1][3];
00448 
00449     if ( !shader->pixels ) {
00450         // assume completely solid
00451         VectorClear( point );
00452         return;
00453     }
00454 
00455     s = s - floor( s );
00456     t = t - floor( t );
00457 
00458     is = s * shader->width;
00459     it = t * shader->height;
00460 
00461     image = shader->pixels + 4 * ( it * shader->width + is );
00462 
00463     // alpha filter
00464     b = image[3];
00465 
00466     // alpha test makes this a binary option
00467     b = b < 128 ? 0 : 255;
00468 
00469     tr->trace->filter[0] = tr->trace->filter[0] * (255-b) / 255;
00470     tr->trace->filter[1] = tr->trace->filter[1] * (255-b) / 255;
00471     tr->trace->filter[2] = tr->trace->filter[2] * (255-b) / 255;
00472 }
00473 
00474 
00475 /*
00476 ====================
00477 TraceAgainstFacet
00478 
00479 Shader is needed for translucent surfaces
00480 ====================
00481 */
00482 void TraceAgainstFacet( traceWork_t *tr, shaderInfo_t *shader, cFacet_t *facet ) {
00483     int         j;
00484     float       d1, d2, d, f;
00485     vec3_t      point;
00486     float       dist;
00487 
00488     // ignore degenerate facets
00489     if ( facet->numBoundaries < 3 ) {
00490         return;
00491     }
00492 
00493     dist = facet->surface[3];
00494 
00495     // compare the trace endpoints against the facet plane
00496     d1 = DotProduct( tr->start, facet->surface ) - dist;
00497     if ( d1 > -1 && d1 < 1 ) {
00498         return;     // don't self intersect
00499     }
00500     d2 = DotProduct( tr->end, facet->surface ) - dist;
00501     if ( d2 > -1 && d2 < 1 ) {
00502         return;     // don't self intersect
00503     }
00504 
00505     // calculate the intersection fraction
00506     f = ( d1 - ON_EPSILON ) / ( d1 - d2 );
00507     if ( f <= 0 ) {
00508         return;
00509     }
00510     if ( f >= tr->trace->hitFraction ) {
00511         return;         // we have hit something earlier
00512     }
00513 
00514     // calculate the intersection point
00515     for ( j = 0 ; j < 3 ; j++ ) {
00516         point[j] = tr->start[j] + f * ( tr->end[j] - tr->start[j] );
00517     }
00518 
00519     // check the point against the facet boundaries
00520     for ( j = 0 ; j < facet->numBoundaries ; j++ ) {
00521         // adjust the plane distance apropriately for mins/maxs
00522         dist = facet->boundaries[j][3];
00523 
00524         d = DotProduct( point, facet->boundaries[j] );
00525         if ( d > dist + ON_EPSILON ) {
00526             break;      // outside the bounds
00527         }
00528     }
00529 
00530     if ( j != facet->numBoundaries ) {
00531         return;         // we are outside the bounds of the facet
00532     }
00533 
00534     // we hit this facet
00535 
00536     // if this is a transparent surface, calculate filter value
00537     if ( shader->surfaceFlags & SURF_ALPHASHADOW ) {
00538         SetFacetFilter( tr, shader, facet, point );
00539     } else {
00540         // completely opaque
00541         VectorClear( tr->trace->filter );
00542         tr->trace->hitFraction = f;
00543     }
00544 
00545 //  VectorCopy( facet->surface, tr->trace->plane.normal );
00546 //  tr->trace->plane.dist = facet->surface[3];
00547 }
00548 
00549 
00550 /*
00551 ===============================================================
00552 
00553   LINE TRACING
00554 
00555 ===============================================================
00556 */
00557 
00558 
00559 #define TRACE_ON_EPSILON    0.1
00560 
00561 typedef struct tnode_s
00562 {
00563     int     type;
00564     vec3_t  normal;
00565     float   dist;
00566     int     children[2];
00567     int     planeNum;
00568 } tnode_t;
00569 
00570 #define MAX_TNODES  (MAX_MAP_NODES*4)
00571 tnode_t     *tnodes, *tnode_p;
00572 
00573 /*
00574 ==============
00575 MakeTnode
00576 
00577 Converts the disk node structure into the efficient tracing structure
00578 ==============
00579 */
00580 void MakeTnode (int nodenum)
00581 {
00582     tnode_t         *t;
00583     dplane_t        *plane;
00584     int             i;
00585     dnode_t         *node;
00586     int             leafNum;
00587 
00588     t = tnode_p++;
00589 
00590     node = dnodes + nodenum;
00591     plane = dplanes + node->planeNum;
00592 
00593     t->planeNum = node->planeNum;
00594     t->type = PlaneTypeForNormal( plane->normal );
00595     VectorCopy (plane->normal, t->normal);
00596     t->dist = plane->dist;
00597     
00598     for (i=0 ; i<2 ; i++)
00599     {
00600         if (node->children[i] < 0) {
00601             leafNum = -node->children[i] - 1;
00602             if ( dleafs[leafNum].cluster == -1  ) {
00603                 // solid
00604                 t->children[i] = leafNum | ( 1 << 31 ) | ( 1 << 30 );
00605             } else {
00606                 t->children[i] = leafNum | ( 1 << 31 );
00607             }
00608         } else {
00609             t->children[i] = tnode_p - tnodes;
00610             MakeTnode (node->children[i]);
00611         }
00612     }
00613             
00614 }
00615 
00616 /*
00617 =============
00618 InitTrace
00619 
00620 Loads the node structure out of a .bsp file to be used for light occlusion
00621 =============
00622 */
00623 void InitTrace( void ) {
00624     // 32 byte align the structs
00625     tnodes = malloc( (MAX_TNODES+1) * sizeof(tnode_t));
00626     tnodes = (tnode_t *)(((int)tnodes + 31)&~31);
00627     tnode_p = tnodes;
00628 
00629     MakeTnode (0);
00630 
00631     InitSurfacesForTesting();
00632 }
00633 
00634 
00635 /*
00636 ===================
00637 PointInSolid
00638 ===================
00639 */
00640 qboolean PointInSolid_r( vec3_t start, int node ) {
00641     tnode_t *tnode;
00642     float   front;
00643 
00644     while ( !(node & (1<<31) ) ) {
00645         tnode = &tnodes[node];
00646         switch (tnode->type) {
00647         case PLANE_X:
00648             front = start[0] - tnode->dist;
00649             break;
00650         case PLANE_Y:
00651             front = start[1] - tnode->dist;
00652             break;
00653         case PLANE_Z:
00654             front = start[2] - tnode->dist;
00655             break;
00656         default:
00657             front = (start[0]*tnode->normal[0] + start[1]*tnode->normal[1] + start[2]*tnode->normal[2]) - tnode->dist;
00658             break;
00659         }
00660 
00661         if ( front == 0 ) {
00662             // exactly on node, must check both sides
00663             return (qboolean) ( PointInSolid_r( start, tnode->children[0] ) 
00664                 | PointInSolid_r( start, tnode->children[1] ) );
00665         }
00666 
00667         if ( front > 0 ) {
00668             node = tnode->children[0];
00669         } else {
00670             node = tnode->children[1];
00671         }
00672     }
00673 
00674     if ( node & ( 1 << 30 ) ) {
00675         return qtrue;
00676     }
00677     return qfalse;
00678 }
00679 
00680 /*
00681 =============
00682 PointInSolid
00683 
00684 =============
00685 */
00686 qboolean PointInSolid( vec3_t start ) {
00687     return PointInSolid_r( start, 0 );
00688 }
00689 
00690 
00691 /*
00692 =============
00693 TraceLine_r
00694 
00695 Returns qtrue if something is hit and tracing can stop
00696 =============
00697 */
00698 int TraceLine_r( int node, const vec3_t start, const vec3_t stop, traceWork_t *tw ) {
00699     tnode_t *tnode;
00700     float   front, back;
00701     vec3_t  mid;
00702     float   frac;
00703     int     side;
00704     int     r;
00705 
00706     if (node & (1<<31)) {
00707         if (node & ( 1 << 30 ) ) {
00708             VectorCopy (start, tw->trace->hit);
00709             tw->trace->passSolid = qtrue;
00710             return qtrue;
00711         } else {
00712             // save the node off for more exact testing
00713             if ( tw->numOpenLeafs == MAX_MAP_LEAFS ) {
00714                 return qfalse;
00715             }
00716             tw->openLeafNumbers[ tw->numOpenLeafs ] = node & ~(3 << 30);
00717             tw->numOpenLeafs++;
00718             return qfalse;
00719         }
00720     }
00721 
00722     tnode = &tnodes[node];
00723     switch (tnode->type) {
00724     case PLANE_X:
00725         front = start[0] - tnode->dist;
00726         back = stop[0] - tnode->dist;
00727         break;
00728     case PLANE_Y:
00729         front = start[1] - tnode->dist;
00730         back = stop[1] - tnode->dist;
00731         break;
00732     case PLANE_Z:
00733         front = start[2] - tnode->dist;
00734         back = stop[2] - tnode->dist;
00735         break;
00736     default:
00737         front = (start[0]*tnode->normal[0] + start[1]*tnode->normal[1] + start[2]*tnode->normal[2]) - tnode->dist;
00738         back = (stop[0]*tnode->normal[0] + stop[1]*tnode->normal[1] + stop[2]*tnode->normal[2]) - tnode->dist;
00739         break;
00740     }
00741 
00742     if (front >= -TRACE_ON_EPSILON && back >= -TRACE_ON_EPSILON) {
00743         return TraceLine_r (tnode->children[0], start, stop, tw);
00744     }
00745     
00746     if (front < TRACE_ON_EPSILON && back < TRACE_ON_EPSILON) {
00747         return TraceLine_r (tnode->children[1], start, stop, tw);
00748     }
00749 
00750     side = front < 0;
00751     
00752     frac = front / (front-back);
00753 
00754     mid[0] = start[0] + (stop[0] - start[0])*frac;
00755     mid[1] = start[1] + (stop[1] - start[1])*frac;
00756     mid[2] = start[2] + (stop[2] - start[2])*frac;
00757 
00758     r = TraceLine_r (tnode->children[side], start, mid, tw);
00759 
00760     if (r) {
00761         return r;
00762     }
00763 
00764 //  trace->planeNum = tnode->planeNum;
00765     return TraceLine_r (tnode->children[!side], mid, stop, tw);
00766 }
00767 
00768 //==========================================================================================
00769 
00770 
00771 /*
00772 ================
00773 SphereCull
00774 ================
00775 */
00776 qboolean    SphereCull( vec3_t start, vec3_t stop, vec3_t origin, float radius ) {
00777     vec3_t      v;
00778     float       d;
00779     vec3_t      dir;
00780     float       len;
00781     vec3_t      on;
00782 
00783     VectorSubtract( stop, start, dir );
00784     len = VectorNormalize( dir, dir );
00785 
00786     VectorSubtract( origin, start, v );
00787     d = DotProduct( v, dir );
00788     if ( d > len + radius ) {
00789         return qtrue;       // too far ahead
00790     }
00791     if ( d < -radius ) {
00792         return qtrue;       // too far behind
00793     }
00794     VectorMA( start, d, dir, on );
00795     
00796     VectorSubtract( on, origin, v );
00797 
00798     len = VectorLength( v );
00799 
00800     if ( len > radius ) {
00801         return qtrue;       // too far to the side
00802     }
00803 
00804     return qfalse;      // must be traced against
00805 }
00806 
00807 /*
00808 ================
00809 TraceAgainstSurface
00810 ================
00811 */
00812 void    TraceAgainstSurface( traceWork_t *tw, surfaceTest_t *surf ) {
00813     int     i;
00814 
00815     // if surfaces are trans
00816     if ( SphereCull( tw->start, tw->end, surf->origin, surf->radius ) ) {
00817         if ( numthreads == 1 ) {
00818             c_cullTrace++;
00819         }
00820         return;
00821     }
00822 
00823     if ( numthreads == 1 ) {
00824         c_testTrace++;
00825         c_testFacets += surf->numFacets;
00826     }
00827 
00828     /*
00829     // MrE: backface culling
00830     if (!surf->patch && surf->numFacets) {
00831         // if the surface does not cast an alpha shadow
00832         if ( !(surf->shader->surfaceFlags & SURF_ALPHASHADOW) ) {
00833             vec3_t vec;
00834             VectorSubtract(tw->end, tw->start, vec);
00835             if (DotProduct(vec, surf->facets->surface) > 0)
00836                 return;
00837         }
00838     }
00839     */
00840 
00841     // test against each facet
00842     for ( i = 0 ; i < surf->numFacets ; i++ ) {
00843         TraceAgainstFacet( tw, surf->shader, surf->facets + i );
00844     }
00845 }
00846 
00847 /*
00848 =============
00849 TraceLine
00850 
00851 Follow the trace just through the solid leafs first, and only
00852 if it passes that, trace against the objects inside the empty leafs
00853 Returns qtrue if the trace hit any
00854 
00855 traceWork_t is only a parameter to crutch up poor large local allocations on
00856 winNT and macOS.  It should be allocated in the worker function, but never
00857 looked at.
00858 
00859 leave testAll false if all you care about is if it hit anything at all.
00860 if you need to know the exact first point of impact (for a sun trace), set
00861 testAll to true
00862 =============
00863 */
00864 extern qboolean patchshadows;
00865 
00866 void TraceLine( const vec3_t start, const vec3_t stop, trace_t *trace, qboolean testAll, traceWork_t *tw ) {
00867     int             r;
00868     int             i, j;
00869     dleaf_t         *leaf;
00870     float           oldHitFrac;
00871     surfaceTest_t   *test;
00872     int             surfaceNum;
00873     byte            surfaceTested[MAX_MAP_DRAW_SURFS/8];
00874     ;
00875 
00876     if ( numthreads == 1 ) {
00877         c_totalTrace++;
00878     }
00879 
00880     // assume all light gets through, unless the ray crosses
00881     // a translucent surface
00882     trace->filter[0] = 1.0;
00883     trace->filter[1] = 1.0;
00884     trace->filter[2] = 1.0;
00885 
00886     VectorCopy( start, tw->start );
00887     VectorCopy( stop, tw->end );
00888     tw->trace = trace;
00889 
00890     tw->numOpenLeafs = 0;
00891 
00892     trace->passSolid = qfalse;
00893     trace->hitFraction = 1.0;
00894 
00895     r = TraceLine_r( 0, start, stop, tw );
00896 
00897     // if we hit a solid leaf, stop without testing the leaf
00898     // surfaces.  Note that the plane and endpoint might not
00899     // be the first solid intersection along the ray.
00900     if ( r && !testAll ) {
00901         return;
00902     }
00903 
00904     if ( noSurfaces ) {
00905         return;
00906     }
00907 
00908     memset( surfaceTested, 0, (numDrawSurfaces+7)/8 );
00909     oldHitFrac = trace->hitFraction;
00910 
00911     for ( i = 0 ; i < tw->numOpenLeafs ; i++ ) {
00912         leaf = &dleafs[ tw->openLeafNumbers[ i ] ];
00913         for ( j = 0 ; j < leaf->numLeafSurfaces ; j++ ) {
00914             surfaceNum = dleafsurfaces[ leaf->firstLeafSurface + j ];
00915 
00916             // make sure we don't test the same ray against a surface more than once
00917             if ( surfaceTested[ surfaceNum>>3 ] & ( 1 << ( surfaceNum & 7) ) ) {
00918                 continue;
00919             }
00920             surfaceTested[ surfaceNum>>3 ] |= ( 1 << ( surfaceNum & 7 ) );
00921 
00922             test = surfaceTest[ surfaceNum ];
00923             if ( !test ) {
00924                 continue;
00925             }
00926             //
00927             if ( !tw->patchshadows && test->patch ) {
00928                 continue;
00929             }
00930             TraceAgainstSurface( tw, test );
00931         }
00932 
00933         // if the trace is now solid, we can't possibly hit anything closer
00934         if ( trace->hitFraction < oldHitFrac ) {
00935             trace->passSolid = qtrue;
00936             break;
00937         }
00938     }
00939     
00940     for ( i = 0 ; i < 3 ; i++ ) {
00941         trace->hit[i] = start[i] + ( stop[i] - start[i] ) * trace->hitFraction;
00942     }
00943 }
00944 

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