tri.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : WWMath *
  23. * *
  24. * $Archive:: /Commando/Code/WWMath/tri.cpp $*
  25. * *
  26. * Author:: Greg Hjelstrom *
  27. * *
  28. * $Modtime:: 5/03/01 3:41p $*
  29. * *
  30. * $Revision:: 8 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * TriClass::Find_Dominant_Plane -- returns indices of the axes of the dominant plane *
  35. * TriClass::Contains_Point -- performs 2D point-in-triangle test. *
  36. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  37. #include "tri.h"
  38. #include "vector2.h"
  39. struct FDPRec
  40. {
  41. int axis1;
  42. int axis2;
  43. int axis3;
  44. };
  45. static inline void find_dominant_plane_fast(const TriClass & tri, FDPRec& info)
  46. {
  47. static const FDPRec dominance[3] =
  48. {
  49. { 1, 2, 0 }, // Dominant is the X axis
  50. { 0, 2, 1 }, // Dominant is the Y axis
  51. { 0, 1, 2 } // Dominant is the Z axis
  52. };
  53. /*
  54. ** Find the largest component of the normal
  55. */
  56. float x = WWMath::Fabs(tri.N->X);
  57. float y = WWMath::Fabs(tri.N->Y);
  58. float z = WWMath::Fabs(tri.N->Z);
  59. float val = x;
  60. int ni = 0;
  61. if (y > val)
  62. {
  63. ni = 1;
  64. val = y;
  65. }
  66. if (z > val)
  67. {
  68. ni = 2;
  69. }
  70. info = dominance[ni];
  71. }
  72. static inline void find_dominant_plane(const TriClass & tri, int * axis1,int * axis2,int * axis3)
  73. {
  74. /*
  75. ** Find the largest component of the normal
  76. */
  77. int ni = 0;
  78. float x = WWMath::Fabs(tri.N->X);
  79. float y = WWMath::Fabs(tri.N->Y);
  80. float z = WWMath::Fabs(tri.N->Z);
  81. float val = x;
  82. if (y > val) {
  83. ni = 1;
  84. val = y;
  85. }
  86. if (z > val) {
  87. ni = 2;
  88. }
  89. /*
  90. ** return the indices of the two axes perpendicular
  91. */
  92. switch (ni)
  93. {
  94. case 0:
  95. // Dominant is the X axis
  96. *axis1 = 1;
  97. *axis2 = 2;
  98. *axis3 = 0;
  99. break;
  100. case 1:
  101. // Dominant is the Y axis
  102. *axis1 = 0;
  103. *axis2 = 2;
  104. *axis3 = 1;
  105. break;
  106. case 2:
  107. // Dominant is the Z axis
  108. *axis1 = 0;
  109. *axis2 = 1;
  110. *axis3 = 2;
  111. break;
  112. }
  113. }
  114. /***********************************************************************************************
  115. * TriClass::Find_Dominant_Plane -- returns indices of the axes of the dominant plane *
  116. * *
  117. * INPUT: *
  118. * *
  119. * OUTPUT: *
  120. * *
  121. * WARNINGS: *
  122. * *
  123. * HISTORY: *
  124. * 3/24/99 GTH : Created. *
  125. *=============================================================================================*/
  126. void TriClass::Find_Dominant_Plane(int * axis1,int * axis2) const
  127. {
  128. /*
  129. ** Find the largest component of the normal
  130. */
  131. int ni = 0;
  132. float x = WWMath::Fabs(N->X);
  133. float y = WWMath::Fabs(N->Y);
  134. float z = WWMath::Fabs(N->Z);
  135. float val = x;
  136. if (y > val) {
  137. ni = 1;
  138. val = y;
  139. }
  140. if (z > val) {
  141. ni = 2;
  142. }
  143. /*
  144. ** return the indices of the two axes perpendicular
  145. */
  146. switch (ni)
  147. {
  148. case 0:
  149. // Dominant is the X axis
  150. *axis1 = 1;
  151. *axis2 = 2;
  152. break;
  153. case 1:
  154. // Dominant is the Y axis
  155. *axis1 = 0;
  156. *axis2 = 2;
  157. break;
  158. case 2:
  159. // Dominant is the Z axis
  160. *axis1 = 0;
  161. *axis2 = 1;
  162. break;
  163. }
  164. }
  165. /***********************************************************************************************
  166. * TriClass::Contains_Point -- performs 2D point-in-triangle test. *
  167. * *
  168. * INPUT: *
  169. * *
  170. * OUTPUT: *
  171. * *
  172. * WARNINGS: *
  173. * Assumes that the point is in the plane of the triangle... use this after you've intersected *
  174. * a ray with the plane of the triangle. *
  175. * *
  176. * HISTORY: *
  177. * 3/24/99 GTH : Created. *
  178. *=============================================================================================*/
  179. bool TriClass::Contains_Point(const Vector3 & ipoint) const
  180. {
  181. #if 0
  182. /*
  183. ** Perform the test in 2d on the plane which the normal
  184. ** is most perpendicular to. (copied from E.Cosky's intersection code)
  185. */
  186. int axis1 = 0;
  187. int axis2 = 0;
  188. Find_Dominant_Plane(&axis1,&axis2);
  189. #if 1
  190. unsigned char flags; // dummy variable passed into function and not used here
  191. return Point_In_Triangle_2D(*V[0], *V[1], *V[2], ipoint, axis1, axis2, flags);
  192. #else
  193. float u0 = ipoint[axis1] - (*V[0])[axis1];
  194. float v0 = ipoint[axis2] - (*V[0])[axis2];
  195. /*
  196. ** determine the 2d vectors on the dominant plane from the first vertex to the other two
  197. */
  198. float u1 = (*V[1])[axis1] - (*V[0])[axis1];
  199. float v1 = (*V[1])[axis2] - (*V[0])[axis2];
  200. float u2 = (*V[2])[axis1] - (*V[0])[axis1];
  201. float v2 = (*V[2])[axis2] - (*V[0])[axis2];
  202. float alpha, beta;
  203. bool intersect = false;
  204. // calculate alpha and beta as normalized (0..1) percentages across the 2d projected triangle
  205. // and do bounds checking (sum <= 1) to determine whether or not the triangle intersection occurs.
  206. if (u1 == 0) {
  207. beta = u0 / u2;
  208. if ((beta >= 0) && (beta <= 1)) {
  209. alpha = (v0 - beta * v2) / v1;
  210. intersect = ((alpha >= 0) && ((alpha + beta) <= 1 + WWMATH_EPSILON));
  211. }
  212. } else {
  213. beta = (v0 * u1 - u0 * v1) / (v2 * u1 - u2 * v1);
  214. if ((beta >= 0) && (beta <= 1)) {
  215. alpha = (u0 - beta * u2) / u1;
  216. intersect = ((alpha >= 0) && ((alpha + beta) <= 1 + WWMATH_EPSILON));
  217. }
  218. }
  219. return intersect;
  220. #endif
  221. #endif
  222. /*
  223. ** New cross-product based point-containment
  224. */
  225. #if 0
  226. int vi;
  227. int axis3 = 0;
  228. for (vi=0; vi<3; vi++) {
  229. if ((axis1 != vi) && (axis2 != vi)) axis3 = vi;
  230. }
  231. Vector3 test_point = ipoint;
  232. test_point[axis3] = 0.0f;
  233. Vector3 points[3];
  234. for (vi=0; vi<3; vi++) {
  235. points[vi] = *(V[vi]);
  236. points[vi][axis3] = 0.0f;
  237. }
  238. bool side[3];
  239. Vector3 edge;
  240. Vector3 cross;
  241. Vector3 dp;
  242. for (vi=0; vi<3; vi++) {
  243. edge = points[(vi+1)%3] - points[vi];
  244. dp = test_point - points[vi];
  245. Vector3::Cross_Product(dp,edge,&cross);
  246. side[vi] = (cross[axis3] > 0.0f);
  247. }
  248. bool my_intersect = ((side[0] == side[1]) && (side[1] == side[2]));
  249. return my_intersect;
  250. #endif
  251. /*
  252. ** "Optimized" version
  253. */
  254. #if 1
  255. #if 0
  256. // srj opto version
  257. /// @todo srj -- profile me to see if this is actually faster
  258. FDPRec info;
  259. find_dominant_plane_fast(*this, info);
  260. /*
  261. ** Compute the 2D cross product of edge0 with a vector to the point
  262. */
  263. float edge_x, edge_y, dp_x, dp_y, cross;
  264. bool side0, side1, side2;
  265. edge_x = (*V[1])[info.axis1] - (*V[0])[info.axis1];
  266. edge_y = (*V[1])[info.axis2] - (*V[0])[info.axis2];
  267. dp_x = ipoint[info.axis1] - (*V[0])[info.axis1];
  268. dp_y = ipoint[info.axis2] - (*V[0])[info.axis2];
  269. cross = edge_x * dp_y - edge_y * dp_x;
  270. side0 = (cross >= 0.0f);
  271. edge_x = (*V[2])[info.axis1] - (*V[1])[info.axis1];
  272. edge_y = (*V[2])[info.axis2] - (*V[1])[info.axis2];
  273. dp_x = ipoint[info.axis1] - (*V[1])[info.axis1];
  274. dp_y = ipoint[info.axis2] - (*V[1])[info.axis2];
  275. cross = edge_x * dp_y - edge_y * dp_x;
  276. side1 = (cross >= 0.0f);
  277. edge_x = (*V[0])[info.axis1] - (*V[2])[info.axis1];
  278. edge_y = (*V[0])[info.axis2] - (*V[2])[info.axis2];
  279. dp_x = ipoint[info.axis1] - (*V[2])[info.axis1];
  280. dp_y = ipoint[info.axis2] - (*V[2])[info.axis2];
  281. cross = edge_x * dp_y - edge_y * dp_x;
  282. side2 = (cross >= 0.0f);
  283. bool my_intersect = ((side0 == side1) && (side1 == side2));
  284. return my_intersect;
  285. #else
  286. int vi;
  287. int axis1 = 0;
  288. int axis2 = 0;
  289. int axis3 = 0;
  290. find_dominant_plane(*this,&axis1,&axis2,&axis3);
  291. bool side[3];
  292. /*
  293. ** Compute the 2D cross product of edge0 with a vector to the point
  294. */
  295. Vector2 edge;
  296. Vector2 dp;
  297. for (vi=0; vi<3; vi++) {
  298. int va=vi;
  299. int vb=(vi+1)%3;
  300. edge.Set((*V[vb])[axis1] - (*V[va])[axis1] , (*V[vb])[axis2] - (*V[va])[axis2]);
  301. dp.Set(ipoint[axis1] - (*V[va])[axis1] , ipoint[axis2] - (*V[va])[axis2]);
  302. float cross = edge.X * dp.Y - edge.Y * dp.X;
  303. side[vi] = (cross >= 0.0f);
  304. }
  305. bool my_intersect = ((side[0] == side[1]) && (side[1] == side[2]));
  306. return my_intersect;
  307. #endif
  308. #endif
  309. }