cm_polylib.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712
  1. // this is only used for visualization tools in cm_ debug functions
  2. #include "cm_local.h"
  3. // counters are only bumped when running single threaded,
  4. // because they are an awefull coherence problem
  5. int c_active_windings;
  6. int c_peak_windings;
  7. int c_winding_allocs;
  8. int c_winding_points;
  9. void pw(winding_t *w)
  10. {
  11. int i;
  12. for (i=0 ; i<w->numpoints ; i++)
  13. printf ("(%5.1f, %5.1f, %5.1f)\n",w->p[i][0], w->p[i][1],w->p[i][2]);
  14. }
  15. /*
  16. =============
  17. AllocWinding
  18. =============
  19. */
  20. winding_t *AllocWinding (int points)
  21. {
  22. winding_t *w;
  23. int s;
  24. c_winding_allocs++;
  25. c_winding_points += points;
  26. c_active_windings++;
  27. if (c_active_windings > c_peak_windings)
  28. c_peak_windings = c_active_windings;
  29. s = sizeof(vec_t)*3*points + sizeof(int);
  30. w = (winding_t *) Z_Malloc (s,TAG_BSP, qtrue);//TAG_WINDING);
  31. // memset (w, 0, s); // qtrue above does this
  32. return w;
  33. }
  34. void FreeWinding (winding_t *w)
  35. {
  36. if (*(unsigned *)w == 0xdeaddead)
  37. Com_Error (ERR_FATAL, "FreeWinding: freed a freed winding");
  38. *(unsigned *)w = 0xdeaddead;
  39. c_active_windings--;
  40. Z_Free (w);
  41. }
  42. /*
  43. ============
  44. RemoveColinearPoints
  45. ============
  46. */
  47. int c_removed;
  48. void RemoveColinearPoints (winding_t *w)
  49. {
  50. int i, j, k;
  51. vec3_t v1, v2;
  52. int nump;
  53. vec3_t p[MAX_POINTS_ON_WINDING];
  54. nump = 0;
  55. for (i=0 ; i<w->numpoints ; i++)
  56. {
  57. j = (i+1)%w->numpoints;
  58. k = (i+w->numpoints-1)%w->numpoints;
  59. VectorSubtract (w->p[j], w->p[i], v1);
  60. VectorSubtract (w->p[i], w->p[k], v2);
  61. VectorNormalize2(v1,v1);
  62. VectorNormalize2(v2,v2);
  63. if (DotProduct(v1, v2) < 0.999)
  64. {
  65. VectorCopy (w->p[i], p[nump]);
  66. nump++;
  67. }
  68. }
  69. if (nump == w->numpoints)
  70. return;
  71. c_removed += w->numpoints - nump;
  72. w->numpoints = nump;
  73. memcpy (w->p, p, nump*sizeof(p[0]));
  74. }
  75. /*
  76. ============
  77. WindingPlane
  78. ============
  79. */
  80. void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist)
  81. {
  82. vec3_t v1, v2;
  83. VectorSubtract (w->p[1], w->p[0], v1);
  84. VectorSubtract (w->p[2], w->p[0], v2);
  85. CrossProduct (v2, v1, normal);
  86. VectorNormalize2(normal, normal);
  87. *dist = DotProduct (w->p[0], normal);
  88. }
  89. /*
  90. =============
  91. WindingArea
  92. =============
  93. */
  94. vec_t WindingArea (winding_t *w)
  95. {
  96. int i;
  97. vec3_t d1, d2, cross;
  98. vec_t total;
  99. total = 0;
  100. for (i=2 ; i<w->numpoints ; i++)
  101. {
  102. VectorSubtract (w->p[i-1], w->p[0], d1);
  103. VectorSubtract (w->p[i], w->p[0], d2);
  104. CrossProduct (d1, d2, cross);
  105. total += 0.5 * VectorLength ( cross );
  106. }
  107. return total;
  108. }
  109. void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs)
  110. {
  111. vec_t v;
  112. int i,j;
  113. mins[0] = mins[1] = mins[2] = WORLD_SIZE; // 99999; // WORLD_SIZE instead of MAX_WORLD_COORD so that...
  114. maxs[0] = maxs[1] = maxs[2] = -WORLD_SIZE; //-99999; // ... it's guaranteed to be outide of legal
  115. for (i=0 ; i<w->numpoints ; i++)
  116. {
  117. for (j=0 ; j<3 ; j++)
  118. {
  119. v = w->p[i][j];
  120. if (v < mins[j])
  121. mins[j] = v;
  122. if (v > maxs[j])
  123. maxs[j] = v;
  124. }
  125. }
  126. }
  127. /*
  128. =============
  129. WindingCenter
  130. =============
  131. */
  132. void WindingCenter (winding_t *w, vec3_t center)
  133. {
  134. int i;
  135. float scale;
  136. VectorCopy (vec3_origin, center);
  137. for (i=0 ; i<w->numpoints ; i++)
  138. VectorAdd (w->p[i], center, center);
  139. scale = 1.0/w->numpoints;
  140. VectorScale (center, scale, center);
  141. }
  142. /*
  143. =================
  144. BaseWindingForPlane
  145. =================
  146. */
  147. winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist)
  148. {
  149. int i, x;
  150. vec_t max, v;
  151. vec3_t org, vright, vup;
  152. winding_t *w;
  153. // find the major axis
  154. max = -MAX_MAP_BOUNDS;
  155. x = -1;
  156. for (i=0 ; i<3; i++)
  157. {
  158. v = fabs(normal[i]);
  159. if (v > max)
  160. {
  161. x = i;
  162. max = v;
  163. }
  164. }
  165. if (x==-1)
  166. Com_Error (ERR_DROP, "BaseWindingForPlane: no axis found");
  167. VectorCopy (vec3_origin, vup);
  168. switch (x)
  169. {
  170. case 0:
  171. case 1:
  172. vup[2] = 1;
  173. break;
  174. case 2:
  175. vup[0] = 1;
  176. break;
  177. }
  178. v = DotProduct (vup, normal);
  179. VectorMA (vup, -v, normal, vup);
  180. VectorNormalize2(vup, vup);
  181. VectorScale (normal, dist, org);
  182. CrossProduct (vup, normal, vright);
  183. VectorScale (vup, MAX_MAP_BOUNDS, vup);
  184. VectorScale (vright, MAX_MAP_BOUNDS, vright);
  185. // project a really big axis aligned box onto the plane
  186. w = AllocWinding (4);
  187. VectorSubtract (org, vright, w->p[0]);
  188. VectorAdd (w->p[0], vup, w->p[0]);
  189. VectorAdd (org, vright, w->p[1]);
  190. VectorAdd (w->p[1], vup, w->p[1]);
  191. VectorAdd (org, vright, w->p[2]);
  192. VectorSubtract (w->p[2], vup, w->p[2]);
  193. VectorSubtract (org, vright, w->p[3]);
  194. VectorSubtract (w->p[3], vup, w->p[3]);
  195. w->numpoints = 4;
  196. return w;
  197. }
  198. /*
  199. ==================
  200. CopyWinding
  201. ==================
  202. */
  203. winding_t *CopyWinding (winding_t *w)
  204. {
  205. int size;
  206. winding_t *c;
  207. c = AllocWinding (w->numpoints);
  208. size = (int)((winding_t *)0)->p[w->numpoints];
  209. memcpy (c, w, size);
  210. return c;
  211. }
  212. /*
  213. ==================
  214. ReverseWinding
  215. ==================
  216. */
  217. winding_t *ReverseWinding (winding_t *w)
  218. {
  219. int i;
  220. winding_t *c;
  221. c = AllocWinding (w->numpoints);
  222. for (i=0 ; i<w->numpoints ; i++)
  223. {
  224. VectorCopy (w->p[w->numpoints-1-i], c->p[i]);
  225. }
  226. c->numpoints = w->numpoints;
  227. return c;
  228. }
  229. /*
  230. =============
  231. ClipWindingEpsilon
  232. =============
  233. */
  234. void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist,
  235. vec_t epsilon, winding_t **front, winding_t **back)
  236. {
  237. vec_t dists[MAX_POINTS_ON_WINDING+4];
  238. int sides[MAX_POINTS_ON_WINDING+4];
  239. int counts[3];
  240. static vec_t dot; // VC 4.2 optimizer bug if not static
  241. int i, j;
  242. vec_t *p1, *p2;
  243. vec3_t mid;
  244. winding_t *f, *b;
  245. int maxpts;
  246. counts[0] = counts[1] = counts[2] = 0;
  247. // determine sides for each point
  248. for (i=0 ; i<in->numpoints ; i++)
  249. {
  250. dot = DotProduct (in->p[i], normal);
  251. dot -= dist;
  252. dists[i] = dot;
  253. if (dot > epsilon)
  254. sides[i] = SIDE_FRONT;
  255. else if (dot < -epsilon)
  256. sides[i] = SIDE_BACK;
  257. else
  258. {
  259. sides[i] = SIDE_ON;
  260. }
  261. counts[sides[i]]++;
  262. }
  263. sides[i] = sides[0];
  264. dists[i] = dists[0];
  265. *front = *back = NULL;
  266. if (!counts[0])
  267. {
  268. *back = CopyWinding (in);
  269. return;
  270. }
  271. if (!counts[1])
  272. {
  273. *front = CopyWinding (in);
  274. return;
  275. }
  276. maxpts = in->numpoints+4; // cant use counts[0]+2 because
  277. // of fp grouping errors
  278. *front = f = AllocWinding (maxpts);
  279. *back = b = AllocWinding (maxpts);
  280. for (i=0 ; i<in->numpoints ; i++)
  281. {
  282. p1 = in->p[i];
  283. if (sides[i] == SIDE_ON)
  284. {
  285. VectorCopy (p1, f->p[f->numpoints]);
  286. f->numpoints++;
  287. VectorCopy (p1, b->p[b->numpoints]);
  288. b->numpoints++;
  289. continue;
  290. }
  291. if (sides[i] == SIDE_FRONT)
  292. {
  293. VectorCopy (p1, f->p[f->numpoints]);
  294. f->numpoints++;
  295. }
  296. if (sides[i] == SIDE_BACK)
  297. {
  298. VectorCopy (p1, b->p[b->numpoints]);
  299. b->numpoints++;
  300. }
  301. if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
  302. continue;
  303. // generate a split point
  304. p2 = in->p[(i+1)%in->numpoints];
  305. dot = dists[i] / (dists[i]-dists[i+1]);
  306. for (j=0 ; j<3 ; j++)
  307. { // avoid round off error when possible
  308. if (normal[j] == 1)
  309. mid[j] = dist;
  310. else if (normal[j] == -1)
  311. mid[j] = -dist;
  312. else
  313. mid[j] = p1[j] + dot*(p2[j]-p1[j]);
  314. }
  315. VectorCopy (mid, f->p[f->numpoints]);
  316. f->numpoints++;
  317. VectorCopy (mid, b->p[b->numpoints]);
  318. b->numpoints++;
  319. }
  320. if (f->numpoints > maxpts || b->numpoints > maxpts)
  321. Com_Error (ERR_DROP, "ClipWinding: points exceeded estimate");
  322. if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING)
  323. Com_Error (ERR_DROP, "ClipWinding: MAX_POINTS_ON_WINDING");
  324. }
  325. /*
  326. =============
  327. ChopWindingInPlace
  328. =============
  329. */
  330. void ChopWindingInPlace (winding_t **inout, vec3_t normal, vec_t dist, vec_t epsilon)
  331. {
  332. winding_t *in;
  333. vec_t dists[MAX_POINTS_ON_WINDING+4];
  334. int sides[MAX_POINTS_ON_WINDING+4];
  335. int counts[3];
  336. static vec_t dot; // VC 4.2 optimizer bug if not static
  337. int i, j;
  338. vec_t *p1, *p2;
  339. vec3_t mid;
  340. winding_t *f;
  341. int maxpts;
  342. in = *inout;
  343. counts[0] = counts[1] = counts[2] = 0;
  344. // determine sides for each point
  345. for (i=0 ; i<in->numpoints ; i++)
  346. {
  347. dot = DotProduct (in->p[i], normal);
  348. dot -= dist;
  349. dists[i] = dot;
  350. if (dot > epsilon)
  351. sides[i] = SIDE_FRONT;
  352. else if (dot < -epsilon)
  353. sides[i] = SIDE_BACK;
  354. else
  355. {
  356. sides[i] = SIDE_ON;
  357. }
  358. counts[sides[i]]++;
  359. }
  360. sides[i] = sides[0];
  361. dists[i] = dists[0];
  362. if (!counts[0])
  363. {
  364. FreeWinding (in);
  365. *inout = NULL;
  366. return;
  367. }
  368. if (!counts[1])
  369. return; // inout stays the same
  370. maxpts = in->numpoints+4; // cant use counts[0]+2 because
  371. // of fp grouping errors
  372. f = AllocWinding (maxpts);
  373. for (i=0 ; i<in->numpoints ; i++)
  374. {
  375. p1 = in->p[i];
  376. if (sides[i] == SIDE_ON)
  377. {
  378. VectorCopy (p1, f->p[f->numpoints]);
  379. f->numpoints++;
  380. continue;
  381. }
  382. if (sides[i] == SIDE_FRONT)
  383. {
  384. VectorCopy (p1, f->p[f->numpoints]);
  385. f->numpoints++;
  386. }
  387. if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
  388. continue;
  389. // generate a split point
  390. p2 = in->p[(i+1)%in->numpoints];
  391. dot = dists[i] / (dists[i]-dists[i+1]);
  392. for (j=0 ; j<3 ; j++)
  393. { // avoid round off error when possible
  394. if (normal[j] == 1)
  395. mid[j] = dist;
  396. else if (normal[j] == -1)
  397. mid[j] = -dist;
  398. else
  399. mid[j] = p1[j] + dot*(p2[j]-p1[j]);
  400. }
  401. VectorCopy (mid, f->p[f->numpoints]);
  402. f->numpoints++;
  403. }
  404. if (f->numpoints > maxpts)
  405. Com_Error (ERR_DROP, "ClipWinding: points exceeded estimate");
  406. if (f->numpoints > MAX_POINTS_ON_WINDING)
  407. Com_Error (ERR_DROP, "ClipWinding: MAX_POINTS_ON_WINDING");
  408. FreeWinding (in);
  409. *inout = f;
  410. }
  411. /*
  412. =================
  413. ChopWinding
  414. Returns the fragment of in that is on the front side
  415. of the cliping plane. The original is freed.
  416. =================
  417. */
  418. winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist)
  419. {
  420. winding_t *f, *b;
  421. ClipWindingEpsilon (in, normal, dist, ON_EPSILON, &f, &b);
  422. FreeWinding (in);
  423. if (b)
  424. FreeWinding (b);
  425. return f;
  426. }
  427. /*
  428. =================
  429. CheckWinding
  430. =================
  431. */
  432. void CheckWinding (winding_t *w)
  433. {
  434. int i, j;
  435. vec_t *p1, *p2;
  436. vec_t d, edgedist;
  437. vec3_t dir, edgenormal, facenormal;
  438. vec_t area;
  439. vec_t facedist;
  440. if (w->numpoints < 3)
  441. Com_Error (ERR_DROP, "CheckWinding: %i points",w->numpoints);
  442. area = WindingArea(w);
  443. if (area < 1)
  444. Com_Error (ERR_DROP, "CheckWinding: %f area", area);
  445. WindingPlane (w, facenormal, &facedist);
  446. for (i=0 ; i<w->numpoints ; i++)
  447. {
  448. p1 = w->p[i];
  449. for (j=0 ; j<3 ; j++)
  450. if (p1[j] > MAX_MAP_BOUNDS || p1[j] < -MAX_MAP_BOUNDS)
  451. Com_Error (ERR_DROP, "CheckFace: BOGUS_RANGE: %f",p1[j]);
  452. j = i+1 == w->numpoints ? 0 : i+1;
  453. // check the point is on the face plane
  454. d = DotProduct (p1, facenormal) - facedist;
  455. if (d < -ON_EPSILON || d > ON_EPSILON)
  456. Com_Error (ERR_DROP, "CheckWinding: point off plane");
  457. // check the edge isnt degenerate
  458. p2 = w->p[j];
  459. VectorSubtract (p2, p1, dir);
  460. if (VectorLength (dir) < ON_EPSILON)
  461. Com_Error (ERR_DROP, "CheckWinding: degenerate edge");
  462. CrossProduct (facenormal, dir, edgenormal);
  463. VectorNormalize2 (edgenormal, edgenormal);
  464. edgedist = DotProduct (p1, edgenormal);
  465. edgedist += ON_EPSILON;
  466. // all other points must be on front side
  467. for (j=0 ; j<w->numpoints ; j++)
  468. {
  469. if (j == i)
  470. continue;
  471. d = DotProduct (w->p[j], edgenormal);
  472. if (d > edgedist)
  473. Com_Error (ERR_DROP, "CheckWinding: non-convex");
  474. }
  475. }
  476. }
  477. /*
  478. ============
  479. WindingOnPlaneSide
  480. ============
  481. */
  482. int WindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist)
  483. {
  484. qboolean front, back;
  485. int i;
  486. vec_t d;
  487. front = qfalse;
  488. back = qfalse;
  489. for (i=0 ; i<w->numpoints ; i++)
  490. {
  491. d = DotProduct (w->p[i], normal) - dist;
  492. if (d < -ON_EPSILON)
  493. {
  494. if (front)
  495. return SIDE_CROSS;
  496. back = qtrue;
  497. continue;
  498. }
  499. if (d > ON_EPSILON)
  500. {
  501. if (back)
  502. return SIDE_CROSS;
  503. front = qtrue;
  504. continue;
  505. }
  506. }
  507. if (back)
  508. return SIDE_BACK;
  509. if (front)
  510. return SIDE_FRONT;
  511. return SIDE_ON;
  512. }
  513. /*
  514. =================
  515. AddWindingToConvexHull
  516. Both w and *hull are on the same plane
  517. =================
  518. */
  519. #define MAX_HULL_POINTS 128
  520. void AddWindingToConvexHull( winding_t *w, winding_t **hull, vec3_t normal ) {
  521. int i, j, k;
  522. float *p, *copy;
  523. vec3_t dir;
  524. float d;
  525. int numHullPoints, numNew;
  526. vec3_t hullPoints[MAX_HULL_POINTS];
  527. vec3_t newHullPoints[MAX_HULL_POINTS];
  528. vec3_t hullDirs[MAX_HULL_POINTS];
  529. qboolean hullSide[MAX_HULL_POINTS];
  530. qboolean outside;
  531. if ( !*hull ) {
  532. *hull = CopyWinding( w );
  533. return;
  534. }
  535. numHullPoints = (*hull)->numpoints;
  536. memcpy( hullPoints, (*hull)->p, numHullPoints * sizeof(vec3_t) );
  537. for ( i = 0 ; i < w->numpoints ; i++ ) {
  538. p = w->p[i];
  539. // calculate hull side vectors
  540. for ( j = 0 ; j < numHullPoints ; j++ ) {
  541. k = ( j + 1 ) % numHullPoints;
  542. VectorSubtract( hullPoints[k], hullPoints[j], dir );
  543. VectorNormalize2( dir, dir );
  544. CrossProduct( normal, dir, hullDirs[j] );
  545. }
  546. outside = qfalse;
  547. for ( j = 0 ; j < numHullPoints ; j++ ) {
  548. VectorSubtract( p, hullPoints[j], dir );
  549. d = DotProduct( dir, hullDirs[j] );
  550. if ( d >= ON_EPSILON ) {
  551. outside = qtrue;
  552. }
  553. if ( d >= -ON_EPSILON ) {
  554. hullSide[j] = qtrue;
  555. } else {
  556. hullSide[j] = qfalse;
  557. }
  558. }
  559. // if the point is effectively inside, do nothing
  560. if ( !outside ) {
  561. continue;
  562. }
  563. // find the back side to front side transition
  564. for ( j = 0 ; j < numHullPoints ; j++ ) {
  565. if ( !hullSide[ j % numHullPoints ] && hullSide[ (j + 1) % numHullPoints ] ) {
  566. break;
  567. }
  568. }
  569. if ( j == numHullPoints ) {
  570. continue;
  571. }
  572. // insert the point here
  573. VectorCopy( p, newHullPoints[0] );
  574. numNew = 1;
  575. // copy over all points that aren't double fronts
  576. j = (j+1)%numHullPoints;
  577. for ( k = 0 ; k < numHullPoints ; k++ ) {
  578. if ( hullSide[ (j+k) % numHullPoints ] && hullSide[ (j+k+1) % numHullPoints ] ) {
  579. continue;
  580. }
  581. copy = hullPoints[ (j+k+1) % numHullPoints ];
  582. VectorCopy( copy, newHullPoints[numNew] );
  583. numNew++;
  584. }
  585. numHullPoints = numNew;
  586. memcpy( hullPoints, newHullPoints, numHullPoints * sizeof(vec3_t) );
  587. }
  588. FreeWinding( *hull );
  589. w = AllocWinding( numHullPoints );
  590. w->numpoints = numHullPoints;
  591. *hull = w;
  592. memcpy( w->p, hullPoints, numHullPoints * sizeof(vec3_t) );
  593. }