portals.c 21 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1997-2006 Id Software, Inc.
  4. This file is part of Quake 2 Tools source code.
  5. Quake 2 Tools 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 2 Tools 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 Quake 2 Tools source code; 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. VisibleContents
  51. Returns the single content bit of the
  52. strongest visible content present
  53. ==============
  54. */
  55. int VisibleContents (int contents)
  56. {
  57. int i;
  58. for (i=1 ; i<=LAST_VISIBLE_CONTENTS ; i<<=1)
  59. if (contents & i )
  60. return i;
  61. return 0;
  62. }
  63. /*
  64. ===============
  65. ClusterContents
  66. ===============
  67. */
  68. int ClusterContents (node_t *node)
  69. {
  70. int c1, c2, c;
  71. if (node->planenum == PLANENUM_LEAF)
  72. return node->contents;
  73. c1 = ClusterContents(node->children[0]);
  74. c2 = ClusterContents(node->children[1]);
  75. c = c1|c2;
  76. // a cluster may include some solid detail areas, but
  77. // still be seen into
  78. if ( ! (c1&CONTENTS_SOLID) || ! (c2&CONTENTS_SOLID) )
  79. c &= ~CONTENTS_SOLID;
  80. return c;
  81. }
  82. /*
  83. =============
  84. Portal_VisFlood
  85. Returns true if the portal is empty or translucent, allowing
  86. the PVS calculation to see through it.
  87. The nodes on either side of the portal may actually be clusters,
  88. not leafs, so all contents should be ored together
  89. =============
  90. */
  91. qboolean Portal_VisFlood (portal_t *p)
  92. {
  93. int c1, c2;
  94. if (!p->onnode)
  95. return false; // to global outsideleaf
  96. c1 = ClusterContents(p->nodes[0]);
  97. c2 = ClusterContents(p->nodes[1]);
  98. if (!VisibleContents (c1^c2))
  99. return true;
  100. if (c1 & (CONTENTS_TRANSLUCENT|CONTENTS_DETAIL))
  101. c1 = 0;
  102. if (c2 & (CONTENTS_TRANSLUCENT|CONTENTS_DETAIL))
  103. c2 = 0;
  104. if ( (c1|c2) & CONTENTS_SOLID )
  105. return false; // can't see through solid
  106. if (! (c1 ^ c2))
  107. return true; // identical on both sides
  108. if (!VisibleContents (c1^c2))
  109. return true;
  110. return false;
  111. }
  112. /*
  113. ===============
  114. Portal_EntityFlood
  115. The entity flood determines which areas are
  116. "outside" on the map, which are then filled in.
  117. Flowing from side s to side !s
  118. ===============
  119. */
  120. qboolean Portal_EntityFlood (portal_t *p, int s)
  121. {
  122. if (p->nodes[0]->planenum != PLANENUM_LEAF
  123. || p->nodes[1]->planenum != PLANENUM_LEAF)
  124. Error ("Portal_EntityFlood: not a leaf");
  125. // can never cross to a solid
  126. if ( (p->nodes[0]->contents & CONTENTS_SOLID)
  127. || (p->nodes[1]->contents & CONTENTS_SOLID) )
  128. return false;
  129. // can flood through everything else
  130. return true;
  131. }
  132. //=============================================================================
  133. int c_tinyportals;
  134. /*
  135. =============
  136. AddPortalToNodes
  137. =============
  138. */
  139. void AddPortalToNodes (portal_t *p, node_t *front, node_t *back)
  140. {
  141. if (p->nodes[0] || p->nodes[1])
  142. Error ("AddPortalToNode: allready included");
  143. p->nodes[0] = front;
  144. p->next[0] = front->portals;
  145. front->portals = p;
  146. p->nodes[1] = back;
  147. p->next[1] = back->portals;
  148. back->portals = p;
  149. }
  150. /*
  151. =============
  152. RemovePortalFromNode
  153. =============
  154. */
  155. void RemovePortalFromNode (portal_t *portal, node_t *l)
  156. {
  157. portal_t **pp, *t;
  158. // remove reference to the current portal
  159. pp = &l->portals;
  160. while (1)
  161. {
  162. t = *pp;
  163. if (!t)
  164. Error ("RemovePortalFromNode: portal not in leaf");
  165. if ( t == portal )
  166. break;
  167. if (t->nodes[0] == l)
  168. pp = &t->next[0];
  169. else if (t->nodes[1] == l)
  170. pp = &t->next[1];
  171. else
  172. Error ("RemovePortalFromNode: portal not bounding leaf");
  173. }
  174. if (portal->nodes[0] == l)
  175. {
  176. *pp = portal->next[0];
  177. portal->nodes[0] = NULL;
  178. }
  179. else if (portal->nodes[1] == l)
  180. {
  181. *pp = portal->next[1];
  182. portal->nodes[1] = NULL;
  183. }
  184. }
  185. //============================================================================
  186. void PrintPortal (portal_t *p)
  187. {
  188. int i;
  189. winding_t *w;
  190. w = p->winding;
  191. for (i=0 ; i<w->numpoints ; i++)
  192. printf ("(%5.0f,%5.0f,%5.0f)\n",w->p[i][0]
  193. , w->p[i][1], w->p[i][2]);
  194. }
  195. /*
  196. ================
  197. MakeHeadnodePortals
  198. The created portals will face the global outside_node
  199. ================
  200. */
  201. #define SIDESPACE 8
  202. void MakeHeadnodePortals (tree_t *tree)
  203. {
  204. vec3_t bounds[2];
  205. int i, j, n;
  206. portal_t *p, *portals[6];
  207. plane_t bplanes[6], *pl;
  208. node_t *node;
  209. node = tree->headnode;
  210. // pad with some space so there will never be null volume leafs
  211. for (i=0 ; i<3 ; i++)
  212. {
  213. bounds[0][i] = tree->mins[i] - SIDESPACE;
  214. bounds[1][i] = tree->maxs[i] + SIDESPACE;
  215. }
  216. tree->outside_node.planenum = PLANENUM_LEAF;
  217. tree->outside_node.brushlist = NULL;
  218. tree->outside_node.portals = NULL;
  219. tree->outside_node.contents = 0;
  220. for (i=0 ; i<3 ; i++)
  221. for (j=0 ; j<2 ; j++)
  222. {
  223. n = j*3 + i;
  224. p = AllocPortal ();
  225. portals[n] = p;
  226. pl = &bplanes[n];
  227. memset (pl, 0, sizeof(*pl));
  228. if (j)
  229. {
  230. pl->normal[i] = -1;
  231. pl->dist = -bounds[j][i];
  232. }
  233. else
  234. {
  235. pl->normal[i] = 1;
  236. pl->dist = bounds[j][i];
  237. }
  238. p->plane = *pl;
  239. p->winding = BaseWindingForPlane (pl->normal, pl->dist);
  240. AddPortalToNodes (p, node, &tree->outside_node);
  241. }
  242. // clip the basewindings by all the other planes
  243. for (i=0 ; i<6 ; i++)
  244. {
  245. for (j=0 ; j<6 ; j++)
  246. {
  247. if (j == i)
  248. continue;
  249. ChopWindingInPlace (&portals[i]->winding, bplanes[j].normal, bplanes[j].dist, ON_EPSILON);
  250. }
  251. }
  252. }
  253. //===================================================
  254. /*
  255. ================
  256. BaseWindingForNode
  257. ================
  258. */
  259. #define BASE_WINDING_EPSILON 0.001
  260. #define SPLIT_WINDING_EPSILON 0.001
  261. winding_t *BaseWindingForNode (node_t *node)
  262. {
  263. winding_t *w;
  264. node_t *n;
  265. plane_t *plane;
  266. vec3_t normal;
  267. vec_t dist;
  268. w = BaseWindingForPlane (mapplanes[node->planenum].normal
  269. , mapplanes[node->planenum].dist);
  270. // clip by all the parents
  271. for (n=node->parent ; n && w ; )
  272. {
  273. plane = &mapplanes[n->planenum];
  274. if (n->children[0] == node)
  275. { // take front
  276. ChopWindingInPlace (&w, plane->normal, plane->dist, BASE_WINDING_EPSILON);
  277. }
  278. else
  279. { // take back
  280. VectorSubtract (vec3_origin, plane->normal, normal);
  281. dist = -plane->dist;
  282. ChopWindingInPlace (&w, normal, dist, BASE_WINDING_EPSILON);
  283. }
  284. node = n;
  285. n = n->parent;
  286. }
  287. return w;
  288. }
  289. //============================================================
  290. qboolean WindingIsTiny (winding_t *w);
  291. /*
  292. ==================
  293. MakeNodePortal
  294. create the new portal by taking the full plane winding for the cutting plane
  295. and clipping it by all of parents of this node
  296. ==================
  297. */
  298. void MakeNodePortal (node_t *node)
  299. {
  300. portal_t *new_portal, *p;
  301. winding_t *w;
  302. vec3_t normal;
  303. float dist;
  304. int side;
  305. w = BaseWindingForNode (node);
  306. // clip the portal by all the other portals in the node
  307. for (p = node->portals ; p && w; p = p->next[side])
  308. {
  309. if (p->nodes[0] == node)
  310. {
  311. side = 0;
  312. VectorCopy (p->plane.normal, normal);
  313. dist = p->plane.dist;
  314. }
  315. else if (p->nodes[1] == node)
  316. {
  317. side = 1;
  318. VectorSubtract (vec3_origin, p->plane.normal, normal);
  319. dist = -p->plane.dist;
  320. }
  321. else
  322. Error ("CutNodePortals_r: mislinked portal");
  323. ChopWindingInPlace (&w, normal, dist, 0.1);
  324. }
  325. if (!w)
  326. {
  327. return;
  328. }
  329. if (WindingIsTiny (w))
  330. {
  331. c_tinyportals++;
  332. FreeWinding (w);
  333. return;
  334. }
  335. new_portal = AllocPortal ();
  336. new_portal->plane = mapplanes[node->planenum];
  337. new_portal->onnode = node;
  338. new_portal->winding = w;
  339. AddPortalToNodes (new_portal, node->children[0], node->children[1]);
  340. }
  341. /*
  342. ==============
  343. SplitNodePortals
  344. Move or split the portals that bound node so that the node's
  345. children have portals instead of node.
  346. ==============
  347. */
  348. void SplitNodePortals (node_t *node)
  349. {
  350. portal_t *p, *next_portal, *new_portal;
  351. node_t *f, *b, *other_node;
  352. int side;
  353. plane_t *plane;
  354. winding_t *frontwinding, *backwinding;
  355. plane = &mapplanes[node->planenum];
  356. f = node->children[0];
  357. b = node->children[1];
  358. for (p = node->portals ; p ; p = next_portal)
  359. {
  360. if (p->nodes[0] == node)
  361. side = 0;
  362. else if (p->nodes[1] == node)
  363. side = 1;
  364. else
  365. Error ("CutNodePortals_r: mislinked portal");
  366. next_portal = p->next[side];
  367. other_node = p->nodes[!side];
  368. RemovePortalFromNode (p, p->nodes[0]);
  369. RemovePortalFromNode (p, p->nodes[1]);
  370. //
  371. // cut the portal into two portals, one on each side of the cut plane
  372. //
  373. ClipWindingEpsilon (p->winding, plane->normal, plane->dist,
  374. SPLIT_WINDING_EPSILON, &frontwinding, &backwinding);
  375. if (frontwinding && WindingIsTiny(frontwinding))
  376. {
  377. FreeWinding (frontwinding);
  378. frontwinding = NULL;
  379. c_tinyportals++;
  380. }
  381. if (backwinding && WindingIsTiny(backwinding))
  382. {
  383. FreeWinding (backwinding);
  384. backwinding = NULL;
  385. c_tinyportals++;
  386. }
  387. if (!frontwinding && !backwinding)
  388. { // tiny windings on both sides
  389. continue;
  390. }
  391. if (!frontwinding)
  392. {
  393. FreeWinding (backwinding);
  394. if (side == 0)
  395. AddPortalToNodes (p, b, other_node);
  396. else
  397. AddPortalToNodes (p, other_node, b);
  398. continue;
  399. }
  400. if (!backwinding)
  401. {
  402. FreeWinding (frontwinding);
  403. if (side == 0)
  404. AddPortalToNodes (p, f, other_node);
  405. else
  406. AddPortalToNodes (p, other_node, f);
  407. continue;
  408. }
  409. // the winding is split
  410. new_portal = AllocPortal ();
  411. *new_portal = *p;
  412. new_portal->winding = backwinding;
  413. FreeWinding (p->winding);
  414. p->winding = frontwinding;
  415. if (side == 0)
  416. {
  417. AddPortalToNodes (p, f, other_node);
  418. AddPortalToNodes (new_portal, b, other_node);
  419. }
  420. else
  421. {
  422. AddPortalToNodes (p, other_node, f);
  423. AddPortalToNodes (new_portal, other_node, b);
  424. }
  425. }
  426. node->portals = NULL;
  427. }
  428. /*
  429. ================
  430. CalcNodeBounds
  431. ================
  432. */
  433. void CalcNodeBounds (node_t *node)
  434. {
  435. portal_t *p;
  436. int s;
  437. int i;
  438. // calc mins/maxs for both leafs and nodes
  439. ClearBounds (node->mins, node->maxs);
  440. for (p = node->portals ; p ; p = p->next[s])
  441. {
  442. s = (p->nodes[1] == node);
  443. for (i=0 ; i<p->winding->numpoints ; i++)
  444. AddPointToBounds (p->winding->p[i], node->mins, node->maxs);
  445. }
  446. }
  447. /*
  448. ==================
  449. MakeTreePortals_r
  450. ==================
  451. */
  452. void MakeTreePortals_r (node_t *node)
  453. {
  454. int i;
  455. CalcNodeBounds (node);
  456. if (node->mins[0] >= node->maxs[0])
  457. {
  458. printf ("WARNING: node without a volume\n");
  459. }
  460. for (i=0 ; i<3 ; i++)
  461. {
  462. if (node->mins[i] < -8000 || node->maxs[i] > 8000)
  463. {
  464. printf ("WARNING: node with unbounded volume\n");
  465. break;
  466. }
  467. }
  468. if (node->planenum == PLANENUM_LEAF)
  469. return;
  470. MakeNodePortal (node);
  471. SplitNodePortals (node);
  472. MakeTreePortals_r (node->children[0]);
  473. MakeTreePortals_r (node->children[1]);
  474. }
  475. /*
  476. ==================
  477. MakeTreePortals
  478. ==================
  479. */
  480. void MakeTreePortals (tree_t *tree)
  481. {
  482. MakeHeadnodePortals (tree);
  483. MakeTreePortals_r (tree->headnode);
  484. }
  485. /*
  486. =========================================================
  487. FLOOD ENTITIES
  488. =========================================================
  489. */
  490. /*
  491. =============
  492. FloodPortals_r
  493. =============
  494. */
  495. void FloodPortals_r (node_t *node, int dist)
  496. {
  497. portal_t *p;
  498. int s;
  499. node->occupied = dist;
  500. for (p=node->portals ; p ; p = p->next[s])
  501. {
  502. s = (p->nodes[1] == node);
  503. if (p->nodes[!s]->occupied)
  504. continue;
  505. if (!Portal_EntityFlood (p, s))
  506. continue;
  507. FloodPortals_r (p->nodes[!s], dist+1);
  508. }
  509. }
  510. /*
  511. =============
  512. PlaceOccupant
  513. =============
  514. */
  515. qboolean PlaceOccupant (node_t *headnode, vec3_t origin, entity_t *occupant)
  516. {
  517. node_t *node;
  518. vec_t d;
  519. plane_t *plane;
  520. // find the leaf to start in
  521. node = headnode;
  522. while (node->planenum != PLANENUM_LEAF)
  523. {
  524. plane = &mapplanes[node->planenum];
  525. d = DotProduct (origin, plane->normal) - plane->dist;
  526. if (d >= 0)
  527. node = node->children[0];
  528. else
  529. node = node->children[1];
  530. }
  531. if (node->contents == CONTENTS_SOLID)
  532. return false;
  533. node->occupant = occupant;
  534. FloodPortals_r (node, 1);
  535. return true;
  536. }
  537. /*
  538. =============
  539. FloodEntities
  540. Marks all nodes that can be reached by entites
  541. =============
  542. */
  543. qboolean FloodEntities (tree_t *tree)
  544. {
  545. int i;
  546. vec3_t origin;
  547. char *cl;
  548. qboolean inside;
  549. node_t *headnode;
  550. headnode = tree->headnode;
  551. qprintf ("--- FloodEntities ---\n");
  552. inside = false;
  553. tree->outside_node.occupied = 0;
  554. for (i=1 ; i<num_entities ; i++)
  555. {
  556. GetVectorForKey (&entities[i], "origin", origin);
  557. if (VectorCompare(origin, vec3_origin))
  558. continue;
  559. cl = ValueForKey (&entities[i], "classname");
  560. origin[2] += 1; // so objects on floor are ok
  561. // nudge playerstart around if needed so clipping hulls allways
  562. // have a vlaid point
  563. if (!strcmp (cl, "info_player_start"))
  564. {
  565. int x, y;
  566. for (x=-16 ; x<=16 ; x += 16)
  567. {
  568. for (y=-16 ; y<=16 ; y += 16)
  569. {
  570. origin[0] += x;
  571. origin[1] += y;
  572. if (PlaceOccupant (headnode, origin, &entities[i]))
  573. {
  574. inside = true;
  575. goto gotit;
  576. }
  577. origin[0] -= x;
  578. origin[1] -= y;
  579. }
  580. }
  581. gotit: ;
  582. }
  583. else
  584. {
  585. if (PlaceOccupant (headnode, origin, &entities[i]))
  586. inside = true;
  587. }
  588. }
  589. if (!inside)
  590. {
  591. qprintf ("no entities in open -- no filling\n");
  592. }
  593. else if (tree->outside_node.occupied)
  594. {
  595. qprintf ("entity reached from outside -- no filling\n");
  596. }
  597. return (qboolean)(inside && !tree->outside_node.occupied);
  598. }
  599. /*
  600. =========================================================
  601. FLOOD AREAS
  602. =========================================================
  603. */
  604. int c_areas;
  605. /*
  606. =============
  607. FloodAreas_r
  608. =============
  609. */
  610. void FloodAreas_r (node_t *node)
  611. {
  612. portal_t *p;
  613. int s;
  614. bspbrush_t *b;
  615. entity_t *e;
  616. if (node->contents == CONTENTS_AREAPORTAL)
  617. {
  618. // this node is part of an area portal
  619. b = node->brushlist;
  620. e = &entities[b->original->entitynum];
  621. // if the current area has allready touched this
  622. // portal, we are done
  623. if (e->portalareas[0] == c_areas || e->portalareas[1] == c_areas)
  624. return;
  625. // note the current area as bounding the portal
  626. if (e->portalareas[1])
  627. {
  628. printf ("WARNING: areaportal entity %i touches > 2 areas\n", b->original->entitynum);
  629. return;
  630. }
  631. if (e->portalareas[0])
  632. e->portalareas[1] = c_areas;
  633. else
  634. e->portalareas[0] = c_areas;
  635. return;
  636. }
  637. if (node->area)
  638. return; // allready got it
  639. node->area = c_areas;
  640. for (p=node->portals ; p ; p = p->next[s])
  641. {
  642. s = (p->nodes[1] == node);
  643. #if 0
  644. if (p->nodes[!s]->occupied)
  645. continue;
  646. #endif
  647. if (!Portal_EntityFlood (p, s))
  648. continue;
  649. FloodAreas_r (p->nodes[!s]);
  650. }
  651. }
  652. /*
  653. =============
  654. FindAreas_r
  655. Just decend the tree, and for each node that hasn't had an
  656. area set, flood fill out from there
  657. =============
  658. */
  659. void FindAreas_r (node_t *node)
  660. {
  661. if (node->planenum != PLANENUM_LEAF)
  662. {
  663. FindAreas_r (node->children[0]);
  664. FindAreas_r (node->children[1]);
  665. return;
  666. }
  667. if (node->area)
  668. return; // allready got it
  669. if (node->contents & CONTENTS_SOLID)
  670. return;
  671. if (!node->occupied)
  672. return; // not reachable by entities
  673. // area portals are allways only flooded into, never
  674. // out of
  675. if (node->contents == CONTENTS_AREAPORTAL)
  676. return;
  677. c_areas++;
  678. FloodAreas_r (node);
  679. }
  680. /*
  681. =============
  682. SetAreaPortalAreas_r
  683. Just decend the tree, and for each node that hasn't had an
  684. area set, flood fill out from there
  685. =============
  686. */
  687. void SetAreaPortalAreas_r (node_t *node)
  688. {
  689. bspbrush_t *b;
  690. entity_t *e;
  691. if (node->planenum != PLANENUM_LEAF)
  692. {
  693. SetAreaPortalAreas_r (node->children[0]);
  694. SetAreaPortalAreas_r (node->children[1]);
  695. return;
  696. }
  697. if (node->contents == CONTENTS_AREAPORTAL)
  698. {
  699. if (node->area)
  700. return; // allready set
  701. b = node->brushlist;
  702. e = &entities[b->original->entitynum];
  703. node->area = e->portalareas[0];
  704. if (!e->portalareas[1])
  705. {
  706. printf ("WARNING: areaportal entity %i doesn't touch two areas\n", b->original->entitynum);
  707. return;
  708. }
  709. }
  710. }
  711. /*
  712. =============
  713. EmitAreaPortals
  714. =============
  715. */
  716. void EmitAreaPortals (node_t *headnode)
  717. {
  718. int i, j;
  719. entity_t *e;
  720. dareaportal_t *dp;
  721. if (c_areas > MAX_MAP_AREAS)
  722. Error ("MAX_MAP_AREAS");
  723. numareas = c_areas+1;
  724. numareaportals = 1; // leave 0 as an error
  725. for (i=1 ; i<=c_areas ; i++)
  726. {
  727. dareas[i].firstareaportal = numareaportals;
  728. for (j=0 ; j<num_entities ; j++)
  729. {
  730. e = &entities[j];
  731. if (!e->areaportalnum)
  732. continue;
  733. dp = &dareaportals[numareaportals];
  734. if (e->portalareas[0] == i)
  735. {
  736. dp->portalnum = e->areaportalnum;
  737. dp->otherarea = e->portalareas[1];
  738. numareaportals++;
  739. }
  740. else if (e->portalareas[1] == i)
  741. {
  742. dp->portalnum = e->areaportalnum;
  743. dp->otherarea = e->portalareas[0];
  744. numareaportals++;
  745. }
  746. }
  747. dareas[i].numareaportals = numareaportals - dareas[i].firstareaportal;
  748. }
  749. qprintf ("%5i numareas\n", numareas);
  750. qprintf ("%5i numareaportals\n", numareaportals);
  751. }
  752. /*
  753. =============
  754. FloodAreas
  755. Mark each leaf with an area, bounded by CONTENTS_AREAPORTAL
  756. =============
  757. */
  758. void FloodAreas (tree_t *tree)
  759. {
  760. qprintf ("--- FloodAreas ---\n");
  761. FindAreas_r (tree->headnode);
  762. SetAreaPortalAreas_r (tree->headnode);
  763. qprintf ("%5i areas\n", c_areas);
  764. }
  765. //======================================================
  766. int c_outside;
  767. int c_inside;
  768. int c_solid;
  769. void FillOutside_r (node_t *node)
  770. {
  771. if (node->planenum != PLANENUM_LEAF)
  772. {
  773. FillOutside_r (node->children[0]);
  774. FillOutside_r (node->children[1]);
  775. return;
  776. }
  777. // anything not reachable by an entity
  778. // can be filled away
  779. if (!node->occupied)
  780. {
  781. if (node->contents != CONTENTS_SOLID)
  782. {
  783. c_outside++;
  784. node->contents = CONTENTS_SOLID;
  785. }
  786. else
  787. c_solid++;
  788. }
  789. else
  790. c_inside++;
  791. }
  792. /*
  793. =============
  794. FillOutside
  795. Fill all nodes that can't be reached by entities
  796. =============
  797. */
  798. void FillOutside (node_t *headnode)
  799. {
  800. c_outside = 0;
  801. c_inside = 0;
  802. c_solid = 0;
  803. qprintf ("--- FillOutside ---\n");
  804. FillOutside_r (headnode);
  805. qprintf ("%5i solid leafs\n", c_solid);
  806. qprintf ("%5i leafs filled\n", c_outside);
  807. qprintf ("%5i inside leafs\n", c_inside);
  808. }
  809. //==============================================================
  810. /*
  811. ============
  812. FindPortalSide
  813. Finds a brush side to use for texturing the given portal
  814. ============
  815. */
  816. void FindPortalSide (portal_t *p)
  817. {
  818. int viscontents;
  819. bspbrush_t *bb;
  820. mapbrush_t *brush;
  821. node_t *n;
  822. int i,j;
  823. int planenum;
  824. side_t *side, *bestside;
  825. float dot, bestdot;
  826. plane_t *p1, *p2;
  827. // decide which content change is strongest
  828. // solid > lava > water, etc
  829. viscontents = VisibleContents (p->nodes[0]->contents ^ p->nodes[1]->contents);
  830. if (!viscontents)
  831. return;
  832. planenum = p->onnode->planenum;
  833. bestside = NULL;
  834. bestdot = 0;
  835. for (j=0 ; j<2 ; j++)
  836. {
  837. n = p->nodes[j];
  838. p1 = &mapplanes[p->onnode->planenum];
  839. for (bb=n->brushlist ; bb ; bb=bb->next)
  840. {
  841. brush = bb->original;
  842. if ( !(brush->contents & viscontents) )
  843. continue;
  844. for (i=0 ; i<brush->numsides ; i++)
  845. {
  846. side = &brush->original_sides[i];
  847. if (side->bevel)
  848. continue;
  849. if (side->texinfo == TEXINFO_NODE)
  850. continue; // non-visible
  851. if ((side->planenum&~1) == planenum)
  852. { // exact match
  853. bestside = &brush->original_sides[i];
  854. goto gotit;
  855. }
  856. // see how close the match is
  857. p2 = &mapplanes[side->planenum&~1];
  858. dot = DotProduct (p1->normal, p2->normal);
  859. if (dot > bestdot)
  860. {
  861. bestdot = dot;
  862. bestside = side;
  863. }
  864. }
  865. }
  866. }
  867. gotit:
  868. if (!bestside)
  869. qprintf ("WARNING: side not found for portal\n");
  870. p->sidefound = true;
  871. p->side = bestside;
  872. }
  873. /*
  874. ===============
  875. MarkVisibleSides_r
  876. ===============
  877. */
  878. void MarkVisibleSides_r (node_t *node)
  879. {
  880. portal_t *p;
  881. int s;
  882. if (node->planenum != PLANENUM_LEAF)
  883. {
  884. MarkVisibleSides_r (node->children[0]);
  885. MarkVisibleSides_r (node->children[1]);
  886. return;
  887. }
  888. // empty leafs are never boundary leafs
  889. if (!node->contents)
  890. return;
  891. // see if there is a visible face
  892. for (p=node->portals ; p ; p = p->next[!s])
  893. {
  894. s = (p->nodes[0] == node);
  895. if (!p->onnode)
  896. continue; // edge of world
  897. if (!p->sidefound)
  898. FindPortalSide (p);
  899. if (p->side)
  900. p->side->visible = true;
  901. }
  902. }
  903. /*
  904. =============
  905. MarkVisibleSides
  906. =============
  907. */
  908. void MarkVisibleSides (tree_t *tree, int startbrush, int endbrush)
  909. {
  910. int i, j;
  911. mapbrush_t *mb;
  912. int numsides;
  913. qprintf ("--- MarkVisibleSides ---\n");
  914. // clear all the visible flags
  915. for (i=startbrush ; i<endbrush ; i++)
  916. {
  917. mb = &mapbrushes[i];
  918. numsides = mb->numsides;
  919. for (j=0 ; j<numsides ; j++)
  920. mb->original_sides[j].visible = false;
  921. }
  922. // set visible flags on the sides that are used by portals
  923. MarkVisibleSides_r (tree->headnode);
  924. }