intersec.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  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. /***********************************************************************************************
  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 : G *
  23. * *
  24. * $Archive:: /Commando/Code/ww3d2/intersec.h $*
  25. * *
  26. * $Author:: Naty_h $*
  27. * *
  28. * $Modtime:: 3/28/01 11:29a $*
  29. * *
  30. * $Revision:: 5 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. /*
  36. Most of the functions of this class are inline functions and if you use them you will need
  37. to include <intersec.inl>.
  38. Exceptions to this are the functions most commonly used by render objects:
  39. The constructors/destructors are inline & implemented here.
  40. */
  41. #if defined(_MSC_VER)
  42. #pragma once
  43. #endif
  44. #ifndef INTERSEC_H
  45. #define INTERSEC_H
  46. #include "always.h"
  47. #include "matrix3d.h"
  48. #include "layer.h"
  49. #include "sphere.h"
  50. #include "coltype.h"
  51. class RenderObjClass;
  52. typedef unsigned short POLYGONINDEX;
  53. /*
  54. **
  55. */
  56. class IntersectionResultClass
  57. {
  58. public:
  59. RenderObjClass * IntersectedRenderObject;
  60. POLYGONINDEX IntersectedPolygon;
  61. Matrix3D ModelMatrix; // this is required for transforming mesh normals from model coords
  62. Vector3 ModelLocation; // ditto
  63. Vector3 Intersection; // location of intersection is placed here
  64. float Range; // distance from ray to point of intersection
  65. float Alpha, Beta; // stored for use by Process_Intersection_Results() - used to interpolate normal across a polygon
  66. bool Intersects; // could be in the intersection_type, but it is used in a number of bool operations
  67. int CollisionType; // mask for which object types to intersect with (added for 'Generals'. MW)
  68. enum INTERSECTION_TYPE {
  69. NONE = 0,
  70. GENERIC,
  71. POLYGON
  72. } IntersectionType;
  73. };
  74. class IntersectionClass
  75. {
  76. // member data
  77. public:
  78. enum {
  79. MAX_POLY_INTERSECTION_COUNT = 1000, // arbitrary size of stack array used for storing intersection results within Intersect_Mesh(). Non-recursive function.
  80. MAX_HIERARCHY_NODE_COUNT = 256
  81. };
  82. // this structure is used to store all intersections on the stack for sorting before
  83. // copying the nearest intersection to IntersectionClassObject->Result.
  84. // note: the convex intersection functions return with the first intersection results.
  85. Vector3 *RayLocation; // note: these pointers must be Set() to valid pointers by external code
  86. Vector3 *RayDirection;
  87. Vector3 *IntersectionNormal; // if non-zero then Process_Intersection_Results() will place the (perhaps vertex interpolated) surface normal here.
  88. // 2d screen coordinates for use by Intersect_Screen_Point...() routines.
  89. float ScreenX, ScreenY;
  90. // if true, then interpolate the normal for a polygon intersection from the vertex normals.
  91. // note: intersection routines below which take a FinalResult argument do not interpolate
  92. // the normal since they are intended to be used to find the nearest of several intersections
  93. // and interpolating the normal for intersections that are tossed would be wasteful.
  94. // If you need the normal interpolated in that case anyways then call Interpolate_Normal().
  95. bool InterpolateNormal;
  96. // if true, then perform potentially much faster convex intersection test which will return
  97. // the first valid intersection. Generally used for producing silhouettes.
  98. // If true, all intersections will be convex tests. If false, test mode will be determined (generally)
  99. // by the render object or whatever called the intersection functions and passes the Convex argument.
  100. bool ConvexTest;
  101. // do not consider intersections beyond this range as an intersection.
  102. // Note: Get_Screen_Ray sets this to scene->zstop.
  103. float MaxDistance;
  104. // final intersection results are contained here
  105. IntersectionResultClass Result;
  106. //
  107. // Implementation
  108. //
  109. // configures the member data to use the passed pointers
  110. inline void Set(Vector3 *location, Vector3 *direction, Vector3 *intersection_normal, bool interpolate_normal, float max_distance, bool convex_test = false)
  111. {
  112. RayLocation = location;
  113. RayDirection = direction;
  114. IntersectionNormal = intersection_normal;
  115. InterpolateNormal = interpolate_normal;
  116. MaxDistance = max_distance;
  117. ConvexTest = convex_test;
  118. }
  119. // this constructor uses static variables for the location/direction/normal variables
  120. // so can be only used one thread at a time unless the Set() function is used to
  121. // set them to private vector3's
  122. inline IntersectionClass()
  123. : ConvexTest(false)
  124. {
  125. RayLocation = &_RayLocation;
  126. RayDirection = &_RayDirection;
  127. IntersectionNormal = &_IntersectionNormal;
  128. Result.CollisionType=COLLISION_TYPE_ALL; //added for 'Generals'. MW
  129. }
  130. // This will be the most commonly used constructor
  131. inline IntersectionClass(Vector3 *location, Vector3 *direction, Vector3 *intersection_normal, bool interpolate_normal = false, float max_distance = WWMATH_FLOAT_MAX, bool convex_test = false)
  132. {
  133. Set(location, direction, intersection_normal, interpolate_normal, max_distance, convex_test);
  134. }
  135. virtual ~IntersectionClass() {}
  136. // this copy routine is used when the model coords are needed to be copied along with the other information.
  137. inline void IntersectionClass::Copy_Results(IntersectionResultClass *Destination, IntersectionResultClass *Source) {
  138. Destination->ModelMatrix = Source->ModelMatrix;
  139. Destination->ModelLocation = Source->ModelLocation;
  140. Copy_Partial_Results(Destination, Source);
  141. Destination->IntersectedRenderObject = Source->IntersectedRenderObject;
  142. }
  143. inline void IntersectionClass::Copy_Results(IntersectionResultClass *Source) {
  144. Copy_Results(&Result, Source);
  145. }
  146. // this is called only for the nearest intersection. If the request passes a Interpolated_Normal pointer then it will be calculated.
  147. // otherwise the results are copied into the request structure.
  148. // This does not copy the matrix or location members; it is intended to be used during poly testing
  149. // where these values are identical between results, or as a completion function for Copy_Results()
  150. inline void IntersectionClass::Copy_Partial_Results(IntersectionResultClass *Destination, IntersectionResultClass *Source)
  151. {
  152. Destination->IntersectedPolygon = Source->IntersectedPolygon;
  153. Destination->Intersection = Source->Intersection;
  154. Destination->Range = Source->Range;
  155. Destination->Alpha = Source->Alpha;
  156. Destination->Beta = Source->Beta;
  157. Destination->Intersects = true;
  158. Destination->IntersectionType = Source->IntersectionType;
  159. }
  160. // used for creating temporary copies
  161. inline IntersectionClass(IntersectionClass *source)
  162. {
  163. *this = source;
  164. }
  165. inline IntersectionClass *operator =(IntersectionClass *source)
  166. {
  167. Set(source->RayLocation, source->RayDirection, source->IntersectionNormal, source->InterpolateNormal, source->MaxDistance, source->ConvexTest);
  168. Copy_Results(&source->Result);
  169. return this;
  170. }
  171. // find the range to the intersection of the ray and sphere (if any)
  172. // note: Intersection_Request->RayDirection must be a unit vector
  173. // To find the actual intersection location and perhaps the intersection normal, use Intersection_Sphere() instead.
  174. // loosly based on code found in Graphics Gems I, p388
  175. // this will only set the result's range if intersection occurs; it is intended to be used as a first pass intersection test
  176. // before intersecting the mesh polygons itself.
  177. // Note: Does NOT do Max_Distance testing
  178. inline bool IntersectionClass::Intersect_Sphere_Quick(SphereClass &Sphere, IntersectionResultClass *FinalResult)
  179. {
  180. // make a unit vector from the ray origin to the sphere center
  181. Vector3 sphere_vector(Sphere.Center - *RayLocation);
  182. // get the dot product between the sphere_vector and the ray vector
  183. FinalResult->Alpha = Vector3::Dot_Product(sphere_vector, *RayDirection);
  184. FinalResult->Beta = Sphere.Radius * Sphere.Radius - (Vector3::Dot_Product(sphere_vector, sphere_vector) - FinalResult->Alpha * FinalResult->Alpha);
  185. if(FinalResult->Beta < 0.0f) {
  186. return FinalResult->Intersects = false;
  187. }
  188. return FinalResult->Intersects = true;
  189. }
  190. // this will find the intersection with the sphere and the intersection normal if needed.
  191. inline bool IntersectionClass::Intersect_Sphere(SphereClass &Sphere, IntersectionResultClass *FinalResult)
  192. {
  193. if(!Intersect_Sphere_Quick(Sphere, FinalResult))
  194. return false;
  195. // determine range to intersection based on stored alpha/beta values
  196. float d = sqrtf(FinalResult->Beta);
  197. FinalResult->Range = FinalResult->Alpha - d;
  198. if(FinalResult->Range > MaxDistance) return false;
  199. FinalResult->Intersection = *RayLocation + FinalResult->Range * (*RayDirection);
  200. if(IntersectionNormal != 0) {
  201. (*IntersectionNormal) = FinalResult->Intersection - Sphere.Center;
  202. }
  203. return true;
  204. }
  205. // inline declarations
  206. // Usage of these functions requires including intersec.inl
  207. // determine location & direction for projected screen coordinate ray
  208. inline void Get_Screen_Ray(float ScreenX, float ScreenY, const LayerClass &Layer);
  209. // uses the Result's range & the Ray_Direction to calculate the actual point of intersection.
  210. inline void Calculate_Intersection(IntersectionResultClass *Result);
  211. // interpolate the normal for a polygon intersection. Will ONLY work for polygon intersections,
  212. // and the Results.Intersection_Data must refer to a polygon with a valid ->mesh pointer.
  213. inline void Interpolate_Intersection_Normal(IntersectionResultClass *FinalResult);
  214. // various methods for performing intersections.
  215. inline bool Intersect_Plane(IntersectionResultClass *Result, Vector3 &Plane_Normal, Vector3 &Plane_Point);
  216. inline bool Intersect_Plane_Quick(IntersectionResultClass *Result, Vector3 &Plane_Normal, Vector3 &Plane_Point);
  217. inline bool Intersect_Polygon(IntersectionResultClass *Result, Vector3 &PolygonNormal, Vector3 &v1, Vector3 &v2, Vector3 &v3);
  218. inline bool Intersect_Polygon(IntersectionResultClass *Result, Vector3 &v1, Vector3 &v2, Vector3 &v3);
  219. inline bool Intersect_Polygon_Z(IntersectionResultClass *Result, Vector3 &PolygonNormal, Vector3 &v1, Vector3 &v2, Vector3 &v3);
  220. /*
  221. ** This function will fill the passed array with the set of points & uv values that represent
  222. ** the boolean operation of the anding of the ClipPoints with the TrianglePoints. The UV values
  223. ** provided for the TrianglePoints triangle are used to generate accurate UV values for any
  224. ** new points created by this operation.
  225. ** The clipped points have Z values that make them sit on the ClipPoints triangle plane.
  226. */
  227. static inline int _Intersect_Triangles_Z(
  228. Vector3 ClipPoints[3],
  229. Vector3 TrianglePoints[3],
  230. Vector2 UV[3],
  231. Vector3 ClippedPoints[6],
  232. Vector2 ClippedUV[6]
  233. );
  234. /*
  235. ** This function will find the z elevation for the passed Vector3 whose x/y components
  236. ** are defined, using the specified vertex & surface normal to determine the correct value
  237. */
  238. static inline float _Get_Z_Elevation(Vector3 &Point, Vector3 &PlanePoint, Vector3 &PlaneNormal);
  239. // test a 2d screen area with the intersection's screen coords, assigning a GENERIC intersection
  240. // to the specified object.
  241. inline bool Intersect_Screen_Object(IntersectionResultClass *Final_Result, Vector4 &Area, RenderObjClass *obj = 0);
  242. // non-inlined declarations
  243. // accumulates an object array for passing into Intersect_ObjectArray
  244. void Append_Object_Array(int MaxCount, int &CurrentCount, RenderObjClass **ObjectArray, RenderObjClass *Object);
  245. // traverses an RenderObjClass object and adds it's subobjects, potentially performing
  246. // a quick sphere intersection test before adding.
  247. void Append_Hierarchy_Objects(int MaxCount, int &CurrentCount, RenderObjClass **ObjectArray, RenderObjClass *Heirarchy, bool Test_Bounding_Spheres, bool Convex);
  248. // top level intersection routines, most store intersection results in the Intersection.Result
  249. // member structure and perform normal interpolation as a final step if indicated in the member data.
  250. bool Intersect_Object_Array(int ObjectCount, RenderObjClass **ObjectArray,IntersectionResultClass *FinalResult, bool Test_Bounding_Sphere, bool Convex);
  251. bool Intersect_Object_Array(int ObjectCount, RenderObjClass **ObjectArray,IntersectionResultClass *FinalResult, IntersectionResultClass *TemporaryResults, bool Test_Bounding_Sphere, bool Convex);
  252. bool Intersect_RenderObject(RenderObjClass *RObj, IntersectionResultClass *FinalResult = 0);
  253. bool Intersect_Screen_Point_RenderObject(float screen_x, float screen_y, const LayerClass &Layer, RenderObjClass *RObj, IntersectionResultClass *FinalResult);
  254. bool Intersect_Screen_Point_Layer_Range(float ScreenX, float ScreenY, const LayerClass &TopLayer, const LayerClass &BackLayer);
  255. bool Intersect_Screen_Point_Layer(float ScreenX, float ScreenY, const LayerClass &Layer);
  256. bool Intersect_Layer(const LayerClass &Layer, bool Test_All = true);
  257. // the various intersection routines, all of which store their intersection results
  258. // in the passed Intersection_Result strucuture.
  259. bool Intersect_Box(Vector3 &Box_Min, Vector3 &Box_Max, IntersectionResultClass *FinalResult);
  260. bool Intersect_Hierarchy(RenderObjClass *Hierarchy, IntersectionResultClass *FinalResult, bool Test_Bounding_Sphere = true, bool Convex = false);
  261. bool Intersect_Hierarchy_Sphere(RenderObjClass *Hierarchy, IntersectionResultClass *FinalResult);
  262. bool Intersect_Hierarchy_Sphere_Quick(RenderObjClass *Hierarchy, IntersectionResultClass *FinalResult);
  263. /*
  264. ** Identifies exactly what sub object of a render object is under the screen space vector
  265. */
  266. RenderObjClass *Intersect_Sub_Object(float screenx, float screeny, LayerClass &layer, RenderObjClass *robj, IntersectionResultClass *result);
  267. /*
  268. ** Functions related to determining if a 3d point is within a triangle.
  269. */
  270. static inline void _Find_Polygon_Dominant_Plane(Vector3 &Normal, int &Axis_1, int &Axis_2);
  271. static inline int _Largest_Normal_Index(Vector3 &v);
  272. static inline bool _Point_In_Polygon(IntersectionResultClass *FinalResult, Vector3 &Normal, Vector3 &loc1, Vector3 &loc2, Vector3 &loc3);
  273. static inline bool _Point_In_Polygon(IntersectionResultClass *FinalResult, Vector3 &loc1, Vector3 &loc2, Vector3 &loc3, int axis_1, int axis_2);
  274. static inline bool _Point_In_Polygon(Vector3 &Point, Vector3 &loc1, Vector3 &loc2, Vector3 &loc3, int axis_1, int axis_2,float &Alpha,float &Beta);
  275. static inline bool _Point_In_Polygon_Z(Vector3 &Point, Vector3 Corners[3]);
  276. static inline bool _Point_In_Polygon_Z(Vector3 &Point, Vector3 &Corner1, Vector3 &Corner2, Vector3 &Corner3);
  277. protected:
  278. /*
  279. ** Find the intersection between two lines and interpolate the UV values for the intersection.
  280. ** Designed for use with _Intersect_Triangles_Z.
  281. */
  282. //static inline void _Intersect_Lines_Z(Vector3 &A, Vector3 &B, Vector2 &UVStart, Vector2 &UVEnd, Vector3 &C, Vector3 &D, Vector3 ClippedPoints[6], Vector2 ClippedUV[6], int &DestIndex);
  283. static inline bool IntersectionClass::In_Front_Of_Line
  284. (
  285. const Vector3 & p, // point to test
  286. const Vector3 & e0, // point on edge
  287. const Vector3 & de // direction of edge
  288. );
  289. static inline float IntersectionClass::Intersect_Lines
  290. (
  291. const Vector3 & p0, // start of line segment
  292. const Vector3 & p1, // end of line segment
  293. const Vector3 & e0, // point on clipping edge
  294. const Vector3 & de // direction of clipping edge
  295. );
  296. static inline int IntersectionClass::Clip_Triangle_To_LineXY(
  297. int incount,
  298. Vector3 * InPoints,
  299. Vector2 * InUVs,
  300. Vector3 * OutPoints,
  301. Vector2 * OutUVs,
  302. const Vector3 & edge_point0,
  303. const Vector3 & edge_point1
  304. );
  305. inline float Plane_Z_Distance(Vector3 &PlaneNormal, Vector3 &PlanePoint);
  306. inline void Transform_Model_To_World_Coords(IntersectionResultClass *FinalResult);
  307. /*
  308. ** Static vars available for use by temporary intersection class objects.
  309. */
  310. static Vector3 _RayLocation, _RayDirection, _IntersectionNormal;
  311. };
  312. #endif