intersec.inl 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096
  1. /*
  2. ** Command & Conquer Generals(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. #if defined(_MSC_VER)
  19. #pragma once
  20. #endif
  21. #ifndef INTERSEC_INL
  22. #define INTERSEC_INL
  23. #include "camera.h"
  24. /// debug code that will be tossed
  25. #ifdef DEBUG_NORMALS
  26. #include "d:/g/app/main/debug_o.h"
  27. inline bool Verify_Normal(Vector3 &Normal, Vector3 &loc1, Vector3 &loc2, Vector3 &loc3)
  28. {
  29. double d1 = Vector3::Dot_Product(Normal, loc1);
  30. double d2 = Vector3::Dot_Product(Normal, loc2);
  31. double d3 = Vector3::Dot_Product(Normal, loc3);
  32. double e1 = d1 - d2;
  33. double e2 = d2 - d3;
  34. double e3 = d3 - d1;
  35. if((fabs(e1) > 0.001) || (fabs(e2) > 0.001) || (fabs(e3) > 0.001)) {
  36. Debug.Print("----------\n");
  37. Debug.Print("dots", Vector3(d1,d2,d3));
  38. Debug.Print("err", Vector3(e1,e2,e3));
  39. return false;
  40. }
  41. return true;
  42. }
  43. inline void Verify_Normal2(Vector3 &Normal, Vector3 &loc1, Vector3 &loc2, Vector3 &loc3)
  44. {
  45. Vector3 v1 = loc2 - loc1;
  46. Vector3 v2 = loc3 - loc1;
  47. Vector3 normal = Vector3::Cross_Product(v1,v2);
  48. normal.Normalize();
  49. if(!Verify_Normal(Normal, loc1,loc2,loc3)) {
  50. Vector3 diff = Normal - normal;
  51. if(Verify_Normal(normal, loc1,loc2,loc3)) {
  52. Debug.Print("calculated worked.\n");
  53. }
  54. }
  55. // Normal = normal;
  56. }
  57. #endif
  58. //// end of debug code to toss
  59. /*
  60. ** Determine the ray that corresponds to the specified screen coordinates with respect
  61. ** to the camera location, direction and projection information.
  62. */
  63. inline void IntersectionClass::Get_Screen_Ray(float screen_x, float screen_y, const LayerClass &Layer)
  64. {
  65. // copy screen coords to member data
  66. ScreenX = screen_x;
  67. ScreenY = screen_y;
  68. // extract needed pointers from the world
  69. CameraClass *camera = Layer.Camera;
  70. // determine the ray corresponding to the camera and distance to projection plane
  71. Matrix3D camera_matrix = camera->Get_Transform();
  72. Vector3 camera_location = camera->Get_Position();
  73. // the projected ray has the same origin as the camera
  74. *RayLocation = camera_location;
  75. // these 6 lines worked for SR 1.1
  76. // build the projected screen vector
  77. // float x_offset = width / (float)Scene->width; // render width in pixels divided by display width in pixels = ratio of displayed area
  78. // float y_offset = height / (float)Scene->height;
  79. // float zmod = Scene->perspective;
  80. // float xmod = ((ScreenX / x_offset) * width - xmid - Scene->xstart) * zmod * 16384.0f/ (Scene->axratio * 128.0f);
  81. // float ymod = ((ScreenY / y_offset) * height - ymid - Scene->ystart) * zmod * 16384.0f/ (Scene->ayratio * 128.0f);
  82. // determine the location of the screen coordinate in camera-model space
  83. const ViewportClass &viewport = camera->Get_Viewport();
  84. // float aspect = camera->Get_Aspect_Ratio();
  85. Vector2 min,max;
  86. camera->Get_View_Plane(min,max);
  87. float xscale = (max.X - min.X);
  88. float yscale = (max.Y - min.Y);
  89. float zmod = -1.0; // Scene->vpd; // Note: view plane distance is now always 1.0 from the camera
  90. float xmod = (-ScreenX + 0.5 + viewport.Min.X) * zmod * xscale;// / aspect;
  91. float ymod = (ScreenY - 0.5 - viewport.Min.Y) * zmod * yscale;// * aspect;
  92. // float xmod = (ScreenX - 0.5 - viewport.Min.X) * zmod / Scene->axratio;
  93. // float ymod = (ScreenY - 0.5 - viewport.Min.Y) * zmod / Scene->ayratio;
  94. // sr1.2
  95. // float xmod = (ScreenX - 0.5 - Scene->xstart) * zmod / Scene->axratio;
  96. // float ymod = (ScreenY - 0.5 - Scene->ystart) * zmod / Scene->ayratio;
  97. // sr1.1
  98. // float xmod = x_offset * zmod; //projection_width;
  99. // float ymod = y_offset * zmod; //projection_height;
  100. // transform the screen coordinates by the camera's matrix into world coordinates.
  101. float x = zmod * camera_matrix[0][2] + xmod * camera_matrix[0][0] + ymod * camera_matrix[0][1];
  102. float y = zmod * camera_matrix[1][2] + xmod * camera_matrix[1][0] + ymod * camera_matrix[1][1];
  103. float z = zmod * camera_matrix[2][2] + xmod * camera_matrix[2][0] + ymod * camera_matrix[2][1];
  104. RayDirection->Set(x,y,z);
  105. RayDirection->Normalize();
  106. // set the maximum intersection distance to the back clipping plane
  107. MaxDistance = camera->Get_Depth();
  108. //Max_Distance = Scene->zstop * Scene->depth;
  109. }
  110. /*
  111. ** This is the Point_In_Polygon_Z low level function, optimized for use by _Intersect_Triangles_Z.
  112. ** If it is inside, it will adjust the Z value of the point to be on the triangle plane.
  113. */
  114. inline bool IntersectionClass::_Point_In_Polygon_Z(
  115. Vector3 &Point,
  116. Vector3 &Corner1,
  117. Vector3 &Corner2,
  118. Vector3 &Corner3
  119. )
  120. {
  121. // these defines could be variables if support for other axis were neccessary
  122. #define AXIS_1 0
  123. #define AXIS_2 1
  124. #define AXIS_3 2
  125. double u0 = Point[AXIS_1] - Corner1[AXIS_1];
  126. double v0 = Point[AXIS_2] - Corner1[AXIS_2];
  127. // determine the 2d vectors on the dominant plane from the first vertex to the other two
  128. double u1 = Corner2[AXIS_1] - Corner1[AXIS_1];
  129. double v1 = Corner2[AXIS_2] - Corner1[AXIS_2];
  130. double u2 = Corner3[AXIS_1] - Corner1[AXIS_1];
  131. double v2 = Corner3[AXIS_2] - Corner1[AXIS_2];
  132. double alpha, beta;
  133. bool intersect = false;
  134. // calculate alpha and beta as normalized (0..1) percentages across the 2d projected triangle
  135. // and do bounds checking (sum <= 1) to determine whether or not the triangle intersection occurs.
  136. if (u1 == 0.0f) {
  137. beta = u0 / u2; // beta is the percentage down the edge Corner1->Corner3
  138. if ((beta >= 0.0f) && (beta <= 1.0f)) { // make sure it's within the edge segment
  139. alpha = (v0 - beta * v2) / v1; // alpha is the percentage down the edge Corner1->Corner2
  140. // if alpha is valid & the sum of alpha & beta is <= 1 then it's within the triangle
  141. // note: 0.00001 added after testing an intersection of a square in the middle indicated
  142. // an error of 0.0000001350, apparently due to roundoff.
  143. intersect = ((alpha >= 0.0) && ((alpha + beta) <= 1.0));
  144. }
  145. } else {
  146. beta = (v0 * u1 - u0 * v1) / (v2 * u1 - u2 * v1);
  147. if ((beta >= 0.0) && (beta <= 1.0)) {
  148. alpha = (u0 - beta * u2) / u1;
  149. intersect = ((alpha >= 0.0) && ((alpha + beta) <= 1.0));
  150. }
  151. }
  152. // if it is inside, adjust the Z value to sit upon the triangle plane.
  153. if(intersect) {
  154. float u3 = Corner2[AXIS_3] - Corner1[AXIS_3];
  155. float v3 = Corner3[AXIS_3] - Corner1[AXIS_3];
  156. Point[AXIS_3] = u3 * alpha + v3 * beta + Corner1[AXIS_3];
  157. }
  158. return intersect;
  159. }
  160. /*
  161. ** Another way to access the Point_In_Polygon function
  162. **
  163. */
  164. inline bool IntersectionClass::_Point_In_Polygon_Z(
  165. Vector3 &Point,
  166. Vector3 Corners[3]
  167. )
  168. {
  169. return _Point_In_Polygon_Z(Point, Corners[0], Corners[1], Corners[2]);
  170. }
  171. /*
  172. ** This is the general purpose Point_In_Polygon low level function. It can be called directly if you know
  173. ** the dominant projection axes, such as in the case of 2d intersecion with heightfields.
  174. */
  175. inline bool IntersectionClass::_Point_In_Polygon(
  176. Vector3 &Point,
  177. Vector3 &loc1,
  178. Vector3 &loc2,
  179. Vector3 &loc3,
  180. int axis_1,
  181. int axis_2,
  182. float &Alpha,
  183. float &Beta)
  184. {
  185. double u0 = Point[axis_1] - loc1[axis_1];
  186. double v0 = Point[axis_2] - loc1[axis_2];
  187. // determine the 2d vectors on the dominant plane from the first vertex to the other two
  188. double u1 = loc2[axis_1] - loc1[axis_1];
  189. double v1 = loc2[axis_2] - loc1[axis_2];
  190. double u2 = loc3[axis_1] - loc1[axis_1];
  191. double v2 = loc3[axis_2] - loc1[axis_2];
  192. double alpha, beta;
  193. bool intersect = false;
  194. // calculate alpha and beta as normalized (0..1) percentages across the 2d projected triangle
  195. // and do bounds checking (sum <= 1) to determine whether or not the triangle intersection occurs.
  196. #ifdef DEBUG_NORMALS
  197. bool debugmode = false;
  198. if(FinalResult->Alpha == 777) {
  199. debugmode = true;
  200. }
  201. #endif
  202. if (u1 == 0.0f) {
  203. Beta = beta = u0 / u2; // beta is the percentage down the edge loc1->loc3
  204. if ((beta >= 0.0f) && (beta <= 1.0f)) { // make sure it's within the edge segment
  205. Alpha = alpha = (v0 - beta * v2) / v1; // alpha is the percentage down the edge loc1->loc2
  206. // if alpha is valid & the sum of alpha & beta is <= 1 then it's within the triangle
  207. // note: 0.00001 added after testing an intersection of a square in the middle indicated
  208. // an error of 0.0000001350, apparently due to roundoff.
  209. intersect = ((alpha >= 0.0) && ((alpha + beta) <= 1.0));
  210. }
  211. } else {
  212. Beta = beta = (v0 * u1 - u0 * v1) / (v2 * u1 - u2 * v1);
  213. if ((beta >= 0.0) && (beta <= 1.0)) {
  214. Alpha = alpha = (u0 - beta * u2) / u1;
  215. intersect = ((alpha >= 0.0) && ((alpha + beta) <= 1.0));
  216. }
  217. }
  218. #ifdef DEBUG_NORMALS
  219. if(debugmode) {
  220. Debug.Print("Intersect", intersect);
  221. Debug.Print("Normal ", Normal);
  222. Debug.Print("Point 1", loc1);
  223. Debug.Print("Point 2", loc2);
  224. Debug.Print("Point 3", loc3);
  225. Debug.Print("Inter ", FinalResult->Intersection);
  226. Debug.Print("a/b", (float) alpha, (float) beta);
  227. Debug.Print("sum", (float) alpha + (float) beta);
  228. Debug.Print("diff", (float) (alpha - beta));
  229. float d1 = Vector3::Dot_Product(Normal, loc1);
  230. float d2 = Vector3::Dot_Product(Normal, loc2);
  231. float d3 = Vector3::Dot_Product(Normal, loc3);
  232. float e1 = d1 - d2;
  233. float e2 = d2 - d3;
  234. float e3 = d3 - d1;
  235. Debug.Print("dots", Vector3(d1,d2,d3));
  236. Debug.Print("err", Vector3(e1,e2,e3));
  237. }
  238. #endif
  239. return intersect;
  240. }
  241. /*
  242. ** This version calls the base form using member data from the FinalResult struct for
  243. ** some of it's arguments.
  244. */
  245. inline bool IntersectionClass::_Point_In_Polygon(
  246. IntersectionResultClass *FinalResult,
  247. Vector3 &loc1,
  248. Vector3 &loc2,
  249. Vector3 &loc3,
  250. int axis_1,
  251. int axis_2)
  252. {
  253. return (FinalResult->Intersects = _Point_In_Polygon( FinalResult->Intersection, loc1, loc2, loc3,
  254. axis_1, axis_2, FinalResult->Alpha, FinalResult->Beta));
  255. }
  256. /*
  257. ** This version determines the dominant plane of the 3d triangle to be point-in-poly tested
  258. ** and then calls the next form of _Point_In_Polygon
  259. */
  260. inline bool IntersectionClass::_Point_In_Polygon(IntersectionResultClass *FinalResult, Vector3 &Normal, Vector3 &loc1, Vector3 &loc2, Vector3 &loc3) {
  261. // first, find the dominant axis and use the plane perpendicular to it as defined by axis_1, axis_2
  262. int axis_1, axis_2;
  263. _Find_Polygon_Dominant_Plane(Normal, axis_1, axis_2);
  264. return _Point_In_Polygon(FinalResult, loc1, loc2, loc3, axis_1, axis_2);
  265. }
  266. /*
  267. ** Determine the Z distance to the specified polygon.
  268. */
  269. inline float IntersectionClass::Plane_Z_Distance(Vector3 &PlaneNormal, Vector3 &PlanePoint)
  270. {
  271. // do a parallel check
  272. float divisor = (PlaneNormal[0] *(*RayDirection)[0] + PlaneNormal[1] *(*RayDirection)[1] + PlaneNormal[2] * (*RayDirection)[2]);
  273. if(divisor == 0) return false; // parallel
  274. // determine distance to plane
  275. double d = - (PlanePoint[0] * PlaneNormal[0] + PlanePoint[1] * PlaneNormal[1] + PlanePoint[2] * PlaneNormal[2]);
  276. float value = - (d + PlaneNormal[0] * (*RayLocation)[0] + PlaneNormal[1] * (*RayLocation)[1] + PlaneNormal[2] * (*RayLocation)[2]) / divisor;
  277. return value;
  278. }
  279. /*
  280. ** This function will find the z elevation for the passed Vector3 whose x/y components
  281. ** are defined, using the specified vertex & surface normal to determine the correct value
  282. */
  283. inline float IntersectionClass::_Get_Z_Elevation(
  284. Vector3 &Point,
  285. Vector3 &PlanePoint,
  286. Vector3 &PlaneNormal)
  287. {
  288. // do a parallel check
  289. if(PlaneNormal[2] == 0) return false;
  290. // determine distance to plane
  291. double d = - (PlanePoint[0] * PlaneNormal[0] + PlanePoint[1] * PlaneNormal[1] + PlanePoint[2] * PlaneNormal[2]);
  292. float value = - (d + PlaneNormal[0] * Point[0] + PlaneNormal[1] * Point[1] ) / PlaneNormal[2];
  293. return value;
  294. }
  295. /*
  296. ** Optimized intersection test that only considers the x/y component of the intersection object
  297. ** and will determine the intersection location down the Z axis.
  298. */
  299. inline bool IntersectionClass::Intersect_Polygon_Z(IntersectionResultClass *Result, Vector3 &PolygonNormal, Vector3 &v1, Vector3 &v2, Vector3 &v3)
  300. {
  301. Result->Range = Plane_Z_Distance(PolygonNormal, v1);
  302. (Result->Intersection)[0] = (*RayLocation)[0];
  303. (Result->Intersection)[1] = (*RayLocation)[1];
  304. (Result->Intersection)[2] = (*RayLocation)[2] - Result->Range;
  305. return _Point_In_Polygon(Result, PolygonNormal, v1, v2, v3);
  306. }
  307. /*
  308. ** Scale the normalized direction ray to the distance of intersection
  309. */
  310. void IntersectionClass::Calculate_Intersection(IntersectionResultClass *Result)
  311. {
  312. (Result->Intersection)[0] = (*RayLocation)[0] + (*RayDirection)[0] * Result->Range;
  313. (Result->Intersection)[1] = (*RayLocation)[1] + (*RayDirection)[1] * Result->Range;
  314. (Result->Intersection)[2] = (*RayLocation)[2] + (*RayDirection)[2] * Result->Range;
  315. }
  316. /*
  317. ** Plane intersection test that assumes a normalized RayDirection. Only determines if
  318. ** plane is parallel and if not, the range to it (which may be negative or beyond MaxRange).
  319. ** It doesn't determine point of intersection either.
  320. */
  321. inline bool IntersectionClass::Intersect_Plane_Quick(IntersectionResultClass *Result, Vector3 &PlaneNormal, Vector3 &PlanePoint)
  322. {
  323. // do a parallel check
  324. float divisor = (PlaneNormal[0] *(*RayDirection)[0] + PlaneNormal[1] *(*RayDirection)[1] + PlaneNormal[2] * (*RayDirection)[2]);
  325. if(divisor == 0) return false; // parallel
  326. // determine distance to plane
  327. float d = - (PlanePoint[0] * PlaneNormal[0] + PlanePoint[1] * PlaneNormal[1] + PlanePoint[2] * PlaneNormal[2]);
  328. Result->Range = - (d + PlaneNormal[0] * (*RayLocation)[0] + PlaneNormal[1] * (*RayLocation)[1] + PlaneNormal[2] * (*RayLocation)[2]) / divisor;
  329. return true;
  330. }
  331. /*
  332. ** Determine if the specified ray will intersect the plane; returns false for planes
  333. ** parallel and behind ray origin.
  334. ** Sets Range to the distance from the ray location to the intersection.
  335. ** Note: Range is undefined if an intersection didn't occur.
  336. */
  337. inline bool IntersectionClass::Intersect_Plane(IntersectionResultClass *Result, Vector3 &PlaneNormal, Vector3 &PlanePoint) {
  338. // normalize the ray direction
  339. RayDirection->Normalize();
  340. // call the quick test routine
  341. if(!Intersect_Plane_Quick(Result, PlaneNormal, PlanePoint)) return false;
  342. // check to make sure it's not behind the ray's origin
  343. if(Result->Range <= 0) return false;
  344. // check to make sure it's not beyond max distance
  345. if(Result->Range > MaxDistance) return false;
  346. // determine point of intersection
  347. Calculate_Intersection(Result);
  348. return true;
  349. }
  350. /*
  351. ** Return the index of the largest normal component 0..2
  352. ** used by Find_Triangle_Dominant_Plane()
  353. */
  354. inline int IntersectionClass::_Largest_Normal_Index(Vector3 &v)
  355. {
  356. float x = fabsf(v[0]);
  357. float y = fabsf(v[1]);
  358. float z = fabsf(v[2]);
  359. if(x > y) {
  360. if(x > z) {
  361. return 0; // x > y && x > z --> x is the max
  362. }
  363. return 2; // x > y && !(x > z) --> z is the max
  364. }
  365. if(y > z)
  366. return 1; // x <= y && y > z --> y is the max
  367. return 2; // y > x && y > z --> z is the max
  368. }
  369. /*
  370. ** Use the Polygon's currently defined surface normal to determine it's dominant axis.
  371. ** Axis_1 and Axis_2 are set to the indices of the two axis that define the dominant plane.
  372. */
  373. inline void IntersectionClass::_Find_Polygon_Dominant_Plane(Vector3 &Normal, int &Axis_1, int &Axis_2)
  374. {
  375. switch (_Largest_Normal_Index(Normal))
  376. {
  377. case 0:
  378. // Dominant is the X axis
  379. Axis_1 = 2;
  380. Axis_2 = 1;
  381. break;
  382. case 1:
  383. // Dominant is the Y axis
  384. Axis_1 = 2;
  385. Axis_2 = 0;
  386. break;
  387. case 2:
  388. // Dominant is the Z axis
  389. Axis_1 = 0;
  390. Axis_2 = 1;
  391. break;
  392. }
  393. }
  394. /*
  395. ** Returns true if ray intersects polygon.
  396. ** Changes passed Intersection argument to location of intersection if it occurs,
  397. ** and sets Range to the distance from the ray location to the intersection.
  398. ** If Interpolated_Normal is specified it will interpolate the surface normal based
  399. ** on the vertex normals.
  400. */
  401. inline bool IntersectionClass::Intersect_Polygon(IntersectionResultClass *Result, Vector3 &PolygonNormal, Vector3 &v1, Vector3 &v2, Vector3 &v3)
  402. {
  403. // first check to see if it hits the plane; determine plane normal and find point on plane (from a vertex)
  404. #ifdef DEBUG_NORMALS
  405. Verify_Normal2(PolygonNormal, v1,v2,v3);
  406. #endif
  407. if(Intersect_Plane(Result, PolygonNormal, v1)) {
  408. // then check to see if it it actually intersects the polygon.
  409. return _Point_In_Polygon(Result, PolygonNormal, v1, v2, v3);
  410. }
  411. // doesn't even hit the plane, return false.
  412. return false;
  413. }
  414. /*
  415. ** This version will calc the normal for the polygon before calling
  416. ** a lower form of Intersect_Polygon
  417. */
  418. inline bool IntersectionClass::Intersect_Polygon(IntersectionResultClass *Result, Vector3 &v1, Vector3 &v2, Vector3 &v3)
  419. {
  420. Vector3 vec1 = v2 - v1;
  421. Vector3 vec2 = v3 - v1;
  422. #ifdef ALLOW_TEMPORARIES
  423. Vector3 normal = Vector3::Cross_Product(vec1, vec2);
  424. #else
  425. Vector3 normal;
  426. Vector3::Cross_Product(vec1, vec2, &normal);
  427. #endif
  428. return Intersect_Polygon(Result, normal, v1,v2,v3);
  429. }
  430. // called after Interpolate_Intersection_Normal.
  431. // transform the intersection and the normal from model coords into world coords
  432. inline void IntersectionClass::Transform_Model_To_World_Coords(IntersectionResultClass *FinalResult)
  433. {
  434. #ifdef ALLOW_TEMPORARIES
  435. FinalResult->Intersection = FinalResult->ModelMatrix * FinalResult->Intersection + FinalResult->ModelLocation;
  436. if(IntersectionNormal != 0)
  437. {
  438. Vector3 normal(*IntersectionNormal);
  439. *IntersectionNormal = FinalResult->ModelMatrix * normal;
  440. }
  441. #else
  442. FinalResult->ModelMatrix.mulVector3(FinalResult->Intersection);
  443. FinalResult->Intersection += FinalResult->ModelLocation;
  444. if(IntersectionNormal != 0)
  445. {
  446. FinalResult->ModelMatrix.mulVector3(*IntersectionNormal);
  447. }
  448. #endif
  449. }
  450. bool IntersectionClass::Intersect_Screen_Object( IntersectionResultClass *Final_Result,
  451. Vector4 &Area,
  452. RenderObjClass *obj)
  453. {
  454. if(Final_Result->Intersects = ((ScreenX >= Area[0]) && (ScreenX <= Area[2]) && (ScreenY >= Area[1]) && (ScreenY <= Area[3]))) {
  455. Final_Result->IntersectionType = IntersectionResultClass::GENERIC;
  456. Final_Result->IntersectedRenderObject = obj;
  457. Final_Result->Range = 0;
  458. return true;
  459. }
  460. return false;
  461. }
  462. /*
  463. ** Determines the point of intersection, if any between the line segments AB and CD.
  464. ** If an intersection occurs, then the UV values are interpolated along AB.
  465. ** Disregards the Z value and considers only the X/Y data except for determining
  466. ** the Z value of the intersection.
  467. ** This function could be easily modified to support other axes.
  468. * /
  469. void IntersectionClass::_Intersect_Lines_Z(
  470. Vector3 &A,
  471. Vector3 &B,
  472. Vector2 &UVStart,
  473. Vector2 &UVEnd,
  474. Vector3 &C,
  475. Vector3 &D,
  476. Vector3 ClippedPoints[6],
  477. Vector2 ClippedUV[6],
  478. int &DestIndex)
  479. {
  480. /*
  481. Let A,B,C,D be 2-space position vectors. Then the directed line segments AB & CD are given by:
  482. AB=A+r(B-A), r in [0,1]
  483. CD=C+s(D-C), s in [0,1]
  484. If AB & CD intersect, then
  485. A+r(B-A)=C+s(D-C), or
  486. Ax+r(Bx-Ax)=Cx+s(Dx-Cx)
  487. Ay+r(By-Ay)=Cy+s(Dy-Cy) for some r,s in [0,1]
  488. Solving the above for r and s yields
  489. (Ay-Cy)(Dx-Cx)-(Ax-Cx)(Dy-Cy)
  490. r = ----------------------------- (eqn 1)
  491. (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx)
  492. (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay)
  493. s = ----------------------------- (eqn 2)
  494. (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx)
  495. Let P be the position vector of the intersection point, then
  496. P=A+r(B-A) or
  497. Px=Ax+r(Bx-Ax)
  498. Py=Ay+r(By-Ay)
  499. By examining the values of r & s, you can also determine some other limiting conditions:
  500. If 0<=r<=1 & 0<=s<=1, intersection exists
  501. r<0 or r>1 or s<0 or s>1 line segments do not intersect
  502. If the denominator in eqn 1 is zero, AB & CD are parallel
  503. If the numerator in eqn 1 is also zero, AB & CD are coincident
  504. If the intersection point of the 2 lines are needed (lines in this context mean infinite lines) regardless whether the two line segments intersect, then
  505. If r>1, P is located on extension of AB
  506. If r<0, P is located on extension of BA
  507. If s>1, P is located on extension of CD
  508. If s<0, P is located on extension of DC
  509. * /
  510. // the numerator is required for all execution routes
  511. float numerator = (A[AXIS_2] - C[AXIS_2]) * (D[AXIS_1] - C[AXIS_1]) - (A[AXIS_1] - C[AXIS_1]) * (D[AXIS_2] - C[AXIS_2]);
  512. // if the denominator is zero, then the segments are parallel.
  513. float denominator = (B[AXIS_1] - A[AXIS_1]) * (D[AXIS_2] - C[AXIS_2]) - (B[AXIS_2] - A[AXIS_2]) * (D[AXIS_1] - C[AXIS_1]);
  514. // r & s are percentages through the line segment.
  515. float r, s;
  516. // check to see if they are parallel
  517. if(denominator == 0) {
  518. // check to see if they are coincident
  519. // a numerator of zero with a denominator of zero indicates coincident lines.
  520. if (numerator != 0) {
  521. // parallel, not coincident lines (and segments) do not intersect.
  522. return;
  523. }
  524. // perform special case for parallel segments
  525. // determine relative position 0..1 of C and D on one of the 1d vectors of A-B
  526. float len = B[AXIS_1] - A[AXIS_1];
  527. float cpos,dpos;
  528. // if the length of the edge on the first axis is zero, use the other axis instead.
  529. if(len) {
  530. len = 1.0 / len;
  531. cpos = (C[AXIS_1] - A[AXIS_1]) * len;
  532. dpos = (D[AXIS_1] - A[AXIS_1]) * len;
  533. } else {
  534. len = B[AXIS_2] - A[AXIS_2];
  535. // degenerate triangle test
  536. if(len == 0)
  537. return;
  538. len = 1.0 / len;
  539. cpos = (C[AXIS_2] - A[AXIS_2]) * len;
  540. dpos = (D[AXIS_2] - A[AXIS_2]) * len;
  541. }
  542. // check to see if there's any overlap
  543. // one of the two pos values must be 0>pos>1 or there is no intersection.
  544. // this test will ensure that cpos & dpos will not both be outside the same end of the segment.
  545. if(((cpos < 0) && (dpos < 0)) || ((cpos > 1) && (dpos > 1)))
  546. return;
  547. if(cpos < 0) {
  548. // C is outside, therefore D is inside or on other side.
  549. // use the original vertex.
  550. ClippedPoints[DestIndex] = A;
  551. ClippedUV[DestIndex++] = UVStart;
  552. } else if (cpos > 1) {
  553. // C is outside far side, therefore D is inside or on other side.
  554. // use the far vertex.
  555. ClippedPoints[DestIndex] = B;
  556. ClippedUV[DestIndex++] = UVEnd;
  557. } else {
  558. // C is inside.
  559. // Use C as the vertex, and interpolate the UV coords.
  560. ClippedPoints[DestIndex] = C;
  561. ClippedUV[DestIndex++] = (UVEnd - UVStart) * cpos + UVStart;
  562. }
  563. if(dpos < 0) {
  564. // D is outside near vertex, therefore C is inside or outside far vertex
  565. // use near vertex
  566. ClippedPoints[DestIndex] = A;
  567. ClippedUV[DestIndex++] = UVStart;
  568. } else if (dpos > 1) {
  569. // D is outside far vertex, therefore C is inside or outside the near vertex.
  570. // use the far vertex.
  571. ClippedPoints[DestIndex] = B;
  572. ClippedUV[DestIndex++] = UVEnd;
  573. } else {
  574. // D is inside.
  575. // Use D as the vertex, and interpolate the UV coords.
  576. ClippedPoints[DestIndex] = D;
  577. ClippedUV[DestIndex++] = (UVEnd - UVStart) * dpos + UVStart;
  578. }
  579. return;
  580. }
  581. // determine the percentage into the line segments that the intersection occurs.
  582. // an intersection of segments will produce r & s values between 0 & 1.
  583. denominator = 1.0 / denominator;
  584. r = numerator * denominator;
  585. numerator = (A[AXIS_2] - C[AXIS_2]) * (B[AXIS_1] - A[AXIS_1]) - (A[AXIS_1] - C[AXIS_1]) * (B[AXIS_2] - A[AXIS_2]);
  586. s = numerator * denominator;
  587. // determine if the line intersect within the defined segments.
  588. if((0.0 <= r) && (r <= 1.0) && (0.0 <= s) && (s <= 1.0)) {
  589. // they intersect.
  590. // determine intersection point
  591. Vector3 v = D - C;
  592. // float len = v.Length();
  593. ClippedPoints[DestIndex] = C + v * s;
  594. // interpolate UV values
  595. Vector2 uv = UVEnd - UVStart;
  596. // len = uv.Length();
  597. ClippedUV[DestIndex++] = UVStart + uv * r;
  598. }
  599. }
  600. /*
  601. A failed attempt to use a graphics gem vol 2 example
  602. // Compute a1, b1, c1, where line joining points 1 and 2
  603. // is "a1 x + b1 y + c1 = 0".
  604. float a1 = B[AXIS_2] - A[AXIS_2];
  605. float b1 = B[AXIS_1] - A[AXIS_1];
  606. float c1 = B[AXIS_2] * A[AXIS_1] - A[AXIS_1] * B[AXIS_2];
  607. // Compute r3 & r4, the sign values
  608. float r3 = a1 * C[AXIS_1] + b1 * C[AXIS_2] + c1;
  609. float r4 = a1 * D[AXIS_1] + b1 * D[AXIS_2] + c1;
  610. // Check signs of r3 and r4. If both point 3 and point 4 lie on
  611. // same side of line 1, the line segments do not intersect.
  612. if ( r3 != 0 && r4 != 0 && (((r3 < 0) && (r4 < 0)) || ((r3 > 0) && (r4 > 0)))
  613. return; // ( DONT_INTERSECT );
  614. // Compute a2, b2, c2
  615. float a2 = D[AXIS_2] - C[AXIS_2];
  616. float b2 = C[AXIS_1] - D[AXIS_1];
  617. float c2 = D[AXIS_1] * C[AXIS_2] - C[AXIS_1] * D[AXIS_2];
  618. // Compute r1 and r2
  619. float r1 = a2 * A[AXIS_1] + b2 * A[AXIS_2] + c2;
  620. float r2 = a2 * B[AXIS_1] + b2 * B[AXIS_2] + c2;
  621. // Check signs of r1 and r2. If both point 1 and point 2 lie
  622. // on same side of second line segment, the line segments do
  623. // not intersect.
  624. if ( r1 != 0 && r2 != 0 && (((r1 < 0) && (r2 < 0)) || ((r1 > 0) && (r2 > 0))))
  625. return; // ( DONT_INTERSECT );
  626. // Line segments intersect: compute intersection point.
  627. float denom = a1 * b2 - a2 * b1;
  628. if ( denom == 0 )
  629. return; // ( COLLINEAR );
  630. float offset = denom < 0 ? - denom * 0.5f : denom * 0.5f;
  631. // The denom/2 is to get rounding instead of truncating. It
  632. // is added or subtracted to the numerator, depending upon the
  633. // sign of the numerator.
  634. float num = b1 * c2 - b2 * c1;
  635. float x = ( num < 0 ? num - offset : num + offset ) / denom;
  636. num = a2 * c1 - a1 * c2;
  637. float y = ( num < 0 ? num - offset : num + offset ) / denom;
  638. ClippedPoints[DestIndex] = Vector3(x,y,0);
  639. ClippedUV[DestIndex++] = Vector3
  640. return; //( DO_INTERSECT ); // lines_intersect
  641. */
  642. inline bool IntersectionClass::In_Front_Of_Line
  643. (
  644. const Vector3 & p, // point to test
  645. const Vector3 & e0, // point on edge
  646. const Vector3 & de // direction of edge
  647. )
  648. {
  649. Vector3 dp = p - e0;
  650. float val = de.X*dp.Y - de.Y*dp.X;
  651. if (val > 0.0f) {
  652. return true;
  653. }
  654. return false;
  655. }
  656. inline float IntersectionClass::Intersect_Lines
  657. (
  658. const Vector3 & p0, // start of line segment
  659. const Vector3 & p1, // end of line segment
  660. const Vector3 & e0, // point on clipping edge
  661. const Vector3 & de // direction of clipping edge
  662. )
  663. {
  664. float dpx = p1.X - p0.X;
  665. float dpy = p1.Y - p0.Y;
  666. float den = de.Y * dpx - de.X * dpy;
  667. if (fabs(den) > WWMATH_EPSILON) {
  668. float num = p0.Y*de.X - p0.X*de.Y + e0.X*de.Y - e0.Y*de.X;
  669. float t = num/den;
  670. if ((t >= 0.0f) && (t <= 1.0f)) {
  671. return t;
  672. }
  673. }
  674. return 0.0f;
  675. }
  676. #define EMIT(p,uv) OutPoints[outnum] = p; OutUVs[outnum] = uv; outnum++;
  677. inline int IntersectionClass::Clip_Triangle_To_LineXY(
  678. int incount,
  679. Vector3 * InPoints,
  680. Vector2 * InUVs,
  681. Vector3 * OutPoints,
  682. Vector2 * OutUVs,
  683. const Vector3 & edge_point0,
  684. const Vector3 & edge_point1
  685. )
  686. {
  687. Vector3 e0 = edge_point0;
  688. Vector3 de = edge_point1 - edge_point0;
  689. // number of verts output.
  690. int outnum = 0;
  691. // start and end verts of the current edge
  692. int p0,p1;
  693. p0 = incount-1;
  694. // intersection temporaries.
  695. float intersection;
  696. Vector3 intersection_point;
  697. Vector2 intersection_uv;
  698. // loop over each edge in the input polygon
  699. for (p1=0; p1<incount; p1++) {
  700. if (In_Front_Of_Line(InPoints[p1],e0,de)) {
  701. if (In_Front_Of_Line(InPoints[p0],e0,de)) {
  702. // both inside, emit p1
  703. EMIT(InPoints[p1],InUVs[p1]);
  704. } else {
  705. // edge going out->in, emit intersection and endpoint
  706. intersection = Intersect_Lines(InPoints[p0], InPoints[p1], e0, de);
  707. intersection_point = (1.0f - intersection) * InPoints[p0] + intersection * InPoints[p1];
  708. intersection_uv = (1.0f - intersection) * InUVs[p0] + intersection * InUVs[p1];
  709. EMIT(intersection_point,intersection_uv);
  710. EMIT(InPoints[p1],InUVs[p1]);
  711. }
  712. } else {
  713. if (In_Front_Of_Line(InPoints[p0], e0, de)) {
  714. // edge going in->out, emit intersection
  715. intersection = Intersect_Lines(InPoints[p0],InPoints[p1], e0, de);
  716. intersection_point = (1.0f - intersection) * InPoints[p0] + intersection * InPoints[p1];
  717. intersection_uv = (1.0f - intersection) * InUVs[p0] + intersection * InUVs[p1];
  718. EMIT(intersection_point,intersection_uv);
  719. }
  720. }
  721. // move to next edge
  722. p0 = p1;
  723. }
  724. return outnum;
  725. }
  726. inline int IntersectionClass::_Intersect_Triangles_Z(
  727. Vector3 ClipPoints[3],
  728. Vector3 TrianglePoints[3],
  729. Vector2 UV[3],
  730. Vector3 ClippedPoints[6],
  731. Vector2 ClippedUV[6]
  732. )
  733. {
  734. int count;
  735. Vector3 tmp_points[6];
  736. Vector2 tmp_uv[6];
  737. count = Clip_Triangle_To_LineXY(3,TrianglePoints,UV,ClippedPoints,ClippedUV,ClipPoints[0],ClipPoints[1]);
  738. count = Clip_Triangle_To_LineXY(count,ClippedPoints,ClippedUV,tmp_points,tmp_uv,ClipPoints[1],ClipPoints[2]);
  739. count = Clip_Triangle_To_LineXY(count,tmp_points,tmp_uv,ClippedPoints,ClippedUV,ClipPoints[2],ClipPoints[0]);
  740. return count;
  741. }
  742. /*
  743. ** This function will fill the passed array with the set of points & uv values that represent
  744. ** the boolean operation of the anding of the ClipPoints with the TrianglePoints. The UV values
  745. ** provided for the TrianglePoints triangle are used to generate accurate UV values for any
  746. ** new points created by this operation.
  747. ** This function returns the number of vertices it required to define the intersection.
  748. * /
  749. int IntersectionClass::_Intersect_Triangles_Z(
  750. Vector3 ClipPoints[3],
  751. Vector3 TrianglePoints[3],
  752. Vector2 UV[3],
  753. Vector3 ClippedPoints[6],
  754. Vector2 ClippedUV[6]
  755. )
  756. {
  757. // first, check to see if all triangle points are inside clip area
  758. // the point in polygon will drop any inside points to the clip triangle plane.
  759. bool inside[3];
  760. bool noclip;
  761. noclip = inside[0] = _Point_In_Polygon_Z(TrianglePoints[0], ClipPoints);
  762. noclip &= inside[1] = _Point_In_Polygon_Z(TrianglePoints[1], ClipPoints);
  763. noclip &= inside[2] = _Point_In_Polygon_Z(TrianglePoints[2], ClipPoints);
  764. // if all points are inside clip area, then copy the triangle points &
  765. // UV's to the destination & return 3 (the number of points in the clipped polygon).
  766. if(noclip) {
  767. ClippedPoints[0] = TrianglePoints[0];
  768. ClippedPoints[1] = TrianglePoints[1];
  769. ClippedPoints[2] = TrianglePoints[2];
  770. ClippedUV[0] = UV[0];
  771. ClippedUV[1] = UV[1];
  772. ClippedUV[2] = UV[2];
  773. return 3;
  774. }
  775. int points = 0; // number of output polygon points
  776. // not all uv triangle points are inside the clip triangle.
  777. // Test to see if any clip points are inside the uv triangle
  778. float alpha, beta;
  779. if(_Point_In_Polygon(ClipPoints[0], TrianglePoints[0], TrianglePoints[1], TrianglePoints[2], 0, 1, alpha, beta)) {
  780. ClippedPoints[points] = ClipPoints[0];
  781. Vector2 uv1 = UV[1] - UV[0];
  782. Vector2 uv2 = UV[2] - UV[0];
  783. ClippedUV[points++] = UV[0] + alpha * uv1 + beta * uv2;
  784. }
  785. if(_Point_In_Polygon(ClipPoints[1], TrianglePoints[0], TrianglePoints[1], TrianglePoints[2], 0, 1, alpha, beta)) {
  786. ClippedPoints[points] = ClipPoints[1];
  787. Vector2 uv1 = UV[1] - UV[0];
  788. Vector2 uv2 = UV[2] - UV[0];
  789. ClippedUV[points++] = UV[0] + alpha * uv1 + beta * uv2;
  790. }
  791. if(_Point_In_Polygon(ClipPoints[2], TrianglePoints[0], TrianglePoints[1], TrianglePoints[2], 0, 1, alpha, beta)) {
  792. ClippedPoints[points] = ClipPoints[2];
  793. Vector2 uv1 = UV[1] - UV[0];
  794. Vector2 uv2 = UV[2] - UV[0];
  795. ClippedUV[points++] = UV[0] + alpha * uv1 + beta * uv2;
  796. }
  797. // if all 3 clip points are inside the decal triangle then return
  798. if(points == 3)
  799. return;
  800. // The clip triangle does not fully contain the uv triangle, and the uv triangle
  801. // does not fully contain the clip triangle.
  802. // Intersect any edge which has at least one outside point with all of the clip edges.
  803. // First, determine which edges to test. Those points that are already clipped (by being inside)
  804. // are immediately copied to the clipped point & uv arrays.
  805. // these bools indicate which edges of the triangle to be clipped are to be tested.
  806. bool test_01 = false;
  807. bool test_02 = false;
  808. bool test_12 = false;
  809. if( inside[0] ) { ClippedPoints[points] = TrianglePoints[0]; ClippedUV[points++] = UV[0]; }
  810. else { test_01 = test_02 = true; }
  811. if( inside[1] ) { ClippedPoints[points] = TrianglePoints[1]; ClippedUV[points++] = UV[1]; }
  812. else { test_01 = test_12 = true; }
  813. if( inside[2] ) { ClippedPoints[points] = TrianglePoints[2]; ClippedUV[points++] = UV[2];}
  814. else { test_02 = test_12 = true; }
  815. // Now test each indicated segment.
  816. // Intersect_2D_Lines will interpolate the clipped UV values if an intersection occurs, and it
  817. // will also increment the points variable (passed as a reference).
  818. // Any intersections are stored in the passed ClippedPoints array.
  819. if(test_01) {
  820. _Intersect_Lines_Z( TrianglePoints[0], TrianglePoints[1],
  821. UV[0], UV[1],
  822. ClipPoints[0], ClipPoints[1],
  823. ClippedPoints,
  824. ClippedUV,
  825. points);
  826. _Intersect_Lines_Z( TrianglePoints[0], TrianglePoints[1],
  827. UV[0], UV[1],
  828. ClipPoints[0], ClipPoints[2],
  829. ClippedPoints,
  830. ClippedUV,
  831. points);
  832. _Intersect_Lines_Z( TrianglePoints[0], TrianglePoints[1],
  833. UV[0], UV[1],
  834. ClipPoints[1], ClipPoints[2],
  835. ClippedPoints,
  836. ClippedUV,
  837. points);
  838. }
  839. if(test_02) {
  840. _Intersect_Lines_Z( TrianglePoints[0], TrianglePoints[2],
  841. UV[0], UV[2],
  842. ClipPoints[0], ClipPoints[1],
  843. ClippedPoints,
  844. ClippedUV,
  845. points);
  846. _Intersect_Lines_Z( TrianglePoints[0], TrianglePoints[2],
  847. UV[0], UV[2],
  848. ClipPoints[0], ClipPoints[2],
  849. ClippedPoints,
  850. ClippedUV,
  851. points);
  852. _Intersect_Lines_Z( TrianglePoints[0], TrianglePoints[2],
  853. UV[0], UV[2],
  854. ClipPoints[1], ClipPoints[2],
  855. ClippedPoints,
  856. ClippedUV,
  857. points);
  858. }
  859. if(test_12) {
  860. _Intersect_Lines_Z( TrianglePoints[1], TrianglePoints[2],
  861. UV[1], UV[2],
  862. ClipPoints[0], ClipPoints[1],
  863. ClippedPoints,
  864. ClippedUV,
  865. points);
  866. _Intersect_Lines_Z( TrianglePoints[1], TrianglePoints[2],
  867. UV[1], UV[2],
  868. ClipPoints[0], ClipPoints[2],
  869. ClippedPoints,
  870. ClippedUV,
  871. points);
  872. _Intersect_Lines_Z( TrianglePoints[1], TrianglePoints[2],
  873. UV[1], UV[2],
  874. ClipPoints[1], ClipPoints[2],
  875. ClippedPoints,
  876. ClippedUV,
  877. points);
  878. }
  879. // If no intersections have occurred, then the triangle must be completely outside
  880. // the clipping area.
  881. /*
  882. // if it is determined that no intersections have occurred, then copy the clip triangle points
  883. // into the destination array and determine the correct UV values for the subset of the
  884. // triangle that was clipped.
  885. if(points == 0) {
  886. ClippedPoints[0] = ClipPoints[0];
  887. ClippedPoints[1] = ClipPoints[1];
  888. ClippedPoints[2] = ClipPoints[2];
  889. ClippedUV[0] = UV[0];
  890. ClippedUV[1] = UV[1];
  891. ClippedUV[2] = UV[2];
  892. return 3;
  893. }
  894. * /
  895. // points will be 0, 3, 4, 5 or 6
  896. if(!((points == 0) || (points == 3) || (points == 4) || (points == 5) || (points == 6))) {
  897. Debug.Print("points", points);
  898. return 0; //_Intersect_Triangles_Z( ClipPoints, TrianglePoints, UV, ClippedPoints, ClippedUV);
  899. }
  900. return points;
  901. }
  902. */
  903. #endif