Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 

271 wiersze
10 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. #include <lol/engine-internal.h>
  12. #include <cstdlib> /* free() */
  13. #include <cstring> /* strdup() */
  14. #include <ostream> /* std::ostream */
  15. namespace lol
  16. {
  17. //Test epsilon stuff
  18. TestEpsilon g_test_epsilon;
  19. float TestEpsilon::Get() { return g_test_epsilon.m_epsilon; }
  20. void TestEpsilon::Set(float epsilon) { g_test_epsilon.m_epsilon = lol::max(epsilon, .0f); }
  21. const TestEpsilon& TestEpsilon::F(float value) { g_test_epsilon.m_value = value; return g_test_epsilon; }
  22. float TestEpsilon::Minus()const { return m_value - m_epsilon; }
  23. float TestEpsilon::Plus() const { return m_value + m_epsilon; }
  24. bool TestEpsilon::operator==(float value)const { return (Minus() <= value && value <= Plus()); }
  25. bool TestEpsilon::operator!=(float value)const { return (value < Minus() || Plus() < value); }
  26. bool TestEpsilon::operator<(float value) const { return (Plus() < value); }
  27. bool TestEpsilon::operator<=(float value)const { return (Minus() <= value); }
  28. bool TestEpsilon::operator>(float value) const { return (Minus() > value); }
  29. bool TestEpsilon::operator>=(float value)const { return (Plus() >= value); }
  30. bool operator==(float value, const TestEpsilon& epsilon) { return epsilon == value; }
  31. bool operator!=(float value, const TestEpsilon& epsilon) { return epsilon != value; }
  32. bool operator<(float value, const TestEpsilon& epsilon) { return epsilon > value; }
  33. bool operator<=(float value, const TestEpsilon& epsilon) { return epsilon >= value; }
  34. bool operator>(float value, const TestEpsilon& epsilon) { return epsilon < value; }
  35. bool operator>=(float value, const TestEpsilon& epsilon) { return epsilon <= value; }
  36. // Line/triangle : sets isec_p as the intersection point & return true if ok.
  37. bool TestRayVsTriangle(vec3 const &ray_point, vec3 const &ray_dir,
  38. vec3 const &tri_p0, vec3 const &tri_p1, vec3 const &tri_p2,
  39. vec3 &isec_p)
  40. {
  41. vec3 v01, v02, h, v0P, q;
  42. float a, f, triU, triV;
  43. //
  44. v01 = tri_p1 - tri_p0;
  45. v02 = tri_p2 - tri_p0;
  46. h = cross(ray_dir, v02);
  47. a = dot(v01, h);
  48. //rayDir is coplanar to the triangle, exit.
  49. if (a > -TestEpsilon::Get() && a < TestEpsilon::Get())
  50. return false;
  51. f = 1 / a;
  52. v0P = ray_point - tri_p0;
  53. triU = f * (dot(v0P, h));
  54. //point is supposed to have an U on the segment v01
  55. if (triU < -TestEpsilon::Get() || triU > 1.0)
  56. return false;
  57. q = cross(v0P, v01);
  58. triV = f * dot(ray_dir, q);
  59. //point is not in the triangle
  60. if (triV < -TestEpsilon::Get() || triU + triV > 1.0)
  61. return false;
  62. // at this stage we can compute t to find out where
  63. // the intersection point is on the line
  64. float t = f * dot(v02, q);
  65. if (t > TestEpsilon::Get()) // ray intersection
  66. {
  67. isec_p = tri_p0 + v01 * triU + v02 * triV;
  68. return true;
  69. }
  70. else // this means that there is a line intersection
  71. // but not a ray intersection
  72. return false;
  73. }
  74. // Triangle/Triangle
  75. bool TestTriangleVsTriangle(vec3 const &v00, vec3 const &v01, vec3 const &v02, //triangle 0
  76. vec3 const &v10, vec3 const &v11, vec3 const &v12, //triangle 1
  77. vec3 &ip00, vec3 &ip10) //triangle intersection, iPx means gives the actual intersection points.
  78. {
  79. vec3 isec[2] = { vec3(0, 0, 0), vec3(0, 0, 0) };
  80. vec3 triV[6] = { v00, v01, v02,
  81. v10, v11, v12 };
  82. vec3 triD[6] = { v01 - v00, v02 - v01, v00 - v02,
  83. v11 - v10, v12 - v11, v10 - v12 };
  84. int isecIdx = 0;
  85. vec3 isec_p(0);
  86. //Check the normal before doing any other calculations
  87. vec3 plane_norm[2] = { cross(normalize(triD[0]), normalize(triD[1])),
  88. cross(normalize(triD[3]), normalize(triD[4])) };
  89. if (abs(dot(plane_norm[0], plane_norm[1])) == 1.0f)
  90. return false;
  91. #if 0
  92. //Precheck to verify if two point of one of the tri-A are on tri-B, and vice versa.
  93. int zero_dist[2] = { 0, 0 };
  94. for (int i = 0; i < 3; i++)
  95. {
  96. if (PointDistToPlane(triV[i], triV[3], plane_norm[1]) < TestEpsilon::Get())
  97. zero_dist[0]++;
  98. if (PointDistToPlane(triV[i + 3], triV[0], plane_norm[0]) < TestEpsilon::Get())
  99. zero_dist[1]++;
  100. }
  101. if (zero_dist[0] >= 2 || zero_dist[0] >= 2)
  102. return false;
  103. #endif
  104. //We first need to find two points intersecting, no matter on which triangle.
  105. for (int i = 0; i < 2 && isecIdx < 2; i++)
  106. {
  107. /*int found_isec = -1;*/
  108. for (int j = 0; j < 3 && isecIdx < 2; j++)
  109. {
  110. int pIdx = j + i * 3;
  111. int tIdx = (1 - i) * 3;
  112. if (TestRayVsTriangle(triV[pIdx], triD[pIdx],
  113. triV[tIdx + 0], triV[tIdx + 1], triV[tIdx + 2],
  114. isec[isecIdx]))
  115. {
  116. #if 1 //if the point is near one the given entry, consider it as being the same point.
  117. for (int k = 0; k < 6; k++)
  118. {
  119. if (length(isec[isecIdx] - triV[k]) < TestEpsilon::Get())
  120. {
  121. isec[isecIdx] = triV[k];
  122. break;
  123. }
  124. }
  125. #endif
  126. //Automatic pass on the first intersection
  127. if (isecIdx == 0 ||
  128. //If we have already found an intersection, pass if it's on this triangle.
  129. /*found_isec == i ||*/
  130. //if it's the second intersection, we need it to be different from the first one.
  131. (isecIdx == 1 && length(isec[0] - isec[1]) > TestEpsilon::Get()))
  132. {
  133. /*found_isec = i;*/
  134. isecIdx++;
  135. }
  136. }
  137. }
  138. }
  139. if (isecIdx >= 2)
  140. {
  141. ip00 = isec[0];
  142. ip10 = isec[1];
  143. return true;
  144. }
  145. return false;
  146. }
  147. //Ray/Line : returns one of the RAY_ISECT_* defines.
  148. int TestRayVsRay(vec3 const &ray_p00, vec3 const &ray_p01,
  149. vec3 const &ray_p10, vec3 const &ray_p11,
  150. vec3 &isec_p)
  151. {
  152. vec3 rayD0 = ray_p01 - ray_p00;
  153. vec3 rayD0N = normalize(rayD0);
  154. vec3 rayD1 = ray_p11 - ray_p10;
  155. vec3 rayD1N = normalize(rayD1);
  156. vec3 rayP0P1 = ray_p10 - ray_p00;
  157. vec3 c01 = cross(rayD0N, rayD1N);
  158. float crs01S = length(c01);
  159. if (crs01S > -TestEpsilon::Get() && crs01S < TestEpsilon::Get())
  160. return 0;
  161. mat3 m0 = mat3(rayP0P1, rayD1N, c01);
  162. float t0 = determinant(m0) / (crs01S * crs01S);
  163. vec3 isec0 = ray_p00 + rayD0N * t0;
  164. mat3 m1 = mat3(rayP0P1, rayD0N, c01);
  165. float t1 = determinant(m1) / (crs01S * crs01S);
  166. vec3 isec1 = ray_p10 + rayD1N * t1;
  167. if (sqlength(isec0 - isec1) < TestEpsilon::Get()) //ray intersection
  168. {
  169. isec_p = (isec0 + isec0) * .5f;
  170. float d0 = (length(ray_p01 - isec_p) < TestEpsilon::Get() || length(ray_p00 - isec_p) < TestEpsilon::Get())?
  171. (-1.0f):
  172. (dot(ray_p00 - isec_p, ray_p01 - isec_p));
  173. float d1 = (length(ray_p10 - isec_p) < TestEpsilon::Get() || length(ray_p11 - isec_p) < TestEpsilon::Get())?
  174. (-1.0f):
  175. (dot(ray_p10 - isec_p, ray_p11 - isec_p));
  176. //if the dot is negative, your point is in each ray, so say OK.
  177. if (d0 < .0f && d1 < .0f)
  178. return RAY_ISECT_ALL;
  179. if (d0 < .0f)
  180. return RAY_ISECT_P0;
  181. if (d1 < .0f)
  182. return RAY_ISECT_P1;
  183. return RAY_ISECT_NONE;
  184. }
  185. else // this means that there is a line intersection
  186. // but not a ray intersection
  187. return RAY_ISECT_NOTHING;
  188. }
  189. //used to find the intersecting points between a triangle side and a coplanar line.
  190. bool TestRayVsTriangleSide(vec3 const &v0, vec3 const &v1, vec3 const &v2,
  191. vec3 const &ip0, vec3 const &ip1,
  192. vec3 &iV0, int &iIdx0, vec3 &iV1, int &iIdx1)
  193. {
  194. vec3 isecV[2] = { vec3(.0f), vec3(.0f) };
  195. int isecI[2] = { -1, -1 };
  196. vec3 triV[3] = { v0, v1, v2 };
  197. int isecIdx = 0;
  198. vec3 isec_p(0);
  199. //Two points given, so we test each triangle side to find the intersect
  200. isecIdx = 0;
  201. for (int j = 0; j < 3 && isecIdx < 2; j++)
  202. {
  203. int Result = TestRayVsRay(triV[j], triV[(j + 1) % 3], ip0, ip1, isec_p);
  204. if (Result == RAY_ISECT_P0 || Result == RAY_ISECT_ALL)
  205. {
  206. isecV[isecIdx] = isec_p;
  207. isecI[isecIdx] = j;
  208. isecIdx++;
  209. }
  210. }
  211. if (isecIdx < 2)
  212. return false;
  213. //We send the infos back to the parent.
  214. //TODO : that can be better than this horrible thing.
  215. iV0 = isecV[0];
  216. iV1 = isecV[1];
  217. iIdx0 = isecI[0];
  218. iIdx1 = isecI[1];
  219. return true;
  220. }
  221. //--
  222. bool TestPointVsFrustum(const vec3& point, const mat4& frustum, vec3* result_point)
  223. {
  224. vec4 proj_point = frustum * vec4(point, 1.f);
  225. proj_point /= proj_point.w;
  226. if (result_point)
  227. *result_point = proj_point.xyz;
  228. for (int i = 0; i < 3; i++)
  229. if (lol::abs(proj_point[i]) > 1.f)
  230. return false;
  231. return true;
  232. }
  233. } /* namespace lol */