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.
 
 
 
 
 
 

383 lines
10 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright © 2010—2020 Sam Hocevar <sam@hocevar.net>
  5. // © 2010—2015 Benjamin “Touky” Huet <huet.benjamin@gmail.com>
  6. //
  7. // Lol Engine is free software. It comes without any warranty, to
  8. // the extent permitted by applicable law. You can redistribute it
  9. // and/or modify it under the terms of the Do What the Fuck You Want
  10. // to Public License, Version 2, as published by the WTFPL Task Force.
  11. // See http://www.wtfpl.net/ for more details.
  12. //
  13. #pragma once
  14. //
  15. // Various geometry functions
  16. // --------------------------
  17. //
  18. #include <lol/base/enum.h>
  19. #include <algorithm>
  20. #include <map>
  21. #include <cmath>
  22. #include <cstdio>
  23. #include <cstdint>
  24. namespace lol
  25. {
  26. //AxisBase --------------------------------------------------------------------
  27. struct AxisBase : public StructSafeEnum
  28. {
  29. enum Type
  30. {
  31. X = 0, Y, Z, MAX, XY = 2, XYZ = 3,
  32. };
  33. protected:
  34. virtual bool BuildEnumMap(std::map<int64_t, std::string>& enum_map)
  35. {
  36. enum_map[X] = "X";
  37. enum_map[Y] = "Y";
  38. enum_map[Z] = "Z";
  39. enum_map[MAX] = "MAX";
  40. enum_map[XY] = "XY";
  41. enum_map[XYZ] = "XYZ";
  42. return true;
  43. }
  44. };
  45. typedef SafeEnum<AxisBase> Axis;
  46. //DirectionBase ---------------------------------------------------------------
  47. struct DirectionBase : public StructSafeEnum
  48. {
  49. enum Type
  50. {
  51. Up = 0, Down, Left, Right, MAX,
  52. };
  53. protected:
  54. virtual bool BuildEnumMap(std::map<int64_t, std::string>& enum_map)
  55. {
  56. enum_map[Up] = "Up";
  57. enum_map[Down] = "Down";
  58. enum_map[Left] = "Left";
  59. enum_map[Right] = "Right";
  60. enum_map[MAX] = "MAX";
  61. return true;
  62. }
  63. };
  64. typedef SafeEnum<DirectionBase> Direction;
  65. /*
  66. * Generic box type names
  67. */
  68. #define T_(tleft, tright, suffix) \
  69. typedef tleft float tright suffix; \
  70. typedef tleft double tright d##suffix; \
  71. typedef tleft int32_t tright i##suffix; \
  72. typedef tleft uint32_t tright u##suffix;
  73. /* Idiotic hack to put "," inside a macro argument */
  74. #define C_ ,
  75. T_(box_t<, C_ 2>, box2)
  76. T_(box_t<, C_ 3>, box3)
  77. T_(box_t<, C_ 4>, box4)
  78. #undef C_
  79. #undef T_
  80. template<typename T, int N>
  81. struct [[nodiscard]] box_t
  82. {
  83. inline box_t()
  84. : aa(vec_t<T, N>(T(0))),
  85. bb(vec_t<T, N>(T(0)))
  86. {}
  87. inline box_t(vec_t<T,N> const &a, vec_t<T,N> const &b)
  88. : aa(a),
  89. bb(b)
  90. {}
  91. inline box_t(T const &ax, T const &ay, T const &bx, T const &by)
  92. : aa(ax, ay),
  93. bb(bx, by)
  94. {}
  95. inline box_t(T const &ax, T const &ay, T const &az,
  96. T const &bx, T const &by, T const &bz)
  97. : aa(ax, ay, az),
  98. bb(bx, by, bz)
  99. {}
  100. box_t<T,N> operator +(vec_t<T,N> const &v) const
  101. {
  102. return box_t<T,N>(aa + v, bb + v);
  103. }
  104. box_t<T,N> &operator +=(vec_t<T,N> const &v)
  105. {
  106. return *this = *this + v;
  107. }
  108. box_t<T,N> operator -(vec_t<T,N> const &v) const
  109. {
  110. return box_t<T,N>(aa - v, bb - v);
  111. }
  112. box_t<T,N> &operator -=(vec_t<T,N> const &v)
  113. {
  114. return *this = *this - v;
  115. }
  116. box_t<T,N> operator *(vec_t<T,N> const &v) const
  117. {
  118. return box_t<T,N>(aa * v, bb * v);
  119. }
  120. box_t<T,N> &operator *=(vec_t<T,N> const &v)
  121. {
  122. return *this = *this * v;
  123. }
  124. box_t<T,N> operator *(T const &s) const
  125. {
  126. return box_t<T,N>(aa * s, bb * s);
  127. }
  128. box_t<T,N> &operator *=(T const &s)
  129. {
  130. return *this = *this * s;
  131. }
  132. [[nodiscard]] bool operator ==(box_t<T,N> const &box) const
  133. {
  134. return aa == box.aa && bb == box.bb;
  135. }
  136. [[nodiscard]] bool operator !=(box_t<T,N> const &box) const
  137. {
  138. return aa != box.aa || bb != box.bb;
  139. }
  140. inline vec_t<T,N> center() const { return (bb + aa) / 2; }
  141. inline vec_t<T,N> extent() const { return bb - aa; }
  142. vec_t<T,N> aa, bb;
  143. };
  144. static_assert(sizeof(box2) == 16, "sizeof(box2) == 16");
  145. static_assert(sizeof(box3) == 24, "sizeof(box3) == 24");
  146. static_assert(sizeof(dbox2) == 32, "sizeof(dbox2) == 32");
  147. static_assert(sizeof(dbox3) == 48, "sizeof(dbox3) == 48");
  148. /*
  149. * Helper geometry functions
  150. */
  151. class TestEpsilon
  152. {
  153. private:
  154. float m_epsilon;
  155. float m_value;
  156. public:
  157. TestEpsilon() { m_value = 0.f; m_epsilon = .0001f; }
  158. static float Get();
  159. static void Set(float epsilon=.0001f);
  160. static const TestEpsilon& F(float value);
  161. private:
  162. float Minus() const;
  163. float Plus() const;
  164. public:
  165. [[nodiscard]] bool operator==(float value) const;
  166. [[nodiscard]] bool operator!=(float value) const;
  167. [[nodiscard]] bool operator<(float value) const;
  168. [[nodiscard]] bool operator<=(float value) const;
  169. [[nodiscard]] bool operator>(float value) const;
  170. [[nodiscard]] bool operator>=(float value) const;
  171. };
  172. [[nodiscard]] bool operator==(float value, const TestEpsilon& epsilon);
  173. [[nodiscard]] bool operator!=(float value, const TestEpsilon& epsilon);
  174. [[nodiscard]] bool operator<(float value, const TestEpsilon& epsilon);
  175. [[nodiscard]] bool operator<=(float value, const TestEpsilon& epsilon);
  176. [[nodiscard]] bool operator>(float value, const TestEpsilon& epsilon);
  177. [[nodiscard]] bool operator>=(float value, const TestEpsilon& epsilon);
  178. //--
  179. static inline bool TestAABBVsAABB(box2 const &b1, box2 const &b2)
  180. {
  181. vec2 c = b1.center() - b2.center();
  182. vec2 e1 = 0.5f * b1.extent();
  183. vec2 e2 = 0.5f * b2.extent();
  184. return abs(c.x) <= e1.x + e2.x
  185. && abs(c.y) <= e1.y + e2.y;
  186. }
  187. static inline bool TestAABBVsPoint(box2 const &b1, vec2 const &p)
  188. {
  189. return TestAABBVsAABB(b1, box2(p, p));
  190. }
  191. static inline bool TestAABBVsAABB(box3 const &b1, box3 const &b2)
  192. {
  193. vec3 c = b1.center() - b2.center();
  194. vec3 e1 = 0.5f * b1.extent();
  195. vec3 e2 = 0.5f * b2.extent();
  196. return abs(c.x) <= e1.x + e2.x
  197. && abs(c.y) <= e1.y + e2.y
  198. && abs(c.z) <= e1.z + e2.z;
  199. }
  200. static inline bool TestAABBVsPoint(box3 const &b1, vec3 const &p)
  201. {
  202. return TestAABBVsAABB(b1, box3(p, p));
  203. }
  204. bool TestTriangleVsTriangle(vec3 const &v00, vec3 const &v01, vec3 const &v02,
  205. vec3 const &v10, vec3 const &v11, vec3 const &v12,
  206. vec3 &ip00, vec3 &ip10);
  207. bool TestRayVsTriangleSide(vec3 const &v0, vec3 const &v1, vec3 const &v2,
  208. vec3 const &ip0, vec3 const &ip1,
  209. vec3 &iV0, int &iIdx0, vec3 &iV1, int &iIdx1);
  210. bool TestRayVsTriangle(vec3 const &ray_point, vec3 const &ray_dir,
  211. vec3 const &tri_p0, vec3 const &tri_p1, vec3 const &tri_p2,
  212. vec3 &vi);
  213. //RayIntersect ----------------------------------------------------------------
  214. struct RayIntersectBase : public StructSafeEnum
  215. {
  216. enum Type
  217. {
  218. Nothing,
  219. All,
  220. None,
  221. P0,
  222. P1,
  223. };
  224. //LOL_DECLARE_ENUM_METHODS(RayIntersectBase)
  225. protected:
  226. virtual bool BuildEnumMap(std::map<int64_t, std::string>& enum_map)
  227. {
  228. enum_map[Nothing] = "Nothing";
  229. enum_map[All] = "All";
  230. enum_map[None] = "None";
  231. enum_map[P0] = "P0";
  232. enum_map[P1] = "P1";
  233. return true;
  234. }
  235. };
  236. typedef SafeEnum<RayIntersectBase> RayIntersect;
  237. #define RAY_ISECT_NOTHING 0
  238. #define RAY_ISECT_ALL 1
  239. #define RAY_ISECT_NONE 2
  240. #define RAY_ISECT_P0 3
  241. #define RAY_ISECT_P1 4
  242. int TestRayVsRay(vec3 const &ray_p00, vec3 const &ray_p01,
  243. vec3 const &ray_p10, vec3 const &ray_p11,
  244. vec3 &isec_p);
  245. bool TestPointVsFrustum(const vec3& point, const mat4& frustum, vec3* result_point = nullptr);
  246. //Ray/Plane : Normal must be given normalized. returns 1 if succeeded.
  247. template <typename TV>
  248. bool TestRayVsPlane(const TV &ray_p0, const TV &ray_p1,
  249. const TV &plane_p, const TV &plane_n,
  250. TV &isec_p, bool test_line_only=false)
  251. {
  252. TV ray_dir = ray_p1 - ray_p0;
  253. float d = dot(ray_dir, plane_n);
  254. if (d > -TestEpsilon::Get() && d < TestEpsilon::Get())
  255. return false;
  256. TV o2p1 = ray_p1 - plane_p;
  257. TV o2p0 = ray_p0 - plane_p;
  258. if (!test_line_only)
  259. {
  260. d = dot(o2p1, plane_n);
  261. d *= dot(o2p0, plane_n);
  262. //point are on the same side, so ray can intersect.
  263. if (d > .0f)
  264. return false;
  265. }
  266. float t = (dot(ProjectPointOnPlane(ray_p0, plane_p, plane_n) - ray_p0, plane_n)) / dot(ray_dir, plane_n);
  267. if (!test_line_only && (t < -TestEpsilon::Get() || t > 1.f + TestEpsilon::Get()))
  268. return false;
  269. isec_p = ray_p0 + t * ray_dir;
  270. return true;
  271. }
  272. //PlaneIntersectionBase -------------------------------------------------------
  273. struct PlaneIntersectionBase : public StructSafeEnum
  274. {
  275. /* A safe enum for Primitive edge face. */
  276. enum Type
  277. {
  278. Back, Front, Plane,
  279. };
  280. protected:
  281. virtual bool BuildEnumMap(std::map<int64_t, std::string>& enum_map)
  282. {
  283. enum_map[Back] = "Back";
  284. enum_map[Front] = "Front";
  285. enum_map[Plane] = "Plane";
  286. return true;
  287. }
  288. };
  289. typedef SafeEnum<PlaneIntersectionBase> PlaneIntersection;
  290. //Point/Plane : Normal must be given normalized.
  291. template <typename TV>
  292. PlaneIntersection TestPointVsPlane(const TV &point, const TV &plane_p, const TV &plane_n)
  293. {
  294. float d = dot(normalize(point - plane_p), plane_n);
  295. if (d > TestEpsilon::Get())
  296. return PlaneIntersection::Front;
  297. else if (d < -TestEpsilon::Get())
  298. return PlaneIntersection::Back;
  299. else
  300. return PlaneIntersection::Plane;
  301. }
  302. /* Project point on plane */
  303. template <typename TV>
  304. TV ProjectPointOnPlane(TV const &p, TV const &origin, TV const &normal)
  305. {
  306. return p - dot(p - origin, normal) * normal;
  307. }
  308. /* Project point on line */
  309. template <typename TV>
  310. TV ProjectPointOnRay(TV const &p, TV const &origin, TV const &direction)
  311. {
  312. return origin + direction * dot(p - origin, direction);
  313. }
  314. /* Distance from point to plane */
  315. template <typename TV>
  316. float PointDistToPlane(TV const &p, TV const &origin, TV const &normal)
  317. {
  318. return abs(dot(p - origin, normal));
  319. }
  320. /* Distance from point to segment */
  321. template <typename TV>
  322. float PointDistToSegment(TV const &p, TV const &a, TV const &b)
  323. {
  324. float d2 = sqlength(b - a);
  325. float u = d2 ? dot(p - a, b - a) / d2 : 0.0f;
  326. return distance(p, mix(a, b, clamp(u, 0.0f, 1.0f)));
  327. }
  328. } /* namespace lol */