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.
 
 
 

362 lines
8.6 KiB

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