PageRenderTime 46ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/utils/qutils/qbsp/solidbsp.c

https://gitlab.com/fzwoch/fodquake
C | 773 lines | 499 code | 113 blank | 161 comment | 112 complexity | 66bb4679bbe5cee73d0d1e3702b926b8 MD5 | raw file
Possible License(s): GPL-2.0
  1. /* Copyright (C) 1996-1997 Id Software, Inc.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation; either version 2 of the License, or
  5. (at your option) any later version.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program; if not, write to the Free Software
  12. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  13. See file, 'COPYING', for details.
  14. */
  15. // solidbsp.c
  16. #include "bsp5.h"
  17. int leaffaces;
  18. int nodefaces;
  19. int splitnodes;
  20. int c_solid, c_empty, c_water;
  21. qboolean usemidsplit;
  22. //============================================================================
  23. /*
  24. ==================
  25. FaceSide
  26. For BSP hueristic
  27. ==================
  28. */
  29. int FaceSide (face_t *in, plane_t *split)
  30. {
  31. int frontcount, backcount;
  32. vec_t dot;
  33. int i;
  34. vec_t *p;
  35. frontcount = backcount = 0;
  36. // axial planes are fast
  37. if (split->type < 3)
  38. for (i=0, p = in->pts[0]+split->type ; i<in->numpoints ; i++, p+=3)
  39. {
  40. if (*p > split->dist + ON_EPSILON)
  41. {
  42. if (backcount)
  43. return SIDE_ON;
  44. frontcount = 1;
  45. }
  46. else if (*p < split->dist - ON_EPSILON)
  47. {
  48. if (frontcount)
  49. return SIDE_ON;
  50. backcount = 1;
  51. }
  52. }
  53. else
  54. // sloping planes take longer
  55. for (i=0, p = in->pts[0] ; i<in->numpoints ; i++, p+=3)
  56. {
  57. dot = DotProduct (p, split->normal);
  58. dot -= split->dist;
  59. if (dot > ON_EPSILON)
  60. {
  61. if (backcount)
  62. return SIDE_ON;
  63. frontcount = 1;
  64. }
  65. else if (dot < -ON_EPSILON)
  66. {
  67. if (frontcount)
  68. return SIDE_ON;
  69. backcount = 1;
  70. }
  71. }
  72. if (!frontcount)
  73. return SIDE_BACK;
  74. if (!backcount)
  75. return SIDE_FRONT;
  76. return SIDE_ON;
  77. }
  78. /*
  79. ==================
  80. ChooseMidPlaneFromList
  81. The clipping hull BSP doesn't worry about avoiding splits
  82. ==================
  83. */
  84. surface_t *ChooseMidPlaneFromList (surface_t *surfaces, vec3_t mins, vec3_t maxs)
  85. {
  86. int j,l;
  87. surface_t *p, *bestsurface;
  88. vec_t bestvalue, value, dist;
  89. plane_t *plane;
  90. //
  91. // pick the plane that splits the least
  92. //
  93. bestvalue = 6*8192*8192;
  94. bestsurface = NULL;
  95. for (p=surfaces ; p ; p=p->next)
  96. {
  97. if (p->onnode)
  98. continue;
  99. plane = &planes[p->planenum];
  100. // check for axis aligned surfaces
  101. l = plane->type;
  102. if (l > PLANE_Z)
  103. continue;
  104. //
  105. // calculate the split metric along axis l, smaller values are better
  106. //
  107. value = 0;
  108. dist = plane->dist * plane->normal[l];
  109. for (j=0 ; j<3 ; j++)
  110. {
  111. if (j == l)
  112. {
  113. value += (maxs[l]-dist)*(maxs[l]-dist);
  114. value += (dist-mins[l])*(dist-mins[l]);
  115. }
  116. else
  117. value += 2*(maxs[j]-mins[j])*(maxs[j]-mins[j]);
  118. }
  119. if (value > bestvalue)
  120. continue;
  121. //
  122. // currently the best!
  123. //
  124. bestvalue = value;
  125. bestsurface = p;
  126. }
  127. if (!bestsurface)
  128. {
  129. for (p=surfaces ; p ; p=p->next)
  130. if (!p->onnode)
  131. return p; // first valid surface
  132. Error ("ChooseMidPlaneFromList: no valid planes");
  133. }
  134. return bestsurface;
  135. }
  136. /*
  137. ==================
  138. ChoosePlaneFromList
  139. The real BSP hueristic
  140. ==================
  141. */
  142. surface_t *ChoosePlaneFromList (surface_t *surfaces, vec3_t mins, vec3_t maxs, qboolean usefloors)
  143. {
  144. int j,k,l;
  145. surface_t *p, *p2, *bestsurface;
  146. vec_t bestvalue, bestdistribution, value, dist;
  147. plane_t *plane;
  148. face_t *f;
  149. //
  150. // pick the plane that splits the least
  151. //
  152. bestvalue = 99999;
  153. bestsurface = NULL;
  154. bestdistribution = 9e30;
  155. for (p=surfaces ; p ; p=p->next)
  156. {
  157. if (p->onnode)
  158. continue;
  159. plane = &planes[p->planenum];
  160. k = 0;
  161. if (!usefloors && plane->normal[2] == 1)
  162. continue;
  163. for (p2=surfaces ; p2 ; p2=p2->next)
  164. {
  165. if (p2 == p)
  166. continue;
  167. if (p2->onnode)
  168. continue;
  169. for (f=p2->faces ; f ; f=f->next)
  170. {
  171. if (FaceSide (f, plane) == SIDE_ON)
  172. {
  173. k++;
  174. if (k >= bestvalue)
  175. break;
  176. }
  177. }
  178. if (k > bestvalue)
  179. break;
  180. }
  181. if (k > bestvalue)
  182. continue;
  183. // if equal numbers, axial planes win, then decide on spatial subdivision
  184. if (k < bestvalue || (k == bestvalue && plane->type < PLANE_ANYX) )
  185. {
  186. // check for axis aligned surfaces
  187. l = plane->type;
  188. if (l <= PLANE_Z)
  189. { // axial aligned
  190. //
  191. // calculate the split metric along axis l
  192. //
  193. value = 0;
  194. for (j=0 ; j<3 ; j++)
  195. {
  196. if (j == l)
  197. {
  198. dist = plane->dist * plane->normal[l];
  199. value += (maxs[l]-dist)*(maxs[l]-dist);
  200. value += (dist-mins[l])*(dist-mins[l]);
  201. }
  202. else
  203. value += 2*(maxs[j]-mins[j])*(maxs[j]-mins[j]);
  204. }
  205. if (value > bestdistribution && k == bestvalue)
  206. continue;
  207. bestdistribution = value;
  208. }
  209. //
  210. // currently the best!
  211. //
  212. bestvalue = k;
  213. bestsurface = p;
  214. }
  215. }
  216. return bestsurface;
  217. }
  218. /*
  219. ==================
  220. SelectPartition
  221. Selects a surface from a linked list of surfaces to split the group on
  222. returns NULL if the surface list can not be divided any more (a leaf)
  223. ==================
  224. */
  225. surface_t *SelectPartition (surface_t *surfaces)
  226. {
  227. int i,j;
  228. vec3_t mins, maxs;
  229. surface_t *p, *bestsurface;
  230. //
  231. // count onnode surfaces
  232. //
  233. i = 0;
  234. bestsurface = NULL;
  235. for (p=surfaces ; p ; p=p->next)
  236. if (!p->onnode)
  237. {
  238. i++;
  239. bestsurface = p;
  240. }
  241. if (i==0)
  242. return NULL;
  243. if (i==1)
  244. return bestsurface; // this is a final split
  245. //
  246. // calculate a bounding box of the entire surfaceset
  247. //
  248. for (i=0 ; i<3 ; i++)
  249. {
  250. mins[i] = 99999;
  251. maxs[i] = -99999;
  252. }
  253. for (p=surfaces ; p ; p=p->next)
  254. for (j=0 ; j<3 ; j++)
  255. {
  256. if (p->mins[j] < mins[j])
  257. mins[j] = p->mins[j];
  258. if (p->maxs[j] > maxs[j])
  259. maxs[j] = p->maxs[j];
  260. }
  261. if (usemidsplit) // do fast way for clipping hull
  262. return ChooseMidPlaneFromList (surfaces, mins, maxs);
  263. // do slow way to save poly splits for drawing hull
  264. #if 0
  265. bestsurface = ChoosePlaneFromList (surfaces, mins, maxs, false);
  266. if (bestsurface)
  267. return bestsurface;
  268. #endif
  269. return ChoosePlaneFromList (surfaces, mins, maxs, true);
  270. }
  271. //============================================================================
  272. /*
  273. =================
  274. CalcSurfaceInfo
  275. Calculates the bounding box
  276. =================
  277. */
  278. void CalcSurfaceInfo (surface_t *surf)
  279. {
  280. int i,j;
  281. face_t *f;
  282. if (!surf->faces)
  283. Error ("CalcSurfaceInfo: surface without a face");
  284. //
  285. // calculate a bounding box
  286. //
  287. for (i=0 ; i<3 ; i++)
  288. {
  289. surf->mins[i] = 99999;
  290. surf->maxs[i] = -99999;
  291. }
  292. for (f=surf->faces ; f ; f=f->next)
  293. {
  294. if (f->contents[0] >= 0 || f->contents[1] >= 0)
  295. Error ("Bad contents");
  296. for (i=0 ; i<f->numpoints ; i++)
  297. for (j=0 ; j<3 ; j++)
  298. {
  299. if (f->pts[i][j] < surf->mins[j])
  300. surf->mins[j] = f->pts[i][j];
  301. if (f->pts[i][j] > surf->maxs[j])
  302. surf->maxs[j] = f->pts[i][j];
  303. }
  304. }
  305. }
  306. /*
  307. ==================
  308. DividePlane
  309. ==================
  310. */
  311. void DividePlane (surface_t *in, plane_t *split, surface_t **front, surface_t **back)
  312. {
  313. face_t *facet, *next;
  314. face_t *frontlist, *backlist;
  315. face_t *frontfrag, *backfrag;
  316. surface_t *news;
  317. plane_t *inplane;
  318. inplane = &planes[in->planenum];
  319. // parallel case is easy
  320. if (VectorCompare (inplane->normal, split->normal))
  321. {
  322. // check for exactly on node
  323. if (inplane->dist == split->dist)
  324. { // divide the facets to the front and back sides
  325. news = AllocSurface ();
  326. *news = *in;
  327. facet=in->faces;
  328. in->faces = NULL;
  329. news->faces = NULL;
  330. in->onnode = news->onnode = true;
  331. for ( ; facet ; facet=next)
  332. {
  333. next = facet->next;
  334. if (facet->planeside == 1)
  335. {
  336. facet->next = news->faces;
  337. news->faces = facet;
  338. }
  339. else
  340. {
  341. facet->next = in->faces;
  342. in->faces = facet;
  343. }
  344. }
  345. if (in->faces)
  346. *front = in;
  347. else
  348. *front = NULL;
  349. if (news->faces)
  350. *back = news;
  351. else
  352. *back = NULL;
  353. return;
  354. }
  355. if (inplane->dist > split->dist)
  356. {
  357. *front = in;
  358. *back = NULL;
  359. }
  360. else
  361. {
  362. *front = NULL;
  363. *back = in;
  364. }
  365. return;
  366. }
  367. // do a real split. may still end up entirely on one side
  368. // OPTIMIZE: use bounding box for fast test
  369. frontlist = NULL;
  370. backlist = NULL;
  371. for (facet = in->faces ; facet ; facet = next)
  372. {
  373. next = facet->next;
  374. SplitFace (facet, split, &frontfrag, &backfrag);
  375. if (frontfrag)
  376. {
  377. frontfrag->next = frontlist;
  378. frontlist = frontfrag;
  379. }
  380. if (backfrag)
  381. {
  382. backfrag->next = backlist;
  383. backlist = backfrag;
  384. }
  385. }
  386. // if nothing actually got split, just move the in plane
  387. if (frontlist == NULL)
  388. {
  389. *front = NULL;
  390. *back = in;
  391. in->faces = backlist;
  392. return;
  393. }
  394. if (backlist == NULL)
  395. {
  396. *front = in;
  397. *back = NULL;
  398. in->faces = frontlist;
  399. return;
  400. }
  401. // stuff got split, so allocate one new plane and reuse in
  402. news = AllocSurface ();
  403. *news = *in;
  404. news->faces = backlist;
  405. *back = news;
  406. in->faces = frontlist;
  407. *front = in;
  408. // recalc bboxes and flags
  409. CalcSurfaceInfo (news);
  410. CalcSurfaceInfo (in);
  411. }
  412. /*
  413. ==================
  414. DivideNodeBounds
  415. ==================
  416. */
  417. void DivideNodeBounds (node_t *node, plane_t *split)
  418. {
  419. VectorCopy (node->mins, node->children[0]->mins);
  420. VectorCopy (node->mins, node->children[1]->mins);
  421. VectorCopy (node->maxs, node->children[0]->maxs);
  422. VectorCopy (node->maxs, node->children[1]->maxs);
  423. // OPTIMIZE: sloping cuts can give a better bbox than this...
  424. if (split->type > 2)
  425. return;
  426. node->children[0]->mins[split->type] =
  427. node->children[1]->maxs[split->type] = split->dist;
  428. }
  429. /*
  430. ==================
  431. LinkConvexFaces
  432. Determines the contents of the leaf and creates the final list of
  433. original faces that have some fragment inside this leaf
  434. ==================
  435. */
  436. void LinkConvexFaces (surface_t *planelist, node_t *leafnode)
  437. {
  438. face_t *f, *next;
  439. surface_t *surf, *pnext;
  440. int i, count;
  441. leafnode->faces = NULL;
  442. leafnode->contents = 0;
  443. leafnode->planenum = -1;
  444. count = 0;
  445. for ( surf = planelist ; surf ; surf = surf->next)
  446. {
  447. for (f = surf->faces ; f ; f=f->next)
  448. {
  449. count++;
  450. if (!leafnode->contents)
  451. leafnode->contents = f->contents[0];
  452. else if (leafnode->contents != f->contents[0])
  453. Error ("Mixed face contents in leafnode");
  454. }
  455. }
  456. if (!leafnode->contents)
  457. leafnode->contents = CONTENTS_SOLID;
  458. switch (leafnode->contents)
  459. {
  460. case CONTENTS_EMPTY:
  461. c_empty++;
  462. break;
  463. case CONTENTS_SOLID:
  464. c_solid++;
  465. break;
  466. case CONTENTS_WATER:
  467. case CONTENTS_SLIME:
  468. case CONTENTS_LAVA:
  469. case CONTENTS_SKY:
  470. c_water++;
  471. break;
  472. default:
  473. Error ("LinkConvexFaces: bad contents number");
  474. }
  475. //
  476. // write the list of faces, and free the originals
  477. //
  478. leaffaces += count;
  479. leafnode->markfaces = malloc(sizeof(face_t *)*(count+1));
  480. i = 0;
  481. for ( surf = planelist ; surf ; surf = pnext)
  482. {
  483. pnext = surf->next;
  484. for (f = surf->faces ; f ; f=next)
  485. {
  486. next = f->next;
  487. leafnode->markfaces[i] = f->original;
  488. i++;
  489. FreeFace (f);
  490. }
  491. FreeSurface (surf);
  492. }
  493. leafnode->markfaces[i] = NULL; // sentinal
  494. }
  495. /*
  496. ==================
  497. LinkNodeFaces
  498. Returns a duplicated list of all faces on surface
  499. ==================
  500. */
  501. face_t *LinkNodeFaces (surface_t *surface)
  502. {
  503. face_t *f, *new, **prevptr;
  504. face_t *list;
  505. list = NULL;
  506. // subdivide
  507. prevptr = &surface->faces;
  508. while (1)
  509. {
  510. f = *prevptr;
  511. if (!f)
  512. break;
  513. SubdivideFace (f, prevptr);
  514. f = *prevptr;
  515. prevptr = &f->next;
  516. }
  517. // copy
  518. for (f=surface->faces ; f ; f=f->next)
  519. {
  520. nodefaces++;
  521. new = AllocFace ();
  522. *new = *f;
  523. f->original = new;
  524. new->next = list;
  525. list = new;
  526. }
  527. return list;
  528. }
  529. /*
  530. ==================
  531. PartitionSurfaces
  532. ==================
  533. */
  534. void PartitionSurfaces (surface_t *surfaces, node_t *node)
  535. {
  536. surface_t *split, *p, *next;
  537. surface_t *frontlist, *backlist;
  538. surface_t *frontfrag, *backfrag;
  539. plane_t *splitplane;
  540. split = SelectPartition (surfaces);
  541. if (!split)
  542. { // this is a leaf node
  543. node->planenum = PLANENUM_LEAF;
  544. LinkConvexFaces (surfaces, node);
  545. return;
  546. }
  547. splitnodes++;
  548. node->faces = LinkNodeFaces (split);
  549. node->children[0] = AllocNode ();
  550. node->children[1] = AllocNode ();
  551. node->planenum = split->planenum;
  552. splitplane = &planes[split->planenum];
  553. DivideNodeBounds (node, splitplane);
  554. //
  555. // multiple surfaces, so split all the polysurfaces into front and back lists
  556. //
  557. frontlist = NULL;
  558. backlist = NULL;
  559. for (p=surfaces ; p ; p=next)
  560. {
  561. next = p->next;
  562. DividePlane (p, splitplane, &frontfrag, &backfrag);
  563. if (frontfrag && backfrag)
  564. {
  565. // the plane was split, which may expose oportunities to merge
  566. // adjacent faces into a single face
  567. // MergePlaneFaces (frontfrag);
  568. // MergePlaneFaces (backfrag);
  569. }
  570. if (frontfrag)
  571. {
  572. if (!frontfrag->faces)
  573. Error ("surface with no faces");
  574. frontfrag->next = frontlist;
  575. frontlist = frontfrag;
  576. }
  577. if (backfrag)
  578. {
  579. if (!backfrag->faces)
  580. Error ("surface with no faces");
  581. backfrag->next = backlist;
  582. backlist = backfrag;
  583. }
  584. }
  585. PartitionSurfaces (frontlist, node->children[0]);
  586. PartitionSurfaces (backlist, node->children[1]);
  587. }
  588. /*
  589. ==================
  590. DrawSurface
  591. ==================
  592. */
  593. void DrawSurface (surface_t *surf)
  594. {
  595. face_t *f;
  596. for (f=surf->faces ; f ; f=f->next)
  597. Draw_DrawFace (f);
  598. }
  599. /*
  600. ==================
  601. DrawSurfaceList
  602. ==================
  603. */
  604. void DrawSurfaceList (surface_t *surf)
  605. {
  606. Draw_ClearWindow ();
  607. while (surf)
  608. {
  609. DrawSurface (surf);
  610. surf = surf->next;
  611. }
  612. }
  613. /*
  614. ==================
  615. SolidBSP
  616. ==================
  617. */
  618. node_t *SolidBSP (surface_t *surfhead, qboolean midsplit)
  619. {
  620. int i;
  621. node_t *headnode;
  622. qprintf ("----- SolidBSP -----\n");
  623. headnode = AllocNode ();
  624. usemidsplit = midsplit;
  625. //
  626. // calculate a bounding box for the entire model
  627. //
  628. for (i=0 ; i<3 ; i++)
  629. {
  630. headnode->mins[i] = brushset->mins[i] - SIDESPACE;
  631. headnode->maxs[i] = brushset->maxs[i] + SIDESPACE;
  632. }
  633. //
  634. // recursively partition everything
  635. //
  636. Draw_ClearWindow ();
  637. splitnodes = 0;
  638. leaffaces = 0;
  639. nodefaces = 0;
  640. c_solid = c_empty = c_water = 0;
  641. PartitionSurfaces (surfhead, headnode);
  642. qprintf ("%5i split nodes\n", splitnodes);
  643. qprintf ("%5i solid leafs\n", c_solid);
  644. qprintf ("%5i empty leafs\n", c_empty);
  645. qprintf ("%5i water leafs\n", c_water);
  646. qprintf ("%5i leaffaces\n",leaffaces);
  647. qprintf ("%5i nodefaces\n", nodefaces);
  648. return headnode;
  649. }