home *** CD-ROM | disk | FTP | other *** search
/ GameStar 2006 March / Gamestar_82_2006-03_dvd.iso / DVDStar / Editace / quake4_sdkv10.exe / source / game / Pvs.cpp < prev    next >
C/C++ Source or Header  |  2005-11-14  |  37KB  |  1,540 lines

  1.  
  2. #include "../idlib/precompiled.h"
  3. #pragma hdrstop
  4.  
  5. #include "Game_local.h"
  6.  
  7. #define MAX_BOUNDS_AREAS    16
  8.  
  9.  
  10. typedef struct pvsPassage_s {
  11.     byte *                canSee;        // bit set for all portals that can be seen through this passage
  12. } pvsPassage_t;
  13.  
  14.  
  15. typedef struct pvsPortal_s {
  16.     int                    areaNum;    // area this portal leads to
  17.     idWinding *            w;            // winding goes counter clockwise seen from the area this portal is part of
  18.     idBounds            bounds;        // winding bounds
  19.     idPlane                plane;        // winding plane, normal points towards the area this portal leads to
  20.     pvsPassage_t *        passages;    // passages to portals in the area this portal leads to
  21.     bool                done;        // true if pvs is calculated for this portal
  22.     byte *                vis;        // PVS for this portal
  23.     byte *                mightSee;    // used during construction
  24. } pvsPortal_t;
  25.  
  26.  
  27. typedef struct pvsArea_s {
  28.     int                    numPortals;    // number of portals in this area
  29.     idBounds            bounds;        // bounds of the whole area
  30.     pvsPortal_t **        portals;    // array with pointers to the portals of this area
  31. } pvsArea_t;
  32.  
  33.  
  34. typedef struct pvsStack_s {
  35.     struct pvsStack_s *    next;        // next stack entry
  36.     byte *                mightSee;    // bit set for all portals that might be visible through this passage/portal stack
  37. } pvsStack_t;
  38.  
  39.  
  40. /*
  41. ================
  42. idPVS::idPVS
  43. ================
  44. */
  45. idPVS::idPVS( void ) {
  46.     int i;
  47.  
  48.     numAreas = 0;
  49.     numPortals = 0;
  50.  
  51.     connectedAreas = NULL;
  52.     areaQueue = NULL;
  53.     areaPVS = NULL;
  54.  
  55.     for ( i = 0; i < MAX_CURRENT_PVS; i++ ) {
  56.         currentPVS[i].handle.i = -1;
  57.         currentPVS[i].handle.h = 0;
  58.         currentPVS[i].pvs = NULL;
  59.     }
  60.  
  61.     pvsAreas = NULL;
  62.     pvsPortals = NULL;
  63. }
  64.  
  65. /*
  66. ================
  67. idPVS::~idPVS
  68. ================
  69. */
  70. idPVS::~idPVS( void ) {
  71.     Shutdown();
  72. }
  73.  
  74. /*
  75. ================
  76. idPVS::GetPortalCount
  77. ================
  78. */
  79. int idPVS::GetPortalCount( void ) const {
  80.     int i, na, np;
  81.  
  82.     na = gameRenderWorld->NumAreas();
  83.     np = 0;
  84.     for ( i = 0; i < na; i++ ) {
  85.         np += gameRenderWorld->NumPortalsInArea( i );
  86.     }
  87.     return np;
  88. }
  89.  
  90. /*
  91. ================
  92. idPVS::CreatePVSData
  93. ================
  94. */
  95. void idPVS::CreatePVSData( void ) {
  96.     int i, j, n, cp;
  97.     exitPortal_t portal;
  98.     pvsArea_t *area;
  99.     pvsPortal_t *p, **portalPtrs;
  100.  
  101.     if ( !numPortals ) {
  102.         return;
  103.     }
  104.  
  105.     pvsPortals = new pvsPortal_t[numPortals];
  106.     pvsAreas = new pvsArea_t[numAreas];
  107.     memset( pvsAreas, 0, numAreas * sizeof( *pvsAreas ) );
  108.  
  109.     cp = 0;
  110.     portalPtrs = new pvsPortal_t*[numPortals];
  111.  
  112.     for ( i = 0; i < numAreas; i++ ) {
  113.  
  114.         area = &pvsAreas[i];
  115.         area->bounds.Clear();
  116.         area->portals = portalPtrs + cp;
  117.  
  118.         n = gameRenderWorld->NumPortalsInArea( i );
  119.  
  120.         for ( j = 0; j < n; j++ ) {
  121.  
  122.             portal = gameRenderWorld->GetPortal( i, j );
  123.  
  124.             p = &pvsPortals[cp++];
  125.             // the winding goes counter clockwise seen from this area
  126.             p->w = portal.w->Copy();
  127.             p->areaNum = portal.areas[1];    // area[1] is always the area the portal leads to
  128.  
  129.             p->vis = new byte[portalVisBytes];
  130.             memset( p->vis, 0, portalVisBytes );
  131.             p->mightSee = new byte[portalVisBytes];
  132.             memset( p->mightSee, 0, portalVisBytes );
  133.             p->w->GetBounds( p->bounds );
  134.             p->w->GetPlane( p->plane );
  135.             // plane normal points to outside the area
  136.             p->plane = -p->plane;
  137.             // no PVS calculated for this portal yet
  138.             p->done = false;
  139.  
  140.             area->portals[area->numPortals] = p;
  141.             area->numPortals++;
  142.  
  143.             area->bounds += p->bounds;
  144.         }
  145.     }
  146. }
  147.  
  148. /*
  149. ================
  150. idPVS::DestroyPVSData
  151. ================
  152. */
  153. void idPVS::DestroyPVSData( void ) {
  154.     int i;
  155.  
  156.     if ( !pvsAreas ) {
  157.         return;
  158.     }
  159.  
  160.     // delete portal pointer array
  161.     delete[] pvsAreas[0].portals;
  162.  
  163.     // delete all areas
  164.     delete[] pvsAreas;
  165.     pvsAreas = NULL;
  166.  
  167.     // delete portal data
  168.     for ( i = 0; i < numPortals; i++ ) {
  169.         delete[] pvsPortals[i].vis;
  170.         delete[] pvsPortals[i].mightSee;
  171.         delete pvsPortals[i].w;
  172.     }
  173.  
  174.     // delete portals
  175.     delete[] pvsPortals;
  176.     pvsPortals = NULL;
  177. }
  178.  
  179. /*
  180. ================
  181. idPVS::FloodFrontPortalPVS_r
  182. ================
  183. */
  184. void idPVS::FloodFrontPortalPVS_r( pvsPortal_t *portal, int areaNum ) const {
  185.     int i, n;
  186.     pvsArea_t *area;
  187.     pvsPortal_t *p;
  188.  
  189.     area = &pvsAreas[ areaNum ];
  190.  
  191.     for ( i = 0; i < area->numPortals; i++ ) {
  192.         p = area->portals[i];
  193.         n = p - pvsPortals;
  194.         // don't flood through if this portal is not at the front
  195.         if ( !( portal->mightSee[ n>>3 ] & (1 << (n&7)) ) ) {
  196.             continue;
  197.         }
  198.         // don't flood through if already visited this portal
  199.         if ( portal->vis[ n>>3 ] & (1 << (n&7)) ) {
  200.             continue;
  201.         }
  202.         // this portal might be visible
  203.         portal->vis[ n>>3 ] |= (1 << (n&7));
  204.         // flood through the portal
  205.         FloodFrontPortalPVS_r( portal, p->areaNum );
  206.     }
  207. }
  208.  
  209. /*
  210. ================
  211. idPVS::FrontPortalPVS
  212. ================
  213. */
  214. void idPVS::FrontPortalPVS( void ) const {
  215.     int i, j, k, n, p, side1, side2, areaSide;
  216.     pvsPortal_t *p1, *p2;
  217.     pvsArea_t *area;
  218.  
  219.     for ( i = 0; i < numPortals; i++ ) {
  220.         p1 = &pvsPortals[i];
  221.  
  222.         for ( j = 0; j < numAreas; j++ ) {
  223.  
  224.             area = &pvsAreas[j];
  225.  
  226.             areaSide = side1 = area->bounds.PlaneSide( p1->plane );
  227.  
  228.             // if the whole area is at the back side of the portal
  229.             if ( areaSide == PLANESIDE_BACK ) {
  230.                 continue;
  231.             }
  232.  
  233.             for ( p = 0; p < area->numPortals; p++ ) {
  234.     
  235.                 p2 = area->portals[p];
  236.  
  237.                 // if we the whole area is not at the front we need to check
  238.                 if ( areaSide != PLANESIDE_FRONT ) {
  239.                     // if the second portal is completely at the back side of the first portal
  240.                     side1 = p2->bounds.PlaneSide( p1->plane );
  241.                     if ( side1 == PLANESIDE_BACK ) {
  242.                         continue;
  243.                     }
  244.                 }
  245.  
  246.                 // if the first portal is completely at the front of the second portal
  247.                 side2 = p1->bounds.PlaneSide( p2->plane );
  248.                 if ( side2 == PLANESIDE_FRONT ) {
  249.                     continue;
  250.                 }
  251.  
  252.                 // if the second portal is not completely at the front of the first portal
  253.                 if ( side1 != PLANESIDE_FRONT ) {
  254.                     // more accurate check
  255.                     for ( k = 0; k < p2->w->GetNumPoints(); k++ ) {
  256.                         // if more than an epsilon at the front side
  257.                         if ( p1->plane.Side( (*p2->w)[k].ToVec3(), ON_EPSILON ) == PLANESIDE_FRONT ) {
  258.                             break;
  259.                         }
  260.                     }
  261.                     if ( k >= p2->w->GetNumPoints() ) {
  262.                         continue;    // second portal is at the back of the first portal
  263.                     }
  264.                 }
  265.  
  266.                 // if the first portal is not completely at the back side of the second portal
  267.                 if ( side2 != PLANESIDE_BACK ) {
  268.                     // more accurate check
  269.                     for ( k = 0; k < p1->w->GetNumPoints(); k++ ) {
  270.                         // if more than an epsilon at the back side
  271.                         if ( p2->plane.Side( (*p1->w)[k].ToVec3(), ON_EPSILON ) == PLANESIDE_BACK ) {
  272.                             break;
  273.                         }
  274.                     }
  275.                     if ( k >= p1->w->GetNumPoints() ) {
  276.                         continue;    // first portal is at the front of the second portal
  277.                     }
  278.                 }
  279.  
  280.                 // the portal might be visible at the front
  281.                 n = p2 - pvsPortals;
  282.                 p1->mightSee[ n >> 3 ] |= 1 << (n&7);
  283.             }
  284.         }
  285.     }
  286.  
  287.     // flood the front portal pvs for all portals
  288.     for ( i = 0; i < numPortals; i++ ) {
  289.         p1 = &pvsPortals[i];
  290.         FloodFrontPortalPVS_r( p1, p1->areaNum );
  291.     }
  292. }
  293.  
  294. /*
  295. ===============
  296. idPVS::FloodPassagePVS_r
  297. ===============
  298. */
  299. pvsStack_t *idPVS::FloodPassagePVS_r( pvsPortal_t *source, const pvsPortal_t *portal, pvsStack_t *prevStack ) const {
  300.     int i, j, n, m;
  301.     pvsPortal_t *p;
  302.     pvsArea_t *area;
  303.     pvsStack_t *stack;
  304.     pvsPassage_t *passage;
  305.     long *sourceVis, *passageVis, *portalVis, *mightSee, *prevMightSee, more;
  306.  
  307.     area = &pvsAreas[portal->areaNum];
  308.  
  309.     stack = prevStack->next;
  310.     // if no next stack entry allocated
  311.     if ( !stack ) {
  312.         stack = reinterpret_cast<pvsStack_t*>(new byte[sizeof(pvsStack_t) + portalVisBytes]);
  313.         stack->mightSee = (reinterpret_cast<byte *>(stack)) + sizeof(pvsStack_t);
  314.         stack->next = NULL;
  315.         prevStack->next = stack;
  316.     }
  317.  
  318.     // check all portals for flooding into other areas
  319.     for ( i = 0; i < area->numPortals; i++ ) {
  320.  
  321.         passage = &portal->passages[i];
  322.  
  323.         // if this passage is completely empty
  324.         if ( !passage->canSee ) {
  325.             continue;
  326.         }
  327.  
  328.         p = area->portals[i];
  329.         n = p - pvsPortals;
  330.  
  331.         // if this portal cannot be seen through our current portal/passage stack
  332.         if ( !( prevStack->mightSee[n >> 3] & (1 << (n & 7)) ) ) {
  333.             continue;
  334.         }
  335.  
  336.         // mark the portal as visible
  337.         source->vis[n >> 3] |= (1 << (n & 7));
  338.  
  339.         // get pointers to vis data
  340.         prevMightSee = reinterpret_cast<long *>(prevStack->mightSee);
  341.         passageVis = reinterpret_cast<long *>(passage->canSee);
  342.         sourceVis = reinterpret_cast<long *>(source->vis);
  343.         mightSee = reinterpret_cast<long *>(stack->mightSee);
  344.  
  345.         more = 0;
  346.         // use the portal PVS if it has been calculated
  347.         if ( p->done ) {
  348.             portalVis = reinterpret_cast<long *>(p->vis);
  349.             for ( j = 0; j < portalVisLongs; j++ ) {
  350.                 // get new PVS which is decreased by going through this passage
  351.                 m = *prevMightSee++ & *passageVis++ & *portalVis++;
  352.                 // check if anything might be visible through this passage that wasn't yet visible
  353.                 more |= (m & ~(*sourceVis++));
  354.                 // store new PVS
  355.                 *mightSee++ = m;
  356.             }
  357.         }
  358.         else {
  359.             // the p->mightSee is implicitely stored in the passageVis
  360.             for ( j = 0; j < portalVisLongs; j++ ) {
  361.                 // get new PVS which is decreased by going through this passage
  362.                 m = *prevMightSee++ & *passageVis++;
  363.                 // check if anything might be visible through this passage that wasn't yet visible
  364.                 more |= (m & ~(*sourceVis++));
  365.                 // store new PVS
  366.                 *mightSee++ = m;
  367.             }
  368.         }
  369.  
  370.         // if nothing more can be seen
  371.         if ( !more ) {
  372.             continue;
  373.         }
  374.  
  375.         // go through the portal
  376.         stack->next = FloodPassagePVS_r( source, p, stack );
  377.     }
  378.  
  379.     return stack;
  380. }
  381.  
  382. /*
  383. ===============
  384. idPVS::PassagePVS
  385. ===============
  386. */
  387. void idPVS::PassagePVS( void ) const {
  388.     int i;
  389.     pvsPortal_t *source;
  390.     pvsStack_t *stack, *s;
  391.  
  392.     // create the passages
  393.     CreatePassages();
  394.  
  395.     // allocate first stack entry
  396.     stack = reinterpret_cast<pvsStack_t*>(new byte[sizeof(pvsStack_t) + portalVisBytes]);
  397.     stack->mightSee = (reinterpret_cast<byte *>(stack)) + sizeof(pvsStack_t);
  398.     stack->next = NULL;
  399.  
  400.     // calculate portal PVS by flooding through the passages
  401.     for ( i = 0; i < numPortals; i++ ) {
  402.         source = &pvsPortals[i];
  403.         memset( source->vis, 0, portalVisBytes );
  404. // RAVEN BEGIN
  405. // JSinger: Changed to call optimized memcpy
  406.         SIMDProcessor->Memcpy( stack->mightSee, source->mightSee, portalVisBytes );
  407. // RAVEN END
  408.         FloodPassagePVS_r( source, source, stack );
  409.         source->done = true;
  410.     }
  411.  
  412.     // free the allocated stack
  413.     for ( s = stack; s; s = stack ) {
  414.         stack = stack->next;
  415.         delete[] s;
  416.     }
  417.  
  418.     // destroy the passages
  419.     DestroyPassages();
  420. }
  421.  
  422. /*
  423. ===============
  424. idPVS::AddPassageBoundaries
  425. ===============
  426. */
  427. void idPVS::AddPassageBoundaries( const idWinding &source, const idWinding &pass, bool flipClip, idPlane *bounds, int &numBounds, int maxBounds ) const {
  428.     int            i, j, k, l;
  429.     idVec3        v1, v2, normal;
  430.     float        d, dist;
  431.     bool        flipTest, front;
  432.     idPlane        plane;
  433.  
  434.  
  435.     // check all combinations    
  436.     for ( i = 0; i < source.GetNumPoints(); i++ ) {
  437.  
  438.         l = (i + 1) % source.GetNumPoints();
  439.         v1 = source[l].ToVec3() - source[i].ToVec3();
  440.  
  441.         // find a vertex of pass that makes a plane that puts all of the
  442.         // vertices of pass on the front side and all of the vertices of
  443.         // source on the back side
  444.         for ( j = 0; j < pass.GetNumPoints(); j++ ) {
  445.  
  446.             v2 = pass[j].ToVec3() - source[i].ToVec3();
  447.  
  448.             normal = v1.Cross( v2 );
  449.             if ( normal.Normalize() < 0.01f ) {
  450.                 continue;
  451.             }
  452.             dist = normal * pass[j].ToVec3();
  453.  
  454.             //
  455.             // find out which side of the generated seperating plane has the
  456.             // source portal
  457.             //
  458.             flipTest = false;
  459.             for ( k = 0; k < source.GetNumPoints(); k++ ) {
  460.                 if ( k == i || k == l ) {
  461.                     continue;
  462.                 }
  463.                 d = source[k].ToVec3() * normal - dist;
  464.                 if ( d < -ON_EPSILON ) {
  465.                     // source is on the negative side, so we want all
  466.                     // pass and target on the positive side
  467.                     flipTest = false;
  468.                     break;
  469.                 }
  470.                 else if ( d > ON_EPSILON ) {
  471.                     // source is on the positive side, so we want all
  472.                     // pass and target on the negative side
  473.                     flipTest = true;
  474.                     break;
  475.                 }
  476.             }
  477.             if ( k == source.GetNumPoints() ) {
  478.                 continue;        // planar with source portal
  479.             }
  480.  
  481.             // flip the normal if the source portal is backwards
  482.             if (flipTest) {
  483.                 normal = -normal;
  484.                 dist = -dist;
  485.             }
  486.  
  487.             // if all of the pass portal points are now on the positive side,
  488.             // this is the seperating plane
  489.             front = false;
  490.             for ( k = 0; k < pass.GetNumPoints(); k++ ) {
  491.                 if ( k == j ) {
  492.                     continue;
  493.                 }
  494.                 d = pass[k].ToVec3() * normal - dist;
  495.                 if ( d < -ON_EPSILON ) {
  496.                     break;
  497.                 }
  498.                 else if ( d > ON_EPSILON ) {
  499.                     front = true;
  500.                 }
  501.             }
  502.             if ( k < pass.GetNumPoints() ) {
  503.                 continue;    // points on negative side, not a seperating plane
  504.             }
  505.             if ( !front ) {
  506.                 continue;    // planar with seperating plane
  507.             }
  508.  
  509.             // flip the normal if we want the back side
  510.             if ( flipClip ) {
  511.                 plane.SetNormal( -normal );
  512.                 plane.SetDist( -dist );
  513.             }
  514.             else {
  515.                 plane.SetNormal( normal );
  516.                 plane.SetDist( dist );
  517.             }
  518.  
  519.             // check if the plane is already a passage boundary
  520.             for ( k = 0; k < numBounds; k++ ) {
  521.                 if ( plane.Compare( bounds[k], 0.001f, 0.01f ) ) {
  522.                     break;
  523.                 }
  524.             }
  525.             if ( k < numBounds ) {
  526.                 break;
  527.             }
  528.  
  529.             if ( numBounds >= maxBounds ) {
  530.                 gameLocal.Warning( "max passage boundaries." );
  531.                 break;
  532.             }
  533.             bounds[numBounds] = plane;
  534.             numBounds++;
  535.             break;
  536.         }
  537.     }
  538. }
  539.  
  540. /*
  541. ================
  542. idPVS::CreatePassages
  543. ================
  544. */
  545. #define MAX_PASSAGE_BOUNDS        128
  546.  
  547. void idPVS::CreatePassages( void ) const {
  548.     int i, j, l, n, numBounds, front, passageMemory, byteNum, bitNum;
  549.     int sides[MAX_PASSAGE_BOUNDS];
  550.     idPlane passageBounds[MAX_PASSAGE_BOUNDS];
  551.     pvsPortal_t *source, *target, *p;
  552.     pvsArea_t *area;
  553.     pvsPassage_t *passage;
  554.     idFixedWinding winding;
  555.     byte canSee, mightSee, bit;
  556.  
  557.     passageMemory = 0;
  558.     for ( i = 0; i < numPortals; i++ ) {
  559.         source = &pvsPortals[i];
  560.         area = &pvsAreas[source->areaNum];
  561.  
  562.         source->passages = new pvsPassage_t[area->numPortals];
  563.  
  564.         for ( j = 0; j < area->numPortals; j++ ) {
  565.             target = area->portals[j];
  566.             n = target - pvsPortals;
  567.  
  568.             passage = &source->passages[j];
  569.  
  570.             // if the source portal cannot see this portal
  571.             if ( !( source->mightSee[ n>>3 ] & (1 << (n&7)) ) ) {
  572.                 // not all portals in the area have to be visible because areas are not necesarily convex
  573.                 // also no passage has to be created for the portal which is the opposite of the source
  574.                 passage->canSee = NULL;
  575.                 continue;
  576.             }
  577.  
  578.             passage->canSee = new byte[portalVisBytes];
  579.             passageMemory += portalVisBytes;
  580.  
  581.             // boundary plane normals point inwards
  582.             numBounds = 0;
  583.             AddPassageBoundaries( *(source->w), *(target->w), false, passageBounds, numBounds, MAX_PASSAGE_BOUNDS );
  584.             AddPassageBoundaries( *(target->w), *(source->w), true, passageBounds, numBounds, MAX_PASSAGE_BOUNDS );
  585.  
  586.             // get all portals visible through this passage
  587.             for ( byteNum = 0; byteNum < portalVisBytes; byteNum++) {
  588.  
  589.                 canSee = 0;
  590.                 mightSee = source->mightSee[byteNum] & target->mightSee[byteNum];
  591.  
  592.                 // go through eight portals at a time to speed things up
  593.                 for ( bitNum = 0; bitNum < 8; bitNum++ ) {
  594.  
  595.                     bit = 1 << bitNum;
  596.  
  597.                     if ( !( mightSee & bit ) ) {
  598.                         continue;
  599.                     }
  600.  
  601.                     p = &pvsPortals[(byteNum << 3) + bitNum];
  602.     
  603.                     if ( p->areaNum == source->areaNum ) {
  604.                         continue;
  605.                     }
  606.  
  607.                     for ( front = 0, l = 0; l < numBounds; l++ ) {
  608.                         sides[l] = p->bounds.PlaneSide( passageBounds[l] );
  609.                         // if completely at the back of the passage bounding plane
  610.                         if ( sides[l] == PLANESIDE_BACK ) {
  611.                             break;
  612.                         }
  613.                         // if completely at the front
  614.                         if ( sides[l] == PLANESIDE_FRONT ) {
  615.                             front++;
  616.                         }
  617.                     }
  618.                     // if completely outside the passage
  619.                     if ( l < numBounds ) {
  620.                         continue;
  621.                     }
  622.  
  623.                     // if not at the front of all bounding planes and thus not completely inside the passage
  624.                     if ( front != numBounds ) {
  625.  
  626.                         winding = *p->w;
  627.  
  628.                         for ( l = 0; l < numBounds; l++ ) {
  629.                             // only clip if the winding possibly crosses this plane
  630.                             if ( sides[l] != PLANESIDE_CROSS ) {
  631.                                 continue;
  632.                             }
  633.                             // clip away the part at the back of the bounding plane
  634.                             winding.ClipInPlace( passageBounds[l] );
  635.                             // if completely clipped away
  636.                             if ( !winding.GetNumPoints() ) {
  637.                                 break;
  638.                             }
  639.                         }
  640.                         // if completely outside the passage
  641.                         if ( l < numBounds ) {
  642.                             continue;
  643.                         }
  644.                     }
  645.  
  646.                     canSee |= bit;
  647.                 }
  648.  
  649.                 // store results of all eight portals
  650.                 passage->canSee[byteNum] = canSee;
  651.             }
  652.  
  653.             // can always see the target portal
  654.             passage->canSee[n >> 3] |= (1 << (n&7));
  655.         }
  656.     }
  657.     if ( passageMemory < 1024 ) {
  658.         gameLocal.Printf( "%5d bytes passage memory used to build PVS\n", passageMemory );
  659.     }
  660.     else {
  661.         gameLocal.Printf( "%5d KB passage memory used to build PVS\n", passageMemory>>10 );
  662.     }
  663. }
  664.  
  665. /*
  666. ================
  667. idPVS::DestroyPassages
  668. ================
  669. */
  670. void idPVS::DestroyPassages( void ) const {
  671.     int i, j;
  672.     pvsPortal_t *p;
  673.     pvsArea_t *area;
  674.  
  675.     for ( i = 0; i < numPortals; i++ ) {
  676.         p = &pvsPortals[i];
  677.         area = &pvsAreas[p->areaNum];
  678.         for ( j = 0; j < area->numPortals; j++ ) {
  679.             if ( p->passages[j].canSee ) {
  680.                 delete[] p->passages[j].canSee;
  681.             }
  682.         }
  683.         delete[] p->passages;
  684.     }
  685. }
  686.  
  687. /*
  688. ================
  689. idPVS::CopyPortalPVSToMightSee
  690. ================
  691. */
  692. void idPVS::CopyPortalPVSToMightSee( void ) const {
  693.     int i;
  694.     pvsPortal_t *p;
  695.  
  696.     for ( i = 0; i < numPortals; i++ ) {
  697.         p = &pvsPortals[i];
  698. // RAVEN BEGIN
  699. // JSinger: Changed to call optimized memcpy
  700.         SIMDProcessor->Memcpy( p->mightSee, p->vis, portalVisBytes );
  701. // RAVEN BEGIN
  702.     }
  703. }
  704.  
  705. /*
  706. ================
  707. idPVS::AreaPVSFromPortalPVS
  708. ================
  709. */
  710. int idPVS::AreaPVSFromPortalPVS( void ) const {
  711.     int i, j, k, areaNum, totalVisibleAreas;
  712.     long *p1, *p2;
  713.     byte *pvs, *portalPVS;
  714.     pvsArea_t *area;
  715.  
  716.     totalVisibleAreas = 0;
  717.  
  718.     if ( !numPortals ) {
  719.         return totalVisibleAreas;
  720.     }
  721.  
  722.     memset( areaPVS, 0, numAreas * areaVisBytes );
  723.  
  724.     for ( i = 0; i < numAreas; i++ ) {
  725.         area = &pvsAreas[i];
  726.         pvs = areaPVS + i * areaVisBytes;
  727.  
  728.         // the area is visible to itself
  729.         pvs[ i >> 3 ] |= 1 << (i & 7);
  730.  
  731.         if ( !area->numPortals ) {
  732.             continue;
  733.         }
  734.  
  735.         // store the PVS of all portals in this area at the first portal
  736.         for ( j = 1; j < area->numPortals; j++ ) {
  737.             p1 = reinterpret_cast<long *>(area->portals[0]->vis);
  738.             p2 = reinterpret_cast<long *>(area->portals[j]->vis);
  739.             for ( k = 0; k < portalVisLongs; k++ ) {
  740.                 *p1++ |= *p2++;
  741.             }
  742.         }
  743.  
  744.         // the portals of this area are always visible
  745.         for ( j = 0; j < area->numPortals; j++ ) {
  746.             k = area->portals[j] - pvsPortals;
  747.             area->portals[0]->vis[ k >> 3 ] |= 1 << (k & 7);
  748.         }
  749.  
  750.         // set all areas to visible that can be seen from the portals of this area
  751.         portalPVS = area->portals[0]->vis;
  752.         for ( j = 0; j < numPortals; j++ ) {
  753.             // if this portal is visible
  754.             if ( portalPVS[j>>3] & (1 << (j&7)) ) {
  755.                 areaNum = pvsPortals[j].areaNum;
  756.                 pvs[ areaNum >> 3 ] |= 1 << (areaNum & 7);
  757.             }
  758.         }
  759.  
  760.         // count the number of visible areas
  761.         for ( j = 0; j < numAreas; j++ ) {
  762.             if ( pvs[j>>3] & (1 << (j&7)) ) {
  763.                 totalVisibleAreas++;
  764.             }
  765.         }
  766.     }
  767.     return totalVisibleAreas;
  768. }
  769.  
  770. /*
  771. ================
  772. idPVS::Init
  773. ================
  774. */
  775. void idPVS::Init( void ) {
  776.     int totalVisibleAreas;
  777.  
  778.     Shutdown();
  779.  
  780.     numAreas = gameRenderWorld->NumAreas();
  781.     if ( numAreas <= 0 ) {
  782.         return;
  783.     }
  784.  
  785.     connectedAreas = new bool[numAreas];
  786.     areaQueue = new int[numAreas];
  787.  
  788.     areaVisBytes = ( ((numAreas+31)&~31) >> 3);
  789.     areaVisLongs = areaVisBytes/sizeof(long);
  790.  
  791. // RAVEN BEGIN
  792. // mwhitlock: Xenon texture streaming
  793. #if defined(_XENON)
  794.     justOutOfViewAreasBits = new byte[areaVisBytes];
  795. #endif
  796. // RAVEN END
  797.  
  798.     areaPVS = new byte[numAreas * areaVisBytes];
  799.     memset( areaPVS, 0xFF, numAreas * areaVisBytes );
  800.  
  801.     numPortals = GetPortalCount();
  802.  
  803.     portalVisBytes = ( ((numPortals+31)&~31) >> 3);
  804.     portalVisLongs = portalVisBytes/sizeof(long);
  805.  
  806.     for ( int i = 0; i < MAX_CURRENT_PVS; i++ ) {
  807.         currentPVS[i].handle.i = -1;
  808.         currentPVS[i].handle.h = 0;
  809.         currentPVS[i].pvs = new byte[areaVisBytes];
  810.         memset( currentPVS[i].pvs, 0, areaVisBytes );
  811.     }
  812.  
  813.     idTimer timer;
  814.     timer.Start();
  815.  
  816.     CreatePVSData();
  817.  
  818.     FrontPortalPVS();
  819.  
  820.     CopyPortalPVSToMightSee();
  821.  
  822.     PassagePVS();
  823.  
  824.     totalVisibleAreas = AreaPVSFromPortalPVS();
  825.  
  826.     DestroyPVSData();
  827.  
  828.     timer.Stop();
  829.  
  830.     gameLocal.Printf( "%5.0f msec to calculate PVS\n", timer.Milliseconds() );
  831.     gameLocal.Printf( "%5d areas\n", numAreas );
  832.     gameLocal.Printf( "%5d portals\n", numPortals );
  833.  
  834. // RAVEN BEGIN
  835. // rjohnson: fix for div by 0
  836.     if( numAreas ) {
  837.         gameLocal.Printf( "%5d areas visible on average\n", totalVisibleAreas / numAreas );
  838.     }
  839. // RAVEN END
  840.  
  841.     if ( numAreas * areaVisBytes < 1024 ) {
  842.         gameLocal.Printf( "%5d bytes PVS data\n", numAreas * areaVisBytes );
  843.     }
  844.     else {
  845.         gameLocal.Printf( "%5d KB PVS data\n", (numAreas * areaVisBytes) >> 10 );
  846.     }
  847. }
  848.  
  849. /*
  850. ================
  851. idPVS::Shutdown
  852. ================
  853. */
  854. void idPVS::Shutdown( void ) {
  855.     if ( connectedAreas ) {
  856.         delete connectedAreas;
  857.         connectedAreas = NULL;
  858.     }
  859. // RAVEN BEGIN
  860. // mwhitlock: Xenon texture streaming
  861. #if defined(_XENON)
  862.     if ( justOutOfViewAreasBits )
  863.     {
  864.         delete justOutOfViewAreasBits;
  865.         justOutOfViewAreasBits = NULL;
  866.     }
  867. #endif
  868. // RAVEN END
  869.     if ( areaQueue ) {
  870.         delete areaQueue;
  871.         areaQueue = NULL;
  872.     }
  873.     if ( areaPVS ) {
  874.         delete areaPVS;
  875.         areaPVS = NULL;
  876.     }
  877.     if ( currentPVS ) {
  878.         for ( int i = 0; i < MAX_CURRENT_PVS; i++ ) {
  879. // RAVEN BEGIN
  880. // jsinger: modified to check to make sure the pointers have a value before attempting to delete
  881. //          them.  This prevents a call through the unified allocator before it has been initialized
  882.             if(currentPVS[i].pvs)
  883.             {
  884.                 delete currentPVS[i].pvs;
  885.             }
  886. // RAVEN END
  887.             currentPVS[i].pvs = NULL;
  888.         }
  889.     }
  890. }
  891.  
  892. /*
  893. ================
  894. idPVS::GetConnectedAreas
  895.  
  896.   assumes the 'areas' array is initialized to false
  897. ================
  898. */
  899. void idPVS::GetConnectedAreas( int srcArea, bool *areas ) const {
  900.     int curArea, nextArea;
  901.     int queueStart, queueEnd;
  902.     int i, n;
  903.     exitPortal_t portal;
  904.  
  905.     queueStart = -1;
  906.     queueEnd = 0;
  907.     areas[srcArea] = true;
  908.  
  909.     for ( curArea = srcArea; queueStart < queueEnd; curArea = areaQueue[++queueStart] ) {
  910.  
  911.         n = gameRenderWorld->NumPortalsInArea( curArea );
  912.  
  913.         for ( i = 0; i < n; i++ ) {
  914.             portal = gameRenderWorld->GetPortal( curArea, i );
  915.  
  916.             if ( portal.blockingBits & PS_BLOCK_VIEW ) {
  917.                 continue;
  918.             }
  919.  
  920.             // area[1] is always the area the portal leads to
  921.             nextArea = portal.areas[1];
  922.  
  923.             // if already visited this area
  924.             if ( areas[nextArea] ) {
  925.                 continue;
  926.             }
  927.  
  928.             // add area to queue
  929.             areaQueue[queueEnd++] = nextArea;
  930.             areas[nextArea] = true;
  931.         }
  932.     }
  933. }
  934.  
  935. // RAVEN BEGIN
  936. // mwhitlock: Xenon texture streaming
  937. #if defined(_XENON)
  938. /*
  939. ================
  940. idPVS::GetAreasJustOutOfView
  941.  
  942. assumes the 'areas' array is initialized to -1
  943. ================
  944. */
  945. int idPVS::DetermineAreasJustOutOfView( int srcArea ) {
  946.     int curArea, nextArea;
  947.     int queueStart, queueEnd;
  948.     int i, n;
  949.     exitPortal_t portal;
  950.     int numOutOfView=0;
  951.  
  952.     queueStart = -1;
  953.     queueEnd = 0;
  954.     memset( connectedAreas, 0, numAreas * sizeof( *connectedAreas ) );
  955.     memset( justOutOfViewAreasBits, 0, areaVisBytes );
  956.     assert(srcArea!=-1);
  957.     connectedAreas[srcArea] = true;
  958.  
  959.     for ( curArea = srcArea; queueStart < queueEnd; curArea = areaQueue[++queueStart] ) {
  960.  
  961.         n = gameRenderWorld->NumPortalsInArea( curArea );
  962.  
  963.         for ( i = 0; i < n; i++ ) {
  964.             portal = gameRenderWorld->GetPortal( curArea, i );
  965.             
  966.             assert(portal.areas[1]!=-1);
  967.  
  968.             // If nextArea cannot *ever* be viewed from srcArea, add it to our
  969.             // list of areas that are just out of view.
  970.             if(portal.areas[1]!=-1)
  971.             {
  972.                 byte* pvs = areaPVS +  srcArea * areaVisBytes;
  973.                 if(!pvs[portal.areas[1]>>3] & (1<<(portal.areas[1]&7)))
  974.                 {
  975.                     assert(numOutOfView<4096);
  976.                     justOutOfViewAreasBits[portal.areas[1]>>3] |= 1<<(portal.areas[1]&7);
  977.                     numOutOfView++;
  978.                     continue;
  979.                 }
  980.             }
  981.  
  982.             // If nextArea could potentially be viewed from srcArea, but cannot
  983.             // currently be viewed from srcArea because the portal is closed, add
  984.             // it to our list of areas that are just out of view.
  985.             if ( portal.blockingBits & PS_BLOCK_VIEW )
  986.             {
  987.                 if(portal.areas[1]!=-1)
  988.                 {
  989.                     assert(numOutOfView<4096);
  990.                     justOutOfViewAreasBits[portal.areas[1]>>3] |= 1<<(portal.areas[1]&7);
  991.                     numOutOfView++;
  992.                 }
  993.                 continue;
  994.             }
  995.  
  996.             // Area given by portal.area[1] is always the area the portal leads to.
  997.             nextArea = portal.areas[1];
  998.  
  999.             // If already visited this area, skip it.
  1000.             if ( connectedAreas[nextArea] ) {
  1001.                 continue;
  1002.             }
  1003.         
  1004.             // add area to queue
  1005.             areaQueue[queueEnd++] = nextArea;
  1006.             connectedAreas[nextArea] = true;
  1007.             
  1008.             // Well we got here so remove it from the set of just out of view areas.
  1009.             justOutOfViewAreasBits[nextArea>>3] &= ~(1<<(nextArea&7));
  1010.         }
  1011.     }
  1012.     return numOutOfView;
  1013. }
  1014.  
  1015. /*
  1016. ================
  1017. idPVS::JustOutOFView
  1018. ================
  1019. */
  1020. bool idPVS::JustOutOfView(const int *targetAreas, int numTargetAreas ) const {
  1021.     int i;
  1022.     
  1023.     for ( i = 0; i < numTargetAreas; i++ ) {
  1024.         if ( targetAreas[i] < 0 || targetAreas[i] >= numAreas ) {
  1025.             continue;
  1026.         }
  1027.         if ( justOutOfViewAreasBits[targetAreas[i]>>3] & (1 << (targetAreas[i]&7)) ) {
  1028.             return true;
  1029.         }
  1030.     }
  1031.     return false;
  1032. }
  1033. #endif
  1034. // RAVEN END
  1035.  
  1036. /*
  1037. ================
  1038. idPVS::GetPVSArea
  1039. ================
  1040. */
  1041. int idPVS::GetPVSArea( const idVec3 &point ) const {
  1042.     return gameRenderWorld->PointInArea( point );
  1043. }
  1044.  
  1045. /*
  1046. ================
  1047. idPVS::GetPVSAreas
  1048. ================
  1049. */
  1050. int idPVS::GetPVSAreas( const idBounds &bounds, int *areas, int maxAreas ) const {
  1051.     return gameRenderWorld->BoundsInAreas( bounds, areas, maxAreas );
  1052. }
  1053.  
  1054. /*
  1055. ================
  1056. idPVS::SetupCurrentPVS
  1057. ================
  1058. */
  1059. pvsHandle_t idPVS::SetupCurrentPVS( const idVec3 &source, const pvsType_t type ) const {
  1060.     int sourceArea;
  1061.  
  1062.     sourceArea = gameRenderWorld->PointInArea( source );
  1063.  
  1064.     return SetupCurrentPVS( sourceArea, type );
  1065. }
  1066.  
  1067. /*
  1068. ================
  1069. idPVS::SetupCurrentPVS
  1070. ================
  1071. */
  1072. pvsHandle_t idPVS::SetupCurrentPVS( const idBounds &source, const pvsType_t type ) const {
  1073.     int numSourceAreas, sourceAreas[MAX_BOUNDS_AREAS];
  1074.  
  1075.     numSourceAreas = gameRenderWorld->BoundsInAreas( source, sourceAreas, MAX_BOUNDS_AREAS );
  1076.  
  1077.     return SetupCurrentPVS( sourceAreas, numSourceAreas, type );
  1078. }
  1079.  
  1080. /*
  1081. ================
  1082. idPVS::SetupCurrentPVS
  1083. ================
  1084. */
  1085. pvsHandle_t idPVS::SetupCurrentPVS( const int sourceArea, const pvsType_t type ) const {
  1086.     int i;
  1087.     pvsHandle_t handle;
  1088.  
  1089.     handle = AllocCurrentPVS( *reinterpret_cast<const unsigned int *>(&sourceArea) );
  1090.  
  1091.     if ( sourceArea < 0 || sourceArea >= numAreas ) {
  1092.         memset( currentPVS[handle.i].pvs, 0, areaVisBytes );
  1093.         return handle;
  1094.     }
  1095.  
  1096.     if ( type != PVS_CONNECTED_AREAS ) {
  1097. // RAVEN BEGIN
  1098. // JSinger: Changed to call optimized memcpy
  1099.         SIMDProcessor->Memcpy( currentPVS[handle.i].pvs, areaPVS + sourceArea * areaVisBytes, areaVisBytes );
  1100. // RAVEN END
  1101.     } else {
  1102.         memset( currentPVS[handle.i].pvs, -1, areaVisBytes );
  1103.     }
  1104.  
  1105.     if ( type == PVS_ALL_PORTALS_OPEN ) {
  1106.         return handle;
  1107.     }
  1108.  
  1109.     memset( connectedAreas, 0, numAreas * sizeof( *connectedAreas ) );
  1110.  
  1111.     GetConnectedAreas( sourceArea, connectedAreas );
  1112.  
  1113.     for ( i = 0; i < numAreas; i++ ) {
  1114.         if ( !connectedAreas[i] ) {
  1115.             currentPVS[handle.i].pvs[i>>3] &= ~(1 << (i&7));
  1116.         }
  1117.     }
  1118.  
  1119.     return handle;
  1120. }
  1121.  
  1122. /*
  1123. ================
  1124. idPVS::SetupCurrentPVS
  1125. ================
  1126. */
  1127. pvsHandle_t idPVS::SetupCurrentPVS( const int *sourceAreas, const int numSourceAreas, const pvsType_t type ) const {
  1128.     int i, j;
  1129.     unsigned int h;
  1130.     long *vis, *pvs;
  1131.     pvsHandle_t handle;
  1132.  
  1133.     h = 0;
  1134.     for ( i = 0; i < numSourceAreas; i++ ) {
  1135.         h ^= *reinterpret_cast<const unsigned int *>(&sourceAreas[i]);
  1136.     }
  1137.     handle = AllocCurrentPVS( h );
  1138.  
  1139.     if ( !numSourceAreas || sourceAreas[0] < 0 || sourceAreas[0] >= numAreas) {
  1140.         memset( currentPVS[handle.i].pvs, 0, areaVisBytes );
  1141.         return handle;
  1142.     }
  1143.  
  1144.     if ( type != PVS_CONNECTED_AREAS ) {
  1145.         // merge PVS of all areas the source is in
  1146. // RAVEN BEGIN
  1147. // JSinger: Changed to call optimized memcpy
  1148.         SIMDProcessor->Memcpy( currentPVS[handle.i].pvs, areaPVS + sourceAreas[0] * areaVisBytes, areaVisBytes );
  1149. // RAVEN END
  1150.         for ( i = 1; i < numSourceAreas; i++ ) {
  1151.  
  1152.             assert( sourceAreas[i] >= 0 && sourceAreas[i] < numAreas );
  1153.  
  1154.             vis = reinterpret_cast<long*>(areaPVS + sourceAreas[i] * areaVisBytes);
  1155.             pvs = reinterpret_cast<long*>(currentPVS[handle.i].pvs);
  1156.             for ( j = 0; j < areaVisLongs; j++ ) {
  1157.                 *pvs++ |= *vis++;
  1158.             }
  1159.         }
  1160.     } else {
  1161.         memset( currentPVS[handle.i].pvs, -1, areaVisBytes );
  1162.     }
  1163.  
  1164.     if ( type == PVS_ALL_PORTALS_OPEN ) {
  1165.         return handle;
  1166.     }
  1167.  
  1168.     memset( connectedAreas, 0, numAreas * sizeof( *connectedAreas ) );
  1169.  
  1170.     // get all areas connected to any of the source areas
  1171.     for ( i = 0; i < numSourceAreas; i++ ) {
  1172.         if ( !connectedAreas[sourceAreas[i]] ) {
  1173.             GetConnectedAreas( sourceAreas[i], connectedAreas );
  1174.         }
  1175.     }
  1176.  
  1177.     // remove unconnected areas from the PVS
  1178.     for ( i = 0; i < numAreas; i++ ) {
  1179.         if ( !connectedAreas[i] ) {
  1180.             currentPVS[handle.i].pvs[i>>3] &= ~(1 << (i&7));
  1181.         }
  1182.     }
  1183.  
  1184.     return handle;
  1185. }
  1186.  
  1187. /*
  1188. ================
  1189. idPVS::MergeCurrentPVS
  1190. ================
  1191. */
  1192. pvsHandle_t idPVS::MergeCurrentPVS( pvsHandle_t pvs1, pvsHandle_t pvs2 ) const {
  1193.     int i;
  1194.     long *pvs1Ptr, *pvs2Ptr, *ptr;
  1195.     pvsHandle_t handle;
  1196.  
  1197.     if ( pvs1.i < 0 || pvs1.i >= MAX_CURRENT_PVS || pvs1.h != currentPVS[pvs1.i].handle.h ||
  1198.         pvs2.i < 0 || pvs2.i >= MAX_CURRENT_PVS || pvs2.h != currentPVS[pvs2.i].handle.h ) {
  1199.         gameLocal.Error( "idPVS::MergeCurrentPVS: invalid handle" );
  1200.     }
  1201.  
  1202.     handle = AllocCurrentPVS( pvs1.h ^ pvs2.h );
  1203.  
  1204.     ptr = reinterpret_cast<long*>(currentPVS[handle.i].pvs);
  1205.     pvs1Ptr = reinterpret_cast<long*>(currentPVS[pvs1.i].pvs);
  1206.     pvs2Ptr = reinterpret_cast<long*>(currentPVS[pvs2.i].pvs);
  1207.  
  1208.     for ( i = 0; i < areaVisLongs; i++ ) {
  1209.         *ptr++ = *pvs1Ptr++ | *pvs2Ptr++;
  1210.     }
  1211.  
  1212.     return handle;
  1213. }
  1214.  
  1215. /*
  1216. ================
  1217. idPVS::AllocCurrentPVS
  1218. ================
  1219. */
  1220. pvsHandle_t idPVS::AllocCurrentPVS( unsigned int h ) const {
  1221.     int i;
  1222.     pvsHandle_t handle;
  1223.  
  1224.     for ( i = 0; i < MAX_CURRENT_PVS; i++ ) {
  1225.         if ( currentPVS[i].handle.i == -1 ) {
  1226.             currentPVS[i].handle.i = i;
  1227.             currentPVS[i].handle.h = h;
  1228.             return currentPVS[i].handle;
  1229.         }
  1230.     }
  1231.  
  1232.     gameLocal.Error( "idPVS::AllocCurrentPVS: no free PVS left" );
  1233.  
  1234.     handle.i = -1;
  1235.     handle.h = 0;
  1236.     return handle;
  1237. }
  1238.  
  1239. /*
  1240. ================
  1241. idPVS::FreeCurrentPVS
  1242. ================
  1243. */
  1244. void idPVS::FreeCurrentPVS( pvsHandle_t handle ) const {
  1245.     if ( handle.i < 0 || handle.i >= MAX_CURRENT_PVS || handle.h != currentPVS[handle.i].handle.h ) {
  1246.         gameLocal.Error( "idPVS::FreeCurrentPVS: invalid handle" );
  1247.     }
  1248.     currentPVS[handle.i].handle.i = -1;
  1249. }
  1250.  
  1251. /*
  1252. ================
  1253. idPVS::InCurrentPVS
  1254. ================
  1255. */
  1256. bool idPVS::InCurrentPVS( const pvsHandle_t handle, const idVec3 &target ) const {
  1257.     int targetArea;
  1258.  
  1259.     if ( handle.i < 0 || handle.i >= MAX_CURRENT_PVS ||
  1260.         handle.h != currentPVS[handle.i].handle.h ) {
  1261.         gameLocal.Error( "idPVS::InCurrentPVS: invalid handle" );
  1262.     }
  1263.  
  1264.     targetArea = gameRenderWorld->PointInArea( target );
  1265.  
  1266.     if ( targetArea == -1 ) {
  1267.         return false;
  1268.     }
  1269.  
  1270.     return ( ( currentPVS[handle.i].pvs[targetArea>>3] & (1 << (targetArea&7)) ) != 0 );
  1271. }
  1272.  
  1273. /*
  1274. ================
  1275. idPVS::InCurrentPVS
  1276. ================
  1277. */
  1278. bool idPVS::InCurrentPVS( const pvsHandle_t handle, const idBounds &target ) const {
  1279.     int i, numTargetAreas, targetAreas[MAX_BOUNDS_AREAS];
  1280.  
  1281.     if ( handle.i < 0 || handle.i >= MAX_CURRENT_PVS ||
  1282.         handle.h != currentPVS[handle.i].handle.h ) {
  1283.         gameLocal.Error( "idPVS::InCurrentPVS: invalid handle" );
  1284.     }
  1285.  
  1286.     numTargetAreas = gameRenderWorld->BoundsInAreas( target, targetAreas, MAX_BOUNDS_AREAS );
  1287.  
  1288.     for ( i = 0; i < numTargetAreas; i++ ) {
  1289.         if ( currentPVS[handle.i].pvs[targetAreas[i]>>3] & (1 << (targetAreas[i]&7)) ) {
  1290.             return true;
  1291.         }
  1292.     }
  1293.     return false;
  1294. }
  1295.  
  1296. /*
  1297. ================
  1298. idPVS::InCurrentPVS
  1299. ================
  1300. */
  1301. bool idPVS::InCurrentPVS( const pvsHandle_t handle, const int targetArea ) const {
  1302.  
  1303.     if ( handle.i < 0 || handle.i >= MAX_CURRENT_PVS ||
  1304.         handle.h != currentPVS[handle.i].handle.h ) {
  1305.         gameLocal.Error( "idPVS::InCurrentPVS: invalid handle" );
  1306.     }
  1307.  
  1308.     if ( targetArea < 0 || targetArea >= numAreas ) {
  1309.         return false;
  1310.     }
  1311.  
  1312.     return ( ( currentPVS[handle.i].pvs[targetArea>>3] & (1 << (targetArea&7)) ) != 0 );
  1313. }
  1314.  
  1315. /*
  1316. ================
  1317. idPVS::InCurrentPVS
  1318. ================
  1319. */
  1320. bool idPVS::InCurrentPVS( const pvsHandle_t handle, const int *targetAreas, int numTargetAreas ) const {
  1321.     int i;
  1322.  
  1323.     if ( handle.i < 0 || handle.i >= MAX_CURRENT_PVS ||
  1324.         handle.h != currentPVS[handle.i].handle.h ) {
  1325.         gameLocal.Error( "idPVS::InCurrentPVS: invalid handle" );
  1326.     }
  1327.  
  1328.     for ( i = 0; i < numTargetAreas; i++ ) {
  1329.         if ( targetAreas[i] < 0 || targetAreas[i] >= numAreas ) {
  1330.             continue;
  1331.         }
  1332.         if ( currentPVS[handle.i].pvs[targetAreas[i]>>3] & (1 << (targetAreas[i]&7)) ) {
  1333.             return true;
  1334.         }
  1335.     }
  1336.     return false;
  1337. }
  1338.  
  1339. /*
  1340. ================
  1341. idPVS::DrawPVS
  1342. ================
  1343. */
  1344. void idPVS::DrawPVS( const idVec3 &source, const pvsType_t type ) const {
  1345.     int i, j, k, numPoints, n, sourceArea;
  1346.     exitPortal_t portal;
  1347.     idPlane plane;
  1348.     idVec3 offset;
  1349.     idVec4 *color;
  1350.     pvsHandle_t handle;
  1351.  
  1352.     sourceArea = gameRenderWorld->PointInArea( source );
  1353.  
  1354.     if ( sourceArea == -1 ) {
  1355.         return;
  1356.     }
  1357.  
  1358.     handle = SetupCurrentPVS( source, type );
  1359.  
  1360.     for ( j = 0; j < numAreas; j++ ) {
  1361.  
  1362.         if ( !( currentPVS[handle.i].pvs[j>>3] & (1 << (j&7)) ) ) {
  1363.             continue;
  1364.         }
  1365.  
  1366.         if ( j == sourceArea ) {
  1367.             color = &colorRed;
  1368.         }
  1369.         else {
  1370.             color = &colorCyan;
  1371.         }
  1372.  
  1373.         n = gameRenderWorld->NumPortalsInArea( j );
  1374.  
  1375.         // draw all the portals of the area
  1376.         for ( i = 0; i < n; i++ ) {
  1377.             portal = gameRenderWorld->GetPortal( j, i );
  1378.  
  1379.             numPoints = portal.w->GetNumPoints();
  1380.  
  1381.             portal.w->GetPlane( plane );
  1382.             offset = plane.Normal() * 4.0f;
  1383.             for ( k = 0; k < numPoints; k++ ) {
  1384.                 gameRenderWorld->DebugLine( *color, (*portal.w)[k].ToVec3() + offset, (*portal.w)[(k+1)%numPoints].ToVec3() + offset );
  1385.             }
  1386.         }
  1387.     }
  1388.  
  1389.     FreeCurrentPVS( handle );
  1390. }
  1391.  
  1392. /*
  1393. ================
  1394. idPVS::DrawPVS
  1395. ================
  1396. */
  1397. void idPVS::DrawPVS( const idBounds &source, const pvsType_t type ) const {
  1398.     int i, j, k, numPoints, n, num, areas[MAX_BOUNDS_AREAS];
  1399.     exitPortal_t portal;
  1400.     idPlane plane;
  1401.     idVec3 offset;
  1402.     idVec4 *color;
  1403.     pvsHandle_t handle;
  1404.  
  1405.     num = gameRenderWorld->BoundsInAreas( source, areas, MAX_BOUNDS_AREAS );
  1406.  
  1407.     if ( !num ) {
  1408.         return;
  1409.     }
  1410.  
  1411.     handle = SetupCurrentPVS( source, type );
  1412.  
  1413.     for ( j = 0; j < numAreas; j++ ) {
  1414.  
  1415.         if ( !( currentPVS[handle.i].pvs[j>>3] & (1 << (j&7)) ) ) {
  1416.             continue;
  1417.         }
  1418.  
  1419.         for ( i = 0; i < num; i++ ) {
  1420.             if ( j == areas[i] ) {
  1421.                 break;
  1422.             }
  1423.         }
  1424.         if ( i < num ) {
  1425.             color = &colorRed;
  1426.         }
  1427.         else {
  1428.             color = &colorCyan;
  1429.         }
  1430.  
  1431.         n = gameRenderWorld->NumPortalsInArea( j );
  1432.  
  1433.         // draw all the portals of the area
  1434.         for ( i = 0; i < n; i++ ) {
  1435.             portal = gameRenderWorld->GetPortal( j, i );
  1436.  
  1437.             numPoints = portal.w->GetNumPoints();
  1438.  
  1439.             portal.w->GetPlane( plane );
  1440.             offset = plane.Normal() * 4.0f;
  1441.             for ( k = 0; k < numPoints; k++ ) {
  1442.                 gameRenderWorld->DebugLine( *color, (*portal.w)[k].ToVec3() + offset, (*portal.w)[(k+1)%numPoints].ToVec3() + offset );
  1443.             }
  1444.         }
  1445.     }
  1446.  
  1447.     FreeCurrentPVS( handle );
  1448. }
  1449.  
  1450. /*
  1451. ================
  1452. idPVS::DrawPVS
  1453. ================
  1454. */
  1455. void idPVS::DrawCurrentPVS( const pvsHandle_t handle, const idVec3 &source ) const {
  1456.     int i, j, k, numPoints, n, sourceArea;
  1457.     exitPortal_t portal;
  1458.     idPlane plane;
  1459.     idVec3 offset;
  1460.     idVec4 *color;
  1461.  
  1462.     if ( handle.i < 0 || handle.i >= MAX_CURRENT_PVS ||
  1463.         handle.h != currentPVS[handle.i].handle.h ) {
  1464.         gameLocal.Error( "idPVS::DrawCurrentPVS: invalid handle" );
  1465.     }
  1466.  
  1467.     sourceArea = gameRenderWorld->PointInArea( source );
  1468.  
  1469.     if ( sourceArea == -1 ) {
  1470.         return;
  1471.     }
  1472.  
  1473.     for ( j = 0; j < numAreas; j++ ) {
  1474.  
  1475.         if ( !( currentPVS[handle.i].pvs[j>>3] & (1 << (j&7)) ) ) {
  1476.             continue;
  1477.         }
  1478.  
  1479.         if ( j == sourceArea ) {
  1480.             color = &colorRed;
  1481.         }
  1482.         else {
  1483.             color = &colorCyan;
  1484.         }
  1485.  
  1486.         n = gameRenderWorld->NumPortalsInArea( j );
  1487.  
  1488.         // draw all the portals of the area
  1489.         for ( i = 0; i < n; i++ ) {
  1490.             portal = gameRenderWorld->GetPortal( j, i );
  1491.  
  1492.             numPoints = portal.w->GetNumPoints();
  1493.  
  1494.             portal.w->GetPlane( plane );
  1495.             offset = plane.Normal() * 4.0f;
  1496.             for ( k = 0; k < numPoints; k++ ) {
  1497.                 gameRenderWorld->DebugLine( *color, (*portal.w)[k].ToVec3() + offset, (*portal.w)[(k+1)%numPoints].ToVec3() + offset );
  1498.             }
  1499.         }
  1500.     }
  1501. }
  1502.  
  1503. #if ASYNC_WRITE_PVS
  1504.  
  1505. /*
  1506. ===================
  1507. idPVS::WritePVS
  1508. ===================
  1509. */
  1510. void idPVS::WritePVS( const pvsHandle_t handle, idBitMsg &msg ) {
  1511.     msg.WriteData( currentPVS[ handle.i ].pvs, areaVisBytes );
  1512. }
  1513.  
  1514. /*
  1515. ===================
  1516. idPVS::ReadPVS
  1517. ===================
  1518. */
  1519. void idPVS::ReadPVS( const pvsHandle_t handle, const idBitMsg &msg ) {
  1520.     byte    l_pvs[ 256 ];
  1521.     int        i;
  1522.  
  1523.     assert( areaVisBytes <= 256 );
  1524.     msg.ReadData( l_pvs, areaVisBytes );
  1525.     if ( memcmp( l_pvs, currentPVS[ handle.i ].pvs, areaVisBytes ) ) {
  1526.         common->Printf( "PVS not matching ( %d areaVisBytes ) - server then client:\n", areaVisBytes );
  1527.         for ( i = 0; i < areaVisBytes; i++ ) {
  1528.             common->Printf( "%x ", l_pvs[ i ] );
  1529.         }
  1530.         common->Printf( "\n" );
  1531.         for ( i = 0; i < areaVisBytes; i++ ) {
  1532.             common->Printf( "%x ", currentPVS[ handle.i ].pvs[ i ] );
  1533.         }
  1534.         common->Printf( "\n" );
  1535.     }
  1536. }
  1537.  
  1538. #endif
  1539.  
  1540.