void TraceLine( trace_t *trace ){ int i, j; traceNode_t *node; traceTriangle_t *tt; traceInfo_t *ti; /* setup output (note: this code assumes the input data is completely filled out) */ trace->passSolid = qfalse; trace->opaque = qfalse; trace->compileFlags = 0; trace->numTestNodes = 0; /* early outs */ if ( !trace->recvShadows || !trace->testOcclusion || trace->distance <= 0.00001f ) { return; } /* trace through nodes */ TraceLine_r( headNodeNum, trace->origin, trace->end, trace ); if ( trace->passSolid && !trace->testAll ) { trace->opaque = qtrue; return; } /* skip surfaces? */ if ( noSurfaces ) { return; } /* testall means trace through sky */ if ( trace->testAll && trace->numTestNodes < MAX_TRACE_TEST_NODES && trace->compileFlags & C_SKY && ( trace->numSurfaces == 0 || surfaceInfos[ trace->surfaces[ 0 ] ].childSurfaceNum < 0 ) ) { //% trace->testNodes[ trace->numTestNodes++ ] = skyboxNodeNum; TraceLine_r( skyboxNodeNum, trace->origin, trace->end, trace ); } /* walk node list */ for ( i = 0; i < trace->numTestNodes; i++ ) { /* get node */ node = &traceNodes[ trace->testNodes[ i ] ]; /* walk node item list */ for ( j = 0; j < node->numItems; j++ ) { tt = &traceTriangles[ node->items[ j ] ]; ti = &traceInfos[ tt->infoNum ]; if ( TraceTriangle( ti, tt, trace ) ) { return; } //% if( TraceWinding( &traceWindings[ node->items[ j ] ], trace ) ) //% return; } } }
static qboolean TraceLine_r(int nodeNum, vec3_t origin, vec3_t end, trace_t * trace) { traceNode_t *node; int side; float front, back, frac; vec3_t mid; qboolean r; /* bogus node number means solid, end tracing unless testing all */ if(nodeNum < 0) { VectorCopy(origin, trace->hit); trace->passSolid = qtrue; return qtrue; } /* get node */ node = &traceNodes[nodeNum]; /* solid? */ if(node->type == TRACE_LEAF_SOLID) { VectorCopy(origin, trace->hit); trace->passSolid = qtrue; return qtrue; } /* leafnode? */ if(node->type < 0) { /* note leaf and return */ if(node->numItems > 0 && trace->numTestNodes < MAX_TRACE_TEST_NODES) trace->testNodes[trace->numTestNodes++] = nodeNum; return qfalse; } /* ydnar 2003-09-07: don't test branches of the bsp with nothing in them when testall is enabled */ if(trace->testAll && node->numItems == 0) return qfalse; /* classify beginning and end points */ switch (node->type) { case PLANE_X: front = origin[0] - node->plane[3]; back = end[0] - node->plane[3]; break; case PLANE_Y: front = origin[1] - node->plane[3]; back = end[1] - node->plane[3]; break; case PLANE_Z: front = origin[2] - node->plane[3]; back = end[2] - node->plane[3]; break; default: front = DotProduct(origin, node->plane) - node->plane[3]; back = DotProduct(end, node->plane) - node->plane[3]; break; } /* entirely in front side? */ if(front >= -TRACE_ON_EPSILON && back >= -TRACE_ON_EPSILON) return TraceLine_r(node->children[0], origin, end, trace); /* entirely on back side? */ if(front < TRACE_ON_EPSILON && back < TRACE_ON_EPSILON) return TraceLine_r(node->children[1], origin, end, trace); /* select side */ side = front < 0; /* calculate intercept point */ frac = front / (front - back); mid[0] = origin[0] + (end[0] - origin[0]) * frac; mid[1] = origin[1] + (end[1] - origin[1]) * frac; mid[2] = origin[2] + (end[2] - origin[2]) * frac; /* fixme: check inhibit radius, then solid nodes and ignore */ /* set trace hit here */ //% VectorCopy( mid, trace->hit ); /* trace first side */ r = TraceLine_r(node->children[side], origin, mid, trace); if(r) return r; /* trace other side */ return TraceLine_r(node->children[!side], mid, end, trace); }
void TraceLine( const vec3_t start, const vec3_t stop, trace_t *trace, qboolean testAll, traceWork_t *tw ) { int r; int i, j; dleaf_t *leaf; float oldHitFrac; surfaceTest_t *test; int surfaceNum; byte surfaceTested[MAX_MAP_DRAW_SURFS/8]; ; if ( numthreads == 1 ) { c_totalTrace++; } // assume all light gets through, unless the ray crosses // a translucent surface trace->filter[0] = 1.0; trace->filter[1] = 1.0; trace->filter[2] = 1.0; VectorCopy( start, tw->start ); VectorCopy( stop, tw->end ); tw->trace = trace; tw->numOpenLeafs = 0; trace->passSolid = qfalse; trace->hitFraction = 1.0; r = TraceLine_r( 0, start, stop, tw ); // if we hit a solid leaf, stop without testing the leaf // surfaces. Note that the plane and endpoint might not // be the first solid intersection along the ray. if ( r && !testAll ) { return; } if ( noSurfaces ) { return; } memset( surfaceTested, 0, (numDrawSurfaces+7)/8 ); oldHitFrac = trace->hitFraction; for ( i = 0 ; i < tw->numOpenLeafs ; i++ ) { leaf = &dleafs[ tw->openLeafNumbers[ i ] ]; for ( j = 0 ; j < leaf->numLeafSurfaces ; j++ ) { surfaceNum = dleafsurfaces[ leaf->firstLeafSurface + j ]; // make sure we don't test the same ray against a surface more than once if ( surfaceTested[ surfaceNum>>3 ] & ( 1 << ( surfaceNum & 7) ) ) { continue; } surfaceTested[ surfaceNum>>3 ] |= ( 1 << ( surfaceNum & 7 ) ); test = surfaceTest[ surfaceNum ]; if ( !test ) { continue; } // if ( !tw->patchshadows && test->patch ) { continue; } TraceAgainstSurface( tw, test ); } // if the trace is now solid, we can't possibly hit anything closer if ( trace->hitFraction < oldHitFrac ) { trace->passSolid = qtrue; break; } } for ( i = 0 ; i < 3 ; i++ ) { trace->hit[i] = start[i] + ( stop[i] - start[i] ) * trace->hitFraction; } }
/* ============= TraceLine_r Returns qtrue if something is hit and tracing can stop ============= */ int TraceLine_r( int node, const vec3_t start, const vec3_t stop, traceWork_t *tw ) { tnode_t *tnode; float front, back; vec3_t mid; float frac; int side; int r; if (node & (1<<31)) { if (node & ( 1 << 30 ) ) { VectorCopy (start, tw->trace->hit); tw->trace->passSolid = qtrue; return qtrue; } else { // save the node off for more exact testing if ( tw->numOpenLeafs == MAX_MAP_LEAFS ) { return qfalse; } tw->openLeafNumbers[ tw->numOpenLeafs ] = node & ~(3 << 30); tw->numOpenLeafs++; return qfalse; } } tnode = &tnodes[node]; switch (tnode->type) { case PLANE_X: front = start[0] - tnode->dist; back = stop[0] - tnode->dist; break; case PLANE_Y: front = start[1] - tnode->dist; back = stop[1] - tnode->dist; break; case PLANE_Z: front = start[2] - tnode->dist; back = stop[2] - tnode->dist; break; default: front = (start[0]*tnode->normal[0] + start[1]*tnode->normal[1] + start[2]*tnode->normal[2]) - tnode->dist; back = (stop[0]*tnode->normal[0] + stop[1]*tnode->normal[1] + stop[2]*tnode->normal[2]) - tnode->dist; break; } if (front >= -TRACE_ON_EPSILON && back >= -TRACE_ON_EPSILON) { return TraceLine_r (tnode->children[0], start, stop, tw); } if (front < TRACE_ON_EPSILON && back < TRACE_ON_EPSILON) { return TraceLine_r (tnode->children[1], start, stop, tw); } side = front < 0; frac = front / (front-back); mid[0] = start[0] + (stop[0] - start[0])*frac; mid[1] = start[1] + (stop[1] - start[1])*frac; mid[2] = start[2] + (stop[2] - start[2])*frac; r = TraceLine_r (tnode->children[side], start, mid, tw); if (r) { return r; } // trace->planeNum = tnode->planeNum; return TraceLine_r (tnode->children[!side], mid, stop, tw); }