Pvs.cpp 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. 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.
  17. 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.
  18. ===========================================================================
  19. */
  20. #include "../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "Game_local.h"
  23. #define MAX_BOUNDS_AREAS 16
  24. typedef struct pvsPassage_s {
  25. byte * canSee; // bit set for all portals that can be seen through this passage
  26. } pvsPassage_t;
  27. typedef struct pvsPortal_s {
  28. int areaNum; // area this portal leads to
  29. idWinding * w; // winding goes counter clockwise seen from the area this portal is part of
  30. idBounds bounds; // winding bounds
  31. idPlane plane; // winding plane, normal points towards the area this portal leads to
  32. pvsPassage_t * passages; // passages to portals in the area this portal leads to
  33. bool done; // true if pvs is calculated for this portal
  34. byte * vis; // PVS for this portal
  35. byte * mightSee; // used during construction
  36. } pvsPortal_t;
  37. typedef struct pvsArea_s {
  38. int numPortals; // number of portals in this area
  39. idBounds bounds; // bounds of the whole area
  40. pvsPortal_t ** portals; // array with pointers to the portals of this area
  41. } pvsArea_t;
  42. typedef struct pvsStack_s {
  43. struct pvsStack_s * next; // next stack entry
  44. byte * mightSee; // bit set for all portals that might be visible through this passage/portal stack
  45. } pvsStack_t;
  46. /*
  47. ================
  48. idPVS::idPVS
  49. ================
  50. */
  51. idPVS::idPVS( void ) {
  52. int i;
  53. numAreas = 0;
  54. numPortals = 0;
  55. connectedAreas = NULL;
  56. areaQueue = NULL;
  57. areaPVS = NULL;
  58. for ( i = 0; i < MAX_CURRENT_PVS; i++ ) {
  59. currentPVS[i].handle.i = -1;
  60. currentPVS[i].handle.h = 0;
  61. currentPVS[i].pvs = NULL;
  62. }
  63. pvsAreas = NULL;
  64. pvsPortals = NULL;
  65. }
  66. /*
  67. ================
  68. idPVS::~idPVS
  69. ================
  70. */
  71. idPVS::~idPVS( void ) {
  72. Shutdown();
  73. }
  74. /*
  75. ================
  76. idPVS::GetPortalCount
  77. ================
  78. */
  79. int idPVS::GetPortalCount( void ) const {
  80. int i, na, np;
  81. na = gameRenderWorld->NumAreas();
  82. np = 0;
  83. for ( i = 0; i < na; i++ ) {
  84. np += gameRenderWorld->NumPortalsInArea( i );
  85. }
  86. return np;
  87. }
  88. /*
  89. ================
  90. idPVS::CreatePVSData
  91. ================
  92. */
  93. void idPVS::CreatePVSData( void ) {
  94. int i, j, n, cp;
  95. exitPortal_t portal;
  96. pvsArea_t *area;
  97. pvsPortal_t *p, **portalPtrs;
  98. if ( !numPortals ) {
  99. return;
  100. }
  101. pvsPortals = new pvsPortal_t[numPortals];
  102. pvsAreas = new pvsArea_t[numAreas];
  103. memset( pvsAreas, 0, numAreas * sizeof( *pvsAreas ) );
  104. cp = 0;
  105. portalPtrs = new pvsPortal_t*[numPortals];
  106. for ( i = 0; i < numAreas; i++ ) {
  107. area = &pvsAreas[i];
  108. area->bounds.Clear();
  109. area->portals = portalPtrs + cp;
  110. n = gameRenderWorld->NumPortalsInArea( i );
  111. for ( j = 0; j < n; j++ ) {
  112. portal = gameRenderWorld->GetPortal( i, j );
  113. p = &pvsPortals[cp++];
  114. // the winding goes counter clockwise seen from this area
  115. p->w = portal.w->Copy();
  116. p->areaNum = portal.areas[1]; // area[1] is always the area the portal leads to
  117. p->vis = new byte[portalVisBytes];
  118. memset( p->vis, 0, portalVisBytes );
  119. p->mightSee = new byte[portalVisBytes];
  120. memset( p->mightSee, 0, portalVisBytes );
  121. p->w->GetBounds( p->bounds );
  122. p->w->GetPlane( p->plane );
  123. // plane normal points to outside the area
  124. p->plane = -p->plane;
  125. // no PVS calculated for this portal yet
  126. p->done = false;
  127. area->portals[area->numPortals] = p;
  128. area->numPortals++;
  129. area->bounds += p->bounds;
  130. }
  131. }
  132. }
  133. /*
  134. ================
  135. idPVS::DestroyPVSData
  136. ================
  137. */
  138. void idPVS::DestroyPVSData( void ) {
  139. int i;
  140. if ( !pvsAreas ) {
  141. return;
  142. }
  143. // delete portal pointer array
  144. delete[] pvsAreas[0].portals;
  145. // delete all areas
  146. delete[] pvsAreas;
  147. pvsAreas = NULL;
  148. // delete portal data
  149. for ( i = 0; i < numPortals; i++ ) {
  150. delete[] pvsPortals[i].vis;
  151. delete[] pvsPortals[i].mightSee;
  152. delete pvsPortals[i].w;
  153. }
  154. // delete portals
  155. delete[] pvsPortals;
  156. pvsPortals = NULL;
  157. }
  158. /*
  159. ================
  160. idPVS::FloodFrontPortalPVS_r
  161. ================
  162. */
  163. void idPVS::FloodFrontPortalPVS_r( pvsPortal_t *portal, int areaNum ) const {
  164. int i, n;
  165. pvsArea_t *area;
  166. pvsPortal_t *p;
  167. area = &pvsAreas[ areaNum ];
  168. for ( i = 0; i < area->numPortals; i++ ) {
  169. p = area->portals[i];
  170. n = p - pvsPortals;
  171. // don't flood through if this portal is not at the front
  172. if ( !( portal->mightSee[ n>>3 ] & (1 << (n&7)) ) ) {
  173. continue;
  174. }
  175. // don't flood through if already visited this portal
  176. if ( portal->vis[ n>>3 ] & (1 << (n&7)) ) {
  177. continue;
  178. }
  179. // this portal might be visible
  180. portal->vis[ n>>3 ] |= (1 << (n&7));
  181. // flood through the portal
  182. FloodFrontPortalPVS_r( portal, p->areaNum );
  183. }
  184. }
  185. /*
  186. ================
  187. idPVS::FrontPortalPVS
  188. ================
  189. */
  190. void idPVS::FrontPortalPVS( void ) const {
  191. int i, j, k, n, p, side1, side2, areaSide;
  192. pvsPortal_t *p1, *p2;
  193. pvsArea_t *area;
  194. for ( i = 0; i < numPortals; i++ ) {
  195. p1 = &pvsPortals[i];
  196. for ( j = 0; j < numAreas; j++ ) {
  197. area = &pvsAreas[j];
  198. areaSide = side1 = area->bounds.PlaneSide( p1->plane );
  199. // if the whole area is at the back side of the portal
  200. if ( areaSide == PLANESIDE_BACK ) {
  201. continue;
  202. }
  203. for ( p = 0; p < area->numPortals; p++ ) {
  204. p2 = area->portals[p];
  205. // if we the whole area is not at the front we need to check
  206. if ( areaSide != PLANESIDE_FRONT ) {
  207. // if the second portal is completely at the back side of the first portal
  208. side1 = p2->bounds.PlaneSide( p1->plane );
  209. if ( side1 == PLANESIDE_BACK ) {
  210. continue;
  211. }
  212. }
  213. // if the first portal is completely at the front of the second portal
  214. side2 = p1->bounds.PlaneSide( p2->plane );
  215. if ( side2 == PLANESIDE_FRONT ) {
  216. continue;
  217. }
  218. // if the second portal is not completely at the front of the first portal
  219. if ( side1 != PLANESIDE_FRONT ) {
  220. // more accurate check
  221. for ( k = 0; k < p2->w->GetNumPoints(); k++ ) {
  222. // if more than an epsilon at the front side
  223. if ( p1->plane.Side( (*p2->w)[k].ToVec3(), ON_EPSILON ) == PLANESIDE_FRONT ) {
  224. break;
  225. }
  226. }
  227. if ( k >= p2->w->GetNumPoints() ) {
  228. continue; // second portal is at the back of the first portal
  229. }
  230. }
  231. // if the first portal is not completely at the back side of the second portal
  232. if ( side2 != PLANESIDE_BACK ) {
  233. // more accurate check
  234. for ( k = 0; k < p1->w->GetNumPoints(); k++ ) {
  235. // if more than an epsilon at the back side
  236. if ( p2->plane.Side( (*p1->w)[k].ToVec3(), ON_EPSILON ) == PLANESIDE_BACK ) {
  237. break;
  238. }
  239. }
  240. if ( k >= p1->w->GetNumPoints() ) {
  241. continue; // first portal is at the front of the second portal
  242. }
  243. }
  244. // the portal might be visible at the front
  245. n = p2 - pvsPortals;
  246. p1->mightSee[ n >> 3 ] |= 1 << (n&7);
  247. }
  248. }
  249. }
  250. // flood the front portal pvs for all portals
  251. for ( i = 0; i < numPortals; i++ ) {
  252. p1 = &pvsPortals[i];
  253. FloodFrontPortalPVS_r( p1, p1->areaNum );
  254. }
  255. }
  256. /*
  257. ===============
  258. idPVS::FloodPassagePVS_r
  259. ===============
  260. */
  261. pvsStack_t *idPVS::FloodPassagePVS_r( pvsPortal_t *source, const pvsPortal_t *portal, pvsStack_t *prevStack ) const {
  262. int i, j, n, m;
  263. pvsPortal_t *p;
  264. pvsArea_t *area;
  265. pvsStack_t *stack;
  266. pvsPassage_t *passage;
  267. long *sourceVis, *passageVis, *portalVis, *mightSee, *prevMightSee, more;
  268. area = &pvsAreas[portal->areaNum];
  269. stack = prevStack->next;
  270. // if no next stack entry allocated
  271. if ( !stack ) {
  272. stack = reinterpret_cast<pvsStack_t*>(new byte[sizeof(pvsStack_t) + portalVisBytes]);
  273. stack->mightSee = (reinterpret_cast<byte *>(stack)) + sizeof(pvsStack_t);
  274. stack->next = NULL;
  275. prevStack->next = stack;
  276. }
  277. // check all portals for flooding into other areas
  278. for ( i = 0; i < area->numPortals; i++ ) {
  279. passage = &portal->passages[i];
  280. // if this passage is completely empty
  281. if ( !passage->canSee ) {
  282. continue;
  283. }
  284. p = area->portals[i];
  285. n = p - pvsPortals;
  286. // if this portal cannot be seen through our current portal/passage stack
  287. if ( !( prevStack->mightSee[n >> 3] & (1 << (n & 7)) ) ) {
  288. continue;
  289. }
  290. // mark the portal as visible
  291. source->vis[n >> 3] |= (1 << (n & 7));
  292. // get pointers to vis data
  293. prevMightSee = reinterpret_cast<long *>(prevStack->mightSee);
  294. passageVis = reinterpret_cast<long *>(passage->canSee);
  295. sourceVis = reinterpret_cast<long *>(source->vis);
  296. mightSee = reinterpret_cast<long *>(stack->mightSee);
  297. more = 0;
  298. // use the portal PVS if it has been calculated
  299. if ( p->done ) {
  300. portalVis = reinterpret_cast<long *>(p->vis);
  301. for ( j = 0; j < portalVisLongs; j++ ) {
  302. // get new PVS which is decreased by going through this passage
  303. m = *prevMightSee++ & *passageVis++ & *portalVis++;
  304. // check if anything might be visible through this passage that wasn't yet visible
  305. more |= (m & ~(*sourceVis++));
  306. // store new PVS
  307. *mightSee++ = m;
  308. }
  309. }
  310. else {
  311. // the p->mightSee is implicitely stored in the passageVis
  312. for ( j = 0; j < portalVisLongs; j++ ) {
  313. // get new PVS which is decreased by going through this passage
  314. m = *prevMightSee++ & *passageVis++;
  315. // check if anything might be visible through this passage that wasn't yet visible
  316. more |= (m & ~(*sourceVis++));
  317. // store new PVS
  318. *mightSee++ = m;
  319. }
  320. }
  321. // if nothing more can be seen
  322. if ( !more ) {
  323. continue;
  324. }
  325. // go through the portal
  326. stack->next = FloodPassagePVS_r( source, p, stack );
  327. }
  328. return stack;
  329. }
  330. /*
  331. ===============
  332. idPVS::PassagePVS
  333. ===============
  334. */
  335. void idPVS::PassagePVS( void ) const {
  336. int i;
  337. pvsPortal_t *source;
  338. pvsStack_t *stack, *s;
  339. // create the passages
  340. CreatePassages();
  341. // allocate first stack entry
  342. stack = reinterpret_cast<pvsStack_t*>(new byte[sizeof(pvsStack_t) + portalVisBytes]);
  343. stack->mightSee = (reinterpret_cast<byte *>(stack)) + sizeof(pvsStack_t);
  344. stack->next = NULL;
  345. // calculate portal PVS by flooding through the passages
  346. for ( i = 0; i < numPortals; i++ ) {
  347. source = &pvsPortals[i];
  348. memset( source->vis, 0, portalVisBytes );
  349. memcpy( stack->mightSee, source->mightSee, portalVisBytes );
  350. FloodPassagePVS_r( source, source, stack );
  351. source->done = true;
  352. }
  353. // free the allocated stack
  354. for ( s = stack; s; s = stack ) {
  355. stack = stack->next;
  356. delete[] s;
  357. }
  358. // destroy the passages
  359. DestroyPassages();
  360. }
  361. /*
  362. ===============
  363. idPVS::AddPassageBoundaries
  364. ===============
  365. */
  366. void idPVS::AddPassageBoundaries( const idWinding &source, const idWinding &pass, bool flipClip, idPlane *bounds, int &numBounds, int maxBounds ) const {
  367. int i, j, k, l;
  368. idVec3 v1, v2, normal;
  369. float d, dist;
  370. bool flipTest, front;
  371. idPlane plane;
  372. // check all combinations
  373. for ( i = 0; i < source.GetNumPoints(); i++ ) {
  374. l = (i + 1) % source.GetNumPoints();
  375. v1 = source[l].ToVec3() - source[i].ToVec3();
  376. // find a vertex of pass that makes a plane that puts all of the
  377. // vertices of pass on the front side and all of the vertices of
  378. // source on the back side
  379. for ( j = 0; j < pass.GetNumPoints(); j++ ) {
  380. v2 = pass[j].ToVec3() - source[i].ToVec3();
  381. normal = v1.Cross( v2 );
  382. if ( normal.Normalize() < 0.01f ) {
  383. continue;
  384. }
  385. dist = normal * pass[j].ToVec3();
  386. //
  387. // find out which side of the generated seperating plane has the
  388. // source portal
  389. //
  390. flipTest = false;
  391. for ( k = 0; k < source.GetNumPoints(); k++ ) {
  392. if ( k == i || k == l ) {
  393. continue;
  394. }
  395. d = source[k].ToVec3() * normal - dist;
  396. if ( d < -ON_EPSILON ) {
  397. // source is on the negative side, so we want all
  398. // pass and target on the positive side
  399. flipTest = false;
  400. break;
  401. }
  402. else if ( d > ON_EPSILON ) {
  403. // source is on the positive side, so we want all
  404. // pass and target on the negative side
  405. flipTest = true;
  406. break;
  407. }
  408. }
  409. if ( k == source.GetNumPoints() ) {
  410. continue; // planar with source portal
  411. }
  412. // flip the normal if the source portal is backwards
  413. if (flipTest) {
  414. normal = -normal;
  415. dist = -dist;
  416. }
  417. // if all of the pass portal points are now on the positive side,
  418. // this is the seperating plane
  419. front = false;
  420. for ( k = 0; k < pass.GetNumPoints(); k++ ) {
  421. if ( k == j ) {
  422. continue;
  423. }
  424. d = pass[k].ToVec3() * normal - dist;
  425. if ( d < -ON_EPSILON ) {
  426. break;
  427. }
  428. else if ( d > ON_EPSILON ) {
  429. front = true;
  430. }
  431. }
  432. if ( k < pass.GetNumPoints() ) {
  433. continue; // points on negative side, not a seperating plane
  434. }
  435. if ( !front ) {
  436. continue; // planar with seperating plane
  437. }
  438. // flip the normal if we want the back side
  439. if ( flipClip ) {
  440. plane.SetNormal( -normal );
  441. plane.SetDist( -dist );
  442. }
  443. else {
  444. plane.SetNormal( normal );
  445. plane.SetDist( dist );
  446. }
  447. // check if the plane is already a passage boundary
  448. for ( k = 0; k < numBounds; k++ ) {
  449. if ( plane.Compare( bounds[k], 0.001f, 0.01f ) ) {
  450. break;
  451. }
  452. }
  453. if ( k < numBounds ) {
  454. break;
  455. }
  456. if ( numBounds >= maxBounds ) {
  457. gameLocal.Warning( "max passage boundaries." );
  458. break;
  459. }
  460. bounds[numBounds] = plane;
  461. numBounds++;
  462. break;
  463. }
  464. }
  465. }
  466. /*
  467. ================
  468. idPVS::CreatePassages
  469. ================
  470. */
  471. #define MAX_PASSAGE_BOUNDS 128
  472. void idPVS::CreatePassages( void ) const {
  473. int i, j, l, n, numBounds, front, passageMemory, byteNum, bitNum;
  474. int sides[MAX_PASSAGE_BOUNDS];
  475. idPlane passageBounds[MAX_PASSAGE_BOUNDS];
  476. pvsPortal_t *source, *target, *p;
  477. pvsArea_t *area;
  478. pvsPassage_t *passage;
  479. idFixedWinding winding;
  480. byte canSee, mightSee, bit;
  481. passageMemory = 0;
  482. for ( i = 0; i < numPortals; i++ ) {
  483. source = &pvsPortals[i];
  484. area = &pvsAreas[source->areaNum];
  485. source->passages = new pvsPassage_t[area->numPortals];
  486. for ( j = 0; j < area->numPortals; j++ ) {
  487. target = area->portals[j];
  488. n = target - pvsPortals;
  489. passage = &source->passages[j];
  490. // if the source portal cannot see this portal
  491. if ( !( source->mightSee[ n>>3 ] & (1 << (n&7)) ) ) {
  492. // not all portals in the area have to be visible because areas are not necesarily convex
  493. // also no passage has to be created for the portal which is the opposite of the source
  494. passage->canSee = NULL;
  495. continue;
  496. }
  497. passage->canSee = new byte[portalVisBytes];
  498. passageMemory += portalVisBytes;
  499. // boundary plane normals point inwards
  500. numBounds = 0;
  501. AddPassageBoundaries( *(source->w), *(target->w), false, passageBounds, numBounds, MAX_PASSAGE_BOUNDS );
  502. AddPassageBoundaries( *(target->w), *(source->w), true, passageBounds, numBounds, MAX_PASSAGE_BOUNDS );
  503. // get all portals visible through this passage
  504. for ( byteNum = 0; byteNum < portalVisBytes; byteNum++) {
  505. canSee = 0;
  506. mightSee = source->mightSee[byteNum] & target->mightSee[byteNum];
  507. // go through eight portals at a time to speed things up
  508. for ( bitNum = 0; bitNum < 8; bitNum++ ) {
  509. bit = 1 << bitNum;
  510. if ( !( mightSee & bit ) ) {
  511. continue;
  512. }
  513. p = &pvsPortals[(byteNum << 3) + bitNum];
  514. if ( p->areaNum == source->areaNum ) {
  515. continue;
  516. }
  517. for ( front = 0, l = 0; l < numBounds; l++ ) {
  518. sides[l] = p->bounds.PlaneSide( passageBounds[l] );
  519. // if completely at the back of the passage bounding plane
  520. if ( sides[l] == PLANESIDE_BACK ) {
  521. break;
  522. }
  523. // if completely at the front
  524. if ( sides[l] == PLANESIDE_FRONT ) {
  525. front++;
  526. }
  527. }
  528. // if completely outside the passage
  529. if ( l < numBounds ) {
  530. continue;
  531. }
  532. // if not at the front of all bounding planes and thus not completely inside the passage
  533. if ( front != numBounds ) {
  534. winding = *p->w;
  535. for ( l = 0; l < numBounds; l++ ) {
  536. // only clip if the winding possibly crosses this plane
  537. if ( sides[l] != PLANESIDE_CROSS ) {
  538. continue;
  539. }
  540. // clip away the part at the back of the bounding plane
  541. winding.ClipInPlace( passageBounds[l] );
  542. // if completely clipped away
  543. if ( !winding.GetNumPoints() ) {
  544. break;
  545. }
  546. }
  547. // if completely outside the passage
  548. if ( l < numBounds ) {
  549. continue;
  550. }
  551. }
  552. canSee |= bit;
  553. }
  554. // store results of all eight portals
  555. passage->canSee[byteNum] = canSee;
  556. }
  557. // can always see the target portal
  558. passage->canSee[n >> 3] |= (1 << (n&7));
  559. }
  560. }
  561. if ( passageMemory < 1024 ) {
  562. gameLocal.Printf( "%5d bytes passage memory used to build PVS\n", passageMemory );
  563. }
  564. else {
  565. gameLocal.Printf( "%5d KB passage memory used to build PVS\n", passageMemory>>10 );
  566. }
  567. }
  568. /*
  569. ================
  570. idPVS::DestroyPassages
  571. ================
  572. */
  573. void idPVS::DestroyPassages( void ) const {
  574. int i, j;
  575. pvsPortal_t *p;
  576. pvsArea_t *area;
  577. for ( i = 0; i < numPortals; i++ ) {
  578. p = &pvsPortals[i];
  579. area = &pvsAreas[p->areaNum];
  580. for ( j = 0; j < area->numPortals; j++ ) {
  581. if ( p->passages[j].canSee ) {
  582. delete[] p->passages[j].canSee;
  583. }
  584. }
  585. delete[] p->passages;
  586. }
  587. }
  588. /*
  589. ================
  590. idPVS::CopyPortalPVSToMightSee
  591. ================
  592. */
  593. void idPVS::CopyPortalPVSToMightSee( void ) const {
  594. int i;
  595. pvsPortal_t *p;
  596. for ( i = 0; i < numPortals; i++ ) {
  597. p = &pvsPortals[i];
  598. memcpy( p->mightSee, p->vis, portalVisBytes );
  599. }
  600. }
  601. /*
  602. ================
  603. idPVS::AreaPVSFromPortalPVS
  604. ================
  605. */
  606. int idPVS::AreaPVSFromPortalPVS( void ) const {
  607. int i, j, k, areaNum, totalVisibleAreas;
  608. long *p1, *p2;
  609. byte *pvs, *portalPVS;
  610. pvsArea_t *area;
  611. totalVisibleAreas = 0;
  612. if ( !numPortals ) {
  613. return totalVisibleAreas;
  614. }
  615. memset( areaPVS, 0, numAreas * areaVisBytes );
  616. for ( i = 0; i < numAreas; i++ ) {
  617. area = &pvsAreas[i];
  618. pvs = areaPVS + i * areaVisBytes;
  619. // the area is visible to itself
  620. pvs[ i >> 3 ] |= 1 << (i & 7);
  621. if ( !area->numPortals ) {
  622. continue;
  623. }
  624. // store the PVS of all portals in this area at the first portal
  625. for ( j = 1; j < area->numPortals; j++ ) {
  626. p1 = reinterpret_cast<long *>(area->portals[0]->vis);
  627. p2 = reinterpret_cast<long *>(area->portals[j]->vis);
  628. for ( k = 0; k < portalVisLongs; k++ ) {
  629. *p1++ |= *p2++;
  630. }
  631. }
  632. // the portals of this area are always visible
  633. for ( j = 0; j < area->numPortals; j++ ) {
  634. k = area->portals[j] - pvsPortals;
  635. area->portals[0]->vis[ k >> 3 ] |= 1 << (k & 7);
  636. }
  637. // set all areas to visible that can be seen from the portals of this area
  638. portalPVS = area->portals[0]->vis;
  639. for ( j = 0; j < numPortals; j++ ) {
  640. // if this portal is visible
  641. if ( portalPVS[j>>3] & (1 << (j&7)) ) {
  642. areaNum = pvsPortals[j].areaNum;
  643. pvs[ areaNum >> 3 ] |= 1 << (areaNum & 7);
  644. }
  645. }
  646. // count the number of visible areas
  647. for ( j = 0; j < numAreas; j++ ) {
  648. if ( pvs[j>>3] & (1 << (j&7)) ) {
  649. totalVisibleAreas++;
  650. }
  651. }
  652. }
  653. return totalVisibleAreas;
  654. }
  655. /*
  656. ================
  657. idPVS::Init
  658. ================
  659. */
  660. void idPVS::Init( void ) {
  661. int totalVisibleAreas;
  662. Shutdown();
  663. numAreas = gameRenderWorld->NumAreas();
  664. if ( numAreas <= 0 ) {
  665. return;
  666. }
  667. connectedAreas = new bool[numAreas];
  668. areaQueue = new int[numAreas];
  669. areaVisBytes = ( ((numAreas+31)&~31) >> 3);
  670. areaVisLongs = areaVisBytes/sizeof(long);
  671. areaPVS = new byte[numAreas * areaVisBytes];
  672. memset( areaPVS, 0xFF, numAreas * areaVisBytes );
  673. numPortals = GetPortalCount();
  674. portalVisBytes = ( ((numPortals+31)&~31) >> 3);
  675. portalVisLongs = portalVisBytes/sizeof(long);
  676. for ( int i = 0; i < MAX_CURRENT_PVS; i++ ) {
  677. currentPVS[i].handle.i = -1;
  678. currentPVS[i].handle.h = 0;
  679. currentPVS[i].pvs = new byte[areaVisBytes];
  680. memset( currentPVS[i].pvs, 0, areaVisBytes );
  681. }
  682. idTimer timer;
  683. timer.Start();
  684. CreatePVSData();
  685. FrontPortalPVS();
  686. CopyPortalPVSToMightSee();
  687. PassagePVS();
  688. totalVisibleAreas = AreaPVSFromPortalPVS();
  689. DestroyPVSData();
  690. timer.Stop();
  691. gameLocal.Printf( "%5.0f msec to calculate PVS\n", timer.Milliseconds() );
  692. gameLocal.Printf( "%5d areas\n", numAreas );
  693. gameLocal.Printf( "%5d portals\n", numPortals );
  694. gameLocal.Printf( "%5d areas visible on average\n", totalVisibleAreas / numAreas );
  695. if ( numAreas * areaVisBytes < 1024 ) {
  696. gameLocal.Printf( "%5d bytes PVS data\n", numAreas * areaVisBytes );
  697. }
  698. else {
  699. gameLocal.Printf( "%5d KB PVS data\n", (numAreas * areaVisBytes) >> 10 );
  700. }
  701. }
  702. /*
  703. ================
  704. idPVS::Shutdown
  705. ================
  706. */
  707. void idPVS::Shutdown( void ) {
  708. if ( connectedAreas ) {
  709. delete connectedAreas;
  710. connectedAreas = NULL;
  711. }
  712. if ( areaQueue ) {
  713. delete areaQueue;
  714. areaQueue = NULL;
  715. }
  716. if ( areaPVS ) {
  717. delete areaPVS;
  718. areaPVS = NULL;
  719. }
  720. if ( currentPVS ) {
  721. for ( int i = 0; i < MAX_CURRENT_PVS; i++ ) {
  722. delete currentPVS[i].pvs;
  723. currentPVS[i].pvs = NULL;
  724. }
  725. }
  726. }
  727. /*
  728. ================
  729. idPVS::GetConnectedAreas
  730. assumes the 'areas' array is initialized to false
  731. ================
  732. */
  733. void idPVS::GetConnectedAreas( int srcArea, bool *areas ) const {
  734. int curArea, nextArea;
  735. int queueStart, queueEnd;
  736. int i, n;
  737. exitPortal_t portal;
  738. queueStart = -1;
  739. queueEnd = 0;
  740. areas[srcArea] = true;
  741. for ( curArea = srcArea; queueStart < queueEnd; curArea = areaQueue[++queueStart] ) {
  742. n = gameRenderWorld->NumPortalsInArea( curArea );
  743. for ( i = 0; i < n; i++ ) {
  744. portal = gameRenderWorld->GetPortal( curArea, i );
  745. if ( portal.blockingBits & PS_BLOCK_VIEW ) {
  746. continue;
  747. }
  748. // area[1] is always the area the portal leads to
  749. nextArea = portal.areas[1];
  750. // if already visited this area
  751. if ( areas[nextArea] ) {
  752. continue;
  753. }
  754. // add area to queue
  755. areaQueue[queueEnd++] = nextArea;
  756. areas[nextArea] = true;
  757. }
  758. }
  759. }
  760. /*
  761. ================
  762. idPVS::GetPVSArea
  763. ================
  764. */
  765. int idPVS::GetPVSArea( const idVec3 &point ) const {
  766. return gameRenderWorld->PointInArea( point );
  767. }
  768. /*
  769. ================
  770. idPVS::GetPVSAreas
  771. ================
  772. */
  773. int idPVS::GetPVSAreas( const idBounds &bounds, int *areas, int maxAreas ) const {
  774. return gameRenderWorld->BoundsInAreas( bounds, areas, maxAreas );
  775. }
  776. /*
  777. ================
  778. idPVS::SetupCurrentPVS
  779. ================
  780. */
  781. pvsHandle_t idPVS::SetupCurrentPVS( const idVec3 &source, const pvsType_t type ) const {
  782. int sourceArea;
  783. sourceArea = gameRenderWorld->PointInArea( source );
  784. return SetupCurrentPVS( sourceArea, type );
  785. }
  786. /*
  787. ================
  788. idPVS::SetupCurrentPVS
  789. ================
  790. */
  791. pvsHandle_t idPVS::SetupCurrentPVS( const idBounds &source, const pvsType_t type ) const {
  792. int numSourceAreas, sourceAreas[MAX_BOUNDS_AREAS];
  793. numSourceAreas = gameRenderWorld->BoundsInAreas( source, sourceAreas, MAX_BOUNDS_AREAS );
  794. return SetupCurrentPVS( sourceAreas, numSourceAreas, type );
  795. }
  796. /*
  797. ================
  798. idPVS::SetupCurrentPVS
  799. ================
  800. */
  801. pvsHandle_t idPVS::SetupCurrentPVS( const int sourceArea, const pvsType_t type ) const {
  802. int i;
  803. pvsHandle_t handle;
  804. handle = AllocCurrentPVS( *reinterpret_cast<const unsigned int *>(&sourceArea) );
  805. if ( sourceArea < 0 || sourceArea >= numAreas ) {
  806. memset( currentPVS[handle.i].pvs, 0, areaVisBytes );
  807. return handle;
  808. }
  809. if ( type != PVS_CONNECTED_AREAS ) {
  810. memcpy( currentPVS[handle.i].pvs, areaPVS + sourceArea * areaVisBytes, areaVisBytes );
  811. } else {
  812. memset( currentPVS[handle.i].pvs, -1, areaVisBytes );
  813. }
  814. if ( type == PVS_ALL_PORTALS_OPEN ) {
  815. return handle;
  816. }
  817. memset( connectedAreas, 0, numAreas * sizeof( *connectedAreas ) );
  818. GetConnectedAreas( sourceArea, connectedAreas );
  819. for ( i = 0; i < numAreas; i++ ) {
  820. if ( !connectedAreas[i] ) {
  821. currentPVS[handle.i].pvs[i>>3] &= ~(1 << (i&7));
  822. }
  823. }
  824. return handle;
  825. }
  826. /*
  827. ================
  828. idPVS::SetupCurrentPVS
  829. ================
  830. */
  831. pvsHandle_t idPVS::SetupCurrentPVS( const int *sourceAreas, const int numSourceAreas, const pvsType_t type ) const {
  832. int i, j;
  833. unsigned int h;
  834. long *vis, *pvs;
  835. pvsHandle_t handle;
  836. h = 0;
  837. for ( i = 0; i < numSourceAreas; i++ ) {
  838. h ^= *reinterpret_cast<const unsigned int *>(&sourceAreas[i]);
  839. }
  840. handle = AllocCurrentPVS( h );
  841. if ( !numSourceAreas || sourceAreas[0] < 0 || sourceAreas[0] >= numAreas) {
  842. memset( currentPVS[handle.i].pvs, 0, areaVisBytes );
  843. return handle;
  844. }
  845. if ( type != PVS_CONNECTED_AREAS ) {
  846. // merge PVS of all areas the source is in
  847. memcpy( currentPVS[handle.i].pvs, areaPVS + sourceAreas[0] * areaVisBytes, areaVisBytes );
  848. for ( i = 1; i < numSourceAreas; i++ ) {
  849. assert( sourceAreas[i] >= 0 && sourceAreas[i] < numAreas );
  850. vis = reinterpret_cast<long*>(areaPVS + sourceAreas[i] * areaVisBytes);
  851. pvs = reinterpret_cast<long*>(currentPVS[handle.i].pvs);
  852. for ( j = 0; j < areaVisLongs; j++ ) {
  853. *pvs++ |= *vis++;
  854. }
  855. }
  856. } else {
  857. memset( currentPVS[handle.i].pvs, -1, areaVisBytes );
  858. }
  859. if ( type == PVS_ALL_PORTALS_OPEN ) {
  860. return handle;
  861. }
  862. memset( connectedAreas, 0, numAreas * sizeof( *connectedAreas ) );
  863. // get all areas connected to any of the source areas
  864. for ( i = 0; i < numSourceAreas; i++ ) {
  865. if ( !connectedAreas[sourceAreas[i]] ) {
  866. GetConnectedAreas( sourceAreas[i], connectedAreas );
  867. }
  868. }
  869. // remove unconnected areas from the PVS
  870. for ( i = 0; i < numAreas; i++ ) {
  871. if ( !connectedAreas[i] ) {
  872. currentPVS[handle.i].pvs[i>>3] &= ~(1 << (i&7));
  873. }
  874. }
  875. return handle;
  876. }
  877. /*
  878. ================
  879. idPVS::MergeCurrentPVS
  880. ================
  881. */
  882. pvsHandle_t idPVS::MergeCurrentPVS( pvsHandle_t pvs1, pvsHandle_t pvs2 ) const {
  883. int i;
  884. long *pvs1Ptr, *pvs2Ptr, *ptr;
  885. pvsHandle_t handle;
  886. if ( pvs1.i < 0 || pvs1.i >= MAX_CURRENT_PVS || pvs1.h != currentPVS[pvs1.i].handle.h ||
  887. pvs2.i < 0 || pvs2.i >= MAX_CURRENT_PVS || pvs2.h != currentPVS[pvs2.i].handle.h ) {
  888. gameLocal.Error( "idPVS::MergeCurrentPVS: invalid handle" );
  889. }
  890. handle = AllocCurrentPVS( pvs1.h ^ pvs2.h );
  891. ptr = reinterpret_cast<long*>(currentPVS[handle.i].pvs);
  892. pvs1Ptr = reinterpret_cast<long*>(currentPVS[pvs1.i].pvs);
  893. pvs2Ptr = reinterpret_cast<long*>(currentPVS[pvs2.i].pvs);
  894. for ( i = 0; i < areaVisLongs; i++ ) {
  895. *ptr++ = *pvs1Ptr++ | *pvs2Ptr++;
  896. }
  897. return handle;
  898. }
  899. /*
  900. ================
  901. idPVS::AllocCurrentPVS
  902. ================
  903. */
  904. pvsHandle_t idPVS::AllocCurrentPVS( unsigned int h ) const {
  905. int i;
  906. pvsHandle_t handle;
  907. for ( i = 0; i < MAX_CURRENT_PVS; i++ ) {
  908. if ( currentPVS[i].handle.i == -1 ) {
  909. currentPVS[i].handle.i = i;
  910. currentPVS[i].handle.h = h;
  911. return currentPVS[i].handle;
  912. }
  913. }
  914. gameLocal.Error( "idPVS::AllocCurrentPVS: no free PVS left" );
  915. handle.i = -1;
  916. handle.h = 0;
  917. return handle;
  918. }
  919. /*
  920. ================
  921. idPVS::FreeCurrentPVS
  922. ================
  923. */
  924. void idPVS::FreeCurrentPVS( pvsHandle_t handle ) const {
  925. if ( handle.i < 0 || handle.i >= MAX_CURRENT_PVS || handle.h != currentPVS[handle.i].handle.h ) {
  926. gameLocal.Error( "idPVS::FreeCurrentPVS: invalid handle" );
  927. }
  928. currentPVS[handle.i].handle.i = -1;
  929. }
  930. /*
  931. ================
  932. idPVS::InCurrentPVS
  933. ================
  934. */
  935. bool idPVS::InCurrentPVS( const pvsHandle_t handle, const idVec3 &target ) const {
  936. int targetArea;
  937. if ( handle.i < 0 || handle.i >= MAX_CURRENT_PVS ||
  938. handle.h != currentPVS[handle.i].handle.h ) {
  939. gameLocal.Error( "idPVS::InCurrentPVS: invalid handle" );
  940. }
  941. targetArea = gameRenderWorld->PointInArea( target );
  942. if ( targetArea == -1 ) {
  943. return false;
  944. }
  945. return ( ( currentPVS[handle.i].pvs[targetArea>>3] & (1 << (targetArea&7)) ) != 0 );
  946. }
  947. /*
  948. ================
  949. idPVS::InCurrentPVS
  950. ================
  951. */
  952. bool idPVS::InCurrentPVS( const pvsHandle_t handle, const idBounds &target ) const {
  953. int i, numTargetAreas, targetAreas[MAX_BOUNDS_AREAS];
  954. if ( handle.i < 0 || handle.i >= MAX_CURRENT_PVS ||
  955. handle.h != currentPVS[handle.i].handle.h ) {
  956. gameLocal.Error( "idPVS::InCurrentPVS: invalid handle" );
  957. }
  958. numTargetAreas = gameRenderWorld->BoundsInAreas( target, targetAreas, MAX_BOUNDS_AREAS );
  959. for ( i = 0; i < numTargetAreas; i++ ) {
  960. if ( currentPVS[handle.i].pvs[targetAreas[i]>>3] & (1 << (targetAreas[i]&7)) ) {
  961. return true;
  962. }
  963. }
  964. return false;
  965. }
  966. /*
  967. ================
  968. idPVS::InCurrentPVS
  969. ================
  970. */
  971. bool idPVS::InCurrentPVS( const pvsHandle_t handle, const int targetArea ) const {
  972. if ( handle.i < 0 || handle.i >= MAX_CURRENT_PVS ||
  973. handle.h != currentPVS[handle.i].handle.h ) {
  974. gameLocal.Error( "idPVS::InCurrentPVS: invalid handle" );
  975. }
  976. if ( targetArea < 0 || targetArea >= numAreas ) {
  977. return false;
  978. }
  979. return ( ( currentPVS[handle.i].pvs[targetArea>>3] & (1 << (targetArea&7)) ) != 0 );
  980. }
  981. /*
  982. ================
  983. idPVS::InCurrentPVS
  984. ================
  985. */
  986. bool idPVS::InCurrentPVS( const pvsHandle_t handle, const int *targetAreas, int numTargetAreas ) const {
  987. int i;
  988. if ( handle.i < 0 || handle.i >= MAX_CURRENT_PVS ||
  989. handle.h != currentPVS[handle.i].handle.h ) {
  990. gameLocal.Error( "idPVS::InCurrentPVS: invalid handle" );
  991. }
  992. for ( i = 0; i < numTargetAreas; i++ ) {
  993. if ( targetAreas[i] < 0 || targetAreas[i] >= numAreas ) {
  994. continue;
  995. }
  996. if ( currentPVS[handle.i].pvs[targetAreas[i]>>3] & (1 << (targetAreas[i]&7)) ) {
  997. return true;
  998. }
  999. }
  1000. return false;
  1001. }
  1002. /*
  1003. ================
  1004. idPVS::DrawPVS
  1005. ================
  1006. */
  1007. void idPVS::DrawPVS( const idVec3 &source, const pvsType_t type ) const {
  1008. int i, j, k, numPoints, n, sourceArea;
  1009. exitPortal_t portal;
  1010. idPlane plane;
  1011. idVec3 offset;
  1012. idVec4 *color;
  1013. pvsHandle_t handle;
  1014. sourceArea = gameRenderWorld->PointInArea( source );
  1015. if ( sourceArea == -1 ) {
  1016. return;
  1017. }
  1018. handle = SetupCurrentPVS( source, type );
  1019. for ( j = 0; j < numAreas; j++ ) {
  1020. if ( !( currentPVS[handle.i].pvs[j>>3] & (1 << (j&7)) ) ) {
  1021. continue;
  1022. }
  1023. if ( j == sourceArea ) {
  1024. color = &colorRed;
  1025. }
  1026. else {
  1027. color = &colorCyan;
  1028. }
  1029. n = gameRenderWorld->NumPortalsInArea( j );
  1030. // draw all the portals of the area
  1031. for ( i = 0; i < n; i++ ) {
  1032. portal = gameRenderWorld->GetPortal( j, i );
  1033. numPoints = portal.w->GetNumPoints();
  1034. portal.w->GetPlane( plane );
  1035. offset = plane.Normal() * 4.0f;
  1036. for ( k = 0; k < numPoints; k++ ) {
  1037. gameRenderWorld->DebugLine( *color, (*portal.w)[k].ToVec3() + offset, (*portal.w)[(k+1)%numPoints].ToVec3() + offset );
  1038. }
  1039. }
  1040. }
  1041. FreeCurrentPVS( handle );
  1042. }
  1043. /*
  1044. ================
  1045. idPVS::DrawPVS
  1046. ================
  1047. */
  1048. void idPVS::DrawPVS( const idBounds &source, const pvsType_t type ) const {
  1049. int i, j, k, numPoints, n, num, areas[MAX_BOUNDS_AREAS];
  1050. exitPortal_t portal;
  1051. idPlane plane;
  1052. idVec3 offset;
  1053. idVec4 *color;
  1054. pvsHandle_t handle;
  1055. num = gameRenderWorld->BoundsInAreas( source, areas, MAX_BOUNDS_AREAS );
  1056. if ( !num ) {
  1057. return;
  1058. }
  1059. handle = SetupCurrentPVS( source, type );
  1060. for ( j = 0; j < numAreas; j++ ) {
  1061. if ( !( currentPVS[handle.i].pvs[j>>3] & (1 << (j&7)) ) ) {
  1062. continue;
  1063. }
  1064. for ( i = 0; i < num; i++ ) {
  1065. if ( j == areas[i] ) {
  1066. break;
  1067. }
  1068. }
  1069. if ( i < num ) {
  1070. color = &colorRed;
  1071. }
  1072. else {
  1073. color = &colorCyan;
  1074. }
  1075. n = gameRenderWorld->NumPortalsInArea( j );
  1076. // draw all the portals of the area
  1077. for ( i = 0; i < n; i++ ) {
  1078. portal = gameRenderWorld->GetPortal( j, i );
  1079. numPoints = portal.w->GetNumPoints();
  1080. portal.w->GetPlane( plane );
  1081. offset = plane.Normal() * 4.0f;
  1082. for ( k = 0; k < numPoints; k++ ) {
  1083. gameRenderWorld->DebugLine( *color, (*portal.w)[k].ToVec3() + offset, (*portal.w)[(k+1)%numPoints].ToVec3() + offset );
  1084. }
  1085. }
  1086. }
  1087. FreeCurrentPVS( handle );
  1088. }
  1089. /*
  1090. ================
  1091. idPVS::DrawPVS
  1092. ================
  1093. */
  1094. void idPVS::DrawCurrentPVS( const pvsHandle_t handle, const idVec3 &source ) const {
  1095. int i, j, k, numPoints, n, sourceArea;
  1096. exitPortal_t portal;
  1097. idPlane plane;
  1098. idVec3 offset;
  1099. idVec4 *color;
  1100. if ( handle.i < 0 || handle.i >= MAX_CURRENT_PVS ||
  1101. handle.h != currentPVS[handle.i].handle.h ) {
  1102. gameLocal.Error( "idPVS::DrawCurrentPVS: invalid handle" );
  1103. }
  1104. sourceArea = gameRenderWorld->PointInArea( source );
  1105. if ( sourceArea == -1 ) {
  1106. return;
  1107. }
  1108. for ( j = 0; j < numAreas; j++ ) {
  1109. if ( !( currentPVS[handle.i].pvs[j>>3] & (1 << (j&7)) ) ) {
  1110. continue;
  1111. }
  1112. if ( j == sourceArea ) {
  1113. color = &colorRed;
  1114. }
  1115. else {
  1116. color = &colorCyan;
  1117. }
  1118. n = gameRenderWorld->NumPortalsInArea( j );
  1119. // draw all the portals of the area
  1120. for ( i = 0; i < n; i++ ) {
  1121. portal = gameRenderWorld->GetPortal( j, i );
  1122. numPoints = portal.w->GetNumPoints();
  1123. portal.w->GetPlane( plane );
  1124. offset = plane.Normal() * 4.0f;
  1125. for ( k = 0; k < numPoints; k++ ) {
  1126. gameRenderWorld->DebugLine( *color, (*portal.w)[k].ToVec3() + offset, (*portal.w)[(k+1)%numPoints].ToVec3() + offset );
  1127. }
  1128. }
  1129. }
  1130. }
  1131. #if ASYNC_WRITE_PVS
  1132. /*
  1133. ===================
  1134. idPVS::WritePVS
  1135. ===================
  1136. */
  1137. void idPVS::WritePVS( const pvsHandle_t handle, idBitMsg &msg ) {
  1138. msg.WriteData( currentPVS[ handle.i ].pvs, areaVisBytes );
  1139. }
  1140. /*
  1141. ===================
  1142. idPVS::ReadPVS
  1143. ===================
  1144. */
  1145. void idPVS::ReadPVS( const pvsHandle_t handle, const idBitMsg &msg ) {
  1146. byte l_pvs[ 256 ];
  1147. int i;
  1148. assert( areaVisBytes <= 256 );
  1149. msg.ReadData( l_pvs, areaVisBytes );
  1150. if ( memcmp( l_pvs, currentPVS[ handle.i ].pvs, areaVisBytes ) ) {
  1151. common->Printf( "PVS not matching ( %d areaVisBytes ) - server then client:\n", areaVisBytes );
  1152. for ( i = 0; i < areaVisBytes; i++ ) {
  1153. common->Printf( "%x ", l_pvs[ i ] );
  1154. }
  1155. common->Printf( "\n" );
  1156. for ( i = 0; i < areaVisBytes; i++ ) {
  1157. common->Printf( "%x ", currentPVS[ handle.i ].pvs[ i ] );
  1158. }
  1159. common->Printf( "\n" );
  1160. }
  1161. }
  1162. #endif