]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/q2map/flow.c
Merge branch 'master' into divVerent/farplanedist-sky-fix
[xonotic/netradiant.git] / tools / quake2 / q2map / flow.c
1 /*
2    Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3    For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5    This file is part of GtkRadiant.
6
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    GtkRadiant is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 #include "qvis.h"
22
23 /*
24
25    each portal will have a list of all possible to see from first portal
26
27    if (!thread->portalmightsee[portalnum])
28
29    portal mightsee
30
31    for p2 = all other portals in leaf
32     get sperating planes
33     for all portals that might be seen by p2
34         mark as unseen if not present in seperating plane
35     flood fill a new mightsee
36     save as passagemightsee
37
38
39    void CalcMightSee (leaf_t *leaf,
40  */
41
42 int CountBits( byte *bits, int numbits ){
43         int i;
44         int c;
45
46         c = 0;
47         for ( i = 0 ; i < numbits ; i++ )
48                 if ( bits[i >> 3] & ( 1 << ( i & 7 ) ) ) {
49                         c++;
50                 }
51
52         return c;
53 }
54
55 int c_fullskip;
56 int c_portalskip, c_leafskip;
57 int c_vistest, c_mighttest;
58
59 int c_chop, c_nochop;
60
61 int active;
62
63 void CheckStack( leaf_t *leaf, threaddata_t *thread ){
64         pstack_t    *p, *p2;
65
66         for ( p = thread->pstack_head.next ; p ; p = p->next )
67         {
68 //              printf ("=");
69                 if ( p->leaf == leaf ) {
70                         Error( "CheckStack: leaf recursion" );
71                 }
72                 for ( p2 = thread->pstack_head.next ; p2 != p ; p2 = p2->next )
73                         if ( p2->leaf == p->leaf ) {
74                                 Error( "CheckStack: late leaf recursion" );
75                         }
76         }
77 //      printf ("\n");
78 }
79
80
81 winding_t *AllocStackWinding( pstack_t *stack ){
82         int i;
83
84         for ( i = 0 ; i < 3 ; i++ )
85         {
86                 if ( stack->freewindings[i] ) {
87                         stack->freewindings[i] = 0;
88                         return &stack->windings[i];
89                 }
90         }
91
92         Error( "AllocStackWinding: failed" );
93
94         return NULL;
95 }
96
97 void FreeStackWinding( winding_t *w, pstack_t *stack ){
98         int i;
99
100         i = w - stack->windings;
101
102         if ( i < 0 || i > 2 ) {
103                 return;     // not from local
104
105         }
106         if ( stack->freewindings[i] ) {
107                 Error( "FreeStackWinding: allready free" );
108         }
109         stack->freewindings[i] = 1;
110 }
111
112 /*
113    ==============
114    Vis_ChopWinding
115
116    ==============
117  */
118 winding_t   *Vis_ChopWinding( winding_t *in, pstack_t *stack, plane_t *split ){
119         vec_t dists[128];
120         int sides[128];
121         int counts[3];
122         vec_t dot;
123         int i, j;
124         vec_t   *p1, *p2;
125         vec3_t mid;
126         winding_t   *neww;
127
128         counts[0] = counts[1] = counts[2] = 0;
129
130 // determine sides for each point
131         for ( i = 0 ; i < in->numpoints ; i++ )
132         {
133                 dot = DotProduct( in->points[i], split->normal );
134                 dot -= split->dist;
135                 dists[i] = dot;
136                 if ( dot > ON_EPSILON ) {
137                         sides[i] = SIDE_FRONT;
138                 }
139                 else if ( dot < -ON_EPSILON ) {
140                         sides[i] = SIDE_BACK;
141                 }
142                 else
143                 {
144                         sides[i] = SIDE_ON;
145                 }
146                 counts[sides[i]]++;
147         }
148
149         if ( !counts[1] ) {
150                 return in;      // completely on front side
151
152         }
153         if ( !counts[0] ) {
154                 FreeStackWinding( in, stack );
155                 return NULL;
156         }
157
158         sides[i] = sides[0];
159         dists[i] = dists[0];
160
161         neww = AllocStackWinding( stack );
162
163         neww->numpoints = 0;
164
165         for ( i = 0 ; i < in->numpoints ; i++ )
166         {
167                 p1 = in->points[i];
168
169                 if ( neww->numpoints == MAX_POINTS_ON_FIXED_WINDING ) {
170                         FreeStackWinding( neww, stack );
171                         return in;      // can't chop -- fall back to original
172                 }
173
174                 if ( sides[i] == SIDE_ON ) {
175                         VectorCopy( p1, neww->points[neww->numpoints] );
176                         neww->numpoints++;
177                         continue;
178                 }
179
180                 if ( sides[i] == SIDE_FRONT ) {
181                         VectorCopy( p1, neww->points[neww->numpoints] );
182                         neww->numpoints++;
183                 }
184
185                 if ( sides[i + 1] == SIDE_ON || sides[i + 1] == sides[i] ) {
186                         continue;
187                 }
188
189                 if ( neww->numpoints == MAX_POINTS_ON_FIXED_WINDING ) {
190                         FreeStackWinding( neww, stack );
191                         return in;      // can't chop -- fall back to original
192                 }
193
194                 // generate a split point
195                 p2 = in->points[( i + 1 ) % in->numpoints];
196
197                 dot = dists[i] / ( dists[i] - dists[i + 1] );
198                 for ( j = 0 ; j < 3 ; j++ )
199                 {   // avoid round off error when possible
200                         if ( split->normal[j] == 1 ) {
201                                 mid[j] = split->dist;
202                         }
203                         else if ( split->normal[j] == -1 ) {
204                                 mid[j] = -split->dist;
205                         }
206                         else{
207                                 mid[j] = p1[j] + dot * ( p2[j] - p1[j] );
208                         }
209                 }
210
211                 VectorCopy( mid, neww->points[neww->numpoints] );
212                 neww->numpoints++;
213         }
214
215 // free the original winding
216         FreeStackWinding( in, stack );
217
218         return neww;
219 }
220
221
222 /*
223    ==============
224    ClipToSeperators
225
226    Source, pass, and target are an ordering of portals.
227
228    Generates seperating planes canidates by taking two points from source and one
229    point from pass, and clips target by them.
230
231    If target is totally clipped away, that portal can not be seen through.
232
233    Normal clip keeps target on the same side as pass, which is correct if the
234    order goes source, pass, target.  If the order goes pass, source, target then
235    flipclip should be set.
236    ==============
237  */
238 winding_t   *ClipToSeperators( winding_t *source, winding_t *pass, winding_t *target, qboolean flipclip, pstack_t *stack ){
239         int i, j, k, l;
240         plane_t plane;
241         vec3_t v1, v2;
242         float d;
243         vec_t length;
244         int counts[3];
245         qboolean fliptest;
246
247 // check all combinations
248         for ( i = 0 ; i < source->numpoints ; i++ )
249         {
250                 l = ( i + 1 ) % source->numpoints;
251                 VectorSubtract( source->points[l], source->points[i], v1 );
252
253                 // fing a vertex of pass that makes a plane that puts all of the
254                 // vertexes of pass on the front side and all of the vertexes of
255                 // source on the back side
256                 for ( j = 0 ; j < pass->numpoints ; j++ )
257                 {
258                         VectorSubtract( pass->points[j], source->points[i], v2 );
259
260                         plane.normal[0] = v1[1] * v2[2] - v1[2] * v2[1];
261                         plane.normal[1] = v1[2] * v2[0] - v1[0] * v2[2];
262                         plane.normal[2] = v1[0] * v2[1] - v1[1] * v2[0];
263
264                         // if points don't make a valid plane, skip it
265
266                         length = plane.normal[0] * plane.normal[0]
267                                          + plane.normal[1] * plane.normal[1]
268                                          + plane.normal[2] * plane.normal[2];
269
270                         if ( length < ON_EPSILON ) {
271                                 continue;
272                         }
273
274                         length = 1 / sqrt( length );
275
276                         plane.normal[0] *= length;
277                         plane.normal[1] *= length;
278                         plane.normal[2] *= length;
279
280                         plane.dist = DotProduct( pass->points[j], plane.normal );
281
282                         //
283                         // find out which side of the generated seperating plane has the
284                         // source portal
285                         //
286 #if 1
287                         fliptest = false;
288                         for ( k = 0 ; k < source->numpoints ; k++ )
289                         {
290                                 if ( k == i || k == l ) {
291                                         continue;
292                                 }
293                                 d = DotProduct( source->points[k], plane.normal ) - plane.dist;
294                                 if ( d < -ON_EPSILON ) { // source is on the negative side, so we want all
295                                                             // pass and target on the positive side
296                                         fliptest = false;
297                                         break;
298                                 }
299                                 else if ( d > ON_EPSILON ) { // source is on the positive side, so we want all
300                                                                 // pass and target on the negative side
301                                         fliptest = true;
302                                         break;
303                                 }
304                         }
305                         if ( k == source->numpoints ) {
306                                 continue;       // planar with source portal
307                         }
308 #else
309                         fliptest = flipclip;
310 #endif
311                         //
312                         // flip the normal if the source portal is backwards
313                         //
314                         if ( fliptest ) {
315                                 VectorSubtract( vec3_origin, plane.normal, plane.normal );
316                                 plane.dist = -plane.dist;
317                         }
318 #if 1
319                         //
320                         // if all of the pass portal points are now on the positive side,
321                         // this is the seperating plane
322                         //
323                         counts[0] = counts[1] = counts[2] = 0;
324                         for ( k = 0 ; k < pass->numpoints ; k++ )
325                         {
326                                 if ( k == j ) {
327                                         continue;
328                                 }
329                                 d = DotProduct( pass->points[k], plane.normal ) - plane.dist;
330                                 if ( d < -ON_EPSILON ) {
331                                         break;
332                                 }
333                                 else if ( d > ON_EPSILON ) {
334                                         counts[0]++;
335                                 }
336                                 else{
337                                         counts[2]++;
338                                 }
339                         }
340                         if ( k != pass->numpoints ) {
341                                 continue;   // points on negative side, not a seperating plane
342
343                         }
344                         if ( !counts[0] ) {
345                                 continue;   // planar with seperating plane
346                         }
347 #else
348                         k = ( j + 1 ) % pass->numpoints;
349                         d = DotProduct( pass->points[k], plane.normal ) - plane.dist;
350                         if ( d < -ON_EPSILON ) {
351                                 continue;
352                         }
353                         k = ( j + pass->numpoints - 1 ) % pass->numpoints;
354                         d = DotProduct( pass->points[k], plane.normal ) - plane.dist;
355                         if ( d < -ON_EPSILON ) {
356                                 continue;
357                         }
358 #endif
359                         //
360                         // flip the normal if we want the back side
361                         //
362                         if ( flipclip ) {
363                                 VectorSubtract( vec3_origin, plane.normal, plane.normal );
364                                 plane.dist = -plane.dist;
365                         }
366
367                         //
368                         // clip target by the seperating plane
369                         //
370                         target = Vis_ChopWinding( target, stack, &plane );
371                         if ( !target ) {
372                                 return NULL;        // target is not visible
373                         }
374                 }
375         }
376
377         return target;
378 }
379
380
381
382 /*
383    ==================
384    RecursiveLeafFlow
385
386    Flood fill through the leafs
387    If src_portal is NULL, this is the originating leaf
388    ==================
389  */
390 void RecursiveLeafFlow( int leafnum, threaddata_t *thread, pstack_t *prevstack ){
391         pstack_t stack;
392         portal_t    *p;
393         plane_t backplane;
394         leaf_t      *leaf;
395         int i, j;
396         long        *test, *might, *vis, more;
397         int pnum;
398
399         thread->c_chains++;
400
401         leaf = &leafs[leafnum];
402 //      CheckStack (leaf, thread);
403
404         prevstack->next = &stack;
405
406         stack.next = NULL;
407         stack.leaf = leaf;
408         stack.portal = NULL;
409
410         might = (long *)stack.mightsee;
411         vis = (long *)thread->base->portalvis;
412
413 // check all portals for flowing into other leafs
414         for ( i = 0 ; i < leaf->numportals ; i++ )
415         {
416                 p = leaf->portals[i];
417                 pnum = p - portals;
418
419                 if ( !( prevstack->mightsee[pnum >> 3] & ( 1 << ( pnum & 7 ) ) ) ) {
420                         continue;   // can't possibly see it
421                 }
422
423                 // if the portal can't see anything we haven't allready seen, skip it
424                 if ( p->status == stat_done ) {
425                         test = (long *)p->portalvis;
426                 }
427                 else
428                 {
429                         test = (long *)p->portalflood;
430                 }
431
432                 more = 0;
433                 for ( j = 0 ; j < portallongs ; j++ )
434                 {
435                         might[j] = ( (long *)prevstack->mightsee )[j] & test[j];
436                         more |= ( might[j] & ~vis[j] );
437                 }
438
439                 if ( !more &&
440                          ( thread->base->portalvis[pnum >> 3] & ( 1 << ( pnum & 7 ) ) ) ) { // can't see anything new
441                         continue;
442                 }
443
444                 // get plane of portal, point normal into the neighbor leaf
445                 stack.portalplane = p->plane;
446                 VectorSubtract( vec3_origin, p->plane.normal, backplane.normal );
447                 backplane.dist = -p->plane.dist;
448
449 //              c_portalcheck++;
450
451                 stack.portal = p;
452                 stack.next = NULL;
453                 stack.freewindings[0] = 1;
454                 stack.freewindings[1] = 1;
455                 stack.freewindings[2] = 1;
456
457 #if 1
458                 {
459                         float d;
460
461                         d = DotProduct( p->origin, thread->pstack_head.portalplane.normal );
462                         d -= thread->pstack_head.portalplane.dist;
463                         if ( d < -p->radius ) {
464                                 continue;
465                         }
466                         else if ( d > p->radius ) {
467                                 stack.pass = p->winding;
468                         }
469                         else
470                         {
471                                 stack.pass = Vis_ChopWinding( p->winding, &stack, &thread->pstack_head.portalplane );
472                                 if ( !stack.pass ) {
473                                         continue;
474                                 }
475                         }
476                 }
477 #else
478                 stack.pass = Vis_ChopWinding( p->winding, &stack, &thread->pstack_head.portalplane );
479                 if ( !stack.pass ) {
480                         continue;
481                 }
482 #endif
483
484
485 #if 1
486                 {
487                         float d;
488
489                         d = DotProduct( thread->base->origin, p->plane.normal );
490                         d -= p->plane.dist;
491                         if ( d > p->radius ) {
492                                 continue;
493                         }
494                         else if ( d < -p->radius ) {
495                                 stack.source = prevstack->source;
496                         }
497                         else
498                         {
499                                 stack.source = Vis_ChopWinding( prevstack->source, &stack, &backplane );
500                                 if ( !stack.source ) {
501                                         continue;
502                                 }
503                         }
504                 }
505 #else
506                 stack.source = Vis_ChopWinding( prevstack->source, &stack, &backplane );
507                 if ( !stack.source ) {
508                         continue;
509                 }
510 #endif
511
512                 if ( !prevstack->pass ) { // the second leaf can only be blocked if coplanar
513
514                         // mark the portal as visible
515                         thread->base->portalvis[pnum >> 3] |= ( 1 << ( pnum & 7 ) );
516
517                         RecursiveLeafFlow( p->leaf, thread, &stack );
518                         continue;
519                 }
520
521                 stack.pass = ClipToSeperators( stack.source, prevstack->pass, stack.pass, false, &stack );
522                 if ( !stack.pass ) {
523                         continue;
524                 }
525
526                 stack.pass = ClipToSeperators( prevstack->pass, stack.source, stack.pass, true, &stack );
527                 if ( !stack.pass ) {
528                         continue;
529                 }
530
531                 // mark the portal as visible
532                 thread->base->portalvis[pnum >> 3] |= ( 1 << ( pnum & 7 ) );
533
534                 // flow through it for real
535                 RecursiveLeafFlow( p->leaf, thread, &stack );
536         }
537 }
538
539
540 /*
541    ===============
542    PortalFlow
543
544    generates the portalvis bit vector
545    ===============
546  */
547 void PortalFlow( int portalnum ){
548         threaddata_t data;
549         int i;
550         portal_t        *p;
551         int c_might, c_can;
552
553         p = sorted_portals[portalnum];
554         p->status = stat_working;
555
556         c_might = CountBits( p->portalflood, numportals * 2 );
557
558         memset( &data, 0, sizeof( data ) );
559         data.base = p;
560
561         data.pstack_head.portal = p;
562         data.pstack_head.source = p->winding;
563         data.pstack_head.portalplane = p->plane;
564         for ( i = 0 ; i < portallongs ; i++ )
565                 ( (long *)data.pstack_head.mightsee )[i] = ( (long *)p->portalflood )[i];
566         RecursiveLeafFlow( p->leaf, &data, &data.pstack_head );
567
568         p->status = stat_done;
569
570         c_can = CountBits( p->portalvis, numportals * 2 );
571
572         Sys_FPrintf( SYS_VRB, "portal:%4i  mightsee:%4i  cansee:%4i (%i chains)\n",
573                                  (int)( p - portals ), c_might, c_can, data.c_chains );
574 }
575
576
577 /*
578    ===============================================================================
579
580    This is a rough first-order aproximation that is used to trivially reject some
581    of the final calculations.
582
583
584    Calculates portalfront and portalflood bit vectors
585
586    thinking about:
587
588    typedef struct passage_s
589    {
590     struct passage_s    *next;
591     struct portal_s             *to;
592     stryct sep_s                *seperators;
593     byte                                *mightsee;
594    } passage_t;
595
596    typedef struct portal_s
597    {
598     struct passage_s    *passages;
599     int                                 leaf;           // leaf portal faces into
600    } portal_s;
601
602    leaf = portal->leaf
603    clear
604    for all portals
605
606
607    calc portal visibility
608     clear bit vector
609     for all passages
610         passage visibility
611
612
613    for a portal to be visible to a passage, it must be on the front of
614    all seperating planes, and both portals must be behind the mew portal
615
616    ===============================================================================
617  */
618
619 int c_flood, c_vis;
620
621
622 /*
623    ==================
624    SimpleFlood
625
626    ==================
627  */
628 void SimpleFlood( portal_t *srcportal, int leafnum ){
629         int i;
630         leaf_t  *leaf;
631         portal_t    *p;
632         int pnum;
633
634         leaf = &leafs[leafnum];
635
636         for ( i = 0 ; i < leaf->numportals ; i++ )
637         {
638                 p = leaf->portals[i];
639                 pnum = p - portals;
640                 if ( !( srcportal->portalfront[pnum >> 3] & ( 1 << ( pnum & 7 ) ) ) ) {
641                         continue;
642                 }
643
644                 if ( srcportal->portalflood[pnum >> 3] & ( 1 << ( pnum & 7 ) ) ) {
645                         continue;
646                 }
647
648                 srcportal->portalflood[pnum >> 3] |= ( 1 << ( pnum & 7 ) );
649
650                 SimpleFlood( srcportal, p->leaf );
651         }
652 }
653
654 /*
655    ==============
656    BasePortalVis
657    ==============
658  */
659 void BasePortalVis( int portalnum ){
660         int j, k;
661         portal_t    *tp, *p;
662         float d;
663         winding_t   *w;
664
665         p = portals + portalnum;
666
667         p->portalfront = malloc( portalbytes );
668         memset( p->portalfront, 0, portalbytes );
669
670         p->portalflood = malloc( portalbytes );
671         memset( p->portalflood, 0, portalbytes );
672
673         p->portalvis = malloc( portalbytes );
674         memset( p->portalvis, 0, portalbytes );
675
676         for ( j = 0, tp = portals ; j < numportals * 2 ; j++, tp++ )
677         {
678                 if ( j == portalnum ) {
679                         continue;
680                 }
681                 w = tp->winding;
682                 for ( k = 0 ; k < w->numpoints ; k++ )
683                 {
684                         d = DotProduct( w->points[k], p->plane.normal )
685                                 - p->plane.dist;
686                         if ( d > ON_EPSILON ) {
687                                 break;
688                         }
689                 }
690                 if ( k == w->numpoints ) {
691                         continue;   // no points on front
692
693                 }
694                 w = p->winding;
695                 for ( k = 0 ; k < w->numpoints ; k++ )
696                 {
697                         d = DotProduct( w->points[k], tp->plane.normal )
698                                 - tp->plane.dist;
699                         if ( d < -ON_EPSILON ) {
700                                 break;
701                         }
702                 }
703                 if ( k == w->numpoints ) {
704                         continue;   // no points on front
705
706                 }
707                 p->portalfront[j >> 3] |= ( 1 << ( j & 7 ) );
708         }
709
710         SimpleFlood( p, p->leaf );
711
712         p->nummightsee = CountBits( p->portalflood, numportals * 2 );
713 //      printf ("portal %i: %i mightsee\n", portalnum, p->nummightsee);
714         c_flood += p->nummightsee;
715 }
716
717
718
719
720
721 /*
722    ===============================================================================
723
724    This is a second order aproximation
725
726    Calculates portalvis bit vector
727
728    WAAAAAAY too slow.
729
730    ===============================================================================
731  */
732
733 /*
734    ==================
735    RecursiveLeafBitFlow
736
737    ==================
738  */
739 void RecursiveLeafBitFlow( int leafnum, byte *mightsee, byte *cansee ){
740         portal_t    *p;
741         leaf_t      *leaf;
742         int i, j;
743         long more;
744         int pnum;
745         byte newmight[MAX_PORTALS / 8];
746
747         leaf = &leafs[leafnum];
748
749 // check all portals for flowing into other leafs
750         for ( i = 0 ; i < leaf->numportals ; i++ )
751         {
752                 p = leaf->portals[i];
753                 pnum = p - portals;
754
755                 // if some previous portal can't see it, skip
756                 if ( !( mightsee[pnum >> 3] & ( 1 << ( pnum & 7 ) ) ) ) {
757                         continue;
758                 }
759
760                 // if this portal can see some portals we mightsee, recurse
761                 more = 0;
762                 for ( j = 0 ; j < portallongs ; j++ )
763                 {
764                         ( (long *)newmight )[j] = ( (long *)mightsee )[j]
765                                                                           & ( (long *)p->portalflood )[j];
766                         more |= ( (long *)newmight )[j] & ~( (long *)cansee )[j];
767                 }
768
769                 if ( !more ) {
770                         continue;   // can't see anything new
771
772                 }
773                 cansee[pnum >> 3] |= ( 1 << ( pnum & 7 ) );
774
775                 RecursiveLeafBitFlow( p->leaf, newmight, cansee );
776         }
777 }
778
779 /*
780    ==============
781    BetterPortalVis
782    ==============
783  */
784 void BetterPortalVis( int portalnum ){
785         portal_t    *p;
786
787         p = portals + portalnum;
788
789         RecursiveLeafBitFlow( p->leaf, p->portalflood, p->portalvis );
790
791         // build leaf vis information
792         p->nummightsee = CountBits( p->portalvis, numportals * 2 );
793         c_vis += p->nummightsee;
794 }