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.

915 lines
18 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. // $NoKeywords: $
  8. //=============================================================================//
  9. #include "cmdlib.h"
  10. #include "mathlib/mathlib.h"
  11. #include "polylib.h"
  12. #include "worldsize.h"
  13. #include "threads.h"
  14. #include "tier0/dbg.h"
  15. // doesn't seem to need to be here? -- in threads.h
  16. //extern int numthreads;
  17. // counters are only bumped when running single threaded,
  18. // because they are an awefull coherence problem
  19. int c_active_windings;
  20. int c_peak_windings;
  21. int c_winding_allocs;
  22. int c_winding_points;
  23. void pw(winding_t *w)
  24. {
  25. int i;
  26. for (i=0 ; i<w->numpoints ; i++)
  27. printf ("(%5.1f, %5.1f, %5.1f)\n",w->p[i][0], w->p[i][1],w->p[i][2]);
  28. }
  29. winding_t *winding_pool[MAX_POINTS_ON_WINDING+4];
  30. /*
  31. =============
  32. AllocWinding
  33. =============
  34. */
  35. winding_t *AllocWinding (int points)
  36. {
  37. winding_t *w;
  38. if (numthreads == 1)
  39. {
  40. c_winding_allocs++;
  41. c_winding_points += points;
  42. c_active_windings++;
  43. if (c_active_windings > c_peak_windings)
  44. c_peak_windings = c_active_windings;
  45. }
  46. ThreadLock();
  47. if (winding_pool[points])
  48. {
  49. w = winding_pool[points];
  50. winding_pool[points] = w->next;
  51. }
  52. else
  53. {
  54. w = (winding_t *)malloc(sizeof(*w));
  55. w->p = (Vector *)calloc( points, sizeof(Vector) );
  56. }
  57. ThreadUnlock();
  58. w->numpoints = 0; // None are occupied yet even though allocated.
  59. w->maxpoints = points;
  60. w->next = NULL;
  61. return w;
  62. }
  63. void FreeWinding (winding_t *w)
  64. {
  65. if (w->numpoints == 0xdeaddead)
  66. Error ("FreeWinding: freed a freed winding");
  67. ThreadLock();
  68. w->numpoints = 0xdeaddead; // flag as freed
  69. w->next = winding_pool[w->maxpoints];
  70. winding_pool[w->maxpoints] = w;
  71. ThreadUnlock();
  72. }
  73. /*
  74. ============
  75. RemoveColinearPoints
  76. ============
  77. */
  78. int c_removed;
  79. void RemoveColinearPoints (winding_t *w)
  80. {
  81. int i, j, k;
  82. Vector v1, v2;
  83. int nump;
  84. Vector p[MAX_POINTS_ON_WINDING];
  85. nump = 0;
  86. for (i=0 ; i<w->numpoints ; i++)
  87. {
  88. j = (i+1)%w->numpoints;
  89. k = (i+w->numpoints-1)%w->numpoints;
  90. VectorSubtract (w->p[j], w->p[i], v1);
  91. VectorSubtract (w->p[i], w->p[k], v2);
  92. VectorNormalize(v1);
  93. VectorNormalize(v2);
  94. if (DotProduct(v1, v2) < 0.999)
  95. {
  96. VectorCopy (w->p[i], p[nump]);
  97. nump++;
  98. }
  99. }
  100. if (nump == w->numpoints)
  101. return;
  102. if (numthreads == 1)
  103. c_removed += w->numpoints - nump;
  104. w->numpoints = nump;
  105. memcpy (w->p, p, nump*sizeof(p[0]));
  106. }
  107. /*
  108. ============
  109. WindingPlane
  110. ============
  111. */
  112. void WindingPlane (winding_t *w, Vector &normal, vec_t *dist)
  113. {
  114. Vector v1, v2;
  115. VectorSubtract (w->p[1], w->p[0], v1);
  116. // HACKHACK: Avoid potentially collinear verts
  117. if ( w->numpoints > 3 )
  118. {
  119. VectorSubtract (w->p[3], w->p[0], v2);
  120. }
  121. else
  122. {
  123. VectorSubtract (w->p[2], w->p[0], v2);
  124. }
  125. CrossProduct (v2, v1, normal);
  126. VectorNormalize (normal);
  127. *dist = DotProduct (w->p[0], normal);
  128. }
  129. /*
  130. =============
  131. WindingArea
  132. =============
  133. */
  134. vec_t WindingArea(winding_t *w)
  135. {
  136. int i;
  137. Vector d1, d2, cross;
  138. vec_t total;
  139. total = 0;
  140. for (i=2 ; i<w->numpoints ; i++)
  141. {
  142. VectorSubtract (w->p[i-1], w->p[0], d1);
  143. VectorSubtract (w->p[i], w->p[0], d2);
  144. CrossProduct (d1, d2, cross);
  145. total += VectorLength ( cross );
  146. }
  147. return total * 0.5;
  148. }
  149. void WindingBounds (winding_t *w, Vector &mins, Vector &maxs)
  150. {
  151. vec_t v;
  152. int i,j;
  153. mins[0] = mins[1] = mins[2] = 99999;
  154. maxs[0] = maxs[1] = maxs[2] = -99999;
  155. for (i=0 ; i<w->numpoints ; i++)
  156. {
  157. for (j=0 ; j<3 ; j++)
  158. {
  159. v = w->p[i][j];
  160. if (v < mins[j])
  161. mins[j] = v;
  162. if (v > maxs[j])
  163. maxs[j] = v;
  164. }
  165. }
  166. }
  167. /*
  168. =============
  169. WindingCenter
  170. =============
  171. */
  172. void WindingCenter (winding_t *w, Vector &center)
  173. {
  174. int i;
  175. float scale;
  176. VectorCopy (vec3_origin, center);
  177. for (i=0 ; i<w->numpoints ; i++)
  178. VectorAdd (w->p[i], center, center);
  179. scale = 1.0/w->numpoints;
  180. VectorScale (center, scale, center);
  181. }
  182. /*
  183. =============
  184. WindingCenter
  185. =============
  186. */
  187. vec_t WindingAreaAndBalancePoint( winding_t *w, Vector &center )
  188. {
  189. int i;
  190. Vector d1, d2, cross;
  191. vec_t total;
  192. VectorCopy (vec3_origin, center);
  193. if ( !w )
  194. return 0.0f;
  195. total = 0;
  196. for (i=2 ; i<w->numpoints ; i++)
  197. {
  198. VectorSubtract (w->p[i-1], w->p[0], d1);
  199. VectorSubtract (w->p[i], w->p[0], d2);
  200. CrossProduct (d1, d2, cross);
  201. float area = VectorLength ( cross );
  202. total += area;
  203. // center of triangle, weighed by area
  204. VectorMA( center, area / 3.0, w->p[i-1], center );
  205. VectorMA( center, area / 3.0, w->p[i], center );
  206. VectorMA( center, area / 3.0, w->p[0], center );
  207. }
  208. if (total)
  209. {
  210. VectorScale( center, 1.0 / total, center );
  211. }
  212. return total * 0.5;
  213. }
  214. /*
  215. =================
  216. BaseWindingForPlane
  217. =================
  218. */
  219. winding_t *BaseWindingForPlane (const Vector &normal, vec_t dist)
  220. {
  221. int i, x;
  222. vec_t max, v;
  223. Vector org, vright, vup;
  224. winding_t *w;
  225. // find the major axis
  226. max = -1;
  227. x = -1;
  228. for (i=0 ; i<3; i++)
  229. {
  230. v = fabs(normal[i]);
  231. if (v > max)
  232. {
  233. x = i;
  234. max = v;
  235. }
  236. }
  237. if (x==-1)
  238. Error ("BaseWindingForPlane: no axis found");
  239. VectorCopy (vec3_origin, vup);
  240. switch (x)
  241. {
  242. case 0:
  243. case 1:
  244. vup[2] = 1;
  245. break;
  246. case 2:
  247. vup[0] = 1;
  248. break;
  249. }
  250. v = DotProduct (vup, normal);
  251. VectorMA (vup, -v, normal, vup);
  252. VectorNormalize (vup);
  253. VectorScale (normal, dist, org);
  254. CrossProduct (vup, normal, vright);
  255. VectorScale (vup, (MAX_COORD_INTEGER*4), vup);
  256. VectorScale (vright, (MAX_COORD_INTEGER*4), vright);
  257. // project a really big axis aligned box onto the plane
  258. w = AllocWinding (4);
  259. VectorSubtract (org, vright, w->p[0]);
  260. VectorAdd (w->p[0], vup, w->p[0]);
  261. VectorAdd (org, vright, w->p[1]);
  262. VectorAdd (w->p[1], vup, w->p[1]);
  263. VectorAdd (org, vright, w->p[2]);
  264. VectorSubtract (w->p[2], vup, w->p[2]);
  265. VectorSubtract (org, vright, w->p[3]);
  266. VectorSubtract (w->p[3], vup, w->p[3]);
  267. w->numpoints = 4;
  268. return w;
  269. }
  270. /*
  271. ==================
  272. CopyWinding
  273. ==================
  274. */
  275. winding_t *CopyWinding (winding_t *w)
  276. {
  277. int size;
  278. winding_t *c;
  279. c = AllocWinding (w->numpoints);
  280. c->numpoints = w->numpoints;
  281. size = w->numpoints*sizeof(w->p[0]);
  282. memcpy (c->p, w->p, size);
  283. return c;
  284. }
  285. /*
  286. ==================
  287. ReverseWinding
  288. ==================
  289. */
  290. winding_t *ReverseWinding (winding_t *w)
  291. {
  292. int i;
  293. winding_t *c;
  294. c = AllocWinding (w->numpoints);
  295. for (i=0 ; i<w->numpoints ; i++)
  296. {
  297. VectorCopy (w->p[w->numpoints-1-i], c->p[i]);
  298. }
  299. c->numpoints = w->numpoints;
  300. return c;
  301. }
  302. // BUGBUG: Hunt this down - it's causing CSG errors
  303. #pragma optimize("g", off)
  304. /*
  305. =============
  306. ClipWindingEpsilon
  307. =============
  308. */
  309. void ClipWindingEpsilon (winding_t *in, const Vector &normal, vec_t dist,
  310. vec_t epsilon, winding_t **front, winding_t **back)
  311. {
  312. vec_t dists[MAX_POINTS_ON_WINDING+4];
  313. int sides[MAX_POINTS_ON_WINDING+4];
  314. int counts[3];
  315. vec_t dot;
  316. int i, j;
  317. Vector mid = vec3_origin;
  318. winding_t *f, *b;
  319. int maxpts;
  320. counts[0] = counts[1] = counts[2] = 0;
  321. // determine sides for each point
  322. for (i=0 ; i<in->numpoints ; i++)
  323. {
  324. dot = DotProduct (in->p[i], normal);
  325. dot -= dist;
  326. dists[i] = dot;
  327. if (dot > epsilon)
  328. sides[i] = SIDE_FRONT;
  329. else if (dot < -epsilon)
  330. sides[i] = SIDE_BACK;
  331. else
  332. {
  333. sides[i] = SIDE_ON;
  334. }
  335. counts[sides[i]]++;
  336. }
  337. sides[i] = sides[0];
  338. dists[i] = dists[0];
  339. *front = *back = NULL;
  340. if (!counts[0])
  341. {
  342. *back = CopyWinding (in);
  343. return;
  344. }
  345. if (!counts[1])
  346. {
  347. *front = CopyWinding (in);
  348. return;
  349. }
  350. maxpts = in->numpoints+4; // cant use counts[0]+2 because
  351. // of fp grouping errors
  352. *front = f = AllocWinding (maxpts);
  353. *back = b = AllocWinding (maxpts);
  354. for (i=0 ; i<in->numpoints ; i++)
  355. {
  356. Vector& p1 = in->p[i];
  357. if (sides[i] == SIDE_ON)
  358. {
  359. VectorCopy (p1, f->p[f->numpoints]);
  360. f->numpoints++;
  361. VectorCopy (p1, b->p[b->numpoints]);
  362. b->numpoints++;
  363. continue;
  364. }
  365. if (sides[i] == SIDE_FRONT)
  366. {
  367. VectorCopy (p1, f->p[f->numpoints]);
  368. f->numpoints++;
  369. }
  370. if (sides[i] == SIDE_BACK)
  371. {
  372. VectorCopy (p1, b->p[b->numpoints]);
  373. b->numpoints++;
  374. }
  375. if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
  376. continue;
  377. // generate a split point
  378. Vector& p2 = in->p[(i+1)%in->numpoints];
  379. dot = dists[i] / (dists[i]-dists[i+1]);
  380. for (j=0 ; j<3 ; j++)
  381. { // avoid round off error when possible
  382. if (normal[j] == 1)
  383. mid[j] = dist;
  384. else if (normal[j] == -1)
  385. mid[j] = -dist;
  386. else
  387. mid[j] = p1[j] + dot*(p2[j]-p1[j]);
  388. }
  389. VectorCopy (mid, f->p[f->numpoints]);
  390. f->numpoints++;
  391. VectorCopy (mid, b->p[b->numpoints]);
  392. b->numpoints++;
  393. }
  394. if (f->numpoints > maxpts || b->numpoints > maxpts)
  395. Error ("ClipWinding: points exceeded estimate");
  396. if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING)
  397. Error ("ClipWinding: MAX_POINTS_ON_WINDING");
  398. }
  399. #pragma optimize("", on)
  400. // NOTE: This is identical to ClipWindingEpsilon, but it does a pre/post translation to improve precision
  401. void ClipWindingEpsilon_Offset( winding_t *in, const Vector &normal, vec_t dist, vec_t epsilon, winding_t **front, winding_t **back, const Vector &offset )
  402. {
  403. TranslateWinding( in, offset );
  404. ClipWindingEpsilon( in, normal, dist+DotProduct(offset,normal), epsilon, front, back );
  405. TranslateWinding( in, -offset );
  406. if ( front && *front )
  407. {
  408. TranslateWinding( *front, -offset );
  409. }
  410. if ( back && *back )
  411. {
  412. TranslateWinding( *back, -offset );
  413. }
  414. }
  415. void ClassifyWindingEpsilon_Offset( winding_t *in, const Vector &normal, vec_t dist, vec_t epsilon, winding_t **front, winding_t **back, winding_t **on, const Vector &offset)
  416. {
  417. TranslateWinding( in, offset );
  418. ClassifyWindingEpsilon( in, normal, dist+DotProduct(offset,normal), epsilon, front, back, on );
  419. TranslateWinding( in, -offset );
  420. if ( front && *front )
  421. {
  422. TranslateWinding( *front, -offset );
  423. }
  424. if ( back && *back )
  425. {
  426. TranslateWinding( *back, -offset );
  427. }
  428. if ( on && *on )
  429. {
  430. TranslateWinding( *on, -offset );
  431. }
  432. }
  433. /*
  434. =============
  435. ClassifyWindingEpsilon
  436. =============
  437. */
  438. // This version returns the winding as "on" if all verts lie in the plane
  439. void ClassifyWindingEpsilon( winding_t *in, const Vector &normal, vec_t dist,
  440. vec_t epsilon, winding_t **front, winding_t **back, winding_t **on)
  441. {
  442. vec_t dists[MAX_POINTS_ON_WINDING+4];
  443. int sides[MAX_POINTS_ON_WINDING+4];
  444. int counts[3];
  445. vec_t dot;
  446. int i, j;
  447. Vector mid = vec3_origin;
  448. winding_t *f, *b;
  449. int maxpts;
  450. counts[0] = counts[1] = counts[2] = 0;
  451. // determine sides for each point
  452. for (i=0 ; i<in->numpoints ; i++)
  453. {
  454. dot = DotProduct (in->p[i], normal);
  455. dot -= dist;
  456. dists[i] = dot;
  457. if (dot > epsilon)
  458. sides[i] = SIDE_FRONT;
  459. else if (dot < -epsilon)
  460. sides[i] = SIDE_BACK;
  461. else
  462. {
  463. sides[i] = SIDE_ON;
  464. }
  465. counts[sides[i]]++;
  466. }
  467. sides[i] = sides[0];
  468. dists[i] = dists[0];
  469. *front = *back = *on = NULL;
  470. if ( !counts[0] && !counts[1] )
  471. {
  472. *on = CopyWinding(in);
  473. return;
  474. }
  475. if (!counts[0])
  476. {
  477. *back = CopyWinding(in);
  478. return;
  479. }
  480. if (!counts[1])
  481. {
  482. *front = CopyWinding(in);
  483. return;
  484. }
  485. maxpts = in->numpoints+4; // cant use counts[0]+2 because
  486. // of fp grouping errors
  487. *front = f = AllocWinding (maxpts);
  488. *back = b = AllocWinding (maxpts);
  489. for (i=0 ; i<in->numpoints ; i++)
  490. {
  491. Vector& p1 = in->p[i];
  492. if (sides[i] == SIDE_ON)
  493. {
  494. VectorCopy (p1, f->p[f->numpoints]);
  495. f->numpoints++;
  496. VectorCopy (p1, b->p[b->numpoints]);
  497. b->numpoints++;
  498. continue;
  499. }
  500. if (sides[i] == SIDE_FRONT)
  501. {
  502. VectorCopy (p1, f->p[f->numpoints]);
  503. f->numpoints++;
  504. }
  505. if (sides[i] == SIDE_BACK)
  506. {
  507. VectorCopy (p1, b->p[b->numpoints]);
  508. b->numpoints++;
  509. }
  510. if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
  511. continue;
  512. // generate a split point
  513. Vector& p2 = in->p[(i+1)%in->numpoints];
  514. dot = dists[i] / (dists[i]-dists[i+1]);
  515. for (j=0 ; j<3 ; j++)
  516. { // avoid round off error when possible
  517. if (normal[j] == 1)
  518. mid[j] = dist;
  519. else if (normal[j] == -1)
  520. mid[j] = -dist;
  521. else
  522. mid[j] = p1[j] + dot*(p2[j]-p1[j]);
  523. }
  524. VectorCopy (mid, f->p[f->numpoints]);
  525. f->numpoints++;
  526. VectorCopy (mid, b->p[b->numpoints]);
  527. b->numpoints++;
  528. }
  529. if (f->numpoints > maxpts || b->numpoints > maxpts)
  530. Error ("ClipWinding: points exceeded estimate");
  531. if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING)
  532. Error ("ClipWinding: MAX_POINTS_ON_WINDING");
  533. }
  534. /*
  535. =============
  536. ChopWindingInPlace
  537. =============
  538. */
  539. void ChopWindingInPlace (winding_t **inout, const Vector &normal, vec_t dist, vec_t epsilon)
  540. {
  541. winding_t *in;
  542. vec_t dists[MAX_POINTS_ON_WINDING+4];
  543. int sides[MAX_POINTS_ON_WINDING+4];
  544. int counts[3];
  545. vec_t dot;
  546. int i, j;
  547. Vector mid = vec3_origin;
  548. winding_t *f;
  549. int maxpts;
  550. in = *inout;
  551. counts[0] = counts[1] = counts[2] = 0;
  552. // determine sides for each point
  553. for (i=0 ; i<in->numpoints ; i++)
  554. {
  555. dot = DotProduct (in->p[i], normal);
  556. dot -= dist;
  557. dists[i] = dot;
  558. if (dot > epsilon)
  559. {
  560. sides[i] = SIDE_FRONT;
  561. }
  562. else if (dot < -epsilon)
  563. {
  564. sides[i] = SIDE_BACK;
  565. }
  566. else
  567. {
  568. sides[i] = SIDE_ON;
  569. }
  570. counts[sides[i]]++;
  571. }
  572. sides[i] = sides[0];
  573. dists[i] = dists[0];
  574. if (!counts[0])
  575. {
  576. FreeWinding (in);
  577. *inout = NULL;
  578. return;
  579. }
  580. if (!counts[1])
  581. return; // inout stays the same
  582. maxpts = in->numpoints+4; // cant use counts[0]+2 because
  583. // of fp grouping errors
  584. f = AllocWinding (maxpts);
  585. for (i=0 ; i<in->numpoints ; i++)
  586. {
  587. Vector& p1 = in->p[i];
  588. if (sides[i] == SIDE_ON)
  589. {
  590. VectorCopy (p1, f->p[f->numpoints]);
  591. f->numpoints++;
  592. continue;
  593. }
  594. if (sides[i] == SIDE_FRONT)
  595. {
  596. VectorCopy (p1, f->p[f->numpoints]);
  597. f->numpoints++;
  598. }
  599. if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
  600. continue;
  601. // generate a split point
  602. Vector& p2 = in->p[(i+1)%in->numpoints];
  603. dot = dists[i] / (dists[i]-dists[i+1]);
  604. for (j=0 ; j<3 ; j++)
  605. { // avoid round off error when possible
  606. if (normal[j] == 1)
  607. mid[j] = dist;
  608. else if (normal[j] == -1)
  609. mid[j] = -dist;
  610. else
  611. mid[j] = p1[j] + dot*(p2[j]-p1[j]);
  612. }
  613. VectorCopy (mid, f->p[f->numpoints]);
  614. f->numpoints++;
  615. }
  616. if (f->numpoints > maxpts)
  617. Error ("ClipWinding: points exceeded estimate");
  618. if (f->numpoints > MAX_POINTS_ON_WINDING)
  619. Error ("ClipWinding: MAX_POINTS_ON_WINDING");
  620. FreeWinding (in);
  621. *inout = f;
  622. }
  623. /*
  624. =================
  625. ChopWinding
  626. Returns the fragment of in that is on the front side
  627. of the cliping plane. The original is freed.
  628. =================
  629. */
  630. winding_t *ChopWinding (winding_t *in, const Vector &normal, vec_t dist)
  631. {
  632. winding_t *f, *b;
  633. ClipWindingEpsilon (in, normal, dist, ON_EPSILON, &f, &b);
  634. FreeWinding (in);
  635. if (b)
  636. FreeWinding (b);
  637. return f;
  638. }
  639. /*
  640. =================
  641. CheckWinding
  642. =================
  643. */
  644. void CheckWinding (winding_t *w)
  645. {
  646. int i, j;
  647. vec_t d, edgedist;
  648. Vector dir, edgenormal, facenormal;
  649. vec_t area;
  650. vec_t facedist;
  651. if (w->numpoints < 3)
  652. Error ("CheckWinding: %i points",w->numpoints);
  653. area = WindingArea(w);
  654. if (area < 1)
  655. Error ("CheckWinding: %f area", area);
  656. WindingPlane (w, facenormal, &facedist);
  657. for (i=0 ; i<w->numpoints ; i++)
  658. {
  659. Vector& p1 = w->p[i];
  660. for (j=0 ; j<3 ; j++)
  661. {
  662. if (p1[j] > MAX_COORD_INTEGER || p1[j] < MIN_COORD_INTEGER)
  663. Error ("CheckFace: out of range: %f",p1[j]);
  664. }
  665. j = i+1 == w->numpoints ? 0 : i+1;
  666. // check the point is on the face plane
  667. d = DotProduct (p1, facenormal) - facedist;
  668. if (d < -ON_EPSILON || d > ON_EPSILON)
  669. Error ("CheckWinding: point off plane");
  670. // check the edge isnt degenerate
  671. Vector& p2 = w->p[j];
  672. VectorSubtract (p2, p1, dir);
  673. if (VectorLength (dir) < ON_EPSILON)
  674. Error ("CheckWinding: degenerate edge");
  675. CrossProduct (facenormal, dir, edgenormal);
  676. VectorNormalize (edgenormal);
  677. edgedist = DotProduct (p1, edgenormal);
  678. edgedist += ON_EPSILON;
  679. // all other points must be on front side
  680. for (j=0 ; j<w->numpoints ; j++)
  681. {
  682. if (j == i)
  683. continue;
  684. d = DotProduct (w->p[j], edgenormal);
  685. if (d > edgedist)
  686. Error ("CheckWinding: non-convex");
  687. }
  688. }
  689. }
  690. /*
  691. ============
  692. WindingOnPlaneSide
  693. ============
  694. */
  695. int WindingOnPlaneSide (winding_t *w, const Vector &normal, vec_t dist)
  696. {
  697. qboolean front, back;
  698. int i;
  699. vec_t d;
  700. front = false;
  701. back = false;
  702. for (i=0 ; i<w->numpoints ; i++)
  703. {
  704. d = DotProduct (w->p[i], normal) - dist;
  705. if (d < -ON_EPSILON)
  706. {
  707. if (front)
  708. return SIDE_CROSS;
  709. back = true;
  710. continue;
  711. }
  712. if (d > ON_EPSILON)
  713. {
  714. if (back)
  715. return SIDE_CROSS;
  716. front = true;
  717. continue;
  718. }
  719. }
  720. if (back)
  721. return SIDE_BACK;
  722. if (front)
  723. return SIDE_FRONT;
  724. return SIDE_ON;
  725. }
  726. //-----------------------------------------------------------------------------
  727. // Purpose: 2d point inside of winding test (assumes the point resides in the
  728. // winding plane)
  729. //-----------------------------------------------------------------------------
  730. bool PointInWinding( const Vector &pt, winding_t *pWinding )
  731. {
  732. if( !pWinding )
  733. return false;
  734. #if 0
  735. //
  736. // NOTE: this will be a quicker way to calculate this, however I don't
  737. // know the trick off hand (post dot product tests??)
  738. // TODO: look in graphics gems!!!! (cab)
  739. //
  740. Vector edge1, edge2;
  741. for( int ndxPt = 0; ndxPt < pWinding->numpoints; ndxPt++ )
  742. {
  743. edge1 = pWinding->p[ndxPt] - pt;
  744. edge2 = pWinding->p[(ndxPt+1)%pWinding->numpoints] - pt;
  745. VectorNormalize( edge1 );
  746. VectorNormalize( edge2 );
  747. if( edge2.Dot( edge1 ) < 0.0f )
  748. return false;
  749. }
  750. return true;
  751. #else
  752. Vector edge, toPt, cross, testCross;
  753. //
  754. // get the first normal to test
  755. //
  756. toPt = pt - pWinding->p[0];
  757. edge = pWinding->p[1] - pWinding->p[0];
  758. testCross = edge.Cross( toPt );
  759. VectorNormalize( testCross );
  760. for( int ndxPt = 1; ndxPt < pWinding->numpoints; ndxPt++ )
  761. {
  762. toPt = pt - pWinding->p[ndxPt];
  763. edge = pWinding->p[(ndxPt+1)%pWinding->numpoints] - pWinding->p[ndxPt];
  764. cross = edge.Cross( toPt );
  765. VectorNormalize( cross );
  766. if( cross.Dot( testCross ) < 0.0f )
  767. return false;
  768. }
  769. return true;
  770. #endif
  771. }
  772. void TranslateWinding( winding_t *pWinding, const Vector &offset )
  773. {
  774. for ( int i = 0; i < pWinding->numpoints; i++ )
  775. {
  776. pWinding->p[i] += offset;
  777. }
  778. }