Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

881 lines
18 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "vis.h"
  9. #include "vmpi.h"
  10. int g_TraceClusterStart = -1;
  11. int g_TraceClusterStop = -1;
  12. /*
  13. each portal will have a list of all possible to see from first portal
  14. if (!thread->portalmightsee[portalnum])
  15. portal mightsee
  16. for p2 = all other portals in leaf
  17. get sperating planes
  18. for all portals that might be seen by p2
  19. mark as unseen if not present in seperating plane
  20. flood fill a new mightsee
  21. save as passagemightsee
  22. void CalcMightSee (leaf_t *leaf,
  23. */
  24. int CountBits (byte *bits, int numbits)
  25. {
  26. int i;
  27. int c;
  28. c = 0;
  29. for (i=0 ; i<numbits ; i++)
  30. if ( CheckBit( bits, i ) )
  31. c++;
  32. return c;
  33. }
  34. int c_fullskip;
  35. int c_portalskip, c_leafskip;
  36. int c_vistest, c_mighttest;
  37. int c_chop, c_nochop;
  38. int active;
  39. extern bool g_bVMPIEarlyExit;
  40. void CheckStack (leaf_t *leaf, threaddata_t *thread)
  41. {
  42. pstack_t *p, *p2;
  43. for (p=thread->pstack_head.next ; p ; p=p->next)
  44. {
  45. // Msg ("=");
  46. if (p->leaf == leaf)
  47. Error ("CheckStack: leaf recursion");
  48. for (p2=thread->pstack_head.next ; p2 != p ; p2=p2->next)
  49. if (p2->leaf == p->leaf)
  50. Error ("CheckStack: late leaf recursion");
  51. }
  52. // Msg ("\n");
  53. }
  54. winding_t *AllocStackWinding (pstack_t *stack)
  55. {
  56. int i;
  57. for (i=0 ; i<3 ; i++)
  58. {
  59. if (stack->freewindings[i])
  60. {
  61. stack->freewindings[i] = 0;
  62. return &stack->windings[i];
  63. }
  64. }
  65. Error ("Out of memory. AllocStackWinding: failed");
  66. return NULL;
  67. }
  68. void FreeStackWinding (winding_t *w, pstack_t *stack)
  69. {
  70. int i;
  71. i = w - stack->windings;
  72. if (i<0 || i>2)
  73. return; // not from local
  74. if (stack->freewindings[i])
  75. Error ("FreeStackWinding: allready free");
  76. stack->freewindings[i] = 1;
  77. }
  78. /*
  79. ==============
  80. ChopWinding
  81. ==============
  82. */
  83. #ifdef _WIN32
  84. #pragma warning (disable:4701)
  85. #endif
  86. winding_t *ChopWinding (winding_t *in, pstack_t *stack, plane_t *split)
  87. {
  88. vec_t dists[128];
  89. int sides[128];
  90. int counts[3];
  91. vec_t dot;
  92. int i, j;
  93. Vector mid;
  94. winding_t *neww;
  95. counts[0] = counts[1] = counts[2] = 0;
  96. // determine sides for each point
  97. for (i=0 ; i<in->numpoints ; i++)
  98. {
  99. dot = DotProduct (in->points[i], split->normal);
  100. dot -= split->dist;
  101. dists[i] = dot;
  102. if (dot > ON_VIS_EPSILON)
  103. sides[i] = SIDE_FRONT;
  104. else if (dot < -ON_VIS_EPSILON)
  105. sides[i] = SIDE_BACK;
  106. else
  107. {
  108. sides[i] = SIDE_ON;
  109. }
  110. counts[sides[i]]++;
  111. }
  112. if (!counts[1])
  113. return in; // completely on front side
  114. if (!counts[0])
  115. {
  116. FreeStackWinding (in, stack);
  117. return NULL;
  118. }
  119. sides[i] = sides[0];
  120. dists[i] = dists[0];
  121. neww = AllocStackWinding (stack);
  122. neww->numpoints = 0;
  123. for (i=0 ; i<in->numpoints ; i++)
  124. {
  125. Vector& p1 = in->points[i];
  126. if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING)
  127. {
  128. FreeStackWinding (neww, stack);
  129. return in; // can't chop -- fall back to original
  130. }
  131. if (sides[i] == SIDE_ON)
  132. {
  133. VectorCopy (p1, neww->points[neww->numpoints]);
  134. neww->numpoints++;
  135. continue;
  136. }
  137. if (sides[i] == SIDE_FRONT)
  138. {
  139. VectorCopy (p1, neww->points[neww->numpoints]);
  140. neww->numpoints++;
  141. }
  142. if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
  143. continue;
  144. if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING)
  145. {
  146. FreeStackWinding (neww, stack);
  147. return in; // can't chop -- fall back to original
  148. }
  149. // generate a split point
  150. Vector& p2 = in->points[(i+1)%in->numpoints];
  151. dot = dists[i] / (dists[i]-dists[i+1]);
  152. for (j=0 ; j<3 ; j++)
  153. { // avoid round off error when possible
  154. if (split->normal[j] == 1)
  155. mid[j] = split->dist;
  156. else if (split->normal[j] == -1)
  157. mid[j] = -split->dist;
  158. else
  159. mid[j] = p1[j] + dot*(p2[j]-p1[j]);
  160. }
  161. VectorCopy (mid, neww->points[neww->numpoints]);
  162. neww->numpoints++;
  163. }
  164. // free the original winding
  165. FreeStackWinding (in, stack);
  166. return neww;
  167. }
  168. #ifdef _WIN32
  169. #pragma warning (default:4701)
  170. #endif
  171. /*
  172. ==============
  173. ClipToSeperators
  174. Source, pass, and target are an ordering of portals.
  175. Generates seperating planes canidates by taking two points from source and one
  176. point from pass, and clips target by them.
  177. If target is totally clipped away, that portal can not be seen through.
  178. Normal clip keeps target on the same side as pass, which is correct if the
  179. order goes source, pass, target. If the order goes pass, source, target then
  180. flipclip should be set.
  181. ==============
  182. */
  183. winding_t *ClipToSeperators (winding_t *source, winding_t *pass, winding_t *target, bool flipclip, pstack_t *stack)
  184. {
  185. int i, j, k, l;
  186. plane_t plane;
  187. Vector v1, v2;
  188. float d;
  189. vec_t length;
  190. int counts[3];
  191. bool fliptest;
  192. // check all combinations
  193. for (i=0 ; i<source->numpoints ; i++)
  194. {
  195. l = (i+1)%source->numpoints;
  196. VectorSubtract (source->points[l] , source->points[i], v1);
  197. // fing a vertex of pass that makes a plane that puts all of the
  198. // vertexes of pass on the front side and all of the vertexes of
  199. // source on the back side
  200. for (j=0 ; j<pass->numpoints ; j++)
  201. {
  202. VectorSubtract (pass->points[j], source->points[i], v2);
  203. plane.normal[0] = v1[1]*v2[2] - v1[2]*v2[1];
  204. plane.normal[1] = v1[2]*v2[0] - v1[0]*v2[2];
  205. plane.normal[2] = v1[0]*v2[1] - v1[1]*v2[0];
  206. // if points don't make a valid plane, skip it
  207. length = plane.normal[0] * plane.normal[0]
  208. + plane.normal[1] * plane.normal[1]
  209. + plane.normal[2] * plane.normal[2];
  210. if (length < ON_VIS_EPSILON)
  211. continue;
  212. length = 1/sqrt(length);
  213. plane.normal[0] *= length;
  214. plane.normal[1] *= length;
  215. plane.normal[2] *= length;
  216. plane.dist = DotProduct (pass->points[j], plane.normal);
  217. //
  218. // find out which side of the generated seperating plane has the
  219. // source portal
  220. //
  221. #if 1
  222. fliptest = false;
  223. for (k=0 ; k<source->numpoints ; k++)
  224. {
  225. if (k == i || k == l)
  226. continue;
  227. d = DotProduct (source->points[k], plane.normal) - plane.dist;
  228. if (d < -ON_VIS_EPSILON)
  229. { // source is on the negative side, so we want all
  230. // pass and target on the positive side
  231. fliptest = false;
  232. break;
  233. }
  234. else if (d > ON_VIS_EPSILON)
  235. { // source is on the positive side, so we want all
  236. // pass and target on the negative side
  237. fliptest = true;
  238. break;
  239. }
  240. }
  241. if (k == source->numpoints)
  242. continue; // planar with source portal
  243. #else
  244. fliptest = flipclip;
  245. #endif
  246. //
  247. // flip the normal if the source portal is backwards
  248. //
  249. if (fliptest)
  250. {
  251. VectorSubtract (vec3_origin, plane.normal, plane.normal);
  252. plane.dist = -plane.dist;
  253. }
  254. #if 1
  255. //
  256. // if all of the pass portal points are now on the positive side,
  257. // this is the seperating plane
  258. //
  259. counts[0] = counts[1] = counts[2] = 0;
  260. for (k=0 ; k<pass->numpoints ; k++)
  261. {
  262. if (k==j)
  263. continue;
  264. d = DotProduct (pass->points[k], plane.normal) - plane.dist;
  265. if (d < -ON_VIS_EPSILON)
  266. break;
  267. else if (d > ON_VIS_EPSILON)
  268. counts[0]++;
  269. else
  270. counts[2]++;
  271. }
  272. if (k != pass->numpoints)
  273. continue; // points on negative side, not a seperating plane
  274. if (!counts[0])
  275. continue; // planar with seperating plane
  276. #else
  277. k = (j+1)%pass->numpoints;
  278. d = DotProduct (pass->points[k], plane.normal) - plane.dist;
  279. if (d < -ON_VIS_EPSILON)
  280. continue;
  281. k = (j+pass->numpoints-1)%pass->numpoints;
  282. d = DotProduct (pass->points[k], plane.normal) - plane.dist;
  283. if (d < -ON_VIS_EPSILON)
  284. continue;
  285. #endif
  286. //
  287. // flip the normal if we want the back side
  288. //
  289. if (flipclip)
  290. {
  291. VectorSubtract (vec3_origin, plane.normal, plane.normal);
  292. plane.dist = -plane.dist;
  293. }
  294. //
  295. // clip target by the seperating plane
  296. //
  297. target = ChopWinding (target, stack, &plane);
  298. if (!target)
  299. return NULL; // target is not visible
  300. // JAY: End the loop, no need to find additional separators on this edge ?
  301. // j = pass->numpoints;
  302. }
  303. }
  304. return target;
  305. }
  306. class CPortalTrace
  307. {
  308. public:
  309. CUtlVector<Vector> m_list;
  310. CThreadFastMutex m_mutex;
  311. } g_PortalTrace;
  312. void WindingCenter (winding_t *w, Vector &center)
  313. {
  314. int i;
  315. float scale;
  316. VectorCopy (vec3_origin, center);
  317. for (i=0 ; i<w->numpoints ; i++)
  318. VectorAdd (w->points[i], center, center);
  319. scale = 1.0/w->numpoints;
  320. VectorScale (center, scale, center);
  321. }
  322. Vector ClusterCenter( int cluster )
  323. {
  324. Vector mins, maxs;
  325. ClearBounds(mins, maxs);
  326. int count = leafs[cluster].portals.Count();
  327. for ( int i = 0; i < count; i++ )
  328. {
  329. winding_t *w = leafs[cluster].portals[i]->winding;
  330. for ( int j = 0; j < w->numpoints; j++ )
  331. {
  332. AddPointToBounds( w->points[j], mins, maxs );
  333. }
  334. }
  335. return (mins + maxs) * 0.5f;
  336. }
  337. void DumpPortalTrace( pstack_t *pStack )
  338. {
  339. AUTO_LOCK(g_PortalTrace.m_mutex);
  340. if ( g_PortalTrace.m_list.Count() )
  341. return;
  342. Warning("Dumped cluster trace!!!\n");
  343. Vector mid;
  344. mid = ClusterCenter( g_TraceClusterStart );
  345. g_PortalTrace.m_list.AddToTail(mid);
  346. for ( ; pStack != NULL; pStack = pStack->next )
  347. {
  348. winding_t *w = pStack->pass ? pStack->pass : pStack->portal->winding;
  349. WindingCenter (w, mid);
  350. g_PortalTrace.m_list.AddToTail(mid);
  351. for ( int i = 0; i < w->numpoints; i++ )
  352. {
  353. g_PortalTrace.m_list.AddToTail(w->points[i]);
  354. g_PortalTrace.m_list.AddToTail(mid);
  355. }
  356. for ( int i = 0; i < w->numpoints; i++ )
  357. {
  358. g_PortalTrace.m_list.AddToTail(w->points[i]);
  359. }
  360. g_PortalTrace.m_list.AddToTail(w->points[0]);
  361. g_PortalTrace.m_list.AddToTail(mid);
  362. }
  363. mid = ClusterCenter( g_TraceClusterStop );
  364. g_PortalTrace.m_list.AddToTail(mid);
  365. }
  366. void WritePortalTrace( const char *source )
  367. {
  368. Vector mid;
  369. FILE *linefile;
  370. char filename[1024];
  371. if ( !g_PortalTrace.m_list.Count() )
  372. {
  373. Warning("No trace generated from %d to %d\n", g_TraceClusterStart, g_TraceClusterStop );
  374. return;
  375. }
  376. sprintf (filename, "%s.lin", source);
  377. linefile = fopen (filename, "w");
  378. if (!linefile)
  379. Error ("Couldn't open %s\n", filename);
  380. for ( int i = 0; i < g_PortalTrace.m_list.Count(); i++ )
  381. {
  382. Vector p = g_PortalTrace.m_list[i];
  383. fprintf (linefile, "%f %f %f\n", p[0], p[1], p[2]);
  384. }
  385. fclose (linefile);
  386. Warning("Wrote %s!!!\n", filename);
  387. }
  388. /*
  389. ==================
  390. RecursiveLeafFlow
  391. Flood fill through the leafs
  392. If src_portal is NULL, this is the originating leaf
  393. ==================
  394. */
  395. void RecursiveLeafFlow (int leafnum, threaddata_t *thread, pstack_t *prevstack)
  396. {
  397. pstack_t stack;
  398. portal_t *p;
  399. plane_t backplane;
  400. leaf_t *leaf;
  401. int i, j;
  402. long *test, *might, *vis, more;
  403. int pnum;
  404. // Early-out if we're a VMPI worker that's told to exit. If we don't do this here, then the
  405. // worker might spin its wheels for a while on an expensive work unit and not be available to the pool.
  406. // This is pretty common in vis.
  407. if ( g_bVMPIEarlyExit )
  408. return;
  409. if ( leafnum == g_TraceClusterStop )
  410. {
  411. DumpPortalTrace(&thread->pstack_head);
  412. return;
  413. }
  414. thread->c_chains++;
  415. leaf = &leafs[leafnum];
  416. prevstack->next = &stack;
  417. stack.next = NULL;
  418. stack.leaf = leaf;
  419. stack.portal = NULL;
  420. might = (long *)stack.mightsee;
  421. vis = (long *)thread->base->portalvis;
  422. // check all portals for flowing into other leafs
  423. for (i=0 ; i<leaf->portals.Count() ; i++)
  424. {
  425. p = leaf->portals[i];
  426. pnum = p - portals;
  427. if ( ! (prevstack->mightsee[pnum >> 3] & (1<<(pnum&7)) ) )
  428. {
  429. continue; // can't possibly see it
  430. }
  431. // if the portal can't see anything we haven't allready seen, skip it
  432. if (p->status == stat_done)
  433. {
  434. test = (long *)p->portalvis;
  435. }
  436. else
  437. {
  438. test = (long *)p->portalflood;
  439. }
  440. more = 0;
  441. for (j=0 ; j<portallongs ; j++)
  442. {
  443. might[j] = ((long *)prevstack->mightsee)[j] & test[j];
  444. more |= (might[j] & ~vis[j]);
  445. }
  446. if ( !more && CheckBit( thread->base->portalvis, pnum ) )
  447. { // can't see anything new
  448. continue;
  449. }
  450. // get plane of portal, point normal into the neighbor leaf
  451. stack.portalplane = p->plane;
  452. VectorSubtract (vec3_origin, p->plane.normal, backplane.normal);
  453. backplane.dist = -p->plane.dist;
  454. stack.portal = p;
  455. stack.next = NULL;
  456. stack.freewindings[0] = 1;
  457. stack.freewindings[1] = 1;
  458. stack.freewindings[2] = 1;
  459. float d = DotProduct (p->origin, thread->pstack_head.portalplane.normal);
  460. d -= thread->pstack_head.portalplane.dist;
  461. if (d < -p->radius)
  462. {
  463. continue;
  464. }
  465. else if (d > p->radius)
  466. {
  467. stack.pass = p->winding;
  468. }
  469. else
  470. {
  471. stack.pass = ChopWinding (p->winding, &stack, &thread->pstack_head.portalplane);
  472. if (!stack.pass)
  473. continue;
  474. }
  475. d = DotProduct (thread->base->origin, p->plane.normal);
  476. d -= p->plane.dist;
  477. if (d > thread->base->radius)
  478. {
  479. continue;
  480. }
  481. else if (d < -thread->base->radius)
  482. {
  483. stack.source = prevstack->source;
  484. }
  485. else
  486. {
  487. stack.source = ChopWinding (prevstack->source, &stack, &backplane);
  488. if (!stack.source)
  489. continue;
  490. }
  491. if (!prevstack->pass)
  492. { // the second leaf can only be blocked if coplanar
  493. // mark the portal as visible
  494. SetBit( thread->base->portalvis, pnum );
  495. RecursiveLeafFlow (p->leaf, thread, &stack);
  496. continue;
  497. }
  498. stack.pass = ClipToSeperators (stack.source, prevstack->pass, stack.pass, false, &stack);
  499. if (!stack.pass)
  500. continue;
  501. stack.pass = ClipToSeperators (prevstack->pass, stack.source, stack.pass, true, &stack);
  502. if (!stack.pass)
  503. continue;
  504. // mark the portal as visible
  505. SetBit( thread->base->portalvis, pnum );
  506. // flow through it for real
  507. RecursiveLeafFlow (p->leaf, thread, &stack);
  508. }
  509. }
  510. /*
  511. ===============
  512. PortalFlow
  513. generates the portalvis bit vector
  514. ===============
  515. */
  516. void PortalFlow (int iThread, int portalnum)
  517. {
  518. threaddata_t data;
  519. int i;
  520. portal_t *p;
  521. int c_might, c_can;
  522. p = sorted_portals[portalnum];
  523. p->status = stat_working;
  524. c_might = CountBits (p->portalflood, g_numportals*2);
  525. memset (&data, 0, sizeof(data));
  526. data.base = p;
  527. data.pstack_head.portal = p;
  528. data.pstack_head.source = p->winding;
  529. data.pstack_head.portalplane = p->plane;
  530. for (i=0 ; i<portallongs ; i++)
  531. ((long *)data.pstack_head.mightsee)[i] = ((long *)p->portalflood)[i];
  532. RecursiveLeafFlow (p->leaf, &data, &data.pstack_head);
  533. p->status = stat_done;
  534. c_can = CountBits (p->portalvis, g_numportals*2);
  535. qprintf ("portal:%4i mightsee:%4i cansee:%4i (%i chains)\n",
  536. (int)(p - portals), c_might, c_can, data.c_chains);
  537. }
  538. /*
  539. ===============================================================================
  540. This is a rough first-order aproximation that is used to trivially reject some
  541. of the final calculations.
  542. Calculates portalfront and portalflood bit vectors
  543. ===============================================================================
  544. */
  545. int c_flood, c_vis;
  546. /*
  547. ==================
  548. SimpleFlood
  549. ==================
  550. */
  551. void SimpleFlood (portal_t *srcportal, int leafnum)
  552. {
  553. int i;
  554. leaf_t *leaf;
  555. portal_t *p;
  556. int pnum;
  557. leaf = &leafs[leafnum];
  558. for (i=0 ; i<leaf->portals.Count(); i++)
  559. {
  560. p = leaf->portals[i];
  561. pnum = p - portals;
  562. if ( !CheckBit( srcportal->portalfront, pnum ) )
  563. continue;
  564. if ( CheckBit( srcportal->portalflood, pnum ) )
  565. continue;
  566. SetBit( srcportal->portalflood, pnum );
  567. SimpleFlood (srcportal, p->leaf);
  568. }
  569. }
  570. /*
  571. ==============
  572. BasePortalVis
  573. ==============
  574. */
  575. void BasePortalVis (int iThread, int portalnum)
  576. {
  577. int j, k;
  578. portal_t *tp, *p;
  579. float d;
  580. winding_t *w;
  581. Vector segment;
  582. double dist2, minDist2;
  583. // get the portal
  584. p = portals+portalnum;
  585. //
  586. // allocate memory for bitwise vis solutions for this portal
  587. //
  588. p->portalfront = (byte*)malloc (portalbytes);
  589. memset (p->portalfront, 0, portalbytes);
  590. p->portalflood = (byte*)malloc (portalbytes);
  591. memset (p->portalflood, 0, portalbytes);
  592. p->portalvis = (byte*)malloc (portalbytes);
  593. memset (p->portalvis, 0, portalbytes);
  594. //
  595. // test the given portal against all of the portals in the map
  596. //
  597. for (j=0, tp = portals ; j<g_numportals*2 ; j++, tp++)
  598. {
  599. // don't test against itself
  600. if (j == portalnum)
  601. continue;
  602. //
  603. //
  604. //
  605. w = tp->winding;
  606. for (k=0 ; k<w->numpoints ; k++)
  607. {
  608. d = DotProduct (w->points[k], p->plane.normal) - p->plane.dist;
  609. if (d > ON_VIS_EPSILON)
  610. break;
  611. }
  612. if (k == w->numpoints)
  613. continue; // no points on front
  614. //
  615. //
  616. //
  617. w = p->winding;
  618. for (k=0 ; k<w->numpoints ; k++)
  619. {
  620. d = DotProduct (w->points[k], tp->plane.normal) - tp->plane.dist;
  621. if (d < -ON_VIS_EPSILON)
  622. break;
  623. }
  624. if (k == w->numpoints)
  625. continue; // no points on front
  626. //
  627. // if using radius visibility -- check to see if any portal points lie inside of the
  628. // radius given
  629. //
  630. if( g_bUseRadius )
  631. {
  632. w = tp->winding;
  633. minDist2 = 1024000000.0; // 32000^2
  634. for( k = 0; k < w->numpoints; k++ )
  635. {
  636. VectorSubtract( w->points[k], p->origin, segment );
  637. dist2 = ( segment[0] * segment[0] ) + ( segment[1] * segment[1] ) + ( segment[2] * segment[2] );
  638. if( dist2 < minDist2 )
  639. {
  640. minDist2 = dist2;
  641. }
  642. }
  643. if( minDist2 > g_VisRadius )
  644. continue;
  645. }
  646. // add current portal to given portal's list of visible portals
  647. SetBit( p->portalfront, j );
  648. }
  649. SimpleFlood (p, p->leaf);
  650. p->nummightsee = CountBits (p->portalflood, g_numportals*2);
  651. // Msg ("portal %i: %i mightsee\n", portalnum, p->nummightsee);
  652. c_flood += p->nummightsee;
  653. }
  654. /*
  655. ===============================================================================
  656. This is a second order aproximation
  657. Calculates portalvis bit vector
  658. WAAAAAAY too slow.
  659. ===============================================================================
  660. */
  661. /*
  662. ==================
  663. RecursiveLeafBitFlow
  664. ==================
  665. */
  666. void RecursiveLeafBitFlow (int leafnum, byte *mightsee, byte *cansee)
  667. {
  668. portal_t *p;
  669. leaf_t *leaf;
  670. int i, j;
  671. long more;
  672. int pnum;
  673. byte newmight[MAX_PORTALS/8];
  674. leaf = &leafs[leafnum];
  675. // check all portals for flowing into other leafs
  676. for (i=0 ; i<leaf->portals.Count(); i++)
  677. {
  678. p = leaf->portals[i];
  679. pnum = p - portals;
  680. // if some previous portal can't see it, skip
  681. if ( !CheckBit( mightsee, pnum ) )
  682. continue;
  683. // if this portal can see some portals we mightsee, recurse
  684. more = 0;
  685. for (j=0 ; j<portallongs ; j++)
  686. {
  687. ((long *)newmight)[j] = ((long *)mightsee)[j]
  688. & ((long *)p->portalflood)[j];
  689. more |= ((long *)newmight)[j] & ~((long *)cansee)[j];
  690. }
  691. if (!more)
  692. continue; // can't see anything new
  693. SetBit( cansee, pnum );
  694. RecursiveLeafBitFlow (p->leaf, newmight, cansee);
  695. }
  696. }
  697. /*
  698. ==============
  699. BetterPortalVis
  700. ==============
  701. */
  702. void BetterPortalVis (int portalnum)
  703. {
  704. portal_t *p;
  705. p = portals+portalnum;
  706. RecursiveLeafBitFlow (p->leaf, p->portalflood, p->portalvis);
  707. // build leaf vis information
  708. p->nummightsee = CountBits (p->portalvis, g_numportals*2);
  709. c_vis += p->nummightsee;
  710. }