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