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

visflow.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 #include "vis.h"
00023 
00024 /*
00025 
00026   each portal will have a list of all possible to see from first portal
00027 
00028   if (!thread->portalmightsee[portalnum])
00029 
00030   portal mightsee
00031 
00032   for p2 = all other portals in leaf
00033     get sperating planes
00034     for all portals that might be seen by p2
00035         mark as unseen if not present in seperating plane
00036     flood fill a new mightsee
00037     save as passagemightsee
00038 
00039 
00040   void CalcMightSee (leaf_t *leaf, 
00041 */
00042 
00043 int CountBits (byte *bits, int numbits)
00044 {
00045     int     i;
00046     int     c;
00047 
00048     c = 0;
00049     for (i=0 ; i<numbits ; i++)
00050         if (bits[i>>3] & (1<<(i&7)) )
00051             c++;
00052 
00053     return c;
00054 }
00055 
00056 int     c_fullskip;
00057 int     c_portalskip, c_leafskip;
00058 int     c_vistest, c_mighttest;
00059 
00060 int     c_chop, c_nochop;
00061 
00062 int     active;
00063 
00064 void CheckStack (leaf_t *leaf, threaddata_t *thread)
00065 {
00066     pstack_t    *p, *p2;
00067 
00068     for (p=thread->pstack_head.next ; p ; p=p->next)
00069     {
00070 //      _printf ("=");
00071         if (p->leaf == leaf)
00072             Error ("CheckStack: leaf recursion");
00073         for (p2=thread->pstack_head.next ; p2 != p ; p2=p2->next)
00074             if (p2->leaf == p->leaf)
00075                 Error ("CheckStack: late leaf recursion");
00076     }
00077 //  _printf ("\n");
00078 }
00079 
00080 
00081 winding_t *AllocStackWinding (pstack_t *stack)
00082 {
00083     int     i;
00084 
00085     for (i=0 ; i<3 ; i++)
00086     {
00087         if (stack->freewindings[i])
00088         {
00089             stack->freewindings[i] = 0;
00090             return &stack->windings[i];
00091         }
00092     }
00093 
00094     Error ("AllocStackWinding: failed");
00095 
00096     return NULL;
00097 }
00098 
00099 void FreeStackWinding (winding_t *w, pstack_t *stack)
00100 {
00101     int     i;
00102 
00103     i = w - stack->windings;
00104 
00105     if (i<0 || i>2)
00106         return;     // not from local
00107 
00108     if (stack->freewindings[i])
00109         Error ("FreeStackWinding: allready free");
00110     stack->freewindings[i] = 1;
00111 }
00112 
00113 /*
00114 ==============
00115 VisChopWinding
00116 
00117 ==============
00118 */
00119 winding_t   *VisChopWinding (winding_t *in, pstack_t *stack, plane_t *split)
00120 {
00121     vec_t   dists[128];
00122     int     sides[128];
00123     int     counts[3];
00124     vec_t   dot;
00125     int     i, j;
00126     vec_t   *p1, *p2;
00127     vec3_t  mid;
00128     winding_t   *neww;
00129 
00130     counts[0] = counts[1] = counts[2] = 0;
00131 
00132     // determine sides for each point
00133     for (i=0 ; i<in->numpoints ; i++)
00134     {
00135         dot = DotProduct (in->points[i], split->normal);
00136         dot -= split->dist;
00137         dists[i] = dot;
00138         if (dot > ON_EPSILON)
00139             sides[i] = SIDE_FRONT;
00140         else if (dot < -ON_EPSILON)
00141             sides[i] = SIDE_BACK;
00142         else
00143         {
00144             sides[i] = SIDE_ON;
00145         }
00146         counts[sides[i]]++;
00147     }
00148 
00149     if (!counts[1])
00150         return in;      // completely on front side
00151     
00152     if (!counts[0])
00153     {
00154         FreeStackWinding (in, stack);
00155         return NULL;
00156     }
00157 
00158     sides[i] = sides[0];
00159     dists[i] = dists[0];
00160     
00161     neww = AllocStackWinding (stack);
00162 
00163     neww->numpoints = 0;
00164 
00165     for (i=0 ; i<in->numpoints ; i++)
00166     {
00167         p1 = in->points[i];
00168 
00169         if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING)
00170         {
00171             FreeStackWinding (neww, stack);
00172             return in;      // can't chop -- fall back to original
00173         }
00174 
00175         if (sides[i] == SIDE_ON)
00176         {
00177             VectorCopy (p1, neww->points[neww->numpoints]);
00178             neww->numpoints++;
00179             continue;
00180         }
00181     
00182         if (sides[i] == SIDE_FRONT)
00183         {
00184             VectorCopy (p1, neww->points[neww->numpoints]);
00185             neww->numpoints++;
00186         }
00187         
00188         if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
00189             continue;
00190             
00191         if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING)
00192         {
00193             FreeStackWinding (neww, stack);
00194             return in;      // can't chop -- fall back to original
00195         }
00196 
00197         // generate a split point
00198         p2 = in->points[(i+1)%in->numpoints];
00199         
00200         dot = dists[i] / (dists[i]-dists[i+1]);
00201         for (j=0 ; j<3 ; j++)
00202         {   // avoid round off error when possible
00203             if (split->normal[j] == 1)
00204                 mid[j] = split->dist;
00205             else if (split->normal[j] == -1)
00206                 mid[j] = -split->dist;
00207             else
00208                 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
00209         }
00210             
00211         VectorCopy (mid, neww->points[neww->numpoints]);
00212         neww->numpoints++;
00213     }
00214     
00215     // free the original winding
00216     FreeStackWinding (in, stack);
00217     
00218     return neww;
00219 }
00220 
00221 /*
00222 ==============
00223 ClipToSeperators
00224 
00225 Source, pass, and target are an ordering of portals.
00226 
00227 Generates seperating planes canidates by taking two points from source and one
00228 point from pass, and clips target by them.
00229 
00230 If target is totally clipped away, that portal can not be seen through.
00231 
00232 Normal clip keeps target on the same side as pass, which is correct if the
00233 order goes source, pass, target.  If the order goes pass, source, target then
00234 flipclip should be set.
00235 ==============
00236 */
00237 winding_t   *ClipToSeperators (winding_t *source, winding_t *pass, winding_t *target, qboolean flipclip, pstack_t *stack)
00238 {
00239     int         i, j, k, l;
00240     plane_t     plane;
00241     vec3_t      v1, v2;
00242     float       d;
00243     vec_t       length;
00244     int         counts[3];
00245     qboolean        fliptest;
00246 
00247     // check all combinations   
00248     for (i=0 ; i<source->numpoints ; i++)
00249     {
00250         l = (i+1)%source->numpoints;
00251         VectorSubtract (source->points[l] , source->points[i], v1);
00252 
00253         // find a vertex of pass that makes a plane that puts all of the
00254         // vertexes of pass on the front side and all of the vertexes of
00255         // source on the back side
00256         for (j=0 ; j<pass->numpoints ; j++)
00257         {
00258             VectorSubtract (pass->points[j], source->points[i], v2);
00259 
00260             plane.normal[0] = v1[1]*v2[2] - v1[2]*v2[1];
00261             plane.normal[1] = v1[2]*v2[0] - v1[0]*v2[2];
00262             plane.normal[2] = v1[0]*v2[1] - v1[1]*v2[0];
00263             
00264             // if points don't make a valid plane, skip it
00265 
00266             length = plane.normal[0] * plane.normal[0]
00267             + plane.normal[1] * plane.normal[1]
00268             + plane.normal[2] * plane.normal[2];
00269             
00270             if (length < ON_EPSILON)
00271                 continue;
00272 
00273             length = 1/sqrt(length);
00274             
00275             plane.normal[0] *= length;
00276             plane.normal[1] *= length;
00277             plane.normal[2] *= length;
00278 
00279             plane.dist = DotProduct (pass->points[j], plane.normal);
00280 
00281             //
00282             // find out which side of the generated seperating plane has the
00283             // source portal
00284             //
00285 #if 1
00286             fliptest = qfalse;
00287             for (k=0 ; k<source->numpoints ; k++)
00288             {
00289                 if (k == i || k == l)
00290                     continue;
00291                 d = DotProduct (source->points[k], plane.normal) - plane.dist;
00292                 if (d < -ON_EPSILON)
00293                 {   // source is on the negative side, so we want all
00294                     // pass and target on the positive side
00295                     fliptest = qfalse;
00296                     break;
00297                 }
00298                 else if (d > ON_EPSILON)
00299                 {   // source is on the positive side, so we want all
00300                     // pass and target on the negative side
00301                     fliptest = qtrue;
00302                     break;
00303                 }
00304             }
00305             if (k == source->numpoints)
00306                 continue;       // planar with source portal
00307 #else
00308             fliptest = flipclip;
00309 #endif
00310             //
00311             // flip the normal if the source portal is backwards
00312             //
00313             if (fliptest)
00314             {
00315                 VectorSubtract (vec3_origin, plane.normal, plane.normal);
00316                 plane.dist = -plane.dist;
00317             }
00318 #if 1
00319             //
00320             // if all of the pass portal points are now on the positive side,
00321             // this is the seperating plane
00322             //
00323             counts[0] = counts[1] = counts[2] = 0;
00324             for (k=0 ; k<pass->numpoints ; k++)
00325             {
00326                 if (k==j)
00327                     continue;
00328                 d = DotProduct (pass->points[k], plane.normal) - plane.dist;
00329                 if (d < -ON_EPSILON)
00330                     break;
00331                 else if (d > ON_EPSILON)
00332                     counts[0]++;
00333                 else
00334                     counts[2]++;
00335             }
00336             if (k != pass->numpoints)
00337                 continue;   // points on negative side, not a seperating plane
00338                 
00339             if (!counts[0])
00340                 continue;   // planar with seperating plane
00341 #else
00342             k = (j+1)%pass->numpoints;
00343             d = DotProduct (pass->points[k], plane.normal) - plane.dist;
00344             if (d < -ON_EPSILON)
00345                 continue;
00346             k = (j+pass->numpoints-1)%pass->numpoints;
00347             d = DotProduct (pass->points[k], plane.normal) - plane.dist;
00348             if (d < -ON_EPSILON)
00349                 continue;           
00350 #endif
00351             //
00352             // flip the normal if we want the back side
00353             //
00354             if (flipclip)
00355             {
00356                 VectorSubtract (vec3_origin, plane.normal, plane.normal);
00357                 plane.dist = -plane.dist;
00358             }
00359 
00360 #ifdef SEPERATORCACHE
00361             stack->seperators[flipclip][stack->numseperators[flipclip]] = plane;
00362             if (++stack->numseperators[flipclip] >= MAX_SEPERATORS)
00363                 Error("MAX_SEPERATORS");
00364 #endif
00365             //MrE: fast check first
00366             d = DotProduct (stack->portal->origin, plane.normal) - plane.dist;
00367             //if completely at the back of the seperator plane
00368             if (d < -stack->portal->radius)
00369                 return NULL;
00370             //if completely on the front of the seperator plane
00371             if (d > stack->portal->radius)
00372                 break;
00373 
00374             //
00375             // clip target by the seperating plane
00376             //
00377             target = VisChopWinding (target, stack, &plane);
00378             if (!target)
00379                 return NULL;        // target is not visible
00380 
00381             break;      // optimization by Antony Suter
00382         }
00383     }
00384     
00385     return target;
00386 }
00387 
00388 /*
00389 ==================
00390 RecursiveLeafFlow
00391 
00392 Flood fill through the leafs
00393 If src_portal is NULL, this is the originating leaf
00394 ==================
00395 */
00396 void RecursiveLeafFlow (int leafnum, threaddata_t *thread, pstack_t *prevstack)
00397 {
00398     pstack_t    stack;
00399     vportal_t   *p;
00400     plane_t     backplane;
00401     leaf_t      *leaf;
00402     int         i, j, n;
00403     long        *test, *might, *prevmight, *vis, more;
00404     int         pnum;
00405 
00406     thread->c_chains++;
00407 
00408     leaf = &leafs[leafnum];
00409 //  CheckStack (leaf, thread);
00410 
00411     prevstack->next = &stack;
00412 
00413     stack.next = NULL;
00414     stack.leaf = leaf;
00415     stack.portal = NULL;
00416     stack.depth = prevstack->depth + 1;
00417 
00418 #ifdef SEPERATORCACHE
00419     stack.numseperators[0] = 0;
00420     stack.numseperators[1] = 0;
00421 #endif
00422 
00423     might = (long *)stack.mightsee;
00424     vis = (long *)thread->base->portalvis;
00425     
00426     // check all portals for flowing into other leafs   
00427     for (i = 0; i < leaf->numportals; i++)
00428     {
00429         p = leaf->portals[i];
00430         if (p->removed)
00431             continue;
00432         pnum = p - portals;
00433 
00434         /* MrE: portal trace debug code
00435         {
00436             int portaltrace[] = {13, 16, 17, 37};
00437             pstack_t *s;
00438 
00439             s = &thread->pstack_head;
00440             for (j = 0; s->next && j < sizeof(portaltrace)/sizeof(int) - 1; j++, s = s->next)
00441             {
00442                 if (s->portal->num != portaltrace[j])
00443                     break;
00444             }
00445             if (j >= sizeof(portaltrace)/sizeof(int) - 1)
00446             {
00447                 if (p->num == portaltrace[j])
00448                     n = 0; //traced through all the portals
00449             }
00450         }
00451         */
00452 
00453         if ( ! (prevstack->mightsee[pnum >> 3] & (1<<(pnum&7)) ) )
00454         {
00455             continue;   // can't possibly see it
00456         }
00457 
00458         // if the portal can't see anything we haven't allready seen, skip it
00459         if (p->status == stat_done)
00460         {
00461             test = (long *)p->portalvis;
00462         }
00463         else
00464         {
00465             test = (long *)p->portalflood;
00466         }
00467 
00468         more = 0;
00469         prevmight = (long *)prevstack->mightsee;
00470         for (j=0 ; j<portallongs ; j++)
00471         {
00472             might[j] = prevmight[j] & test[j];
00473             more |= (might[j] & ~vis[j]);
00474         }
00475         
00476         if (!more && 
00477             (thread->base->portalvis[pnum>>3] & (1<<(pnum&7))) )
00478         {   // can't see anything new
00479             continue;
00480         }
00481 
00482         // get plane of portal, point normal into the neighbor leaf
00483         stack.portalplane = p->plane;
00484         VectorSubtract (vec3_origin, p->plane.normal, backplane.normal);
00485         backplane.dist = -p->plane.dist;
00486         
00487 //      c_portalcheck++;
00488         
00489         stack.portal = p;
00490         stack.next = NULL;
00491         stack.freewindings[0] = 1;
00492         stack.freewindings[1] = 1;
00493         stack.freewindings[2] = 1;
00494         
00495 #if 1
00496         {
00497             float d;
00498 
00499             d = DotProduct (p->origin, thread->pstack_head.portalplane.normal);
00500             d -= thread->pstack_head.portalplane.dist;
00501             if (d < -p->radius)
00502             {
00503                 continue;
00504             }
00505             else if (d > p->radius)
00506             {
00507                 stack.pass = p->winding;
00508             }
00509             else    
00510             {
00511                 stack.pass = VisChopWinding (p->winding, &stack, &thread->pstack_head.portalplane);
00512                 if (!stack.pass)
00513                     continue;
00514             }
00515         }
00516 #else
00517         stack.pass = VisChopWinding (p->winding, &stack, &thread->pstack_head.portalplane);
00518         if (!stack.pass)
00519             continue;
00520 #endif
00521 
00522     
00523 #if 1
00524         {
00525             float d;
00526 
00527             d = DotProduct (thread->base->origin, p->plane.normal);
00528             d -= p->plane.dist;
00529             //MrE: vis-bug fix
00530             //if (d > p->radius)
00531             if (d > thread->base->radius)
00532             {
00533                 continue;
00534             }
00535             //MrE: vis-bug fix
00536             //if (d < -p->radius)
00537             else if (d < -thread->base->radius)
00538             {
00539                 stack.source = prevstack->source;
00540             }
00541             else    
00542             {
00543                 stack.source = VisChopWinding (prevstack->source, &stack, &backplane);
00544                 //FIXME: shouldn't we create a new source origin and radius for fast checks?
00545                 if (!stack.source)
00546                     continue;
00547             }
00548         }
00549 #else
00550         stack.source = VisChopWinding (prevstack->source, &stack, &backplane);
00551         if (!stack.source)
00552             continue;
00553 #endif
00554 
00555         if (!prevstack->pass)
00556         {   // the second leaf can only be blocked if coplanar
00557 
00558             // mark the portal as visible
00559             thread->base->portalvis[pnum>>3] |= (1<<(pnum&7));
00560 
00561             RecursiveLeafFlow (p->leaf, thread, &stack);
00562             continue;
00563         }
00564 
00565 #ifdef SEPERATORCACHE
00566         if (stack.numseperators[0])
00567         {
00568             for (n = 0; n < stack.numseperators[0]; n++)
00569             {
00570                 stack.pass = VisChopWinding (stack.pass, &stack, &stack.seperators[0][n]);
00571                 if (!stack.pass)
00572                     break;      // target is not visible
00573             }
00574             if (n < stack.numseperators[0])
00575                 continue;
00576         }
00577         else
00578         {
00579             stack.pass = ClipToSeperators (prevstack->source, prevstack->pass, stack.pass, qfalse, &stack);
00580         }
00581 #else
00582         stack.pass = ClipToSeperators (stack.source, prevstack->pass, stack.pass, qfalse, &stack);
00583 #endif
00584         if (!stack.pass)
00585             continue;
00586 
00587 #ifdef SEPERATORCACHE
00588         if (stack.numseperators[1])
00589         {
00590             for (n = 0; n < stack.numseperators[1]; n++)
00591             {
00592                 stack.pass = VisChopWinding (stack.pass, &stack, &stack.seperators[1][n]);
00593                 if (!stack.pass)
00594                     break;      // target is not visible
00595             }
00596         }
00597         else
00598         {
00599             stack.pass = ClipToSeperators (prevstack->pass, prevstack->source, stack.pass, qtrue, &stack);
00600         }
00601 #else
00602         stack.pass = ClipToSeperators (prevstack->pass, stack.source, stack.pass, qtrue, &stack);
00603 #endif
00604         if (!stack.pass)
00605             continue;
00606 
00607         // mark the portal as visible
00608         thread->base->portalvis[pnum>>3] |= (1<<(pnum&7));
00609 
00610         // flow through it for real
00611         RecursiveLeafFlow (p->leaf, thread, &stack);
00612         //
00613         stack.next = NULL;
00614     }   
00615 }
00616 
00617 /*
00618 ===============
00619 PortalFlow
00620 
00621 generates the portalvis bit vector
00622 ===============
00623 */
00624 void PortalFlow (int portalnum)
00625 {
00626     threaddata_t    data;
00627     int             i;
00628     vportal_t       *p;
00629     int             c_might, c_can;
00630 
00631 #ifdef MREDEBUG
00632     _printf("\r%6d", portalnum);
00633 #endif
00634 
00635     p = sorted_portals[portalnum];
00636 
00637     if (p->removed)
00638     {
00639         p->status = stat_done;
00640         return;
00641     }
00642 
00643     p->status = stat_working;
00644 
00645     c_might = CountBits (p->portalflood, numportals*2);
00646 
00647     memset (&data, 0, sizeof(data));
00648     data.base = p;
00649     
00650     data.pstack_head.portal = p;
00651     data.pstack_head.source = p->winding;
00652     data.pstack_head.portalplane = p->plane;
00653     data.pstack_head.depth = 0;
00654     for (i=0 ; i<portallongs ; i++)
00655         ((long *)data.pstack_head.mightsee)[i] = ((long *)p->portalflood)[i];
00656 
00657     RecursiveLeafFlow (p->leaf, &data, &data.pstack_head);
00658 
00659     p->status = stat_done;
00660 
00661     c_can = CountBits (p->portalvis, numportals*2);
00662 
00663     qprintf ("portal:%4i  mightsee:%4i  cansee:%4i (%i chains)\n", 
00664         (int)(p - portals), c_might, c_can, data.c_chains);
00665 }
00666 
00667 /*
00668 ==================
00669 RecursivePassageFlow
00670 ==================
00671 */
00672 void RecursivePassageFlow (vportal_t *portal, threaddata_t *thread, pstack_t *prevstack)
00673 {
00674     pstack_t    stack;
00675     vportal_t   *p;
00676     leaf_t      *leaf;
00677     passage_t   *passage, *nextpassage;
00678     int         i, j;
00679     long        *might, *vis, *prevmight, *cansee, *portalvis, more;
00680     int         pnum;
00681 
00682     leaf = &leafs[portal->leaf];
00683 
00684     prevstack->next = &stack;
00685 
00686     stack.next = NULL;
00687     stack.depth = prevstack->depth + 1;
00688 
00689     vis = (long *)thread->base->portalvis;
00690 
00691     passage = portal->passages;
00692     nextpassage = passage;
00693     // check all portals for flowing into other leafs   
00694     for (i = 0; i < leaf->numportals; i++, passage = nextpassage)
00695     {
00696         p = leaf->portals[i];
00697         if ( p->removed ) {
00698             continue;
00699         }
00700         nextpassage = passage->next;
00701         pnum = p - portals;
00702 
00703         if ( ! (prevstack->mightsee[pnum >> 3] & (1<<(pnum&7)) ) ) {
00704             continue;   // can't possibly see it
00705         }
00706 
00707         // mark the portal as visible
00708         thread->base->portalvis[pnum>>3] |= (1<<(pnum&7));
00709 
00710         prevmight = (long *)prevstack->mightsee;
00711         cansee = (long *)passage->cansee;
00712         might = (long *)stack.mightsee;
00713         memcpy(might, prevmight, portalbytes);
00714         if (p->status == stat_done)
00715             portalvis = (long *) p->portalvis;
00716         else
00717             portalvis = (long *) p->portalflood;
00718         more = 0;
00719         for (j = 0; j < portallongs; j++)
00720         {
00721             if (*might)
00722             {
00723                 *might &= *cansee++ & *portalvis++;
00724                 more |= (*might & ~vis[j]);
00725             }
00726             else
00727             {
00728                 cansee++;
00729                 portalvis++;
00730             }
00731             might++;
00732         }
00733 
00734         if ( !more ) {
00735             // can't see anything new
00736             continue;
00737         }
00738 
00739         // flow through it for real
00740         RecursivePassageFlow(p, thread, &stack);
00741 
00742         stack.next = NULL;
00743     }
00744 }
00745 
00746 /*
00747 ===============
00748 PassageFlow
00749 ===============
00750 */
00751 void PassageFlow (int portalnum)
00752 {
00753     threaddata_t    data;
00754     int             i;
00755     vportal_t       *p;
00756 //  int             c_might, c_can;
00757 
00758 #ifdef MREDEBUG
00759     _printf("\r%6d", portalnum);
00760 #endif
00761 
00762     p = sorted_portals[portalnum];
00763 
00764     if (p->removed)
00765     {
00766         p->status = stat_done;
00767         return;
00768     }
00769 
00770     p->status = stat_working;
00771 
00772 //  c_might = CountBits (p->portalflood, numportals*2);
00773 
00774     memset (&data, 0, sizeof(data));
00775     data.base = p;
00776     
00777     data.pstack_head.portal = p;
00778     data.pstack_head.source = p->winding;
00779     data.pstack_head.portalplane = p->plane;
00780     data.pstack_head.depth = 0;
00781     for (i=0 ; i<portallongs ; i++)
00782         ((long *)data.pstack_head.mightsee)[i] = ((long *)p->portalflood)[i];
00783 
00784     RecursivePassageFlow (p, &data, &data.pstack_head);
00785 
00786     p->status = stat_done;
00787 
00788     /*
00789     c_can = CountBits (p->portalvis, numportals*2);
00790 
00791     qprintf ("portal:%4i  mightsee:%4i  cansee:%4i (%i chains)\n", 
00792         (int)(p - portals), c_might, c_can, data.c_chains);
00793     */
00794 }
00795 
00796 /*
00797 ==================
00798 RecursivePassagePortalFlow
00799 ==================
00800 */
00801 void RecursivePassagePortalFlow (vportal_t *portal, threaddata_t *thread, pstack_t *prevstack)
00802 {
00803     pstack_t    stack;
00804     vportal_t   *p;
00805     leaf_t      *leaf;
00806     plane_t     backplane;
00807     passage_t   *passage, *nextpassage;
00808     int         i, j, n;
00809     long        *might, *vis, *prevmight, *cansee, *portalvis, more;
00810     int         pnum;
00811 
00812 //  thread->c_chains++;
00813 
00814     leaf = &leafs[portal->leaf];
00815 //  CheckStack (leaf, thread);
00816 
00817     prevstack->next = &stack;
00818 
00819     stack.next = NULL;
00820     stack.leaf = leaf;
00821     stack.portal = NULL;
00822     stack.depth = prevstack->depth + 1;
00823 
00824 #ifdef SEPERATORCACHE
00825     stack.numseperators[0] = 0;
00826     stack.numseperators[1] = 0;
00827 #endif
00828 
00829     vis = (long *)thread->base->portalvis;
00830 
00831     passage = portal->passages;
00832     nextpassage = passage;
00833     // check all portals for flowing into other leafs   
00834     for (i = 0; i < leaf->numportals; i++, passage = nextpassage)
00835     {
00836         p = leaf->portals[i];
00837         if (p->removed)
00838             continue;
00839         nextpassage = passage->next;
00840         pnum = p - portals;
00841 
00842         if ( ! (prevstack->mightsee[pnum >> 3] & (1<<(pnum&7)) ) )
00843             continue;   // can't possibly see it
00844 
00845         prevmight = (long *)prevstack->mightsee;
00846         cansee = (long *)passage->cansee;
00847         might = (long *)stack.mightsee;
00848         memcpy(might, prevmight, portalbytes);
00849         if (p->status == stat_done)
00850             portalvis = (long *) p->portalvis;
00851         else
00852             portalvis = (long *) p->portalflood;
00853         more = 0;
00854         for (j = 0; j < portallongs; j++)
00855         {
00856             if (*might)
00857             {
00858                 *might &= *cansee++ & *portalvis++;
00859                 more |= (*might & ~vis[j]);
00860             }
00861             else
00862             {
00863                 cansee++;
00864                 portalvis++;
00865             }
00866             might++;
00867         }
00868 
00869         if (!more && (thread->base->portalvis[pnum>>3] & (1<<(pnum&7))) )
00870         {   // can't see anything new
00871             continue;
00872         }
00873 
00874         // get plane of portal, point normal into the neighbor leaf
00875         stack.portalplane = p->plane;
00876         VectorSubtract (vec3_origin, p->plane.normal, backplane.normal);
00877         backplane.dist = -p->plane.dist;
00878         
00879 //      c_portalcheck++;
00880         
00881         stack.portal = p;
00882         stack.next = NULL;
00883         stack.freewindings[0] = 1;
00884         stack.freewindings[1] = 1;
00885         stack.freewindings[2] = 1;
00886 
00887 #if 1
00888         {
00889             float d;
00890 
00891             d = DotProduct (p->origin, thread->pstack_head.portalplane.normal);
00892             d -= thread->pstack_head.portalplane.dist;
00893             if (d < -p->radius)
00894             {
00895                 continue;
00896             }
00897             else if (d > p->radius)
00898             {
00899                 stack.pass = p->winding;
00900             }
00901             else    
00902             {
00903                 stack.pass = VisChopWinding (p->winding, &stack, &thread->pstack_head.portalplane);
00904                 if (!stack.pass)
00905                     continue;
00906             }
00907         }
00908 #else
00909         stack.pass = VisChopWinding (p->winding, &stack, &thread->pstack_head.portalplane);
00910         if (!stack.pass)
00911             continue;
00912 #endif
00913 
00914     
00915 #if 1
00916         {
00917             float d;
00918 
00919             d = DotProduct (thread->base->origin, p->plane.normal);
00920             d -= p->plane.dist;
00921             //MrE: vis-bug fix
00922             //if (d > p->radius)
00923             if (d > thread->base->radius)
00924             {
00925                 continue;
00926             }
00927             //MrE: vis-bug fix
00928             //if (d < -p->radius)
00929             else if (d < -thread->base->radius)
00930             {
00931                 stack.source = prevstack->source;
00932             }
00933             else    
00934             {
00935                 stack.source = VisChopWinding (prevstack->source, &stack, &backplane);
00936                 //FIXME: shouldn't we create a new source origin and radius for fast checks?
00937                 if (!stack.source)
00938                     continue;
00939             }
00940         }
00941 #else
00942         stack.source = VisChopWinding (prevstack->source, &stack, &backplane);
00943         if (!stack.source)
00944             continue;
00945 #endif
00946 
00947         if (!prevstack->pass)
00948         {   // the second leaf can only be blocked if coplanar
00949 
00950             // mark the portal as visible
00951             thread->base->portalvis[pnum>>3] |= (1<<(pnum&7));
00952 
00953             RecursivePassagePortalFlow (p, thread, &stack);
00954             continue;
00955         }
00956 
00957 #ifdef SEPERATORCACHE
00958         if (stack.numseperators[0])
00959         {
00960             for (n = 0; n < stack.numseperators[0]; n++)
00961             {
00962                 stack.pass = VisChopWinding (stack.pass, &stack, &stack.seperators[0][n]);
00963                 if (!stack.pass)
00964                     break;      // target is not visible
00965             }
00966             if (n < stack.numseperators[0])
00967                 continue;
00968         }
00969         else
00970         {
00971             stack.pass = ClipToSeperators (prevstack->source, prevstack->pass, stack.pass, qfalse, &stack);
00972         }
00973 #else
00974         stack.pass = ClipToSeperators (stack.source, prevstack->pass, stack.pass, qfalse, &stack);
00975 #endif
00976         if (!stack.pass)
00977             continue;
00978 
00979 #ifdef SEPERATORCACHE
00980         if (stack.numseperators[1])
00981         {
00982             for (n = 0; n < stack.numseperators[1]; n++)
00983             {
00984                 stack.pass = VisChopWinding (stack.pass, &stack, &stack.seperators[1][n]);
00985                 if (!stack.pass)
00986                     break;      // target is not visible
00987             }
00988         }
00989         else
00990         {
00991             stack.pass = ClipToSeperators (prevstack->pass, prevstack->source, stack.pass, qtrue, &stack);
00992         }
00993 #else
00994         stack.pass = ClipToSeperators (prevstack->pass, stack.source, stack.pass, qtrue, &stack);
00995 #endif
00996         if (!stack.pass)
00997             continue;
00998 
00999         // mark the portal as visible
01000         thread->base->portalvis[pnum>>3] |= (1<<(pnum&7));
01001 
01002         // flow through it for real
01003         RecursivePassagePortalFlow(p, thread, &stack);
01004         //
01005         stack.next = NULL;
01006     }
01007 }
01008 
01009 /*
01010 ===============
01011 PassagePortalFlow
01012 ===============
01013 */
01014 void PassagePortalFlow (int portalnum)
01015 {
01016     threaddata_t    data;
01017     int             i;
01018     vportal_t       *p;
01019 //  int             c_might, c_can;
01020 
01021 #ifdef MREDEBUG
01022     _printf("\r%6d", portalnum);
01023 #endif
01024 
01025     p = sorted_portals[portalnum];
01026 
01027     if (p->removed)
01028     {
01029         p->status = stat_done;
01030         return;
01031     }
01032 
01033     p->status = stat_working;
01034 
01035 //  c_might = CountBits (p->portalflood, numportals*2);
01036 
01037     memset (&data, 0, sizeof(data));
01038     data.base = p;
01039     
01040     data.pstack_head.portal = p;
01041     data.pstack_head.source = p->winding;
01042     data.pstack_head.portalplane = p->plane;
01043     data.pstack_head.depth = 0;
01044     for (i=0 ; i<portallongs ; i++)
01045         ((long *)data.pstack_head.mightsee)[i] = ((long *)p->portalflood)[i];
01046 
01047     RecursivePassagePortalFlow (p, &data, &data.pstack_head);
01048 
01049     p->status = stat_done;
01050 
01051     /*
01052     c_can = CountBits (p->portalvis, numportals*2);
01053 
01054     qprintf ("portal:%4i  mightsee:%4i  cansee:%4i (%i chains)\n", 
01055         (int)(p - portals), c_might, c_can, data.c_chains);
01056     */
01057 }
01058 
01059 winding_t *PassageChopWinding (winding_t *in, winding_t *out, plane_t *split)
01060 {
01061     vec_t   dists[128];
01062     int     sides[128];
01063     int     counts[3];
01064     vec_t   dot;
01065     int     i, j;
01066     vec_t   *p1, *p2;
01067     vec3_t  mid;
01068     winding_t   *neww;
01069 
01070     counts[0] = counts[1] = counts[2] = 0;
01071 
01072     // determine sides for each point
01073     for (i=0 ; i<in->numpoints ; i++)
01074     {
01075         dot = DotProduct (in->points[i], split->normal);
01076         dot -= split->dist;
01077         dists[i] = dot;
01078         if (dot > ON_EPSILON)
01079             sides[i] = SIDE_FRONT;
01080         else if (dot < -ON_EPSILON)
01081             sides[i] = SIDE_BACK;
01082         else
01083         {
01084             sides[i] = SIDE_ON;
01085         }
01086         counts[sides[i]]++;
01087     }
01088 
01089     if (!counts[1])
01090         return in;      // completely on front side
01091     
01092     if (!counts[0])
01093     {
01094         return NULL;
01095     }
01096 
01097     sides[i] = sides[0];
01098     dists[i] = dists[0];
01099     
01100     neww = out;
01101 
01102     neww->numpoints = 0;
01103 
01104     for (i=0 ; i<in->numpoints ; i++)
01105     {
01106         p1 = in->points[i];
01107 
01108         if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING)
01109         {
01110             return in;      // can't chop -- fall back to original
01111         }
01112 
01113         if (sides[i] == SIDE_ON)
01114         {
01115             VectorCopy (p1, neww->points[neww->numpoints]);
01116             neww->numpoints++;
01117             continue;
01118         }
01119     
01120         if (sides[i] == SIDE_FRONT)
01121         {
01122             VectorCopy (p1, neww->points[neww->numpoints]);
01123             neww->numpoints++;
01124         }
01125         
01126         if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
01127             continue;
01128             
01129         if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING)
01130         {
01131             return in;      // can't chop -- fall back to original
01132         }
01133 
01134         // generate a split point
01135         p2 = in->points[(i+1)%in->numpoints];
01136         
01137         dot = dists[i] / (dists[i]-dists[i+1]);
01138         for (j=0 ; j<3 ; j++)
01139         {   // avoid round off error when possible
01140             if (split->normal[j] == 1)
01141                 mid[j] = split->dist;
01142             else if (split->normal[j] == -1)
01143                 mid[j] = -split->dist;
01144             else
01145                 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
01146         }
01147             
01148         VectorCopy (mid, neww->points[neww->numpoints]);
01149         neww->numpoints++;
01150     }
01151     
01152     return neww;
01153 }
01154 
01155 /*
01156 ===============
01157 AddSeperators
01158 ===============
01159 */
01160 int AddSeperators (winding_t *source, winding_t *pass, qboolean flipclip, plane_t *seperators, int maxseperators)
01161 {
01162     int         i, j, k, l;
01163     plane_t     plane;
01164     vec3_t      v1, v2;
01165     float       d;
01166     vec_t       length;
01167     int         counts[3], numseperators;
01168     qboolean    fliptest;
01169 
01170     numseperators = 0;
01171     // check all combinations   
01172     for (i=0 ; i<source->numpoints ; i++)
01173     {
01174         l = (i+1)%source->numpoints;
01175         VectorSubtract (source->points[l] , source->points[i], v1);
01176 
01177         // find a vertex of pass that makes a plane that puts all of the
01178         // vertexes of pass on the front side and all of the vertexes of
01179         // source on the back side
01180         for (j=0 ; j<pass->numpoints ; j++)
01181         {
01182             VectorSubtract (pass->points[j], source->points[i], v2);
01183 
01184             plane.normal[0] = v1[1]*v2[2] - v1[2]*v2[1];
01185             plane.normal[1] = v1[2]*v2[0] - v1[0]*v2[2];
01186             plane.normal[2] = v1[0]*v2[1] - v1[1]*v2[0];
01187             
01188             // if points don't make a valid plane, skip it
01189 
01190             length = plane.normal[0] * plane.normal[0]
01191             + plane.normal[1] * plane.normal[1]
01192             + plane.normal[2] * plane.normal[2];
01193             
01194             if (length < ON_EPSILON)
01195                 continue;
01196 
01197             length = 1/sqrt(length);
01198             
01199             plane.normal[0] *= length;
01200             plane.normal[1] *= length;
01201             plane.normal[2] *= length;
01202 
01203             plane.dist = DotProduct (pass->points[j], plane.normal);
01204 
01205             //
01206             // find out which side of the generated seperating plane has the
01207             // source portal
01208             //
01209 #if 1
01210             fliptest = qfalse;
01211             for (k=0 ; k<source->numpoints ; k++)
01212             {
01213                 if (k == i || k == l)
01214                     continue;
01215                 d = DotProduct (source->points[k], plane.normal) - plane.dist;
01216                 if (d < -ON_EPSILON)
01217                 {   // source is on the negative side, so we want all
01218                     // pass and target on the positive side
01219                     fliptest = qfalse;
01220                     break;
01221                 }
01222                 else if (d > ON_EPSILON)
01223                 {   // source is on the positive side, so we want all
01224                     // pass and target on the negative side
01225                     fliptest = qtrue;
01226                     break;
01227                 }
01228             }
01229             if (k == source->numpoints)
01230                 continue;       // planar with source portal
01231 #else
01232             fliptest = flipclip;
01233 #endif
01234             //
01235             // flip the normal if the source portal is backwards
01236             //
01237             if (fliptest)
01238             {
01239                 VectorSubtract (vec3_origin, plane.normal, plane.normal);
01240                 plane.dist = -plane.dist;
01241             }
01242 #if 1
01243             //
01244             // if all of the pass portal points are now on the positive side,
01245             // this is the seperating plane
01246             //
01247             counts[0] = counts[1] = counts[2] = 0;
01248             for (k=0 ; k<pass->numpoints ; k++)
01249             {
01250                 if (k==j)
01251                     continue;
01252                 d = DotProduct (pass->points[k], plane.normal) - plane.dist;
01253                 if (d < -ON_EPSILON)
01254                     break;
01255                 else if (d > ON_EPSILON)
01256                     counts[0]++;
01257                 else
01258                     counts[2]++;
01259             }
01260             if (k != pass->numpoints)
01261                 continue;   // points on negative side, not a seperating plane
01262                 
01263             if (!counts[0])
01264                 continue;   // planar with seperating plane
01265 #else
01266             k = (j+1)%pass->numpoints;
01267             d = DotProduct (pass->points[k], plane.normal) - plane.dist;
01268             if (d < -ON_EPSILON)
01269                 continue;
01270             k = (j+pass->numpoints-1)%pass->numpoints;
01271             d = DotProduct (pass->points[k], plane.normal) - plane.dist;
01272             if (d < -ON_EPSILON)
01273                 continue;           
01274 #endif
01275             //
01276             // flip the normal if we want the back side
01277             //
01278             if (flipclip)
01279             {
01280                 VectorSubtract (vec3_origin, plane.normal, plane.normal);
01281                 plane.dist = -plane.dist;
01282             }
01283 
01284             if (numseperators >= maxseperators)
01285                 Error("max seperators");
01286             seperators[numseperators] = plane;
01287             numseperators++;
01288             break;
01289         }
01290     }
01291     return numseperators;
01292 }
01293 
01294 /*
01295 ===============
01296 CreatePassages
01297 
01298 MrE: create passages from one portal to all the portals in the leaf the portal leads to
01299      every passage has a cansee bit string with all the portals that can be
01300      seen through the passage
01301 ===============
01302 */
01303 void CreatePassages(int portalnum)
01304 {
01305     int i, j, k, n, numseperators, numsee;
01306     float d;
01307     vportal_t *portal, *p, *target;
01308     leaf_t *leaf;
01309     passage_t   *passage, *lastpassage;
01310     plane_t seperators[MAX_SEPERATORS*2];
01311     winding_t *w;
01312     winding_t in, out, *res;
01313 
01314 #ifdef MREDEBUG
01315     _printf("\r%6d", portalnum);
01316 #endif
01317 
01318     portal = sorted_portals[portalnum];
01319 
01320     if (portal->removed)
01321     {
01322         portal->status = stat_done;
01323         return;
01324     }
01325 
01326     lastpassage = NULL;
01327     leaf = &leafs[portal->leaf];
01328     for (i = 0; i < leaf->numportals; i++)
01329     {
01330         target = leaf->portals[i];
01331         if (target->removed)
01332             continue;
01333 
01334         passage = (passage_t *) malloc(sizeof(passage_t) + portalbytes);
01335         memset(passage, 0, sizeof(passage_t) + portalbytes);
01336         numseperators = AddSeperators(portal->winding, target->winding, qfalse, seperators, MAX_SEPERATORS*2);
01337         numseperators += AddSeperators(target->winding, portal->winding, qtrue, &seperators[numseperators], MAX_SEPERATORS*2-numseperators);
01338 
01339         passage->next = NULL;
01340         if (lastpassage)
01341             lastpassage->next = passage;
01342         else
01343             portal->passages = passage;
01344         lastpassage = passage;
01345 
01346         numsee = 0;
01347         //create the passage->cansee
01348         for (j = 0; j < numportals * 2; j++)
01349         {
01350             p = &portals[j];
01351             if (p->removed)
01352                 continue;
01353             if ( ! (target->portalflood[j >> 3] & (1<<(j&7)) ) )
01354                 continue;
01355             if ( ! (portal->portalflood[j >> 3] & (1<<(j&7)) ) )
01356                 continue;
01357             for (k = 0; k < numseperators; k++)
01358             {
01359                 //
01360                 d = DotProduct (p->origin, seperators[k].normal) - seperators[k].dist;
01361                 //if completely at the back of the seperator plane
01362                 if (d < -p->radius + ON_EPSILON)
01363                     break;
01364                 w = p->winding;
01365                 for (n = 0; n < w->numpoints; n++)
01366                 {
01367