1 /* -------------------------------------------------------------------------------
3 Copyright (C) 1999-2007 id Software, Inc. and contributors.
4 For a list of contributors, see the accompanying CONTRIBUTORS file.
6 This file is part of GtkRadiant.
8 GtkRadiant is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 GtkRadiant is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GtkRadiant; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 ----------------------------------------------------------------------------------
24 This code has been altered significantly from its original form, to support
25 several games based on the Quake III Arena engine, in the form of "Q3Map2."
27 ------------------------------------------------------------------------------- */
45 #define Vector2Copy( a, b ) ( ( b )[ 0 ] = ( a )[ 0 ], ( b )[ 1 ] = ( a )[ 1 ] )
46 #define Vector4Copy( a, b ) ( ( b )[ 0 ] = ( a )[ 0 ], ( b )[ 1 ] = ( a )[ 1 ], ( b )[ 2 ] = ( a )[ 2 ], ( b )[ 3 ] = ( a )[ 3 ] )
48 #define MAX_NODE_ITEMS 5
49 #define MAX_NODE_TRIANGLES 5
50 #define MAX_TRACE_DEPTH 32
51 #define MIN_NODE_SIZE 32.0f
53 #define GROW_TRACE_INFOS 32768 //% 4096
54 #define GROW_TRACE_WINDINGS 65536 //% 32768
55 #define GROW_TRACE_TRIANGLES 131072 //% 32768
56 #define GROW_TRACE_NODES 16384 //% 16384
57 #define GROW_NODE_ITEMS 16 //% 256
59 #define MAX_TW_VERTS 12
61 #define TRACE_ON_EPSILON 0.1f
64 #define TRACE_LEAF_SOLID -2
66 typedef struct traceVert_s
73 typedef struct traceInfo_s
76 int surfaceNum, castShadows;
80 typedef struct traceWinding_s
83 int infoNum, numVerts;
84 traceVert_t v[ MAX_TW_VERTS ];
88 typedef struct traceTriangle_s
96 typedef struct traceNode_s
102 int numItems, maxItems;
108 int noDrawContentFlags, noDrawSurfaceFlags, noDrawCompileFlags;
110 int numTraceInfos = 0, maxTraceInfos = 0, firstTraceInfo = 0;
111 traceInfo_t *traceInfos = NULL;
113 int numTraceWindings = 0, maxTraceWindings = 0, deadWinding = -1;
114 traceWinding_t *traceWindings = NULL;
116 int numTraceTriangles = 0, maxTraceTriangles = 0, deadTriangle = -1;
117 traceTriangle_t *traceTriangles = NULL;
119 int headNodeNum = 0, skyboxNodeNum = 0, maxTraceDepth = 0, numTraceLeafNodes = 0;
120 int numTraceNodes = 0, maxTraceNodes = 0;
121 traceNode_t *traceNodes = NULL;
125 /* -------------------------------------------------------------------------------
127 allocation and list management
129 ------------------------------------------------------------------------------- */
132 AddTraceInfo() - ydnar
133 adds a trace info structure to the pool
136 static int AddTraceInfo( traceInfo_t *ti ){
141 /* find an existing info */
142 for ( num = firstTraceInfo; num < numTraceInfos; num++ )
144 if ( traceInfos[ num ].si == ti->si &&
145 traceInfos[ num ].surfaceNum == ti->surfaceNum &&
146 traceInfos[ num ].castShadows == ti->castShadows ) {
152 if ( numTraceInfos >= maxTraceInfos ) {
153 /* allocate more room */
154 maxTraceInfos += GROW_TRACE_INFOS;
155 temp = safe_malloc( maxTraceInfos * sizeof( *traceInfos ) );
156 if ( traceInfos != NULL ) {
157 memcpy( temp, traceInfos, numTraceInfos * sizeof( *traceInfos ) );
160 traceInfos = (traceInfo_t*) temp;
164 memcpy( &traceInfos[ num ], ti, sizeof( *traceInfos ) );
165 if ( num == numTraceInfos ) {
169 /* return the ti number */
176 AllocTraceNode() - ydnar
177 allocates a new trace node
180 static int AllocTraceNode( void ){
185 if ( numTraceNodes >= maxTraceNodes ) {
186 /* reallocate more room */
187 maxTraceNodes += GROW_TRACE_NODES;
188 temp = safe_malloc( maxTraceNodes * sizeof( traceNode_t ) );
189 if ( traceNodes != NULL ) {
190 memcpy( temp, traceNodes, numTraceNodes * sizeof( traceNode_t ) );
197 memset( &traceNodes[ numTraceNodes ], 0, sizeof( traceNode_t ) );
198 traceNodes[ numTraceNodes ].type = TRACE_LEAF;
199 ClearBounds( traceNodes[ numTraceNodes ].mins, traceNodes[ numTraceNodes ].maxs );
202 /* return the count */
203 return ( numTraceNodes - 1 );
209 AddTraceWinding() - ydnar
210 adds a winding to the raytracing pool
213 static int AddTraceWinding( traceWinding_t *tw ){
218 /* check for a dead winding */
219 if ( deadWinding >= 0 && deadWinding < numTraceWindings ) {
224 /* put winding at the end of the list */
225 num = numTraceWindings;
228 if ( numTraceWindings >= maxTraceWindings ) {
229 /* allocate more room */
230 maxTraceWindings += GROW_TRACE_WINDINGS;
231 temp = safe_malloc( maxTraceWindings * sizeof( *traceWindings ) );
232 if ( traceWindings != NULL ) {
233 memcpy( temp, traceWindings, numTraceWindings * sizeof( *traceWindings ) );
234 free( traceWindings );
236 traceWindings = (traceWinding_t*) temp;
240 /* add the winding */
241 memcpy( &traceWindings[ num ], tw, sizeof( *traceWindings ) );
242 if ( num == numTraceWindings ) {
247 /* return the winding number */
254 AddTraceTriangle() - ydnar
255 adds a triangle to the raytracing pool
258 static int AddTraceTriangle( traceTriangle_t *tt ){
263 /* check for a dead triangle */
264 if ( deadTriangle >= 0 && deadTriangle < numTraceTriangles ) {
269 /* put triangle at the end of the list */
270 num = numTraceTriangles;
273 if ( numTraceTriangles >= maxTraceTriangles ) {
274 /* allocate more room */
275 maxTraceTriangles += GROW_TRACE_TRIANGLES;
276 temp = safe_malloc( maxTraceTriangles * sizeof( *traceTriangles ) );
277 if ( traceTriangles != NULL ) {
278 memcpy( temp, traceTriangles, numTraceTriangles * sizeof( *traceTriangles ) );
279 free( traceTriangles );
281 traceTriangles = (traceTriangle_t*) temp;
285 /* find vectors for two edges sharing the first vert */
286 VectorSubtract( tt->v[ 1 ].xyz, tt->v[ 0 ].xyz, tt->edge1 );
287 VectorSubtract( tt->v[ 2 ].xyz, tt->v[ 0 ].xyz, tt->edge2 );
289 /* add the triangle */
290 memcpy( &traceTriangles[ num ], tt, sizeof( *traceTriangles ) );
291 if ( num == numTraceTriangles ) {
296 /* return the triangle number */
303 AddItemToTraceNode() - ydnar
304 adds an item reference (winding or triangle) to a trace node
307 static int AddItemToTraceNode( traceNode_t *node, int num ){
317 if ( node->numItems >= node->maxItems ) {
318 /* allocate more room */
319 if ( node == traceNodes ) {
323 node->maxItems += GROW_NODE_ITEMS;
325 if ( node->maxItems <= 0 ) {
326 node->maxItems = GROW_NODE_ITEMS;
328 temp = safe_malloc( node->maxItems * sizeof( *node->items ) );
329 if ( node->items != NULL ) {
330 memcpy( temp, node->items, node->numItems * sizeof( *node->items ) );
333 node->items = (int*) temp;
337 node->items[ node->numItems ] = num;
340 /* return the count */
341 return ( node->numItems - 1 );
347 /* -------------------------------------------------------------------------------
351 ------------------------------------------------------------------------------- */
354 SetupTraceNodes_r() - ydnar
355 recursively create the initial trace node structure from the bsp tree
358 static int SetupTraceNodes_r( int bspNodeNum ){
359 int i, nodeNum, bspLeafNum;
364 /* get bsp node and plane */
365 bspNode = &bspNodes[ bspNodeNum ];
366 plane = &bspPlanes[ bspNode->planeNum ];
368 /* allocate a new trace node */
369 nodeNum = AllocTraceNode();
371 /* setup trace node */
372 traceNodes[ nodeNum ].type = PlaneTypeForNormal( plane->normal );
373 VectorCopy( plane->normal, traceNodes[ nodeNum ].plane );
374 traceNodes[ nodeNum ].plane[ 3 ] = plane->dist;
377 for ( i = 0; i < 2; i++ )
380 if ( bspNode->children[ i ] < 0 ) {
381 bspLeafNum = -bspNode->children[ i ] - 1;
384 traceNodes[ nodeNum ].children[ i ] = AllocTraceNode();
385 if ( bspLeafs[ bspLeafNum ].cluster == -1 ) {
386 traceNodes[ traceNodes[ nodeNum ].children[ i ] ].type = TRACE_LEAF_SOLID;
392 traceNodes[ nodeNum ].children[ i ] = SetupTraceNodes_r( bspNode->children[ i ] );
396 /* return node number */
403 ClipTraceWinding() - ydnar
404 clips a trace winding against a plane into one or two parts
407 #define TW_ON_EPSILON 0.25f
409 void ClipTraceWinding( traceWinding_t *tw, vec4_t plane, traceWinding_t *front, traceWinding_t *back ){
411 int sides[ MAX_TW_VERTS ], counts[ 3 ] = { 0, 0, 0 };
412 float dists[ MAX_TW_VERTS ];
414 traceVert_t *a, *b, mid;
417 /* clear front and back */
421 /* classify points */
422 for ( i = 0; i < tw->numVerts; i++ )
424 dists[ i ] = DotProduct( tw->v[ i ].xyz, plane ) - plane[ 3 ];
425 if ( dists[ i ] < -TW_ON_EPSILON ) {
426 sides[ i ] = SIDE_BACK;
428 else if ( dists[ i ] > TW_ON_EPSILON ) {
429 sides[ i ] = SIDE_FRONT;
432 sides[ i ] = SIDE_ON;
434 counts[ sides[ i ] ]++;
437 /* entirely on front? */
438 if ( counts[ SIDE_BACK ] == 0 ) {
439 memcpy( front, tw, sizeof( *front ) );
442 /* entirely on back? */
443 else if ( counts[ SIDE_FRONT ] == 0 ) {
444 memcpy( back, tw, sizeof( *back ) );
447 /* straddles the plane */
450 /* setup front and back */
451 memcpy( front, tw, sizeof( *front ) );
453 memcpy( back, tw, sizeof( *back ) );
456 /* split the winding */
457 for ( i = 0; i < tw->numVerts; i++ )
460 j = ( i + 1 ) % tw->numVerts;
466 /* handle points on the splitting plane */
467 switch ( sides[ i ] )
470 if ( front->numVerts >= MAX_TW_VERTS ) {
471 Error( "MAX_TW_VERTS (%d) exceeded", MAX_TW_VERTS );
473 front->v[ front->numVerts++ ] = *a;
477 if ( back->numVerts >= MAX_TW_VERTS ) {
478 Error( "MAX_TW_VERTS (%d) exceeded", MAX_TW_VERTS );
480 back->v[ back->numVerts++ ] = *a;
484 if ( front->numVerts >= MAX_TW_VERTS || back->numVerts >= MAX_TW_VERTS ) {
485 Error( "MAX_TW_VERTS (%d) exceeded", MAX_TW_VERTS );
487 front->v[ front->numVerts++ ] = *a;
488 back->v[ back->numVerts++ ] = *a;
492 /* check next point to see if we need to split the edge */
493 if ( sides[ j ] == SIDE_ON || sides[ j ] == sides[ i ] ) {
498 if ( front->numVerts >= MAX_TW_VERTS || back->numVerts >= MAX_TW_VERTS ) {
499 Error( "MAX_TW_VERTS (%d) exceeded", MAX_TW_VERTS );
502 /* generate a split point */
503 frac = dists[ i ] / ( dists[ i ] - dists[ j ] );
504 for ( k = 0; k < 3; k++ )
506 /* minimize fp precision errors */
507 if ( plane[ k ] == 1.0f ) {
508 mid.xyz[ k ] = plane[ 3 ];
510 else if ( plane[ k ] == -1.0f ) {
511 mid.xyz[ k ] = -plane[ 3 ];
514 mid.xyz[ k ] = a->xyz[ k ] + frac * ( b->xyz[ k ] - a->xyz[ k ] );
517 /* set texture coordinates */
521 mid.st[ 0 ] = a->st[ 0 ] + frac * ( b->st[ 0 ] - a->st[ 0 ] );
522 mid.st[ 1 ] = a->st[ 1 ] + frac * ( b->st[ 1 ] - a->st[ 1 ] );
525 /* copy midpoint to front and back polygons */
526 front->v[ front->numVerts++ ] = mid;
527 back->v[ back->numVerts++ ] = mid;
535 FilterPointToTraceNodes_r() - ydnar
539 static int FilterPointToTraceNodes_r( vec3_t pt, int nodeNum ){
544 if ( nodeNum < 0 || nodeNum >= numTraceNodes ) {
548 node = &traceNodes[ nodeNum ];
550 if ( node->type >= 0 ) {
551 dot = DotProduct( pt, node->plane ) - node->plane[ 3 ];
552 if ( dot > -0.001f ) {
553 FilterPointToTraceNodes_r( pt, node->children[ 0 ] );
555 if ( dot < 0.001f ) {
556 FilterPointToTraceNodes_r( pt, node->children[ 1 ] );
561 Sys_Printf( "%d ", nodeNum );
569 FilterTraceWindingIntoNodes_r() - ydnar
570 filters a trace winding into the raytracing tree
573 static void FilterTraceWindingIntoNodes_r( traceWinding_t *tw, int nodeNum ){
575 vec4_t plane1, plane2, reverse;
577 traceWinding_t front, back;
580 /* don't filter if passed a bogus node (solid, etc) */
581 if ( nodeNum < 0 || nodeNum >= numTraceNodes ) {
586 node = &traceNodes[ nodeNum ];
588 /* is this a decision node? */
589 if ( node->type >= 0 ) {
590 /* create winding plane if necessary, filtering out bogus windings as well */
591 if ( nodeNum == headNodeNum ) {
592 if ( !PlaneFromPoints( tw->plane, tw->v[ 0 ].xyz, tw->v[ 1 ].xyz, tw->v[ 2 ].xyz ) ) {
597 /* validate the node */
598 if ( node->children[ 0 ] == 0 || node->children[ 1 ] == 0 ) {
599 Error( "Invalid tracenode: %d", nodeNum );
603 Vector4Copy( node->plane, plane1 );
605 /* get winding plane */
606 Vector4Copy( tw->plane, plane2 );
608 /* invert surface plane */
609 VectorSubtract( vec3_origin, plane2, reverse );
610 reverse[ 3 ] = -plane2[ 3 ];
613 if ( DotProduct( plane1, plane2 ) > 0.999f && fabs( plane1[ 3 ] - plane2[ 3 ] ) < 0.001f ) {
614 FilterTraceWindingIntoNodes_r( tw, node->children[ 0 ] );
619 if ( DotProduct( plane1, reverse ) > 0.999f && fabs( plane1[ 3 ] - reverse[ 3 ] ) < 0.001f ) {
620 FilterTraceWindingIntoNodes_r( tw, node->children[ 1 ] );
624 /* clip the winding by node plane */
625 ClipTraceWinding( tw, plane1, &front, &back );
627 /* filter by node plane */
628 if ( front.numVerts >= 3 ) {
629 FilterTraceWindingIntoNodes_r( &front, node->children[ 0 ] );
631 if ( back.numVerts >= 3 ) {
632 FilterTraceWindingIntoNodes_r( &back, node->children[ 1 ] );
635 /* return to caller */
639 /* add winding to leaf node */
640 num = AddTraceWinding( tw );
641 AddItemToTraceNode( node, num );
647 SubdivideTraceNode_r() - ydnar
648 recursively subdivides a tracing node until it meets certain size and complexity criteria
651 static void SubdivideTraceNode_r( int nodeNum, int depth ){
652 int i, j, count, num, frontNum, backNum, type;
656 traceNode_t *node, *frontNode, *backNode;
657 traceWinding_t *tw, front, back;
661 if ( nodeNum < 0 || nodeNum >= numTraceNodes ) {
666 node = &traceNodes[ nodeNum ];
668 /* runaway recursion check */
669 if ( depth >= MAX_TRACE_DEPTH ) {
670 //% Sys_Printf( "Depth: (%d items)\n", node->numItems );
676 /* is this a decision node? */
677 if ( node->type >= 0 ) {
678 /* subdivide children */
679 frontNum = node->children[ 0 ];
680 backNum = node->children[ 1 ];
681 SubdivideTraceNode_r( frontNum, depth );
682 SubdivideTraceNode_r( backNum, depth );
687 ClearBounds( node->mins, node->maxs );
688 VectorClear( average );
690 for ( i = 0; i < node->numItems; i++ )
693 tw = &traceWindings[ node->items[ i ] ];
696 for ( j = 0; j < tw->numVerts; j++ )
698 AddPointToBounds( tw->v[ j ].xyz, node->mins, node->maxs );
699 average[ 0 ] += tw->v[ j ].xyz[ 0 ];
700 average[ 1 ] += tw->v[ j ].xyz[ 1 ];
701 average[ 2 ] += tw->v[ j ].xyz[ 2 ];
706 /* check triangle limit */
707 //% if( node->numItems <= MAX_NODE_ITEMS )
708 if ( ( count - ( node->numItems * 2 ) ) < MAX_NODE_TRIANGLES ) {
709 //% Sys_Printf( "Limit: (%d triangles)\n", (count - (node->numItems * 2)) );
714 /* the largest dimension of the bounding box will be the split axis */
715 VectorSubtract( node->maxs, node->mins, size );
716 if ( size[ 0 ] >= size[ 1 ] && size[ 0 ] >= size[ 2 ] ) {
719 else if ( size[ 1 ] >= size[ 0 ] && size[ 1 ] >= size[ 2 ] ) {
726 /* don't split small nodes */
727 if ( size[ type ] <= MIN_NODE_SIZE ) {
728 //% Sys_Printf( "Limit: %f %f %f (%d items)\n", size[ 0 ], size[ 1 ], size[ 2 ], node->numItems );
733 /* set max trace depth */
734 if ( depth > maxTraceDepth ) {
735 maxTraceDepth = depth;
738 /* snap the average */
739 dist = floor( average[ type ] / count );
742 if ( dist <= node->mins[ type ] || dist >= node->maxs[ type ] ) {
743 dist = floor( 0.5f * ( node->mins[ type ] + node->maxs[ type ] ) );
746 /* allocate child nodes */
747 frontNum = AllocTraceNode();
748 backNum = AllocTraceNode();
751 node = &traceNodes[ nodeNum ];
752 frontNode = &traceNodes[ frontNum ];
753 backNode = &traceNodes[ backNum ];
755 /* attach children */
757 node->plane[ type ] = 1.0f;
758 node->plane[ 3 ] = dist;
759 node->children[ 0 ] = frontNum;
760 node->children[ 1 ] = backNum;
762 /* setup front node */
763 frontNode->maxItems = ( node->maxItems >> 1 );
764 frontNode->items = safe_malloc( frontNode->maxItems * sizeof( *frontNode->items ) );
766 /* setup back node */
767 backNode->maxItems = ( node->maxItems >> 1 );
768 backNode->items = safe_malloc( backNode->maxItems * sizeof( *backNode->items ) );
770 /* filter windings into child nodes */
771 for ( i = 0; i < node->numItems; i++ )
774 tw = &traceWindings[ node->items[ i ] ];
776 /* clip the winding by the new split plane */
777 ClipTraceWinding( tw, node->plane, &front, &back );
779 /* kill the existing winding */
780 if ( front.numVerts >= 3 || back.numVerts >= 3 ) {
781 deadWinding = node->items[ i ];
784 /* add front winding */
785 if ( front.numVerts >= 3 ) {
786 num = AddTraceWinding( &front );
787 AddItemToTraceNode( frontNode, num );
790 /* add back winding */
791 if ( back.numVerts >= 3 ) {
792 num = AddTraceWinding( &back );
793 AddItemToTraceNode( backNode, num );
797 /* free original node winding list */
804 if ( frontNode->numItems <= 0 ) {
805 frontNode->maxItems = 0;
806 free( frontNode->items );
807 frontNode->items = NULL;
810 if ( backNode->numItems <= 0 ) {
811 backNode->maxItems = 0;
812 free( backNode->items );
813 backNode->items = NULL;
816 /* subdivide children */
817 SubdivideTraceNode_r( frontNum, depth );
818 SubdivideTraceNode_r( backNum, depth );
824 TriangulateTraceNode_r()
825 optimizes the tracing data by changing trace windings into triangles
828 static int TriangulateTraceNode_r( int nodeNum ){
829 int i, j, num, frontNum, backNum, numWindings, *windings;
836 if ( nodeNum < 0 || nodeNum >= numTraceNodes ) {
841 node = &traceNodes[ nodeNum ];
843 /* is this a decision node? */
844 if ( node->type >= 0 ) {
845 /* triangulate children */
846 frontNum = node->children[ 0 ];
847 backNum = node->children[ 1 ];
848 node->numItems = TriangulateTraceNode_r( frontNum );
849 node->numItems += TriangulateTraceNode_r( backNum );
850 return node->numItems;
854 if ( node->numItems == 0 ) {
856 if ( node->items != NULL ) {
859 return node->numItems;
862 /* store off winding data */
863 numWindings = node->numItems;
864 windings = node->items;
868 node->maxItems = numWindings * 2;
869 node->items = safe_malloc( node->maxItems * sizeof( tt ) );
871 /* walk winding list */
872 for ( i = 0; i < numWindings; i++ )
875 tw = &traceWindings[ windings[ i ] ];
878 tt.infoNum = tw->infoNum;
879 tt.v[ 0 ] = tw->v[ 0 ];
881 /* walk vertex list */
882 for ( j = 1; j + 1 < tw->numVerts; j++ )
885 tt.v[ 1 ] = tw->v[ j ];
886 tt.v[ 2 ] = tw->v[ j + 1 ];
888 /* find vectors for two edges sharing the first vert */
889 VectorSubtract( tt.v[ 1 ].xyz, tt.v[ 0 ].xyz, tt.edge1 );
890 VectorSubtract( tt.v[ 2 ].xyz, tt.v[ 0 ].xyz, tt.edge2 );
892 /* add it to the node */
893 num = AddTraceTriangle( &tt );
894 AddItemToTraceNode( node, num );
899 if ( windings != NULL ) {
903 /* return item count */
904 return node->numItems;
909 /* -------------------------------------------------------------------------------
911 shadow casting item setup (triangles, patches, entities)
913 ------------------------------------------------------------------------------- */
916 PopulateWithBSPModel() - ydnar
917 filters a bsp model's surfaces into the raytracing tree
920 static void PopulateWithBSPModel( bspModel_t *model, m4x4_t transform ){
921 int i, j, x, y, pw[ 5 ], r, nodeNum;
922 bspDrawSurface_t *ds;
924 bspDrawVert_t *verts;
926 mesh_t srcMesh, *mesh, *subdivided;
932 if ( model == NULL || transform == NULL ) {
936 /* walk the list of surfaces in this model and fill out the info structs */
937 for ( i = 0; i < model->numBSPSurfaces; i++ )
939 /* get surface and info */
940 ds = &bspDrawSurfaces[ model->firstBSPSurface + i ];
941 info = &surfaceInfos[ model->firstBSPSurface + i ];
942 if ( info->si == NULL ) {
947 if ( !info->castShadows ) {
952 if ( ds->surfaceType == MST_PATCH && patchShadows == qfalse ) {
956 /* some surfaces in the bsp might have been tagged as nodraw, with a bogus shader */
957 if ( ( bspShaders[ ds->shaderNum ].contentFlags & noDrawContentFlags ) ||
958 ( bspShaders[ ds->shaderNum ].surfaceFlags & noDrawSurfaceFlags ) ) {
962 /* translucent surfaces that are neither alphashadow or lightfilter don't cast shadows */
963 if ( ( info->si->compileFlags & C_NODRAW ) ) {
966 if ( ( info->si->compileFlags & C_TRANSLUCENT ) &&
967 !( info->si->compileFlags & C_ALPHASHADOW ) &&
968 !( info->si->compileFlags & C_LIGHTFILTER ) ) {
972 /* setup trace info */
974 ti.castShadows = info->castShadows;
975 ti.surfaceNum = model->firstBSPBrush + i;
977 /* choose which node (normal or skybox) */
978 if ( info->parentSurfaceNum >= 0 ) {
979 nodeNum = skyboxNodeNum;
981 /* sky surfaces in portal skies are ignored */
982 if ( info->si->compileFlags & C_SKY ) {
987 nodeNum = headNodeNum;
990 /* setup trace winding */
991 memset( &tw, 0, sizeof( tw ) );
992 tw.infoNum = AddTraceInfo( &ti );
996 switch ( ds->surfaceType )
1000 /* subdivide the surface */
1001 srcMesh.width = ds->patchWidth;
1002 srcMesh.height = ds->patchHeight;
1003 srcMesh.verts = &bspDrawVerts[ ds->firstVert ];
1004 //% subdivided = SubdivideMesh( srcMesh, 8, 512 );
1005 subdivided = SubdivideMesh2( srcMesh, info->patchIterations );
1007 /* fit it to the curve and remove colinear verts on rows/columns */
1008 PutMeshOnCurve( *subdivided );
1009 mesh = RemoveLinearMeshColumnsRows( subdivided );
1010 FreeMesh( subdivided );
1013 verts = mesh->verts;
1015 /* subdivide each quad to place the models */
1016 for ( y = 0; y < ( mesh->height - 1 ); y++ )
1018 for ( x = 0; x < ( mesh->width - 1 ); x++ )
1021 pw[ 0 ] = x + ( y * mesh->width );
1022 pw[ 1 ] = x + ( ( y + 1 ) * mesh->width );
1023 pw[ 2 ] = x + 1 + ( ( y + 1 ) * mesh->width );
1024 pw[ 3 ] = x + 1 + ( y * mesh->width );
1025 pw[ 4 ] = x + ( y * mesh->width ); /* same as pw[ 0 ] */
1030 /* make first triangle */
1031 VectorCopy( verts[ pw[ r + 0 ] ].xyz, tw.v[ 0 ].xyz );
1032 Vector2Copy( verts[ pw[ r + 0 ] ].st, tw.v[ 0 ].st );
1033 VectorCopy( verts[ pw[ r + 1 ] ].xyz, tw.v[ 1 ].xyz );
1034 Vector2Copy( verts[ pw[ r + 1 ] ].st, tw.v[ 1 ].st );
1035 VectorCopy( verts[ pw[ r + 2 ] ].xyz, tw.v[ 2 ].xyz );
1036 Vector2Copy( verts[ pw[ r + 2 ] ].st, tw.v[ 2 ].st );
1037 m4x4_transform_point( transform, tw.v[ 0 ].xyz );
1038 m4x4_transform_point( transform, tw.v[ 1 ].xyz );
1039 m4x4_transform_point( transform, tw.v[ 2 ].xyz );
1040 FilterTraceWindingIntoNodes_r( &tw, nodeNum );
1042 /* make second triangle */
1043 VectorCopy( verts[ pw[ r + 0 ] ].xyz, tw.v[ 0 ].xyz );
1044 Vector2Copy( verts[ pw[ r + 0 ] ].st, tw.v[ 0 ].st );
1045 VectorCopy( verts[ pw[ r + 2 ] ].xyz, tw.v[ 1 ].xyz );
1046 Vector2Copy( verts[ pw[ r + 2 ] ].st, tw.v[ 1 ].st );
1047 VectorCopy( verts[ pw[ r + 3 ] ].xyz, tw.v[ 2 ].xyz );
1048 Vector2Copy( verts[ pw[ r + 3 ] ].st, tw.v[ 2 ].st );
1049 m4x4_transform_point( transform, tw.v[ 0 ].xyz );
1050 m4x4_transform_point( transform, tw.v[ 1 ].xyz );
1051 m4x4_transform_point( transform, tw.v[ 2 ].xyz );
1052 FilterTraceWindingIntoNodes_r( &tw, nodeNum );
1056 /* free the subdivided mesh */
1060 /* handle triangle surfaces */
1061 case MST_TRIANGLE_SOUP:
1063 /* set verts and indexes */
1064 verts = &bspDrawVerts[ ds->firstVert ];
1065 indexes = &bspDrawIndexes[ ds->firstIndex ];
1067 /* walk the triangle list */
1068 for ( j = 0; j < ds->numIndexes; j += 3 )
1070 VectorCopy( verts[ indexes[ j ] ].xyz, tw.v[ 0 ].xyz );
1071 Vector2Copy( verts[ indexes[ j ] ].st, tw.v[ 0 ].st );
1072 VectorCopy( verts[ indexes[ j + 1 ] ].xyz, tw.v[ 1 ].xyz );
1073 Vector2Copy( verts[ indexes[ j + 1 ] ].st, tw.v[ 1 ].st );
1074 VectorCopy( verts[ indexes[ j + 2 ] ].xyz, tw.v[ 2 ].xyz );
1075 Vector2Copy( verts[ indexes[ j + 2 ] ].st, tw.v[ 2 ].st );
1076 m4x4_transform_point( transform, tw.v[ 0 ].xyz );
1077 m4x4_transform_point( transform, tw.v[ 1 ].xyz );
1078 m4x4_transform_point( transform, tw.v[ 2 ].xyz );
1079 FilterTraceWindingIntoNodes_r( &tw, nodeNum );
1083 /* other surface types do not cast shadows */
1093 PopulateWithPicoModel() - ydnar
1094 filters a picomodel's surfaces into the raytracing tree
1097 static void PopulateWithPicoModel( int castShadows, picoModel_t *model, m4x4_t transform ){
1098 int i, j, k, numSurfaces, numIndexes;
1099 picoSurface_t *surface;
1100 picoShader_t *shader;
1101 picoVec_t *xyz, *st;
1102 picoIndex_t *indexes;
1108 if ( model == NULL || transform == NULL ) {
1113 numSurfaces = PicoGetModelNumSurfaces( model );
1115 /* walk the list of surfaces in this model and fill out the info structs */
1116 for ( i = 0; i < numSurfaces; i++ )
1119 surface = PicoGetModelSurface( model, i );
1120 if ( surface == NULL ) {
1124 /* only handle triangle surfaces initially (fixme: support patches) */
1125 if ( PicoGetSurfaceType( surface ) != PICO_TRIANGLES ) {
1129 /* get shader (fixme: support shader remapping) */
1130 shader = PicoGetSurfaceShader( surface );
1131 if ( shader == NULL ) {
1134 ti.si = ShaderInfoForShader( PicoGetShaderName( shader ) );
1135 if ( ti.si == NULL ) {
1139 /* translucent surfaces that are neither alphashadow or lightfilter don't cast shadows */
1140 if ( ( ti.si->compileFlags & C_NODRAW ) ) {
1143 if ( ( ti.si->compileFlags & C_TRANSLUCENT ) &&
1144 !( ti.si->compileFlags & C_ALPHASHADOW ) &&
1145 !( ti.si->compileFlags & C_LIGHTFILTER ) ) {
1149 /* setup trace info */
1150 ti.castShadows = castShadows;
1153 /* setup trace winding */
1154 memset( &tw, 0, sizeof( tw ) );
1155 tw.infoNum = AddTraceInfo( &ti );
1159 numIndexes = PicoGetSurfaceNumIndexes( surface );
1160 indexes = PicoGetSurfaceIndexes( surface, 0 );
1162 /* walk the triangle list */
1163 for ( j = 0; j < numIndexes; j += 3, indexes += 3 )
1165 for ( k = 0; k < 3; k++ )
1167 xyz = PicoGetSurfaceXYZ( surface, indexes[ k ] );
1168 st = PicoGetSurfaceST( surface, 0, indexes[ k ] );
1169 VectorCopy( xyz, tw.v[ k ].xyz );
1170 Vector2Copy( st, tw.v[ k ].st );
1171 m4x4_transform_point( transform, tw.v[ k ].xyz );
1173 FilterTraceWindingIntoNodes_r( &tw, headNodeNum );
1181 PopulateTraceNodes() - ydnar
1182 fills the raytracing tree with world and entity occluders
1185 static void PopulateTraceNodes( void ){
1186 int i, m, frame, castShadows;
1191 vec3_t origin, scale, angles;
1195 /* add worldspawn triangles */
1196 m4x4_identity( transform );
1197 PopulateWithBSPModel( &bspModels[ 0 ], transform );
1199 /* walk each entity list */
1200 for ( i = 1; i < numEntities; i++ )
1205 /* get shadow flags */
1206 castShadows = ENTITY_CAST_SHADOWS;
1207 GetEntityShadowFlags( e, NULL, &castShadows, NULL );
1210 if ( !castShadows ) {
1214 /* get entity origin */
1215 GetVectorForKey( e, "origin", origin );
1218 scale[ 0 ] = scale[ 1 ] = scale[ 2 ] = 1.0f;
1219 temp = FloatForKey( e, "modelscale" );
1220 if ( temp != 0.0f ) {
1221 scale[ 0 ] = scale[ 1 ] = scale[ 2 ] = temp;
1223 value = ValueForKey( e, "modelscale_vec" );
1224 if ( value[ 0 ] != '\0' ) {
1225 sscanf( value, "%f %f %f", &scale[ 0 ], &scale[ 1 ], &scale[ 2 ] );
1228 /* get "angle" (yaw) or "angles" (pitch yaw roll) */
1229 angles[ 0 ] = angles[ 1 ] = angles[ 2 ] = 0.0f;
1230 angles[ 2 ] = FloatForKey( e, "angle" );
1231 value = ValueForKey( e, "angles" );
1232 if ( value[ 0 ] != '\0' ) {
1233 sscanf( value, "%f %f %f", &angles[ 1 ], &angles[ 2 ], &angles[ 0 ] );
1236 /* set transform matrix (thanks spog) */
1237 m4x4_identity( transform );
1238 m4x4_pivoted_transform_by_vec3( transform, origin, angles, eXYZ, scale, vec3_origin );
1240 /* hack: Stable-1_2 and trunk have differing row/column major matrix order
1241 this transpose is necessary with Stable-1_2
1242 uncomment the following line with old m4x4_t (non 1.3/spog_branch) code */
1243 //% m4x4_transpose( transform );
1246 value = ValueForKey( e, "model" );
1248 /* switch on model type */
1249 switch ( value[ 0 ] )
1257 m = atoi( &value[ 1 ] );
1258 if ( m <= 0 || m >= numBSPModels ) {
1261 PopulateWithBSPModel( &bspModels[ m ], transform );
1264 /* external model */
1266 frame = IntForKey( e, "_frame" );
1267 model = LoadModel( (char*) value, frame );
1268 if ( model == NULL ) {
1271 PopulateWithPicoModel( castShadows, model, transform );
1276 value = ValueForKey( e, "model2" );
1278 /* switch on model type */
1279 switch ( value[ 0 ] )
1287 m = atoi( &value[ 1 ] );
1288 if ( m <= 0 || m >= numBSPModels ) {
1291 PopulateWithBSPModel( &bspModels[ m ], transform );
1294 /* external model */
1296 frame = IntForKey( e, "_frame2" );
1297 model = LoadModel( (char*) value, frame );
1298 if ( model == NULL ) {
1301 PopulateWithPicoModel( castShadows, model, transform );
1310 /* -------------------------------------------------------------------------------
1312 trace initialization
1314 ------------------------------------------------------------------------------- */
1317 SetupTraceNodes() - ydnar
1318 creates a balanced bsp with axis-aligned splits for efficient raytracing
1321 void SetupTraceNodes( void ){
1323 Sys_FPrintf( SYS_VRB, "--- SetupTraceNodes ---\n" );
1325 /* find nodraw bit */
1326 noDrawContentFlags = noDrawSurfaceFlags = noDrawCompileFlags = 0;
1327 ApplySurfaceParm( "nodraw", &noDrawContentFlags, &noDrawSurfaceFlags, &noDrawCompileFlags );
1329 /* create the baseline raytracing tree from the bsp tree */
1330 headNodeNum = SetupTraceNodes_r( 0 );
1332 /* create outside node for skybox surfaces */
1333 skyboxNodeNum = AllocTraceNode();
1335 /* populate the tree with triangles from the world and shadow casting entities */
1336 PopulateTraceNodes();
1338 /* create the raytracing bsp */
1339 if ( loMem == qfalse ) {
1340 SubdivideTraceNode_r( headNodeNum, 0 );
1341 SubdivideTraceNode_r( skyboxNodeNum, 0 );
1344 /* create triangles from the trace windings */
1345 TriangulateTraceNode_r( headNodeNum );
1346 TriangulateTraceNode_r( skyboxNodeNum );
1348 /* emit some stats */
1349 //% Sys_FPrintf( SYS_VRB, "%9d original triangles\n", numOriginalTriangles );
1350 Sys_FPrintf( SYS_VRB, "%9d trace windings (%.2fMB)\n", numTraceWindings, (float) ( numTraceWindings * sizeof( *traceWindings ) ) / ( 1024.0f * 1024.0f ) );
1351 Sys_FPrintf( SYS_VRB, "%9d trace triangles (%.2fMB)\n", numTraceTriangles, (float) ( numTraceTriangles * sizeof( *traceTriangles ) ) / ( 1024.0f * 1024.0f ) );
1352 Sys_FPrintf( SYS_VRB, "%9d trace nodes (%.2fMB)\n", numTraceNodes, (float) ( numTraceNodes * sizeof( *traceNodes ) ) / ( 1024.0f * 1024.0f ) );
1353 Sys_FPrintf( SYS_VRB, "%9d leaf nodes (%.2fMB)\n", numTraceLeafNodes, (float) ( numTraceLeafNodes * sizeof( *traceNodes ) ) / ( 1024.0f * 1024.0f ) );
1354 //% Sys_FPrintf( SYS_VRB, "%9d average triangles per leaf node\n", numTraceTriangles / numTraceLeafNodes );
1355 Sys_FPrintf( SYS_VRB, "%9d average windings per leaf node\n", numTraceWindings / ( numTraceLeafNodes + 1 ) );
1356 Sys_FPrintf( SYS_VRB, "%9d max trace depth\n", maxTraceDepth );
1358 /* free trace windings */
1359 free( traceWindings );
1360 numTraceWindings = 0;
1361 maxTraceWindings = 0;
1364 /* debug code: write out trace triangles to an alias obj file */
1369 char filename[ 1024 ];
1374 strcpy( filename, source );
1375 StripExtension( filename );
1376 strcat( filename, ".lin" );
1377 Sys_Printf( "Opening light trace file %s...\n", filename );
1378 file = fopen( filename, "w" );
1379 if ( file == NULL ) {
1380 Error( "Error opening %s for writing", filename );
1383 /* walk node list */
1384 for ( i = 0; i < numTraceWindings; i++ )
1386 tw = &traceWindings[ i ];
1387 for ( j = 0; j < tw->numVerts + 1; j++ )
1388 fprintf( file, "%f %f %f\n",
1389 tw->v[ j % tw->numVerts ].xyz[ 0 ], tw->v[ j % tw->numVerts ].xyz[ 1 ], tw->v[ j % tw->numVerts ].xyz[ 2 ] );
1400 /* -------------------------------------------------------------------------------
1404 ------------------------------------------------------------------------------- */
1408 based on code written by william 'spog' joseph
1409 based on code originally written by tomas moller and ben trumbore, journal of graphics tools, 2(1):21-28, 1997
1412 #define BARY_EPSILON 0.01f
1413 #define ASLF_EPSILON 0.0001f /* so to not get double shadows */
1414 #define COPLANAR_EPSILON 0.25f //% 0.000001f
1415 #define NEAR_SHADOW_EPSILON 1.5f //% 1.25f
1416 #define SELF_SHADOW_EPSILON 0.5f
1418 qboolean TraceTriangle( traceInfo_t *ti, traceTriangle_t *tt, trace_t *trace ){
1420 float tvec[ 3 ], pvec[ 3 ], qvec[ 3 ];
1421 float det, invDet, depth;
1422 float u, v, w, s, t;
1429 /* don't double-trace against sky */
1431 if ( trace->compileFlags & si->compileFlags & C_SKY ) {
1435 /* receive shadows from worldspawn group only */
1436 if ( trace->recvShadows == 1 ) {
1437 if ( ti->castShadows != 1 ) {
1442 /* receive shadows from same group and worldspawn group */
1443 else if ( trace->recvShadows > 1 ) {
1444 if ( ti->castShadows != 1 && abs( ti->castShadows ) != abs( trace->recvShadows ) ) {
1447 //% Sys_Printf( "%d:%d ", tt->castShadows, trace->recvShadows );
1450 /* receive shadows from the same group only (< 0) */
1453 if ( abs( ti->castShadows ) != abs( trace->recvShadows ) ) {
1458 /* begin calculating determinant - also used to calculate u parameter */
1459 CrossProduct( trace->direction, tt->edge2, pvec );
1461 /* if determinant is near zero, trace lies in plane of triangle */
1462 det = DotProduct( tt->edge1, pvec );
1464 /* the non-culling branch */
1465 if ( fabs( det ) < COPLANAR_EPSILON ) {
1468 invDet = 1.0f / det;
1470 /* calculate distance from first vertex to ray origin */
1471 VectorSubtract( trace->origin, tt->v[ 0 ].xyz, tvec );
1473 /* calculate u parameter and test bounds */
1474 u = DotProduct( tvec, pvec ) * invDet;
1475 if ( u < -BARY_EPSILON || u > ( 1.0f + BARY_EPSILON ) ) {
1479 /* prepare to test v parameter */
1480 CrossProduct( tvec, tt->edge1, qvec );
1482 /* calculate v parameter and test bounds */
1483 v = DotProduct( trace->direction, qvec ) * invDet;
1484 if ( v < -BARY_EPSILON || ( u + v ) > ( 1.0f + BARY_EPSILON ) ) {
1488 /* calculate t (depth) */
1489 depth = DotProduct( tt->edge2, qvec ) * invDet;
1490 if ( depth <= trace->inhibitRadius || depth >= trace->distance ) {
1494 /* if hitpoint is really close to trace origin (sample point), then check for self-shadowing */
1495 if ( depth <= SELF_SHADOW_EPSILON ) {
1496 /* don't self-shadow */
1497 for ( i = 0; i < trace->numSurfaces; i++ )
1499 if ( ti->surfaceNum == trace->surfaces[ i ] ) {
1505 /* stack compile flags */
1506 trace->compileFlags |= si->compileFlags;
1508 /* don't trace against sky */
1509 if ( si->compileFlags & C_SKY ) {
1513 /* most surfaces are completely opaque */
1514 if ( !( si->compileFlags & ( C_ALPHASHADOW | C_LIGHTFILTER ) ) ||
1515 si->lightImage == NULL || si->lightImage->pixels == NULL ) {
1516 VectorMA( trace->origin, depth, trace->direction, trace->hit );
1517 VectorClear( trace->color );
1518 trace->opaque = qtrue;
1522 /* try to avoid double shadows near triangle seams */
1523 if ( u < -ASLF_EPSILON || u > ( 1.0f + ASLF_EPSILON ) ||
1524 v < -ASLF_EPSILON || ( u + v ) > ( 1.0f + ASLF_EPSILON ) ) {
1528 /* calculate w parameter */
1529 w = 1.0f - ( u + v );
1531 /* calculate st from uvw (barycentric) coordinates */
1532 s = w * tt->v[ 0 ].st[ 0 ] + u * tt->v[ 1 ].st[ 0 ] + v * tt->v[ 2 ].st[ 0 ];
1533 t = w * tt->v[ 0 ].st[ 1 ] + u * tt->v[ 1 ].st[ 1 ] + v * tt->v[ 2 ].st[ 1 ];
1536 is = s * si->lightImage->width;
1537 it = t * si->lightImage->height;
1540 pixel = si->lightImage->pixels + 4 * ( it * si->lightImage->width + is );
1542 /* ydnar: color filter */
1543 if ( si->compileFlags & C_LIGHTFILTER ) {
1544 /* filter by texture color */
1545 trace->color[ 0 ] *= ( ( 1.0f / 255.0f ) * pixel[ 0 ] );
1546 trace->color[ 1 ] *= ( ( 1.0f / 255.0f ) * pixel[ 1 ] );
1547 trace->color[ 2 ] *= ( ( 1.0f / 255.0f ) * pixel[ 2 ] );
1550 /* ydnar: alpha filter */
1551 if ( si->compileFlags & C_ALPHASHADOW ) {
1552 /* filter by inverse texture alpha */
1553 shadow = ( 1.0f / 255.0f ) * ( 255 - pixel[ 3 ] );
1554 trace->color[ 0 ] *= shadow;
1555 trace->color[ 1 ] *= shadow;
1556 trace->color[ 2 ] *= shadow;
1559 /* check filter for opaque */
1560 if ( trace->color[ 0 ] <= 0.001f && trace->color[ 1 ] <= 0.001f && trace->color[ 2 ] <= 0.001f ) {
1561 VectorMA( trace->origin, depth, trace->direction, trace->hit );
1562 trace->opaque = qtrue;
1566 /* continue tracing */
1573 TraceWinding() - ydnar
1577 qboolean TraceWinding( traceWinding_t *tw, trace_t *trace ){
1583 tt.infoNum = tw->infoNum;
1584 tt.v[ 0 ] = tw->v[ 0 ];
1586 /* walk vertex list */
1587 for ( i = 1; i + 1 < tw->numVerts; i++ )
1590 tt.v[ 1 ] = tw->v[ i ];
1591 tt.v[ 2 ] = tw->v[ i + 1 ];
1593 /* find vectors for two edges sharing the first vert */
1594 VectorSubtract( tt.v[ 1 ].xyz, tt.v[ 0 ].xyz, tt.edge1 );
1595 VectorSubtract( tt.v[ 2 ].xyz, tt.v[ 0 ].xyz, tt.edge2 );
1598 if ( TraceTriangle( &traceInfos[ tt.infoNum ], &tt, trace ) ) {
1612 returns qtrue if something is hit and tracing can stop
1615 static qboolean TraceLine_r( int nodeNum, vec3_t origin, vec3_t end, trace_t *trace ){
1618 float front, back, frac;
1623 /* bogus node number means solid, end tracing unless testing all */
1624 if ( nodeNum < 0 ) {
1625 VectorCopy( origin, trace->hit );
1626 trace->passSolid = qtrue;
1631 node = &traceNodes[ nodeNum ];
1634 if ( node->type == TRACE_LEAF_SOLID ) {
1635 VectorCopy( origin, trace->hit );
1636 trace->passSolid = qtrue;
1641 if ( node->type < 0 ) {
1642 /* note leaf and return */
1643 if ( node->numItems > 0 && trace->numTestNodes < MAX_TRACE_TEST_NODES ) {
1644 trace->testNodes[ trace->numTestNodes++ ] = nodeNum;
1649 /* ydnar 2003-09-07: don't test branches of the bsp with nothing in them when testall is enabled */
1650 if ( trace->testAll && node->numItems == 0 ) {
1654 /* classify beginning and end points */
1655 switch ( node->type )
1658 front = origin[ 0 ] - node->plane[ 3 ];
1659 back = end[ 0 ] - node->plane[ 3 ];
1663 front = origin[ 1 ] - node->plane[ 3 ];
1664 back = end[ 1 ] - node->plane[ 3 ];
1668 front = origin[ 2 ] - node->plane[ 3 ];
1669 back = end[ 2 ] - node->plane[ 3 ];
1673 front = DotProduct( origin, node->plane ) - node->plane[ 3 ];
1674 back = DotProduct( end, node->plane ) - node->plane[ 3 ];
1678 /* entirely in front side? */
1679 if ( front >= -TRACE_ON_EPSILON && back >= -TRACE_ON_EPSILON ) {
1680 return TraceLine_r( node->children[ 0 ], origin, end, trace );
1683 /* entirely on back side? */
1684 if ( front < TRACE_ON_EPSILON && back < TRACE_ON_EPSILON ) {
1685 return TraceLine_r( node->children[ 1 ], origin, end, trace );
1691 /* calculate intercept point */
1692 frac = front / ( front - back );
1693 mid[ 0 ] = origin[ 0 ] + ( end[ 0 ] - origin[ 0 ] ) * frac;
1694 mid[ 1 ] = origin[ 1 ] + ( end[ 1 ] - origin[ 1 ] ) * frac;
1695 mid[ 2 ] = origin[ 2 ] + ( end[ 2 ] - origin[ 2 ] ) * frac;
1697 /* fixme: check inhibit radius, then solid nodes and ignore */
1699 /* set trace hit here */
1700 //% VectorCopy( mid, trace->hit );
1702 /* trace first side */
1703 r = TraceLine_r( node->children[ side ], origin, mid, trace );
1708 /* trace other side */
1709 return TraceLine_r( node->children[ !side ], mid, end, trace );
1716 rewrote this function a bit :)
1719 void TraceLine( trace_t *trace ){
1722 traceTriangle_t *tt;
1726 /* setup output (note: this code assumes the input data is completely filled out) */
1727 trace->passSolid = qfalse;
1728 trace->opaque = qfalse;
1729 trace->compileFlags = 0;
1730 trace->numTestNodes = 0;
1733 if ( !trace->recvShadows || !trace->testOcclusion || trace->distance <= 0.00001f ) {
1737 /* trace through nodes */
1738 TraceLine_r( headNodeNum, trace->origin, trace->end, trace );
1739 if ( trace->passSolid && !trace->testAll ) {
1740 trace->opaque = qtrue;
1744 /* skip surfaces? */
1749 /* testall means trace through sky */
1750 if ( trace->testAll && trace->numTestNodes < MAX_TRACE_TEST_NODES &&
1751 trace->compileFlags & C_SKY &&
1752 ( trace->numSurfaces == 0 || surfaceInfos[ trace->surfaces[ 0 ] ].childSurfaceNum < 0 ) ) {
1753 //% trace->testNodes[ trace->numTestNodes++ ] = skyboxNodeNum;
1754 TraceLine_r( skyboxNodeNum, trace->origin, trace->end, trace );
1757 /* walk node list */
1758 for ( i = 0; i < trace->numTestNodes; i++ )
1761 node = &traceNodes[ trace->testNodes[ i ] ];
1763 /* walk node item list */
1764 for ( j = 0; j < node->numItems; j++ )
1766 tt = &traceTriangles[ node->items[ j ] ];
1767 ti = &traceInfos[ tt->infoNum ];
1768 if ( TraceTriangle( ti, tt, trace ) ) {
1771 //% if( TraceWinding( &traceWindings[ node->items[ j ] ], trace ) )
1780 SetupTrace() - ydnar
1781 sets up certain trace values
1784 float SetupTrace( trace_t *trace ){
1785 VectorSubtract( trace->end, trace->origin, trace->displacement );
1786 trace->distance = VectorNormalize( trace->displacement, trace->direction );
1787 VectorCopy( trace->origin, trace->hit );
1788 return trace->distance;