]> git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3map2/light_trace.c
fix "invalid tracenode: 0" bug
[xonotic/netradiant.git] / tools / quake3 / q3map2 / light_trace.c
1 /* -------------------------------------------------------------------------------
2
3 Copyright (C) 1999-2007 id Software, Inc. and contributors.
4 For a list of contributors, see the accompanying CONTRIBUTORS file.
5
6 This file is part of GtkRadiant.
7
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.
12
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.
17
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
21
22 ----------------------------------------------------------------------------------
23
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."
26
27 ------------------------------------------------------------------------------- */
28
29
30
31 /* marker */
32 #define LIGHT_TRACE_C
33
34
35
36 /* dependencies */
37 #include "q3map2.h"
38
39
40 /* dependencies */
41 #include "q3map2.h"
42
43
44
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 ])
47
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
52
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
58
59 #define MAX_TW_VERTS                    24 // vortex: increased from 12 to 24 for ability co compile some insane maps with large curve count
60
61 #define TRACE_ON_EPSILON                0.1f
62
63 #define TRACE_LEAF                              -1
64 #define TRACE_LEAF_SOLID                -2
65
66 typedef struct traceVert_s
67 {
68         vec3_t                                          xyz;
69         float                                           st[ 2 ];
70 }
71 traceVert_t;
72
73 typedef struct traceInfo_s
74 {
75         shaderInfo_t                            *si;
76         int                                                     surfaceNum, castShadows;
77 }
78 traceInfo_t;
79
80 typedef struct traceWinding_s
81 {
82         vec4_t                                          plane;
83         int                                                     infoNum, numVerts;
84         traceVert_t                                     v[ MAX_TW_VERTS ];
85 }
86 traceWinding_t;
87
88 typedef struct traceTriangle_s
89 {
90         vec3_t                                          edge1, edge2;
91         int                                                     infoNum;
92         traceVert_t                                     v[ 3 ];
93 }
94 traceTriangle_t;
95
96 typedef struct traceNode_s
97 {
98         int                                                     type;
99         vec4_t                                          plane;
100         vec3_t                                          mins, maxs;
101         int                                                     children[ 2 ];
102         int                                                     numItems, maxItems;
103         int                                                     *items;
104 }
105 traceNode_t;
106
107
108 int                                                             noDrawContentFlags, noDrawSurfaceFlags, noDrawCompileFlags;
109
110 int                                                             numTraceInfos = 0, maxTraceInfos = 0, firstTraceInfo = 0;
111 traceInfo_t                                             *traceInfos = NULL;
112
113 int                                                             numTraceWindings = 0, maxTraceWindings = 0, deadWinding = -1;
114 traceWinding_t                                  *traceWindings = NULL;
115
116 int                                                             numTraceTriangles = 0, maxTraceTriangles = 0, deadTriangle = -1;
117 traceTriangle_t                                 *traceTriangles = NULL;
118
119 int                                                             headNodeNum = 0, skyboxNodeNum = 0, maxTraceDepth = 0, numTraceLeafNodes = 0;
120 int                                                             numTraceNodes = 0, maxTraceNodes = 0;
121 traceNode_t                                             *traceNodes = NULL;
122
123
124
125 /* -------------------------------------------------------------------------------
126
127 allocation and list management
128
129 ------------------------------------------------------------------------------- */
130
131 /*
132 AddTraceInfo() - ydnar
133 adds a trace info structure to the pool
134 */
135
136 static int AddTraceInfo( traceInfo_t *ti )
137 {
138         int             num;
139         void    *temp;
140         
141         
142         /* find an existing info */
143         for( num = firstTraceInfo; num < numTraceInfos; num++ )
144         {
145                 if( traceInfos[ num ].si == ti->si &&
146                         traceInfos[ num ].surfaceNum == ti->surfaceNum &&
147                         traceInfos[ num ].castShadows == ti->castShadows )
148                         return num;
149         }
150         
151         /* enough space? */
152         if( numTraceInfos >= maxTraceInfos )
153         {
154                 /* allocate more room */
155                 maxTraceInfos += GROW_TRACE_INFOS;
156                 temp = safe_malloc( maxTraceInfos * sizeof( *traceInfos ) );
157                 if( traceInfos != NULL )
158                 {
159                         memcpy( temp, traceInfos, numTraceInfos * sizeof( *traceInfos ) );
160                         free( traceInfos );
161                 }
162                 traceInfos = (traceInfo_t*) temp;
163         }
164         
165         /* add the info */
166         memcpy( &traceInfos[ num ], ti, sizeof( *traceInfos ) );
167         if( num == numTraceInfos )
168                 numTraceInfos++;
169         
170         /* return the ti number */
171         return num;
172 }
173
174
175
176 /*
177 AllocTraceNode() - ydnar
178 allocates a new trace node
179 */
180
181 static int AllocTraceNode( void )
182 {
183         traceNode_t     *temp;
184         
185         
186         /* enough space? */
187         if( numTraceNodes >= maxTraceNodes )
188         {
189                 /* reallocate more room */
190                 maxTraceNodes += GROW_TRACE_NODES;
191                 temp = safe_malloc( maxTraceNodes * sizeof( traceNode_t ) );
192                 if( traceNodes != NULL )
193                 {
194                         memcpy( temp, traceNodes, numTraceNodes * sizeof( traceNode_t ) );
195                         free( traceNodes );
196                 }
197                 traceNodes = temp;
198         }
199         
200         /* add the node */
201         memset( &traceNodes[ numTraceNodes ], 0, sizeof( traceNode_t ) );
202         traceNodes[ numTraceNodes ].type = TRACE_LEAF;
203         ClearBounds( traceNodes[ numTraceNodes ].mins, traceNodes[ numTraceNodes ].maxs );
204
205         /* Sys_Printf("alloc node %d\n", numTraceNodes); */
206
207         numTraceNodes++;
208         
209         /* return the count */
210         return (numTraceNodes - 1);
211 }
212
213
214
215 /*
216 AddTraceWinding() - ydnar
217 adds a winding to the raytracing pool
218 */
219
220 static int AddTraceWinding( traceWinding_t *tw )
221 {
222         int             num;
223         void    *temp;
224         
225         
226         /* check for a dead winding */
227         if( deadWinding >= 0 && deadWinding < numTraceWindings )
228                 num = deadWinding;
229         else
230         {
231                 /* put winding at the end of the list */
232                 num = numTraceWindings;
233                 
234                 /* enough space? */
235                 if( numTraceWindings >= maxTraceWindings )
236                 {
237                         /* allocate more room */
238                         maxTraceWindings += GROW_TRACE_WINDINGS;
239                         temp = safe_malloc( maxTraceWindings * sizeof( *traceWindings ) );
240                         if( traceWindings != NULL )
241                         {
242                                 memcpy( temp, traceWindings, numTraceWindings * sizeof( *traceWindings ) );
243                                 free( traceWindings );
244                         }
245                         traceWindings = (traceWinding_t*) temp;
246                 }
247         }
248         
249         /* add the winding */
250         memcpy( &traceWindings[ num ], tw, sizeof( *traceWindings ) );
251         if( num == numTraceWindings )
252                 numTraceWindings++;
253         deadWinding = -1;
254         
255         /* return the winding number */
256         return num;
257 }
258
259
260
261 /*
262 AddTraceTriangle() - ydnar
263 adds a triangle to the raytracing pool
264 */
265
266 static int AddTraceTriangle( traceTriangle_t *tt )
267 {
268         int             num;
269         void    *temp;
270         
271         
272         /* check for a dead triangle */
273         if( deadTriangle >= 0 && deadTriangle < numTraceTriangles )
274                 num = deadTriangle;
275         else
276         {
277                 /* put triangle at the end of the list */
278                 num = numTraceTriangles;
279                 
280                 /* enough space? */
281                 if( numTraceTriangles >= maxTraceTriangles )
282                 {
283                         /* allocate more room */
284                         maxTraceTriangles += GROW_TRACE_TRIANGLES;
285                         temp = safe_malloc( maxTraceTriangles * sizeof( *traceTriangles ) );
286                         if( traceTriangles != NULL )
287                         {
288                                 memcpy( temp, traceTriangles, numTraceTriangles * sizeof( *traceTriangles ) );
289                                 free( traceTriangles );
290                         }
291                         traceTriangles = (traceTriangle_t*) temp;
292                 }
293         }
294         
295         /* find vectors for two edges sharing the first vert */
296         VectorSubtract( tt->v[ 1 ].xyz, tt->v[ 0 ].xyz, tt->edge1 );
297         VectorSubtract( tt->v[ 2 ].xyz, tt->v[ 0 ].xyz, tt->edge2 );
298         
299         /* add the triangle */
300         memcpy( &traceTriangles[ num ], tt, sizeof( *traceTriangles ) );
301         if( num == numTraceTriangles )
302                 numTraceTriangles++;
303         deadTriangle = -1;
304         
305         /* return the triangle number */
306         return num;
307 }
308
309
310
311 /*
312 AddItemToTraceNode() - ydnar
313 adds an item reference (winding or triangle) to a trace node
314 */
315
316 static int AddItemToTraceNode( traceNode_t *node, int num )
317 {
318         void                    *temp;
319         
320         
321         /* dummy check */
322         if( num < 0 )
323                 return -1;
324         
325         /* enough space? */
326         if( node->numItems >= node->maxItems )
327         {
328                 /* allocate more room */
329                 if( node == traceNodes )
330                         node->maxItems *= 2;
331                 else
332                         node->maxItems += GROW_NODE_ITEMS;
333                 if( node->maxItems <= 0 )
334                         node->maxItems = GROW_NODE_ITEMS;
335                 temp = safe_malloc( node->maxItems * sizeof( *node->items ) );
336                 if( node->items != NULL )
337                 {
338                         memcpy( temp, node->items, node->numItems * sizeof( *node->items ) );
339                         free( node->items );
340                 }
341                 node->items = (int*) temp;
342         }
343         
344         /* add the poly */
345         node->items[ node->numItems ] = num;
346         node->numItems++;
347         
348         /* return the count */
349         return (node->numItems - 1);
350 }
351
352
353
354
355 /* -------------------------------------------------------------------------------
356
357 trace node setup
358
359 ------------------------------------------------------------------------------- */
360
361 /*
362 SetupTraceNodes_r() - ydnar
363 recursively create the initial trace node structure from the bsp tree
364 */
365
366 static int SetupTraceNodes_r( int bspNodeNum )
367 {
368         int                             i, nodeNum, bspLeafNum, newNode;
369         bspPlane_t              *plane;
370         bspNode_t               *bspNode;
371         
372         
373         /* get bsp node and plane */
374         bspNode = &bspNodes[ bspNodeNum ];
375         plane = &bspPlanes[ bspNode->planeNum ];
376         
377         /* allocate a new trace node */
378         nodeNum = AllocTraceNode();
379         
380         /* setup trace node */
381         traceNodes[ nodeNum ].type = PlaneTypeForNormal( plane->normal );
382         VectorCopy( plane->normal, traceNodes[ nodeNum ].plane );
383         traceNodes[ nodeNum ].plane[ 3 ] = plane->dist;
384         
385         /* setup children */
386         for( i = 0; i < 2; i++ )
387         {
388                 /* leafnode */
389                 if( bspNode->children[ i ] < 0 )
390                 {
391                         bspLeafNum = -bspNode->children[ i ] - 1;
392                         
393                         /* new code */
394                         newNode = AllocTraceNode();
395                         traceNodes[ nodeNum ].children[ i ] = newNode;
396                         /* have to do this separately, as gcc first executes LHS, then RHS, and if a realloc took place, this fails */
397
398                         if( bspLeafs[ bspLeafNum ].cluster == -1 )
399                                 traceNodes[ traceNodes[ nodeNum ].children[ i ] ].type = TRACE_LEAF_SOLID;
400                 }
401                 
402                 /* normal node */
403                 else
404                         traceNodes[ nodeNum ].children[ i ] = SetupTraceNodes_r( bspNode->children[ i ] );
405         }
406
407         /* Sys_Printf("node %d children: %d %d\n", nodeNum, traceNodes[ nodeNum ].children[0], traceNodes[ nodeNum ].children[1]); */
408         
409         /* return node number */
410         return nodeNum;
411 }
412
413
414
415 /*
416 ClipTraceWinding() - ydnar
417 clips a trace winding against a plane into one or two parts
418 */
419
420 #define TW_ON_EPSILON   0.25f
421
422 void ClipTraceWinding( traceWinding_t *tw, vec4_t plane, traceWinding_t *front, traceWinding_t *back )
423 {
424         int                             i, j, k;
425         int                             sides[ MAX_TW_VERTS ], counts[ 3 ] = { 0, 0, 0 };
426         float                   dists[ MAX_TW_VERTS ];
427         float                   frac;
428         traceVert_t             *a, *b, mid;
429         
430         
431         /* clear front and back */
432         front->numVerts = 0;
433         back->numVerts = 0;
434         
435         /* classify points */
436         for( i = 0; i < tw->numVerts; i++ )
437         {
438                 dists[ i ] = DotProduct( tw->v[ i ].xyz, plane ) - plane[ 3 ];
439                 if( dists[ i ] < -TW_ON_EPSILON )
440                         sides[ i ] = SIDE_BACK;
441                 else if( dists[ i ] > TW_ON_EPSILON )
442                         sides[ i ] = SIDE_FRONT;
443                 else
444                         sides[ i ] = SIDE_ON;
445                 counts[ sides[ i ] ]++;
446         }
447         
448         /* entirely on front? */
449         if( counts[ SIDE_BACK ] == 0 )
450                 memcpy( front, tw, sizeof( *front ) );
451         
452         /* entirely on back? */
453         else if( counts[ SIDE_FRONT ] == 0 )
454                 memcpy( back, tw, sizeof( *back ) );
455         
456         /* straddles the plane */
457         else
458         {
459                 /* setup front and back */
460                 memcpy( front, tw, sizeof( *front ) );
461                 front->numVerts = 0;
462                 memcpy( back, tw, sizeof( *back ) ); 
463                 back->numVerts = 0;
464                 
465                 /* split the winding */
466                 for( i = 0; i < tw->numVerts; i++ )
467                 {
468                         /* radix */
469                         j = (i + 1) % tw->numVerts;
470                         
471                         /* get verts */
472                         a = &tw->v[ i ];
473                         b = &tw->v[ j ];
474                         
475                         /* handle points on the splitting plane */
476                         switch( sides[ i ] )
477                         {
478                                 case SIDE_FRONT:
479                                         if( front->numVerts >= MAX_TW_VERTS )
480                                                 Error( "MAX_TW_VERTS (%d) exceeded", MAX_TW_VERTS );
481                                         front->v[ front->numVerts++ ] = *a;
482                                         break;
483                                 
484                                 case SIDE_BACK:
485                                         if( back->numVerts >= MAX_TW_VERTS )
486                                                 Error( "MAX_TW_VERTS (%d) exceeded", MAX_TW_VERTS );
487                                         back->v[ back->numVerts++ ] = *a;
488                                         break;
489                                 
490                                 case SIDE_ON:
491                                         if( front->numVerts >= MAX_TW_VERTS || back->numVerts >= MAX_TW_VERTS )
492                                                 Error( "MAX_TW_VERTS (%d) exceeded", MAX_TW_VERTS );
493                                         front->v[ front->numVerts++ ] = *a;
494                                         back->v[ back->numVerts++ ] = *a;
495                                         continue;
496                         }
497                         
498                         /* check next point to see if we need to split the edge */
499                         if( sides[ j ] == SIDE_ON || sides[ j ] == sides[ i ] )
500                                 continue;
501                         
502                         /* check limit */
503                         if( front->numVerts >= MAX_TW_VERTS || back->numVerts >= MAX_TW_VERTS )
504                                 Error( "MAX_TW_VERTS (%d) exceeded", MAX_TW_VERTS );
505                         
506                         /* generate a split point */
507                         frac = dists[ i ] / (dists[ i ] - dists[ j ]);
508                         for( k = 0; k < 3; k++ )
509                         {
510                                 /* minimize fp precision errors */
511                                 if( plane[ k ] == 1.0f )
512                                         mid.xyz[ k ] = plane[ 3 ];
513                                 else if( plane[ k ] == -1.0f )
514                                         mid.xyz[ k ] = -plane[ 3 ];
515                                 else
516                                         mid.xyz[ k ] = a->xyz[ k ] + frac * (b->xyz[ k ] - a->xyz[ k ]);
517                                 
518                                 /* set texture coordinates */
519                                 if( k > 1 )
520                                         continue;
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 ]);
523                         }
524                         
525                         /* copy midpoint to front and back polygons */
526                         front->v[ front->numVerts++ ] = mid;
527                         back->v[ back->numVerts++ ] = mid;
528                 }
529         }
530 }
531
532
533
534 /*
535 FilterPointToTraceNodes_r() - ydnar
536 debugging tool
537 */
538
539 static int FilterPointToTraceNodes_r( vec3_t pt, int nodeNum )
540 {
541         float                   dot;
542         traceNode_t             *node;
543         
544         
545         if( nodeNum < 0 || nodeNum >= numTraceNodes )
546                 return -1;
547         
548         node = &traceNodes[ nodeNum ];
549         
550         if( node->type >= 0 )
551         {
552                 dot = DotProduct( pt, node->plane ) - node->plane[ 3 ];
553                 if( dot > -0.001f )
554                         FilterPointToTraceNodes_r( pt, node->children[ 0 ] );
555                 if( dot < 0.001f )
556                         FilterPointToTraceNodes_r( pt, node->children[ 1 ] );
557                 return -1;
558         }
559         
560         Sys_Printf( "%d ", nodeNum );
561         
562         return nodeNum;
563 }
564
565
566
567 /*
568 FilterTraceWindingIntoNodes_r() - ydnar
569 filters a trace winding into the raytracing tree
570 */
571
572 static void FilterTraceWindingIntoNodes_r( traceWinding_t *tw, int nodeNum )
573 {
574         int                             num;
575         vec4_t                  plane1, plane2, reverse;
576         traceNode_t             *node;
577         traceWinding_t  front, back;
578         
579         
580         /* don't filter if passed a bogus node (solid, etc) */
581         if( nodeNum < 0 || nodeNum >= numTraceNodes )
582                 return;
583         
584         /* get node */
585         node = &traceNodes[ nodeNum ];
586         
587         /* is this a decision node? */
588         if( node->type >= 0 )
589         {       
590                 /* create winding plane if necessary, filtering out bogus windings as well */
591                 if( nodeNum == headNodeNum )
592                 {
593                         if( !PlaneFromPoints( tw->plane, tw->v[ 0 ].xyz, tw->v[ 1 ].xyz, tw->v[ 2 ].xyz ) )
594                                 return;
595                 }
596         
597                 /* validate the node */
598                 if( node->children[ 0 ] == 0 || node->children[ 1 ] == 0 )
599                         Error( "Invalid tracenode: %d", nodeNum );
600                 
601                 /* get node plane */
602                 Vector4Copy( node->plane, plane1 );
603                 
604                 /* get winding plane */
605                 Vector4Copy( tw->plane, plane2 );
606                 
607                 /* invert surface plane */
608                 VectorSubtract( vec3_origin, plane2, reverse );
609                 reverse[ 3 ] = -plane2[ 3 ];
610                 
611                 /* front only */
612                 if( DotProduct( plane1, plane2 ) > 0.999f && fabs( plane1[ 3 ] - plane2[ 3 ] ) < 0.001f )
613                 {
614                         FilterTraceWindingIntoNodes_r( tw, node->children[ 0 ] );
615                         return;
616                 }
617                 
618                 /* back only */
619                 if( DotProduct( plane1, reverse ) > 0.999f && fabs( plane1[ 3 ] - reverse[ 3 ] ) < 0.001f )
620                 {
621                         FilterTraceWindingIntoNodes_r( tw, node->children[ 1 ] );
622                         return;
623                 }
624                 
625                 /* clip the winding by node plane */
626                 ClipTraceWinding( tw, plane1, &front, &back );
627                 
628                 /* filter by node plane */
629                 if( front.numVerts >= 3 )
630                         FilterTraceWindingIntoNodes_r( &front, node->children[ 0 ] );
631                 if( back.numVerts >= 3 )
632                         FilterTraceWindingIntoNodes_r( &back, node->children[ 1 ] );
633                 
634                 /* return to caller */
635                 return;
636         }
637         
638         /* add winding to leaf node */
639         num = AddTraceWinding( tw );
640         AddItemToTraceNode( node, num );
641 }
642
643
644
645 /*
646 SubdivideTraceNode_r() - ydnar
647 recursively subdivides a tracing node until it meets certain size and complexity criteria
648 */
649
650 static void SubdivideTraceNode_r( int nodeNum, int depth )
651 {
652         int                             i, j, count, num, frontNum, backNum, type;
653         vec3_t                  size;
654         float                   dist;
655         double                  average[ 3 ];
656         traceNode_t             *node, *frontNode, *backNode;
657         traceWinding_t  *tw, front, back;
658         
659         
660         /* dummy check */
661         if( nodeNum < 0 || nodeNum >= numTraceNodes )
662                 return;
663         
664         /* get node */
665         node = &traceNodes[ nodeNum ];
666         
667         /* runaway recursion check */
668         if( depth >= MAX_TRACE_DEPTH )
669         {
670                 //%     Sys_Printf( "Depth: (%d items)\n", node->numItems );
671                 numTraceLeafNodes++;
672                 return;
673         }
674         depth++;
675         
676         /* is this a decision node? */
677         if( node->type >= 0 )
678         {
679                 /* subdivide children */
680                 frontNum = node->children[ 0 ];
681                 backNum = node->children[ 1 ];
682                 SubdivideTraceNode_r( frontNum, depth );
683                 SubdivideTraceNode_r( backNum, depth );
684                 return;
685         }
686         
687         /* bound the node */
688         ClearBounds( node->mins, node->maxs );
689         VectorClear( average );
690         count = 0;
691         for( i = 0; i < node->numItems; i++ )
692         {
693                 /* get winding */
694                 tw = &traceWindings[ node->items[ i ] ];
695                 
696                 /* walk its verts */
697                 for( j = 0; j < tw->numVerts; j++ )
698                 {
699                         AddPointToBounds( tw->v[ j ].xyz, node->mins, node->maxs );
700                         average[ 0 ] += tw->v[ j ].xyz[ 0 ];
701                         average[ 1 ] += tw->v[ j ].xyz[ 1 ];
702                         average[ 2 ] += tw->v[ j ].xyz[ 2 ];
703                         count++;
704                 }
705         }
706         
707         /* check triangle limit */
708         //%     if( node->numItems <= MAX_NODE_ITEMS )
709         if( (count - (node->numItems * 2)) < MAX_NODE_TRIANGLES )
710         {
711                 //%     Sys_Printf( "Limit: (%d triangles)\n", (count - (node->numItems * 2)) );
712                 numTraceLeafNodes++;
713                 return;
714         }
715         
716         /* the largest dimension of the bounding box will be the split axis */
717         VectorSubtract( node->maxs, node->mins, size );
718         if( size[ 0 ] >= size[ 1 ] && size[ 0 ] >= size[ 2 ] )
719                 type = PLANE_X;
720         else if( size[ 1 ] >= size[ 0 ] && size[ 1 ] >= size[ 2 ] )
721                 type = PLANE_Y;
722         else
723                 type = PLANE_Z;
724         
725         /* don't split small nodes */
726         if( size[ type ] <= MIN_NODE_SIZE )
727         {
728                 //%     Sys_Printf( "Limit: %f %f %f (%d items)\n", size[ 0 ], size[ 1 ], size[ 2 ], node->numItems );
729                 numTraceLeafNodes++;
730                 return;
731         }
732         
733         /* set max trace depth */
734         if( depth > maxTraceDepth )
735                 maxTraceDepth = depth;
736         
737         /* snap the average */
738         dist = floor( average[ type ] / count );
739         
740         /* dummy check it */
741         if( dist <= node->mins[ type ] || dist >= node->maxs[ type ] )
742                 dist = floor( 0.5f * (node->mins[ type ] + node->maxs[ type ]) );
743         
744         /* allocate child nodes */
745         frontNum = AllocTraceNode();
746         backNum = AllocTraceNode();
747         
748         /* reset pointers */
749         node = &traceNodes[ nodeNum ];
750         frontNode = &traceNodes[ frontNum ];
751         backNode = &traceNodes[ backNum ];
752         
753         /* attach children */
754         node->type = type;
755         node->plane[ type ] = 1.0f;
756         node->plane[ 3 ] = dist;
757         node->children[ 0 ] = frontNum;
758         node->children[ 1 ] = backNum;
759         
760         /* setup front node */
761         frontNode->maxItems = (node->maxItems >> 1);
762         frontNode->items = safe_malloc( frontNode->maxItems * sizeof( *frontNode->items ) );
763         
764         /* setup back node */
765         backNode->maxItems = (node->maxItems >> 1);
766         backNode->items = safe_malloc( backNode->maxItems * sizeof( *backNode->items ) );
767         
768         /* filter windings into child nodes */
769         for( i = 0; i < node->numItems; i++ )
770         {
771                 /* get winding */
772                 tw = &traceWindings[ node->items[ i ] ];
773                 
774                 /* clip the winding by the new split plane */
775                 ClipTraceWinding( tw, node->plane, &front, &back );
776                 
777                 /* kill the existing winding */
778                 if( front.numVerts >= 3 || back.numVerts >= 3 )
779                         deadWinding = node->items[ i ];
780                 
781                 /* add front winding */
782                 if( front.numVerts >= 3 )
783                 {
784                         num = AddTraceWinding( &front );
785                         AddItemToTraceNode( frontNode, num );
786                 }
787                 
788                 /* add back winding */
789                 if( back.numVerts >= 3 )
790                 {
791                         num = AddTraceWinding( &back );
792                         AddItemToTraceNode( backNode, num );
793                 }
794         }
795         
796         /* free original node winding list */
797         node->numItems = 0;
798         node->maxItems = 0;
799         free( node->items );
800         node->items = NULL;
801         
802         /* check children */
803         if( frontNode->numItems <= 0 )
804         {
805                 frontNode->maxItems = 0;
806                 free( frontNode->items );
807                 frontNode->items = NULL;
808         }
809         
810         if( backNode->numItems <= 0 )
811         {
812                 backNode->maxItems = 0;
813                 free( backNode->items );
814                 backNode->items = NULL;
815         }
816         
817         /* subdivide children */
818         SubdivideTraceNode_r( frontNum, depth );
819         SubdivideTraceNode_r( backNum, depth );
820 }
821
822
823
824 /*
825 TriangulateTraceNode_r()
826 optimizes the tracing data by changing trace windings into triangles
827 */
828
829 static int TriangulateTraceNode_r( int nodeNum )
830 {
831         int                             i, j, num, frontNum, backNum, numWindings, *windings;
832         traceNode_t             *node;
833         traceWinding_t  *tw;
834         traceTriangle_t tt;
835         
836         
837         /* dummy check */
838         if( nodeNum < 0 || nodeNum >= numTraceNodes )
839                 return 0;
840         
841         /* get node */
842         node = &traceNodes[ nodeNum ];
843         
844         /* is this a decision node? */
845         if( node->type >= 0 )
846         {
847                 /* triangulate children */
848                 frontNum = node->children[ 0 ];
849                 backNum = node->children[ 1 ];
850                 node->numItems = TriangulateTraceNode_r( frontNum );
851                 node->numItems += TriangulateTraceNode_r( backNum );
852                 return node->numItems;
853         }
854         
855         /* empty node? */
856         if( node->numItems == 0 )
857         {
858                 node->maxItems = 0;
859                 if( node->items != NULL )
860                         free( node->items );
861                 return node->numItems;
862         }
863         
864         /* store off winding data */
865         numWindings = node->numItems;
866         windings = node->items;
867         
868         /* clear it */
869         node->numItems = 0;
870         node->maxItems = numWindings * 2;
871         node->items = safe_malloc( node->maxItems * sizeof( tt ) );
872         
873         /* walk winding list */
874         for( i = 0; i < numWindings; i++ )
875         {
876                 /* get winding */
877                 tw = &traceWindings[ windings[ i ] ];
878                 
879                 /* initial setup */
880                 tt.infoNum = tw->infoNum;
881                 tt.v[ 0 ] = tw->v[ 0 ];
882                 
883                 /* walk vertex list */
884                 for( j = 1; j + 1 < tw->numVerts; j++ )
885                 {
886                         /* set verts */
887                         tt.v[ 1 ] = tw->v[ j ];
888                         tt.v[ 2 ] = tw->v[ j + 1 ];
889                         
890                         /* find vectors for two edges sharing the first vert */
891                         VectorSubtract( tt.v[ 1 ].xyz, tt.v[ 0 ].xyz, tt.edge1 );
892                         VectorSubtract( tt.v[ 2 ].xyz, tt.v[ 0 ].xyz, tt.edge2 );
893                         
894                         /* add it to the node */
895                         num = AddTraceTriangle( &tt );
896                         AddItemToTraceNode( node, num );
897                 }
898         }
899         
900         /* free windings */
901         if( windings != NULL )
902                 free( windings );
903         
904         /* return item count */
905         return node->numItems;
906 }
907
908
909
910 /* -------------------------------------------------------------------------------
911
912 shadow casting item setup (triangles, patches, entities)
913
914 ------------------------------------------------------------------------------- */
915
916 /*
917 PopulateWithBSPModel() - ydnar
918 filters a bsp model's surfaces into the raytracing tree
919 */
920
921 static void PopulateWithBSPModel( bspModel_t *model, m4x4_t transform )
922 {
923         int                                     i, j, x, y, pw[ 5 ], r, nodeNum;
924         bspDrawSurface_t        *ds;
925         surfaceInfo_t           *info;
926         bspDrawVert_t           *verts;
927         int                                     *indexes;
928         mesh_t                          srcMesh, *mesh, *subdivided;
929         traceInfo_t                     ti;
930         traceWinding_t          tw;
931         
932         
933         /* dummy check */
934         if( model == NULL || transform == NULL )
935                 return;
936         
937         /* walk the list of surfaces in this model and fill out the info structs */
938         for( i = 0; i < model->numBSPSurfaces; i++ )
939         {
940                 /* get surface and info */
941                 ds = &bspDrawSurfaces[ model->firstBSPSurface + i ];
942                 info = &surfaceInfos[ model->firstBSPSurface + i ];
943                 if( info->si == NULL )
944                         continue;
945                 
946                 /* no shadows */
947                 if( !info->castShadows )
948                         continue;
949                 
950                 /* patchshadows? */
951                 if( ds->surfaceType == MST_PATCH && patchShadows == qfalse )
952                         continue;
953                 
954                 /* some surfaces in the bsp might have been tagged as nodraw, with a bogus shader */
955                 if( (bspShaders[ ds->shaderNum ].contentFlags & noDrawContentFlags) || 
956                         (bspShaders[ ds->shaderNum ].surfaceFlags & noDrawSurfaceFlags) )
957                         continue;
958                 
959                 /* translucent surfaces that are neither alphashadow or lightfilter don't cast shadows */
960                 if( (info->si->compileFlags & C_NODRAW) )
961                         continue;
962                 if( (info->si->compileFlags & C_TRANSLUCENT) &&
963                         !(info->si->compileFlags & C_ALPHASHADOW) && 
964                         !(info->si->compileFlags & C_LIGHTFILTER) )
965                         continue;
966                 
967                 /* setup trace info */
968                 ti.si = info->si;
969                 ti.castShadows = info->castShadows;
970                 ti.surfaceNum = model->firstBSPBrush + i;
971                 
972                 /* choose which node (normal or skybox) */
973                 if( info->parentSurfaceNum >= 0 )
974                 {
975                         nodeNum = skyboxNodeNum;
976                         
977                         /* sky surfaces in portal skies are ignored */
978                         if( info->si->compileFlags & C_SKY )
979                                 continue;
980                 }
981                 else
982                         nodeNum = headNodeNum;
983                 
984                 /* setup trace winding */
985                 memset( &tw, 0, sizeof( tw ) );
986                 tw.infoNum = AddTraceInfo( &ti );
987                 tw.numVerts = 3;
988                 
989                 /* switch on type */
990                 switch( ds->surfaceType )
991                 {
992                         /* handle patches */
993                         case MST_PATCH:
994                                 /* subdivide the surface */
995                                 srcMesh.width = ds->patchWidth;
996                                 srcMesh.height = ds->patchHeight;
997                                 srcMesh.verts = &bspDrawVerts[ ds->firstVert ];
998                                 //%     subdivided = SubdivideMesh( srcMesh, 8, 512 );
999                                 subdivided = SubdivideMesh2( srcMesh, info->patchIterations );
1000                                 
1001                                 /* fit it to the curve and remove colinear verts on rows/columns */
1002                                 PutMeshOnCurve( *subdivided );
1003                                 mesh = RemoveLinearMeshColumnsRows( subdivided );
1004                                 FreeMesh( subdivided );
1005                                 
1006                                 /* set verts */
1007                                 verts = mesh->verts;
1008                                 
1009                                 /* subdivide each quad to place the models */
1010                                 for( y = 0; y < (mesh->height - 1); y++ )
1011                                 {
1012                                         for( x = 0; x < (mesh->width - 1); x++ )
1013                                         {
1014                                                 /* set indexes */
1015                                                 pw[ 0 ] = x + (y * mesh->width);
1016                                                 pw[ 1 ] = x + ((y + 1) * mesh->width);
1017                                                 pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
1018                                                 pw[ 3 ] = x + 1 + (y * mesh->width);
1019                                                 pw[ 4 ] = x + (y * mesh->width);        /* same as pw[ 0 ] */
1020                                                 
1021                                                 /* set radix */
1022                                                 r = (x + y) & 1;
1023                                                 
1024                                                 /* make first triangle */
1025                                                 VectorCopy( verts[ pw[ r + 0 ] ].xyz, tw.v[ 0 ].xyz );
1026                                                 Vector2Copy( verts[ pw[ r + 0 ] ].st, tw.v[ 0 ].st );
1027                                                 VectorCopy( verts[ pw[ r + 1 ] ].xyz, tw.v[ 1 ].xyz );
1028                                                 Vector2Copy( verts[ pw[ r + 1 ] ].st, tw.v[ 1 ].st );
1029                                                 VectorCopy( verts[ pw[ r + 2 ] ].xyz, tw.v[ 2 ].xyz );
1030                                                 Vector2Copy( verts[ pw[ r + 2 ] ].st, tw.v[ 2 ].st );
1031                                                 m4x4_transform_point( transform, tw.v[ 0 ].xyz );
1032                                                 m4x4_transform_point( transform, tw.v[ 1 ].xyz );
1033                                                 m4x4_transform_point( transform, tw.v[ 2 ].xyz );
1034                                                 FilterTraceWindingIntoNodes_r( &tw, nodeNum );
1035                                                 
1036                                                 /* make second triangle */
1037                                                 VectorCopy( verts[ pw[ r + 0 ] ].xyz, tw.v[ 0 ].xyz );
1038                                                 Vector2Copy( verts[ pw[ r + 0 ] ].st, tw.v[ 0 ].st );
1039                                                 VectorCopy( verts[ pw[ r + 2 ] ].xyz, tw.v[ 1 ].xyz );
1040                                                 Vector2Copy( verts[ pw[ r + 2 ] ].st, tw.v[ 1 ].st );
1041                                                 VectorCopy( verts[ pw[ r + 3 ] ].xyz, tw.v[ 2 ].xyz );
1042                                                 Vector2Copy( verts[ pw[ r + 3 ] ].st, tw.v[ 2 ].st );
1043                                                 m4x4_transform_point( transform, tw.v[ 0 ].xyz );
1044                                                 m4x4_transform_point( transform, tw.v[ 1 ].xyz );
1045                                                 m4x4_transform_point( transform, tw.v[ 2 ].xyz );
1046                                                 FilterTraceWindingIntoNodes_r( &tw, nodeNum );
1047                                         }
1048                                 }
1049                                 
1050                                 /* free the subdivided mesh */
1051                                 FreeMesh( mesh );
1052                                 break;
1053                         
1054                         /* handle triangle surfaces */
1055                         case MST_TRIANGLE_SOUP:
1056                         case MST_PLANAR:
1057                                 /* set verts and indexes */
1058                                 verts = &bspDrawVerts[ ds->firstVert ];
1059                                 indexes = &bspDrawIndexes[ ds->firstIndex ];
1060                                 
1061                                 /* walk the triangle list */
1062                                 for( j = 0; j < ds->numIndexes; j += 3 )
1063                                 {
1064                                         VectorCopy( verts[ indexes[ j ] ].xyz, tw.v[ 0 ].xyz );
1065                                         Vector2Copy( verts[ indexes[ j ] ].st, tw.v[ 0 ].st );
1066                                         VectorCopy( verts[ indexes[ j + 1 ] ].xyz, tw.v[ 1 ].xyz );
1067                                         Vector2Copy( verts[ indexes[ j + 1 ] ].st, tw.v[ 1 ].st );
1068                                         VectorCopy( verts[ indexes[ j + 2 ] ].xyz, tw.v[ 2 ].xyz );
1069                                         Vector2Copy( verts[ indexes[ j + 2 ] ].st, tw.v[ 2 ].st );
1070                                         m4x4_transform_point( transform, tw.v[ 0 ].xyz );
1071                                         m4x4_transform_point( transform, tw.v[ 1 ].xyz );
1072                                         m4x4_transform_point( transform, tw.v[ 2 ].xyz );
1073                                         FilterTraceWindingIntoNodes_r( &tw, nodeNum );
1074                                 }
1075                                 break;
1076                         
1077                         /* other surface types do not cast shadows */
1078                         default:
1079                                 break;
1080                 }
1081         }
1082 }
1083
1084
1085
1086 /*
1087 PopulateWithPicoModel() - ydnar
1088 filters a picomodel's surfaces into the raytracing tree
1089 */
1090
1091 static void PopulateWithPicoModel( int castShadows, picoModel_t *model, m4x4_t transform )
1092 {
1093         int                                     i, j, k, numSurfaces, numIndexes;
1094         picoSurface_t           *surface;
1095         picoShader_t            *shader;
1096         picoVec_t                       *xyz, *st;
1097         picoIndex_t                     *indexes;
1098         traceInfo_t                     ti;
1099         traceWinding_t          tw;
1100         
1101         
1102         /* dummy check */
1103         if( model == NULL || transform == NULL )
1104                 return;
1105         
1106         /* get info */
1107         numSurfaces = PicoGetModelNumSurfaces( model );
1108         
1109         /* walk the list of surfaces in this model and fill out the info structs */
1110         for( i = 0; i < numSurfaces; i++ )
1111         {
1112                 /* get surface */
1113                 surface = PicoGetModelSurface( model, i );
1114                 if( surface == NULL )
1115                         continue;
1116                 
1117                 /* only handle triangle surfaces initially (fixme: support patches) */
1118                 if( PicoGetSurfaceType( surface ) != PICO_TRIANGLES )
1119                         continue;
1120                 
1121                 /* get shader (fixme: support shader remapping) */
1122                 shader = PicoGetSurfaceShader( surface );
1123                 if( shader == NULL )
1124                         continue;
1125                 ti.si = ShaderInfoForShader( PicoGetShaderName( shader ) );
1126                 if( ti.si == NULL )
1127                         continue;
1128                 
1129                 /* translucent surfaces that are neither alphashadow or lightfilter don't cast shadows */
1130                 if( (ti.si->compileFlags & C_NODRAW) )
1131                         continue;
1132                 if( (ti.si->compileFlags & C_TRANSLUCENT) &&
1133                         !(ti.si->compileFlags & C_ALPHASHADOW) && 
1134                         !(ti.si->compileFlags & C_LIGHTFILTER) )
1135                         continue;
1136                 
1137                 /* setup trace info */
1138                 ti.castShadows = castShadows;
1139                 ti.surfaceNum = -1;
1140                 
1141                 /* setup trace winding */
1142                 memset( &tw, 0, sizeof( tw ) );
1143                 tw.infoNum = AddTraceInfo( &ti );
1144                 tw.numVerts = 3;
1145                 
1146                 /* get info */
1147                 numIndexes = PicoGetSurfaceNumIndexes( surface );
1148                 indexes = PicoGetSurfaceIndexes( surface, 0 );
1149                 
1150                 /* walk the triangle list */
1151                 for( j = 0; j < numIndexes; j += 3, indexes += 3 )
1152                 {
1153                         for( k = 0; k < 3; k++ )
1154                         {
1155                                 xyz = PicoGetSurfaceXYZ( surface, indexes[ k ] );
1156                                 st = PicoGetSurfaceST( surface, 0, indexes[ k ] );
1157                                 VectorCopy( xyz, tw.v[ k ].xyz );
1158                                 Vector2Copy( st, tw.v[ k ].st );
1159                                 m4x4_transform_point( transform, tw.v[ k ].xyz );
1160                         }
1161                         FilterTraceWindingIntoNodes_r( &tw, headNodeNum );
1162                 }
1163         }
1164 }
1165
1166
1167
1168 /*
1169 PopulateTraceNodes() - ydnar
1170 fills the raytracing tree with world and entity occluders
1171 */
1172
1173 static void PopulateTraceNodes( void )
1174 {
1175         int                             i, m, frame, castShadows;
1176         float                   temp;
1177         entity_t                *e;
1178         const char              *value;
1179         picoModel_t             *model;
1180         vec3_t                  origin, scale, angles;
1181         m4x4_t                  transform;
1182
1183         
1184         /* add worldspawn triangles */
1185         m4x4_identity( transform );
1186         PopulateWithBSPModel( &bspModels[ 0 ], transform );
1187         
1188         /* walk each entity list */
1189         for( i = 1; i < numEntities; i++ )
1190         {
1191                 /* get entity */
1192                 e = &entities[ i ];
1193                 
1194                 /* get shadow flags */
1195                 castShadows = ENTITY_CAST_SHADOWS;
1196                 GetEntityShadowFlags( e, NULL, &castShadows, NULL );
1197                 
1198                 /* early out? */
1199                 if( !castShadows )
1200                         continue;
1201                 
1202                 /* get entity origin */
1203                 GetVectorForKey( e, "origin", origin );
1204                 
1205                 /* get scale */
1206                 scale[ 0 ] = scale[ 1 ] = scale[ 2 ] = 1.0f;
1207                 temp = FloatForKey( e, "modelscale" );
1208                 if( temp != 0.0f )
1209                         scale[ 0 ] = scale[ 1 ] = scale[ 2 ] = temp;
1210                 value = ValueForKey( e, "modelscale_vec" );
1211                 if( value[ 0 ] != '\0' )
1212                         sscanf( value, "%f %f %f", &scale[ 0 ], &scale[ 1 ], &scale[ 2 ] );
1213                 
1214                 /* get "angle" (yaw) or "angles" (pitch yaw roll) */
1215                 angles[ 0 ] = angles[ 1 ] = angles[ 2 ] = 0.0f;
1216                 angles[ 2 ] = FloatForKey( e, "angle" );
1217                 value = ValueForKey( e, "angles" );
1218                 if( value[ 0 ] != '\0' )
1219                         sscanf( value, "%f %f %f", &angles[ 1 ], &angles[ 2 ], &angles[ 0 ] );
1220                 
1221                 /* set transform matrix (thanks spog) */
1222                 m4x4_identity( transform );
1223                 m4x4_pivoted_transform_by_vec3( transform, origin, angles, eXYZ, scale, vec3_origin );
1224                 
1225                 /* hack: Stable-1_2 and trunk have differing row/column major matrix order
1226                    this transpose is necessary with Stable-1_2
1227                    uncomment the following line with old m4x4_t (non 1.3/spog_branch) code */
1228                 //%     m4x4_transpose( transform );
1229                 
1230                 /* get model */
1231                 value = ValueForKey( e, "model" );
1232                 
1233                 /* switch on model type */
1234                 switch( value[ 0 ] )
1235                 {
1236                         /* no model */
1237                         case '\0':
1238                                 break;
1239                         
1240                         /* bsp model */
1241                         case '*':
1242                                 m = atoi( &value[ 1 ] );
1243                                 if( m <= 0 || m >= numBSPModels )
1244                                         continue;
1245                                 PopulateWithBSPModel( &bspModels[ m ], transform );
1246                                 break;
1247                         
1248                         /* external model */
1249                         default:
1250                                 frame = IntForKey( e, "_frame" );
1251                                 model = LoadModel( (char*) value, frame );
1252                                 if( model == NULL )
1253                                         continue;
1254                                 PopulateWithPicoModel( castShadows, model, transform );
1255                                 continue;
1256                 }
1257                 
1258                 /* get model2 */
1259                 value = ValueForKey( e, "model2" );
1260                 
1261                 /* switch on model type */
1262                 switch( value[ 0 ] )
1263                 {
1264                         /* no model */
1265                         case '\0':
1266                                 break;
1267                         
1268                         /* bsp model */
1269                         case '*':
1270                                 m = atoi( &value[ 1 ] );
1271                                 if( m <= 0 || m >= numBSPModels )
1272                                         continue;
1273                                 PopulateWithBSPModel( &bspModels[ m ], transform );
1274                                 break;
1275                         
1276                         /* external model */
1277                         default:
1278                                 frame = IntForKey( e, "_frame2" );
1279                                 model = LoadModel( (char*) value, frame );
1280                                 if( model == NULL )
1281                                         continue;
1282                                 PopulateWithPicoModel( castShadows, model, transform );
1283                                 continue;
1284                 }
1285         }
1286 }
1287
1288
1289
1290
1291 /* -------------------------------------------------------------------------------
1292
1293 trace initialization
1294
1295 ------------------------------------------------------------------------------- */
1296
1297 /*
1298 SetupTraceNodes() - ydnar
1299 creates a balanced bsp with axis-aligned splits for efficient raytracing
1300 */
1301
1302 void SetupTraceNodes( void )
1303 {
1304         /* note it */
1305         Sys_FPrintf( SYS_VRB, "--- SetupTraceNodes ---\n" );
1306         
1307         /* find nodraw bit */
1308         noDrawContentFlags = noDrawSurfaceFlags = noDrawCompileFlags = 0;
1309         ApplySurfaceParm( "nodraw", &noDrawContentFlags, &noDrawSurfaceFlags, &noDrawCompileFlags );
1310         
1311         /* create the baseline raytracing tree from the bsp tree */
1312         headNodeNum = SetupTraceNodes_r( 0 );
1313         
1314         /* create outside node for skybox surfaces */
1315         skyboxNodeNum = AllocTraceNode();
1316         
1317         /* populate the tree with triangles from the world and shadow casting entities */
1318         PopulateTraceNodes();
1319         
1320         /* create the raytracing bsp */
1321         if( loMem == qfalse )
1322         {
1323                 SubdivideTraceNode_r( headNodeNum, 0 );
1324                 SubdivideTraceNode_r( skyboxNodeNum, 0 );
1325         }
1326         
1327         /* create triangles from the trace windings */
1328         TriangulateTraceNode_r( headNodeNum );
1329         TriangulateTraceNode_r( skyboxNodeNum );
1330         
1331         /* emit some stats */
1332         //%     Sys_FPrintf( SYS_VRB, "%9d original triangles\n", numOriginalTriangles );
1333         Sys_FPrintf( SYS_VRB, "%9d trace windings (%.2fMB)\n", numTraceWindings, (float) (numTraceWindings * sizeof( *traceWindings )) / (1024.0f * 1024.0f) );
1334         Sys_FPrintf( SYS_VRB, "%9d trace triangles (%.2fMB)\n", numTraceTriangles, (float) (numTraceTriangles * sizeof( *traceTriangles )) / (1024.0f * 1024.0f) );
1335         Sys_FPrintf( SYS_VRB, "%9d trace nodes (%.2fMB)\n", numTraceNodes, (float) (numTraceNodes * sizeof( *traceNodes )) / (1024.0f * 1024.0f) );
1336         Sys_FPrintf( SYS_VRB, "%9d leaf nodes (%.2fMB)\n", numTraceLeafNodes, (float) (numTraceLeafNodes * sizeof( *traceNodes )) / (1024.0f * 1024.0f) );
1337         //%     Sys_FPrintf( SYS_VRB, "%9d average triangles per leaf node\n", numTraceTriangles / numTraceLeafNodes );
1338         Sys_FPrintf( SYS_VRB, "%9d average windings per leaf node\n", numTraceWindings / (numTraceLeafNodes + 1) );
1339         Sys_FPrintf( SYS_VRB, "%9d max trace depth\n", maxTraceDepth );
1340         
1341         /* free trace windings */
1342         free( traceWindings );
1343         numTraceWindings = 0;
1344         maxTraceWindings = 0;
1345         deadWinding = -1;
1346         
1347         /* debug code: write out trace triangles to an alias obj file */
1348         #if 0
1349         {
1350                 int                             i, j;
1351                 FILE                    *file;
1352                 char                    filename[ 1024 ];
1353                 traceWinding_t  *tw;
1354                 
1355                 
1356                 /* open the file */
1357                 strcpy( filename, source );
1358                 StripExtension( filename );
1359                 strcat( filename, ".lin" );
1360                 Sys_Printf( "Opening light trace file %s...\n", filename );
1361                 file = fopen( filename, "w" );
1362                 if( file == NULL )
1363                         Error( "Error opening %s for writing", filename );
1364                 
1365                 /* walk node list */
1366                 for( i = 0; i < numTraceWindings; i++ )
1367                 {
1368                         tw = &traceWindings[ i ];
1369                         for( j = 0; j < tw->numVerts + 1; j++ )
1370                                 fprintf( file, "%f %f %f\n",
1371                                         tw->v[ j % tw->numVerts ].xyz[ 0 ], tw->v[ j % tw->numVerts ].xyz[ 1 ], tw->v[ j % tw->numVerts ].xyz[ 2 ] );
1372                 }
1373                 
1374                 /* close it */
1375                 fclose( file );
1376         }
1377         #endif
1378 }
1379
1380
1381
1382 /* -------------------------------------------------------------------------------
1383
1384 raytracer
1385
1386 ------------------------------------------------------------------------------- */
1387
1388 /*
1389 TraceTriangle()
1390 based on code written by william 'spog' joseph
1391 based on code originally written by tomas moller and ben trumbore, journal of graphics tools, 2(1):21-28, 1997
1392 */
1393
1394 #define BARY_EPSILON                    0.01f
1395 #define ASLF_EPSILON                    0.0001f /* so to not get double shadows */
1396 #define COPLANAR_EPSILON                0.25f   //%     0.000001f
1397 #define NEAR_SHADOW_EPSILON             1.5f    //%     1.25f
1398 #define SELF_SHADOW_EPSILON             0.5f
1399
1400 qboolean TraceTriangle( traceInfo_t *ti, traceTriangle_t *tt, trace_t *trace )
1401 {
1402         int                             i;
1403         float                   tvec[ 3 ], pvec[ 3 ], qvec[ 3 ];
1404         float                   det, invDet, depth;
1405         float                   u, v, w, s, t;
1406         int                             is, it;
1407         byte                    *pixel;
1408         float                   shadow;
1409         shaderInfo_t    *si;
1410         
1411         
1412         /* don't double-trace against sky */
1413         si = ti->si;
1414         if( trace->compileFlags & si->compileFlags & C_SKY )
1415                 return qfalse;
1416         
1417         /* receive shadows from worldspawn group only */
1418         if( trace->recvShadows == 1 )
1419         {
1420                 if( ti->castShadows != 1 )
1421                         return qfalse;
1422         }
1423         
1424         /* receive shadows from same group and worldspawn group */
1425         else if( trace->recvShadows > 1 )
1426         {
1427                 if( ti->castShadows != 1 && abs( ti->castShadows ) != abs( trace->recvShadows ) )
1428                         return qfalse;
1429                 //%     Sys_Printf( "%d:%d ", tt->castShadows, trace->recvShadows );
1430         }
1431         
1432         /* receive shadows from the same group only (< 0) */
1433         else
1434         {
1435                 if( abs( ti->castShadows ) != abs( trace->recvShadows ) )
1436                         return qfalse;
1437         }
1438         
1439         /* begin calculating determinant - also used to calculate u parameter */
1440         CrossProduct( trace->direction, tt->edge2, pvec );
1441         
1442         /* if determinant is near zero, trace lies in plane of triangle */
1443         det = DotProduct( tt->edge1, pvec );
1444         
1445         /* the non-culling branch */
1446         if( fabs( det ) < COPLANAR_EPSILON )
1447                 return qfalse;
1448         invDet = 1.0f / det;
1449         
1450         /* calculate distance from first vertex to ray origin */
1451         VectorSubtract( trace->origin, tt->v[ 0 ].xyz, tvec );
1452         
1453         /* calculate u parameter and test bounds */
1454         u = DotProduct( tvec, pvec ) * invDet;
1455         if( u < -BARY_EPSILON || u > (1.0f + BARY_EPSILON) )
1456                 return qfalse;
1457         
1458         /* prepare to test v parameter */
1459         CrossProduct( tvec, tt->edge1, qvec );
1460         
1461         /* calculate v parameter and test bounds */
1462         v = DotProduct( trace->direction, qvec ) * invDet;
1463         if( v < -BARY_EPSILON || (u + v) > (1.0f + BARY_EPSILON) )
1464                 return qfalse;
1465         
1466         /* calculate t (depth) */
1467         depth = DotProduct( tt->edge2, qvec ) * invDet;
1468         if( depth <= trace->inhibitRadius || depth >= trace->distance )
1469                 return qfalse;
1470         
1471         /* if hitpoint is really close to trace origin (sample point), then check for self-shadowing */
1472         if( depth <= SELF_SHADOW_EPSILON )
1473         {
1474                 /* don't self-shadow */
1475                 for( i = 0; i < trace->numSurfaces; i++ )
1476                 {
1477                         if( ti->surfaceNum == trace->surfaces[ i ] )
1478                                 return qfalse;
1479                 }
1480         }
1481         
1482         /* stack compile flags */
1483         trace->compileFlags |= si->compileFlags;
1484         
1485         /* don't trace against sky */
1486         if( si->compileFlags & C_SKY )
1487                 return qfalse;
1488         
1489         /* most surfaces are completely opaque */
1490         if( !(si->compileFlags & (C_ALPHASHADOW | C_LIGHTFILTER)) ||
1491                 si->lightImage == NULL || si->lightImage->pixels == NULL )
1492         {
1493                 VectorMA( trace->origin, depth, trace->direction, trace->hit );
1494                 VectorClear( trace->color );
1495                 trace->opaque = qtrue;
1496                 return qtrue;
1497         }
1498         
1499         /* try to avoid double shadows near triangle seams */
1500         if( u < -ASLF_EPSILON || u > (1.0f + ASLF_EPSILON) ||
1501                 v < -ASLF_EPSILON || (u + v) > (1.0f + ASLF_EPSILON) )
1502                 return qfalse;
1503         
1504         /* calculate w parameter */
1505         w = 1.0f - (u + v);
1506         
1507         /* calculate st from uvw (barycentric) coordinates */
1508         s = w * tt->v[ 0 ].st[ 0 ] + u * tt->v[ 1 ].st[ 0 ] + v * tt->v[ 2 ].st[ 0 ];
1509         t = w * tt->v[ 0 ].st[ 1 ] + u * tt->v[ 1 ].st[ 1 ] + v * tt->v[ 2 ].st[ 1 ];
1510         s = s - floor( s );
1511         t = t - floor( t );
1512         is = s * si->lightImage->width;
1513         it = t * si->lightImage->height;
1514         
1515         /* get pixel */
1516         pixel = si->lightImage->pixels + 4 * (it * si->lightImage->width + is);
1517         
1518         /* ydnar: color filter */
1519         if( si->compileFlags & C_LIGHTFILTER )
1520         {
1521                 /* filter by texture color */
1522                 trace->color[ 0 ] *= ((1.0f / 255.0f) * pixel[ 0 ]);
1523                 trace->color[ 1 ] *= ((1.0f / 255.0f) * pixel[ 1 ]);
1524                 trace->color[ 2 ] *= ((1.0f / 255.0f) * pixel[ 2 ]);
1525         }
1526         
1527         /* ydnar: alpha filter */
1528         if( si->compileFlags & C_ALPHASHADOW )
1529         {
1530                 /* filter by inverse texture alpha */
1531                 shadow = (1.0f / 255.0f) * (255 - pixel[ 3 ]);
1532                 trace->color[ 0 ] *= shadow;
1533                 trace->color[ 1 ] *= shadow;
1534                 trace->color[ 2 ] *= shadow;
1535         }
1536         
1537         /* check filter for opaque */
1538         if( trace->color[ 0 ] <= 0.001f && trace->color[ 1 ] <= 0.001f && trace->color[ 2 ] <= 0.001f )
1539         {
1540                 VectorMA( trace->origin, depth, trace->direction, trace->hit );
1541                 trace->opaque = qtrue;
1542                 return qtrue;
1543         }
1544         
1545         /* continue tracing */
1546         return qfalse;
1547 }
1548
1549
1550
1551 /*
1552 TraceWinding() - ydnar
1553 temporary hack
1554 */
1555
1556 qboolean TraceWinding( traceWinding_t *tw, trace_t *trace )
1557 {
1558         int                             i;
1559         traceTriangle_t tt;
1560         
1561         
1562         /* initial setup */
1563         tt.infoNum = tw->infoNum;
1564         tt.v[ 0 ] = tw->v[ 0 ];
1565         
1566         /* walk vertex list */
1567         for( i = 1; i + 1 < tw->numVerts; i++ )
1568         {
1569                 /* set verts */
1570                 tt.v[ 1 ] = tw->v[ i ];
1571                 tt.v[ 2 ] = tw->v[ i + 1 ];
1572                 
1573                 /* find vectors for two edges sharing the first vert */
1574                 VectorSubtract( tt.v[ 1 ].xyz, tt.v[ 0 ].xyz, tt.edge1 );
1575                 VectorSubtract( tt.v[ 2 ].xyz, tt.v[ 0 ].xyz, tt.edge2 );
1576                 
1577                 /* trace it */
1578                 if( TraceTriangle( &traceInfos[ tt.infoNum ], &tt, trace ) )
1579                         return qtrue;
1580         }
1581         
1582         /* done */
1583         return qfalse;
1584 }
1585
1586
1587
1588
1589 /*
1590 TraceLine_r()
1591 returns qtrue if something is hit and tracing can stop
1592 */
1593
1594 static qboolean TraceLine_r( int nodeNum, vec3_t origin, vec3_t end, trace_t *trace )
1595 {
1596         traceNode_t             *node;
1597         int                             side;
1598         float                   front, back, frac;
1599         vec3_t                  mid;
1600         qboolean                r;
1601
1602         
1603         /* bogus node number means solid, end tracing unless testing all */
1604         if( nodeNum < 0 )
1605         {
1606                 VectorCopy( origin, trace->hit );
1607                 trace->passSolid = qtrue;
1608                 return qtrue;
1609         }
1610         
1611         /* get node */
1612         node = &traceNodes[ nodeNum ];
1613         
1614         /* solid? */
1615         if( node->type == TRACE_LEAF_SOLID )
1616         {
1617                 VectorCopy( origin, trace->hit );
1618                 trace->passSolid = qtrue;
1619                 return qtrue;
1620         }
1621         
1622         /* leafnode? */
1623         if( node->type < 0 )
1624         {
1625                 /* note leaf and return */      
1626                 if( node->numItems > 0 && trace->numTestNodes < MAX_TRACE_TEST_NODES )
1627                         trace->testNodes[ trace->numTestNodes++ ] = nodeNum;
1628                 return qfalse;
1629         }
1630         
1631         /* ydnar 2003-09-07: don't test branches of the bsp with nothing in them when testall is enabled */
1632         if( trace->testAll && node->numItems == 0 )
1633                 return qfalse;
1634         
1635         /* classify beginning and end points */
1636         switch( node->type )
1637         {
1638                 case PLANE_X:
1639                         front = origin[ 0 ] - node->plane[ 3 ];
1640                         back = end[ 0 ] - node->plane[ 3 ];
1641                         break;
1642                 
1643                 case PLANE_Y:
1644                         front = origin[ 1 ] - node->plane[ 3 ];
1645                         back = end[ 1 ] - node->plane[ 3 ];
1646                         break;
1647                 
1648                 case PLANE_Z:
1649                         front = origin[ 2 ] - node->plane[ 3 ];
1650                         back = end[ 2 ] - node->plane[ 3 ];
1651                         break;
1652                 
1653                 default:
1654                         front = DotProduct( origin, node->plane ) - node->plane[ 3 ];
1655                         back = DotProduct( end, node->plane ) - node->plane[ 3 ];
1656                         break;
1657         }
1658         
1659         /* entirely in front side? */
1660         if( front >= -TRACE_ON_EPSILON && back >= -TRACE_ON_EPSILON )
1661                 return TraceLine_r( node->children[ 0 ], origin, end, trace );
1662         
1663         /* entirely on back side? */
1664         if( front < TRACE_ON_EPSILON && back < TRACE_ON_EPSILON )
1665                 return TraceLine_r( node->children[ 1 ], origin, end, trace );
1666         
1667         /* select side */
1668         side = front < 0;
1669         
1670         /* calculate intercept point */
1671         frac = front / (front - back);
1672         mid[ 0 ] = origin[ 0 ] + (end[ 0 ] - origin[ 0 ]) * frac;
1673         mid[ 1 ] = origin[ 1 ] + (end[ 1 ] - origin[ 1 ]) * frac;
1674         mid[ 2 ] = origin[ 2 ] + (end[ 2 ] - origin[ 2 ]) * frac;
1675         
1676         /* fixme: check inhibit radius, then solid nodes and ignore */
1677         
1678         /* set trace hit here */
1679         //%     VectorCopy( mid, trace->hit );
1680         
1681         /* trace first side */
1682         r = TraceLine_r( node->children[ side ], origin, mid, trace );
1683         if( r )
1684                 return r;
1685         
1686         /* trace other side */
1687         return TraceLine_r( node->children[ !side ], mid, end, trace );
1688 }
1689
1690
1691
1692 /*
1693 TraceLine() - ydnar
1694 rewrote this function a bit :)
1695 */
1696
1697 void TraceLine( trace_t *trace )
1698 {
1699         int                             i, j;
1700         traceNode_t             *node;
1701         traceTriangle_t *tt;
1702         traceInfo_t             *ti;
1703         
1704         
1705         /* setup output (note: this code assumes the input data is completely filled out) */
1706         trace->passSolid = qfalse;
1707         trace->opaque = qfalse;
1708         trace->compileFlags = 0;
1709         trace->numTestNodes = 0;
1710         
1711         /* early outs */
1712         if( !trace->recvShadows || !trace->testOcclusion || trace->distance <= 0.00001f )
1713                 return;
1714         
1715         /* trace through nodes */
1716         TraceLine_r( headNodeNum, trace->origin, trace->end, trace );
1717         if( trace->passSolid && !trace->testAll )
1718         {
1719                 trace->opaque = qtrue;
1720                 return;
1721         }
1722         
1723         /* skip surfaces? */
1724         if( noSurfaces )
1725                 return;
1726         
1727         /* testall means trace through sky */   
1728         if( trace->testAll && trace->numTestNodes < MAX_TRACE_TEST_NODES &&
1729                 trace->compileFlags & C_SKY &&
1730                 (trace->numSurfaces == 0 || surfaceInfos[ trace->surfaces[ 0 ] ].childSurfaceNum < 0) )
1731         {
1732                 //%     trace->testNodes[ trace->numTestNodes++ ] = skyboxNodeNum;
1733                 TraceLine_r( skyboxNodeNum, trace->origin, trace->end, trace );
1734         }
1735         
1736         /* walk node list */
1737         for( i = 0; i < trace->numTestNodes; i++ )
1738         {
1739                 /* get node */
1740                 node = &traceNodes[ trace->testNodes[ i ] ];
1741                 
1742                 /* walk node item list */
1743                 for( j = 0; j < node->numItems; j++ )
1744                 {
1745                         tt = &traceTriangles[ node->items[ j ] ];
1746                         ti = &traceInfos[ tt->infoNum ];
1747                         if( TraceTriangle( ti, tt, trace ) )
1748                                 return;
1749                         //%     if( TraceWinding( &traceWindings[ node->items[ j ] ], trace ) )
1750                         //%             return;
1751                 }
1752         }
1753 }
1754
1755
1756
1757 /*
1758 SetupTrace() - ydnar
1759 sets up certain trace values
1760 */
1761
1762 float SetupTrace( trace_t *trace )
1763 {
1764         VectorSubtract( trace->end, trace->origin, trace->displacement );
1765         trace->distance = VectorNormalize( trace->displacement, trace->direction );
1766         VectorCopy( trace->origin, trace->hit );
1767         return trace->distance;
1768 }