portals.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1999-2005 Id Software, Inc.
  4. This file is part of Quake III Arena source code.
  5. Quake III Arena source code is free software; you can redistribute it
  6. and/or modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2 of the License,
  8. or (at your option) any later version.
  9. Quake III Arena source code is distributed in the hope that it will be
  10. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with Foobar; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. ===========================================================================
  17. */
  18. #include "qbsp.h"
  19. int c_active_portals;
  20. int c_peak_portals;
  21. int c_boundary;
  22. int c_boundary_sides;
  23. /*
  24. ===========
  25. AllocPortal
  26. ===========
  27. */
  28. portal_t *AllocPortal (void)
  29. {
  30. portal_t *p;
  31. if (numthreads == 1)
  32. c_active_portals++;
  33. if (c_active_portals > c_peak_portals)
  34. c_peak_portals = c_active_portals;
  35. p = malloc (sizeof(portal_t));
  36. memset (p, 0, sizeof(portal_t));
  37. return p;
  38. }
  39. void FreePortal (portal_t *p)
  40. {
  41. if (p->winding)
  42. FreeWinding (p->winding);
  43. if (numthreads == 1)
  44. c_active_portals--;
  45. free (p);
  46. }
  47. //==============================================================
  48. /*
  49. =============
  50. Portal_Passable
  51. Returns true if the portal has non-opaque leafs on both sides
  52. =============
  53. */
  54. qboolean Portal_Passable(portal_t *p) {
  55. if (!p->onnode) {
  56. return qfalse; // to global outsideleaf
  57. }
  58. if (p->nodes[0]->planenum != PLANENUM_LEAF
  59. || p->nodes[1]->planenum != PLANENUM_LEAF) {
  60. Error ("Portal_EntityFlood: not a leaf");
  61. }
  62. if ( !p->nodes[0]->opaque && !p->nodes[1]->opaque ) {
  63. return qtrue;
  64. }
  65. return qfalse;
  66. }
  67. //=============================================================================
  68. int c_tinyportals;
  69. /*
  70. =============
  71. AddPortalToNodes
  72. =============
  73. */
  74. void AddPortalToNodes (portal_t *p, node_t *front, node_t *back)
  75. {
  76. if (p->nodes[0] || p->nodes[1])
  77. Error ("AddPortalToNode: allready included");
  78. p->nodes[0] = front;
  79. p->next[0] = front->portals;
  80. front->portals = p;
  81. p->nodes[1] = back;
  82. p->next[1] = back->portals;
  83. back->portals = p;
  84. }
  85. /*
  86. =============
  87. RemovePortalFromNode
  88. =============
  89. */
  90. void RemovePortalFromNode (portal_t *portal, node_t *l)
  91. {
  92. portal_t **pp, *t;
  93. // remove reference to the current portal
  94. pp = &l->portals;
  95. while (1)
  96. {
  97. t = *pp;
  98. if (!t)
  99. Error ("RemovePortalFromNode: portal not in leaf");
  100. if ( t == portal )
  101. break;
  102. if (t->nodes[0] == l)
  103. pp = &t->next[0];
  104. else if (t->nodes[1] == l)
  105. pp = &t->next[1];
  106. else
  107. Error ("RemovePortalFromNode: portal not bounding leaf");
  108. }
  109. if (portal->nodes[0] == l)
  110. {
  111. *pp = portal->next[0];
  112. portal->nodes[0] = NULL;
  113. }
  114. else if (portal->nodes[1] == l)
  115. {
  116. *pp = portal->next[1];
  117. portal->nodes[1] = NULL;
  118. }
  119. }
  120. //============================================================================
  121. void PrintPortal (portal_t *p)
  122. {
  123. int i;
  124. winding_t *w;
  125. w = p->winding;
  126. for (i=0 ; i<w->numpoints ; i++)
  127. _printf ("(%5.0f,%5.0f,%5.0f)\n",w->p[i][0]
  128. , w->p[i][1], w->p[i][2]);
  129. }
  130. /*
  131. ================
  132. MakeHeadnodePortals
  133. The created portals will face the global outside_node
  134. ================
  135. */
  136. #define SIDESPACE 8
  137. void MakeHeadnodePortals (tree_t *tree)
  138. {
  139. vec3_t bounds[2];
  140. int i, j, n;
  141. portal_t *p, *portals[6];
  142. plane_t bplanes[6], *pl;
  143. node_t *node;
  144. node = tree->headnode;
  145. // pad with some space so there will never be null volume leafs
  146. for (i=0 ; i<3 ; i++)
  147. {
  148. bounds[0][i] = tree->mins[i] - SIDESPACE;
  149. bounds[1][i] = tree->maxs[i] + SIDESPACE;
  150. if ( bounds[0][i] >= bounds[1][i] ) {
  151. Error( "Backwards tree volume" );
  152. }
  153. }
  154. tree->outside_node.planenum = PLANENUM_LEAF;
  155. tree->outside_node.brushlist = NULL;
  156. tree->outside_node.portals = NULL;
  157. tree->outside_node.opaque = qfalse;
  158. for (i=0 ; i<3 ; i++)
  159. for (j=0 ; j<2 ; j++)
  160. {
  161. n = j*3 + i;
  162. p = AllocPortal ();
  163. portals[n] = p;
  164. pl = &bplanes[n];
  165. memset (pl, 0, sizeof(*pl));
  166. if (j)
  167. {
  168. pl->normal[i] = -1;
  169. pl->dist = -bounds[j][i];
  170. }
  171. else
  172. {
  173. pl->normal[i] = 1;
  174. pl->dist = bounds[j][i];
  175. }
  176. p->plane = *pl;
  177. p->winding = BaseWindingForPlane (pl->normal, pl->dist);
  178. AddPortalToNodes (p, node, &tree->outside_node);
  179. }
  180. // clip the basewindings by all the other planes
  181. for (i=0 ; i<6 ; i++)
  182. {
  183. for (j=0 ; j<6 ; j++)
  184. {
  185. if (j == i)
  186. continue;
  187. ChopWindingInPlace (&portals[i]->winding, bplanes[j].normal, bplanes[j].dist, ON_EPSILON);
  188. }
  189. }
  190. }
  191. //===================================================
  192. /*
  193. ================
  194. BaseWindingForNode
  195. ================
  196. */
  197. #define BASE_WINDING_EPSILON 0.001
  198. #define SPLIT_WINDING_EPSILON 0.001
  199. winding_t *BaseWindingForNode (node_t *node)
  200. {
  201. winding_t *w;
  202. node_t *n;
  203. plane_t *plane;
  204. vec3_t normal;
  205. vec_t dist;
  206. w = BaseWindingForPlane (mapplanes[node->planenum].normal
  207. , mapplanes[node->planenum].dist);
  208. // clip by all the parents
  209. for (n=node->parent ; n && w ; )
  210. {
  211. plane = &mapplanes[n->planenum];
  212. if (n->children[0] == node)
  213. { // take front
  214. ChopWindingInPlace (&w, plane->normal, plane->dist, BASE_WINDING_EPSILON);
  215. }
  216. else
  217. { // take back
  218. VectorSubtract (vec3_origin, plane->normal, normal);
  219. dist = -plane->dist;
  220. ChopWindingInPlace (&w, normal, dist, BASE_WINDING_EPSILON);
  221. }
  222. node = n;
  223. n = n->parent;
  224. }
  225. return w;
  226. }
  227. //============================================================
  228. /*
  229. ==================
  230. MakeNodePortal
  231. create the new portal by taking the full plane winding for the cutting plane
  232. and clipping it by all of parents of this node
  233. ==================
  234. */
  235. void MakeNodePortal (node_t *node)
  236. {
  237. portal_t *new_portal, *p;
  238. winding_t *w;
  239. vec3_t normal;
  240. float dist;
  241. int side;
  242. w = BaseWindingForNode (node);
  243. // clip the portal by all the other portals in the node
  244. for (p = node->portals ; p && w; p = p->next[side])
  245. {
  246. if (p->nodes[0] == node)
  247. {
  248. side = 0;
  249. VectorCopy (p->plane.normal, normal);
  250. dist = p->plane.dist;
  251. }
  252. else if (p->nodes[1] == node)
  253. {
  254. side = 1;
  255. VectorSubtract (vec3_origin, p->plane.normal, normal);
  256. dist = -p->plane.dist;
  257. }
  258. else
  259. Error ("CutNodePortals_r: mislinked portal");
  260. ChopWindingInPlace (&w, normal, dist, CLIP_EPSILON);
  261. }
  262. if (!w)
  263. {
  264. return;
  265. }
  266. if (WindingIsTiny (w))
  267. {
  268. c_tinyportals++;
  269. FreeWinding (w);
  270. return;
  271. }
  272. new_portal = AllocPortal ();
  273. new_portal->plane = mapplanes[node->planenum];
  274. new_portal->onnode = node;
  275. new_portal->winding = w;
  276. new_portal->hint = node->hint;
  277. AddPortalToNodes (new_portal, node->children[0], node->children[1]);
  278. }
  279. /*
  280. ==============
  281. SplitNodePortals
  282. Move or split the portals that bound node so that the node's
  283. children have portals instead of node.
  284. ==============
  285. */
  286. void SplitNodePortals (node_t *node)
  287. {
  288. portal_t *p, *next_portal, *new_portal;
  289. node_t *f, *b, *other_node;
  290. int side;
  291. plane_t *plane;
  292. winding_t *frontwinding, *backwinding;
  293. plane = &mapplanes[node->planenum];
  294. f = node->children[0];
  295. b = node->children[1];
  296. for (p = node->portals ; p ; p = next_portal)
  297. {
  298. if (p->nodes[0] == node)
  299. side = 0;
  300. else if (p->nodes[1] == node)
  301. side = 1;
  302. else
  303. Error ("SplitNodePortals: mislinked portal");
  304. next_portal = p->next[side];
  305. other_node = p->nodes[!side];
  306. RemovePortalFromNode (p, p->nodes[0]);
  307. RemovePortalFromNode (p, p->nodes[1]);
  308. //
  309. // cut the portal into two portals, one on each side of the cut plane
  310. //
  311. ClipWindingEpsilon (p->winding, plane->normal, plane->dist,
  312. SPLIT_WINDING_EPSILON, &frontwinding, &backwinding);
  313. if (frontwinding && WindingIsTiny(frontwinding))
  314. {
  315. if (!f->tinyportals)
  316. VectorCopy(frontwinding->p[0], f->referencepoint);
  317. f->tinyportals++;
  318. if (!other_node->tinyportals)
  319. VectorCopy(frontwinding->p[0], other_node->referencepoint);
  320. other_node->tinyportals++;
  321. FreeWinding (frontwinding);
  322. frontwinding = NULL;
  323. c_tinyportals++;
  324. }
  325. if (backwinding && WindingIsTiny(backwinding))
  326. {
  327. if (!b->tinyportals)
  328. VectorCopy(backwinding->p[0], b->referencepoint);
  329. b->tinyportals++;
  330. if (!other_node->tinyportals)
  331. VectorCopy(backwinding->p[0], other_node->referencepoint);
  332. other_node->tinyportals++;
  333. FreeWinding (backwinding);
  334. backwinding = NULL;
  335. c_tinyportals++;
  336. }
  337. if (!frontwinding && !backwinding)
  338. { // tiny windings on both sides
  339. continue;
  340. }
  341. if (!frontwinding)
  342. {
  343. FreeWinding (backwinding);
  344. if (side == 0)
  345. AddPortalToNodes (p, b, other_node);
  346. else
  347. AddPortalToNodes (p, other_node, b);
  348. continue;
  349. }
  350. if (!backwinding)
  351. {
  352. FreeWinding (frontwinding);
  353. if (side == 0)
  354. AddPortalToNodes (p, f, other_node);
  355. else
  356. AddPortalToNodes (p, other_node, f);
  357. continue;
  358. }
  359. // the winding is split
  360. new_portal = AllocPortal ();
  361. *new_portal = *p;
  362. new_portal->winding = backwinding;
  363. FreeWinding (p->winding);
  364. p->winding = frontwinding;
  365. if (side == 0)
  366. {
  367. AddPortalToNodes (p, f, other_node);
  368. AddPortalToNodes (new_portal, b, other_node);
  369. }
  370. else
  371. {
  372. AddPortalToNodes (p, other_node, f);
  373. AddPortalToNodes (new_portal, other_node, b);
  374. }
  375. }
  376. node->portals = NULL;
  377. }
  378. /*
  379. ================
  380. CalcNodeBounds
  381. ================
  382. */
  383. void CalcNodeBounds (node_t *node)
  384. {
  385. portal_t *p;
  386. int s;
  387. int i;
  388. // calc mins/maxs for both leafs and nodes
  389. ClearBounds (node->mins, node->maxs);
  390. for (p = node->portals ; p ; p = p->next[s])
  391. {
  392. s = (p->nodes[1] == node);
  393. for (i=0 ; i<p->winding->numpoints ; i++)
  394. AddPointToBounds (p->winding->p[i], node->mins, node->maxs);
  395. }
  396. }
  397. /*
  398. ==================
  399. MakeTreePortals_r
  400. ==================
  401. */
  402. void MakeTreePortals_r (node_t *node)
  403. {
  404. int i;
  405. CalcNodeBounds (node);
  406. if (node->mins[0] >= node->maxs[0])
  407. {
  408. _printf ("WARNING: node without a volume\n");
  409. _printf("node has %d tiny portals\n", node->tinyportals);
  410. _printf("node reference point %1.2f %1.2f %1.2f\n", node->referencepoint[0],
  411. node->referencepoint[1],
  412. node->referencepoint[2]);
  413. }
  414. for (i=0 ; i<3 ; i++)
  415. {
  416. if (node->mins[i] < MIN_WORLD_COORD || node->maxs[i] > MAX_WORLD_COORD)
  417. {
  418. _printf ("WARNING: node with unbounded volume\n");
  419. break;
  420. }
  421. }
  422. if (node->planenum == PLANENUM_LEAF)
  423. return;
  424. MakeNodePortal (node);
  425. SplitNodePortals (node);
  426. MakeTreePortals_r (node->children[0]);
  427. MakeTreePortals_r (node->children[1]);
  428. }
  429. /*
  430. ==================
  431. MakeTreePortals
  432. ==================
  433. */
  434. void MakeTreePortals (tree_t *tree)
  435. {
  436. qprintf( "----- MakeTreePortals -----\n");
  437. MakeHeadnodePortals (tree);
  438. MakeTreePortals_r (tree->headnode);
  439. qprintf("%6d tiny portals\n", c_tinyportals);
  440. }
  441. /*
  442. =========================================================
  443. FLOOD ENTITIES
  444. =========================================================
  445. */
  446. int c_floodedleafs;
  447. /*
  448. =============
  449. FloodPortals_r
  450. =============
  451. */
  452. void FloodPortals_r (node_t *node, int dist) {
  453. portal_t *p;
  454. int s;
  455. if ( node->occupied ) {
  456. return;
  457. }
  458. if ( node->opaque ) {
  459. return;
  460. }
  461. c_floodedleafs++;
  462. node->occupied = dist;
  463. for (p=node->portals ; p ; p = p->next[s]) {
  464. s = (p->nodes[1] == node);
  465. FloodPortals_r (p->nodes[!s], dist+1);
  466. }
  467. }
  468. /*
  469. =============
  470. PlaceOccupant
  471. =============
  472. */
  473. qboolean PlaceOccupant (node_t *headnode, vec3_t origin, entity_t *occupant)
  474. {
  475. node_t *node;
  476. vec_t d;
  477. plane_t *plane;
  478. // find the leaf to start in
  479. node = headnode;
  480. while (node->planenum != PLANENUM_LEAF)
  481. {
  482. plane = &mapplanes[node->planenum];
  483. d = DotProduct (origin, plane->normal) - plane->dist;
  484. if (d >= 0)
  485. node = node->children[0];
  486. else
  487. node = node->children[1];
  488. }
  489. if ( node->opaque )
  490. return qfalse;
  491. node->occupant = occupant;
  492. FloodPortals_r (node, 1);
  493. return qtrue;
  494. }
  495. /*
  496. =============
  497. FloodEntities
  498. Marks all nodes that can be reached by entites
  499. =============
  500. */
  501. qboolean FloodEntities( tree_t *tree ) {
  502. int i;
  503. vec3_t origin;
  504. const char *cl;
  505. qboolean inside;
  506. node_t *headnode;
  507. headnode = tree->headnode;
  508. qprintf ("--- FloodEntities ---\n");
  509. inside = qfalse;
  510. tree->outside_node.occupied = 0;
  511. c_floodedleafs = 0;
  512. for (i=1 ; i<num_entities ; i++)
  513. {
  514. GetVectorForKey (&entities[i], "origin", origin);
  515. if (VectorCompare(origin, vec3_origin))
  516. continue;
  517. cl = ValueForKey (&entities[i], "classname");
  518. origin[2] += 1; // so objects on floor are ok
  519. if (PlaceOccupant (headnode, origin, &entities[i]))
  520. inside = qtrue;
  521. }
  522. qprintf("%5i flooded leafs\n", c_floodedleafs );
  523. if (!inside)
  524. {
  525. qprintf ("no entities in open -- no filling\n");
  526. }
  527. else if (tree->outside_node.occupied)
  528. {
  529. qprintf ("entity reached from outside -- no filling\n");
  530. }
  531. return (qboolean)(inside && !tree->outside_node.occupied);
  532. }
  533. /*
  534. =========================================================
  535. FLOOD AREAS
  536. =========================================================
  537. */
  538. int c_areas;
  539. /*
  540. =============
  541. FloodAreas_r
  542. =============
  543. */
  544. void FloodAreas_r (node_t *node)
  545. {
  546. portal_t *p;
  547. int s;
  548. bspbrush_t *b;
  549. if ( node->areaportal ) {
  550. //
  551. if ( node->area == -1 ) {
  552. node->area = c_areas;
  553. }
  554. // this node is part of an area portal brush
  555. b = node->brushlist->original;
  556. // if the current area has allready touched this
  557. // portal, we are done
  558. if (b->portalareas[0] == c_areas || b->portalareas[1] == c_areas)
  559. return;
  560. // note the current area as bounding the portal
  561. if (b->portalareas[1] != -1)
  562. {
  563. _printf ("WARNING: areaportal brush %i touches > 2 areas\n", b->brushnum );
  564. return;
  565. }
  566. if (b->portalareas[0] != -1) {
  567. b->portalareas[1] = c_areas;
  568. } else {
  569. b->portalareas[0] = c_areas;
  570. }
  571. return;
  572. }
  573. if (node->area != -1) {
  574. return; // allready got it
  575. }
  576. if ( node->cluster == -1 ) {
  577. return;
  578. }
  579. node->area = c_areas;
  580. for (p=node->portals ; p ; p = p->next[s])
  581. {
  582. s = (p->nodes[1] == node);
  583. if ( !Portal_Passable(p) )
  584. continue;
  585. FloodAreas_r (p->nodes[!s]);
  586. }
  587. }
  588. /*
  589. =============
  590. FindAreas_r
  591. Just decend the tree, and for each node that hasn't had an
  592. area set, flood fill out from there
  593. =============
  594. */
  595. void FindAreas_r (node_t *node)
  596. {
  597. if (node->planenum != PLANENUM_LEAF)
  598. {
  599. FindAreas_r (node->children[0]);
  600. FindAreas_r (node->children[1]);
  601. return;
  602. }
  603. if (node->opaque)
  604. return;
  605. if (node->areaportal)
  606. return;
  607. if (node->area != -1)
  608. return; // allready got it
  609. FloodAreas_r (node);
  610. c_areas++;
  611. }
  612. /*
  613. =============
  614. CheckAreas_r
  615. =============
  616. */
  617. void CheckAreas_r (node_t *node)
  618. {
  619. bspbrush_t *b;
  620. if (node->planenum != PLANENUM_LEAF)
  621. {
  622. CheckAreas_r (node->children[0]);
  623. CheckAreas_r (node->children[1]);
  624. return;
  625. }
  626. if (node->opaque)
  627. return;
  628. if (node->cluster != -1)
  629. if (node->area == -1)
  630. _printf("WARNING: cluster %d has area set to -1\n", node->cluster);
  631. if (node->areaportal)
  632. {
  633. b = node->brushlist->original;
  634. // check if the areaportal touches two areas
  635. if (b->portalareas[0] == -1 || b->portalareas[1] == -1)
  636. _printf ("WARNING: areaportal brush %i doesn't touch two areas\n", b->brushnum);
  637. }
  638. }
  639. /*
  640. =============
  641. FloodAreas
  642. Mark each leaf with an area, bounded by CONTENTS_AREAPORTAL
  643. =============
  644. */
  645. void FloodAreas (tree_t *tree)
  646. {
  647. qprintf ("--- FloodAreas ---\n");
  648. FindAreas_r( tree->headnode );
  649. // check for areaportal brushes that don't touch two areas
  650. CheckAreas_r( tree->headnode );
  651. qprintf ("%5i areas\n", c_areas);
  652. }
  653. //======================================================
  654. int c_outside;
  655. int c_inside;
  656. int c_solid;
  657. void FillOutside_r (node_t *node)
  658. {
  659. if (node->planenum != PLANENUM_LEAF)
  660. {
  661. FillOutside_r (node->children[0]);
  662. FillOutside_r (node->children[1]);
  663. return;
  664. }
  665. // anything not reachable by an entity
  666. // can be filled away
  667. if (!node->occupied) {
  668. if ( !node->opaque ) {
  669. c_outside++;
  670. node->opaque = qtrue;
  671. } else {
  672. c_solid++;
  673. }
  674. } else {
  675. c_inside++;
  676. }
  677. }
  678. /*
  679. =============
  680. FillOutside
  681. Fill all nodes that can't be reached by entities
  682. =============
  683. */
  684. void FillOutside (node_t *headnode)
  685. {
  686. c_outside = 0;
  687. c_inside = 0;
  688. c_solid = 0;
  689. qprintf ("--- FillOutside ---\n");
  690. FillOutside_r (headnode);
  691. qprintf ("%5i solid leafs\n", c_solid);
  692. qprintf ("%5i leafs filled\n", c_outside);
  693. qprintf ("%5i inside leafs\n", c_inside);
  694. }
  695. //==============================================================