554 строки
23 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. //
  12. // The EasyMesh class
  13. // ------------------
  14. //
  15. #if defined HAVE_CONFIG_H
  16. # include "config.h"
  17. #endif
  18. #include "core.h"
  19. #include <lol/math/geometry.h>
  20. namespace lol
  21. {
  22. //--
  23. int CsgBsp::AddLeaf(int leaf_type, vec3 origin, vec3 normal, int above_idx)
  24. {
  25. if (leaf_type > 2 && leaf_type < -1)
  26. return -1;
  27. if ((m_tree.Count() == 0 && above_idx == -1) ||
  28. (above_idx >= 0 &&
  29. above_idx < m_tree.Count() &&
  30. leaf_type > LEAF_CURRENT &&
  31. leaf_type < LEAF_ABOVE &&
  32. m_tree[above_idx].m_leaves[leaf_type] == -1))
  33. {
  34. if (m_tree.Count() != 0)
  35. m_tree[above_idx].m_leaves[leaf_type] = m_tree.Count();
  36. m_tree.Push(CsgBspLeaf(origin, normal, above_idx));
  37. return m_tree.Count() - 1;
  38. }
  39. return -1;
  40. }
  41. int CsgBsp::TestPoint(int leaf_idx, vec3 point)
  42. {
  43. if (leaf_idx >= 0 && leaf_idx < m_tree.Count())
  44. {
  45. vec3 p2o = point - m_tree[leaf_idx].m_origin;
  46. if (length(p2o) < TestEpsilon::Get())
  47. return LEAF_CURRENT;
  48. float p2o_dot = dot(normalize(p2o), m_tree[leaf_idx].m_normal);
  49. if (p2o_dot > TestEpsilon::Get())
  50. return LEAF_FRONT;
  51. else if (p2o_dot < -TestEpsilon::Get())
  52. return LEAF_BACK;
  53. }
  54. return LEAF_CURRENT;
  55. }
  56. void CsgBsp::AddTriangleToTree(int const &tri_idx, vec3 const &tri_p0, vec3 const &tri_p1, vec3 const &tri_p2)
  57. {
  58. //<Leaf_Id, v0, v1, v2>
  59. Array< int, vec3, vec3, vec3 > tri_to_process;
  60. //<FW/BW, Leaf_Id, v0, v1, v2, twin_leaf>
  61. Array< int, int, vec3, vec3, vec3, int > Leaf_to_add;
  62. //Tree is empty, so this leaf is the first
  63. if (m_tree.Count() == 0)
  64. {
  65. AddLeaf(LEAF_CURRENT, tri_p0, cross(normalize(tri_p1 - tri_p0), normalize(tri_p2 - tri_p1)), LEAF_CURRENT);
  66. m_tree.Last().m_tri_list.Push(tri_idx, tri_p0, tri_p1, tri_p2);
  67. return;
  68. }
  69. tri_to_process.Reserve(20);
  70. tri_to_process.Push(0, tri_p0, tri_p1, tri_p2);
  71. while (tri_to_process.Count())
  72. {
  73. int leaf_idx = tri_to_process.Last().m1;
  74. vec3 v[3] = { tri_to_process.Last().m2, tri_to_process.Last().m3, tri_to_process.Last().m4 };
  75. int res_nb[3] = { 0, 0, 0 };
  76. int res_side[3] = { -1, -1, -1 };
  77. //Check where each point is located
  78. for (int i = 0; i < 3; i++)
  79. {
  80. int result = TestPoint(leaf_idx, v[i]);
  81. if (result != LEAF_CURRENT)
  82. {
  83. res_nb[result]++;
  84. res_side[i] = result;
  85. }
  86. }
  87. //Points are located on each sides, let's do the mumbo-jumbo
  88. if (res_nb[LEAF_BACK] && res_nb[LEAF_FRONT])
  89. {
  90. //there are two intersections, no more.
  91. vec3 isec_v[2] = { vec3(.0f), vec3(.0f) };
  92. int isec_i[2] = { 0, 0 };
  93. int isec_base = 0;
  94. int isec_idx = 0;
  95. for (int i = 0; i < 3; i++)
  96. {
  97. vec3 ray = v[(i + 1) % 3] - v[i];
  98. if (TestRayVsPlane(v[i], v[(i + 1) % 3],
  99. m_tree[leaf_idx].m_origin, m_tree[leaf_idx].m_normal,
  100. isec_v[isec_idx]))
  101. isec_i[isec_idx++] = i;
  102. else
  103. isec_base = i;
  104. }
  105. int v_idx0 = (isec_base == 1)?(1):(0);
  106. int v_idx1 = (isec_base == 1)?(0):(1);
  107. int leaf_type = res_side[(isec_base + 2) % 3];
  108. tri_to_process.Pop();
  109. #if 1
  110. if (m_tree[leaf_idx].m_leaves[leaf_type] == LEAF_CURRENT)
  111. Leaf_to_add.Push(leaf_type, leaf_idx, v[((isec_base + 2) % 3)], isec_v[v_idx1], isec_v[v_idx0], -1);
  112. else
  113. tri_to_process.Push(leaf_idx, v[((isec_base + 2) % 3)], isec_v[v_idx1], isec_v[v_idx0]);
  114. if (m_tree[leaf_idx].m_leaves[1 - leaf_type] == LEAF_CURRENT)
  115. {
  116. Leaf_to_add.Push(1 - leaf_type, leaf_idx, v[isec_base], v[((isec_base + 1) % 3)], isec_v[v_idx0], -1);
  117. Leaf_to_add.Push(1 - leaf_type, leaf_idx, v[isec_base], isec_v[v_idx0], isec_v[v_idx1], Leaf_to_add.Count() - 1);
  118. }
  119. else
  120. {
  121. tri_to_process.Push(m_tree[leaf_idx].m_leaves[1 - leaf_type], v[isec_base], v[((isec_base + 1) % 3)], isec_v[v_idx0]);
  122. tri_to_process.Push(m_tree[leaf_idx].m_leaves[1 - leaf_type], v[isec_base], isec_v[v_idx0], isec_v[v_idx1]);
  123. }
  124. #else
  125. vec3 new_v[9] = { v[((isec_base + 2) % 3)], isec_v[v_idx1], isec_v[v_idx0],
  126. v[isec_base], v[((isec_base + 1) % 3)], isec_v[v_idx0],
  127. v[isec_base], isec_v[v_idx0], isec_v[v_idx1] };
  128. //Error check : Skip the triangle where two points are on the same location.
  129. //it fixes the problem of having an intersection with one of the isec-point being on one of the triangle vertices.
  130. //(the problem being a very funny infinite loop)
  131. for(int k = 0; k < 9; k += 3)
  132. {
  133. bool skip_tri = false;
  134. for(int l = 0; l < 3; l++)
  135. {
  136. if (length(new_v[k + l] - new_v[k + (l + 1) % 3]) < TestEpsilon::Get())
  137. {
  138. skip_tri = true;
  139. break;
  140. }
  141. }
  142. if (skip_tri)
  143. continue;
  144. tri_to_process.Push(0, new_v[k], new_v[k + 1], new_v[k + 2]);
  145. }
  146. #endif
  147. }
  148. //All points are on one side, transfer to the next leaf
  149. else if (res_nb[LEAF_BACK] || res_nb[LEAF_FRONT])
  150. {
  151. int new_leaf_type = ((res_nb[LEAF_FRONT])?(LEAF_FRONT):(LEAF_BACK));
  152. int new_leaf = m_tree[leaf_idx].m_leaves[new_leaf_type];
  153. //No leaf exist, so add a new one
  154. if (new_leaf == LEAF_CURRENT)
  155. {
  156. tri_to_process.Pop();
  157. Leaf_to_add.Push(new_leaf_type, leaf_idx, v[0], v[1], v[2], -1);
  158. }
  159. else
  160. tri_to_process.Last().m1 = new_leaf;
  161. }
  162. //All points are on the current leaf, add the tri_idx to the list of this leaf.
  163. else
  164. {
  165. tri_to_process.Pop();
  166. bool already_exist = false;
  167. for (int i = 0; !already_exist && i < m_tree[leaf_idx].m_tri_list.Count(); i++)
  168. already_exist = (m_tree[leaf_idx].m_tri_list[i].m1 == tri_idx);
  169. if (!already_exist)
  170. m_tree[leaf_idx].m_tri_list.Push(tri_idx, tri_p0, tri_p1, tri_p2);
  171. }
  172. }
  173. //Add all leaves to the tree.
  174. for (int i = 0; i < Leaf_to_add.Count(); i++)
  175. {
  176. //If we had it to an already existing leaf.
  177. if (Leaf_to_add[i].m2 < m_tree.Count() && m_tree[Leaf_to_add[i].m2].m_leaves[Leaf_to_add[i].m1] == LEAF_CURRENT)
  178. {
  179. AddLeaf(Leaf_to_add[i].m1, tri_p0, cross(normalize(tri_p1 - tri_p0), normalize(tri_p2 - tri_p1)), Leaf_to_add[i].m2);
  180. m_tree.Last().m_tri_list.Push(tri_idx, tri_p0, tri_p1, tri_p2);
  181. }
  182. /*
  183. if (Leaf_to_add[i].m6 == -1)
  184. {
  185. AddLeaf(Leaf_to_add[i].m1, tri_p0, cross(normalize(tri_p1 - tri_p0), normalize(tri_p2 - tri_p1)), Leaf_to_add[i].m2);
  186. m_tree.Last().m_tri_list.Push(tri_idx, tri_p0, tri_p1, tri_p2);
  187. }
  188. else
  189. m_tree[Leaf_to_add[i].m6].m_tri_list.Push(tri_idx, tri_p0, tri_p1, tri_p2);
  190. */
  191. }
  192. }
  193. //return 0 when no split has been done.
  194. //return 1 when split has been done.
  195. //return -1 when error.
  196. int CsgBsp::TestTriangleToTree(vec3 const &tri_p0, vec3 const &tri_p1, vec3 const &tri_p2,
  197. //In order to easily build the actual vertices list afterward, this list stores each Vertices location and its source vertices & Alpha.
  198. //<Point_Loc, Src_V0, Src_V1, Alpha> as { Point_Loc = Src_V0 + (Src_V1 - Src_V0) * Alpha; }
  199. Array< vec3, int, int, float > &vert_list,
  200. //This is the final triangle list : If Side_Status is LEAF_CURRENT, a new test will be done point by point.
  201. //<{IN|OUT}side_status, v0, v1, v2>
  202. Array< int, int, int, int > &tri_list)
  203. {
  204. //This list stores the current triangles to process.
  205. //<Leaf_Id_List, v0, v1, v2, Should_Point_Test>
  206. Array< Array< int >, int, int, int, int > tri_to_process;
  207. //Tree is empty, ABORT !
  208. if (m_tree.Count() == 0)
  209. return -1;
  210. //Let's push the source vertices in here.
  211. vert_list.Push(tri_p0, -1, -1, .0f);
  212. vert_list.Push(tri_p1, -1, -1, .0f);
  213. vert_list.Push(tri_p2, -1, -1, .0f);
  214. //Let's push the triangle in here.
  215. tri_to_process.Reserve(20);
  216. tri_to_process.Push( Array< int >(), 0, 1, 2, 0);
  217. tri_to_process.Last().m1.Push(0);
  218. while (tri_to_process.Count())
  219. {
  220. while (tri_to_process.Count())
  221. {
  222. int leaf_idx = tri_to_process.Last().m1.Last();
  223. int t[3] = { tri_to_process.Last().m2,
  224. tri_to_process.Last().m3,
  225. tri_to_process.Last().m4 };
  226. vec3 v[3] = { vert_list[t[0]].m1,
  227. vert_list[t[1]].m1,
  228. vert_list[t[2]].m1 };
  229. int res_nb[3] = { 0, 0, 0 };
  230. int res_side[3] = { -1, -1, -1 };
  231. //Check where each point is located
  232. for (int i = 0; i < 3; i++)
  233. {
  234. int result = TestPoint(leaf_idx, v[i]);
  235. if (result != LEAF_CURRENT)
  236. {
  237. res_nb[result]++;
  238. res_side[i] = result;
  239. }
  240. }
  241. //Points are located on each sides, let's do the mumbo-jumbo
  242. if (res_nb[LEAF_BACK] && res_nb[LEAF_FRONT])
  243. {
  244. //there are two intersections, no more.
  245. vec3 isec_v[2] = { vec3(.0f), vec3(.0f) };
  246. int isec_i[2] = { 0, 0 };
  247. int new_v_idx[2] = { 0, 0 };
  248. int isec_base = 0;
  249. int isec_idx = 0;
  250. int i = 0;
  251. for (; i < m_tree[leaf_idx].m_tri_list.Count(); i++)
  252. {
  253. if (TestTriangleVsTriangle(v[0], v[1], v[2],
  254. m_tree[leaf_idx].m_tri_list[i].m2, m_tree[leaf_idx].m_tri_list[i].m3, m_tree[leaf_idx].m_tri_list[i].m4,
  255. isec_v[0], isec_v[1]))
  256. break;
  257. }
  258. //There was no triangle intersection, the complex case.
  259. if (i == m_tree[leaf_idx].m_tri_list.Count())
  260. {
  261. if (m_tree[leaf_idx].m_leaves[LEAF_FRONT] == LEAF_CURRENT &&
  262. m_tree[leaf_idx].m_leaves[LEAF_BACK] == LEAF_CURRENT &&
  263. tri_to_process.Last().m1.Count() == 1)
  264. {
  265. tri_list.Push(LEAF_CURRENT, tri_to_process.Last().m2, tri_to_process.Last().m3, tri_to_process.Last().m4);
  266. tri_to_process.Pop();
  267. }
  268. else
  269. {
  270. tri_to_process.Last().m1.Pop();
  271. //Register the triangle as needing to intersect with Front & back leaves.
  272. if (m_tree[leaf_idx].m_leaves[LEAF_FRONT] != LEAF_CURRENT)
  273. tri_to_process.Last().m1.Push(m_tree[leaf_idx].m_leaves[LEAF_FRONT]);
  274. if (m_tree[leaf_idx].m_leaves[LEAF_BACK] != LEAF_CURRENT)
  275. tri_to_process.Last().m1.Push(m_tree[leaf_idx].m_leaves[LEAF_BACK]);
  276. //Mark the triangle as needing point by point test
  277. tri_to_process.Last().m5 = 1;
  278. }
  279. }
  280. //there was an intersection, so let's split the triangle.
  281. else
  282. {
  283. //Get intersection on actual triangle sides.
  284. if (TestRayVsTriangleSide(v[0], v[1], v[2],
  285. isec_v[0], isec_v[1],
  286. isec_v[0], isec_i[0], isec_v[1], isec_i[1]))
  287. {
  288. {
  289. for(int k = 0; k < 2; k++)
  290. {
  291. if (isec_base == isec_i[k])
  292. isec_base++;
  293. #if 1 //Skip point creation if it's on the same location a one of the triangle.
  294. bool skip_point = false;
  295. int l = 0;
  296. for(; l < 3; l++)
  297. {
  298. if (length(v[l] - isec_v[k]) < TestEpsilon::Get())
  299. {
  300. skip_point = true;
  301. new_v_idx[k] = t[l];
  302. break;
  303. }
  304. }
  305. if (skip_point)
  306. continue;
  307. #endif
  308. new_v_idx[k] = vert_list.Count();
  309. vec3 PmV0 = (isec_v[k] - vert_list[t[isec_i[k]]].m1);
  310. vec3 V1mV0 = (vert_list[t[(isec_i[k] + 1) % 3]].m1 - vert_list[t[isec_i[k]]].m1);
  311. float alpha = length(PmV0) / length(V1mV0);
  312. vert_list.Push(isec_v[k],
  313. t[isec_i[k]], t[(isec_i[k] + 1) % 3],
  314. //Alpha = length((Point_Loc - Src_V0) / (Src_V1 - Src_V0));
  315. alpha);
  316. }
  317. int v_idx0 = (isec_base == 1)?(1):(0);
  318. int v_idx1 = (isec_base == 1)?(0):(1);
  319. //Leaf_type is the type for the triangle that is alone on its side.
  320. int leaf_type = res_side[(isec_base + 2) % 3];
  321. int tri_to_remove = tri_to_process.Count() - 1;
  322. #if 0
  323. if (m_tree[leaf_idx].m_leaves[leaf_type] == LEAF_CURRENT && tri_to_process.Last().m1.Last() == 1)
  324. tri_list.Push(leaf_type,
  325. t[(isec_base + 2) % 3], new_v_idx[v_idx1], new_v_idx[v_idx0]);
  326. else
  327. {
  328. tri_to_process.Push(Array< int >(), t[(isec_base + 2) % 3], new_v_idx[v_idx1], new_v_idx[v_idx0], 0);
  329. tri_to_process.Last().m1.Push(0);
  330. }
  331. if (m_tree[leaf_idx].m_leaves[1 - leaf_type] == LEAF_CURRENT && tri_to_process.Last().m1.Last() == 1)
  332. {
  333. tri_list.Push((tri_to_process.Last().m5)?(LEAF_CURRENT):(1 - leaf_type),
  334. t[isec_base], new_v_idx[((isec_base + 1) % 3)], new_v_idx[v_idx0]);
  335. tri_list.Push((tri_to_process.Last().m5)?(LEAF_CURRENT):(1 - leaf_type),
  336. t[isec_base], new_v_idx[v_idx0], new_v_idx[v_idx1]);
  337. }
  338. else
  339. {
  340. tri_to_process.Push(Array< int >(), t[isec_base], t[((isec_base + 1) % 3)], new_v_idx[v_idx0], 0);
  341. tri_to_process.Last().m1.Push(0);
  342. tri_to_process.Push(Array< int >(), t[isec_base], new_v_idx[v_idx0], new_v_idx[v_idx1], 0);
  343. tri_to_process.Last().m1.Push(0);
  344. }
  345. #else
  346. int new_t[9] = { t[(isec_base + 2) % 3], new_v_idx[v_idx1], new_v_idx[v_idx0],
  347. t[isec_base], t[((isec_base + 1) % 3)], new_v_idx[v_idx0],
  348. t[isec_base], new_v_idx[v_idx0], new_v_idx[v_idx1] };
  349. int new_side[3] = { res_side[(isec_base + 2) % 3],
  350. (res_side[isec_base] == LEAF_CURRENT)?(res_side[((isec_base + 1) % 3)]):(res_side[isec_base]),
  351. res_side[isec_base] };
  352. //Error check : Skip the triangle where two points are on the same location.
  353. //it fixes the problem of having an intersection with one of the isec-point being on one of the triangle vertices.
  354. //(the problem being a very funny infinite loop)
  355. for(int k = 0; k < 9; k += 3)
  356. {
  357. #if 1 //Error check
  358. bool skip_tri = false;
  359. for(int l = 0; l < 3; l++)
  360. {
  361. if (length(vert_list[new_t[k + l]].m1 - vert_list[new_t[k + (l + 1) % 3]].m1) < TestEpsilon::Get())
  362. {
  363. skip_tri = true;
  364. break;
  365. }
  366. }
  367. if (skip_tri)
  368. continue;
  369. #endif
  370. #if 0 //Send the newly created triangle back to the beginning
  371. tri_to_process.Push(Array< int >(), new_t[k], new_t[k + 1], new_t[k + 2], 0);
  372. tri_to_process.Last().m1.Push(0);
  373. #else //Inherit parent tree
  374. if (m_tree[leaf_idx].m_leaves[new_side[k / 3]] == LEAF_CURRENT && tri_to_process[tri_to_remove].m1.Count() == 1)
  375. tri_list.Push(new_side[k / 3], new_t[k], new_t[k + 1], new_t[k + 2]);
  376. else
  377. {
  378. tri_to_process.Push(Array< int >(), new_t[k], new_t[k + 1], new_t[k + 2], 0);
  379. tri_to_process.Last().m1 = tri_to_process[tri_to_remove].m1;
  380. if (m_tree[leaf_idx].m_leaves[new_side[k / 3]] == LEAF_CURRENT)
  381. tri_to_process.Last().m1.Pop();
  382. else
  383. tri_to_process.Last().m1.Last() = m_tree[leaf_idx].m_leaves[new_side[k / 3]];
  384. }
  385. #endif
  386. }
  387. #endif
  388. tri_to_process.Remove(tri_to_remove);
  389. }
  390. }
  391. }
  392. }
  393. //All points are on one side, transfer to the next leaf
  394. else if (res_nb[LEAF_BACK] || res_nb[LEAF_FRONT])
  395. {
  396. int new_leaf_type = ((res_nb[LEAF_FRONT])?(LEAF_FRONT):(LEAF_BACK));
  397. int new_leaf = m_tree[leaf_idx].m_leaves[new_leaf_type];
  398. //No leaf exist, we're at the end
  399. if (new_leaf == LEAF_CURRENT)
  400. {
  401. //We still need to test other leaves.
  402. if (tri_to_process.Last().m1.Count() > 1)
  403. tri_to_process.Last().m1.Pop();
  404. else
  405. {
  406. tri_list.Push((tri_to_process.Last().m5)?(LEAF_CURRENT):(new_leaf_type),
  407. tri_to_process.Last().m2, tri_to_process.Last().m3, tri_to_process.Last().m4);
  408. tri_to_process.Pop();
  409. }
  410. }
  411. else
  412. tri_to_process.Last().m1.Last() = new_leaf;
  413. }
  414. //All points are on the current leaf, add the tri_idx to the list of this leaf.
  415. else
  416. {
  417. //TODO : Special case, handle coplanar cut.
  418. tri_list.Push(LEAF_CURRENT, tri_to_process.Last().m2, tri_to_process.Last().m3, tri_to_process.Last().m4);
  419. tri_to_process.Pop();
  420. }
  421. }
  422. //Now that we have all the split points, let's double-check the results
  423. for (int i = 0; i < tri_list.Count(); i++)
  424. {
  425. #define TEST_MAX 4
  426. int t[3] = { tri_list[i].m2,
  427. tri_list[i].m3,
  428. tri_list[i].m4 };
  429. vec3 v[4] = { vert_list[t[0]].m1,
  430. vert_list[t[1]].m1,
  431. vert_list[t[2]].m1,
  432. (vert_list[t[0]].m1 +
  433. vert_list[t[1]].m1 +
  434. vert_list[t[2]].m1) / 3.0f };
  435. int res_total = 0;
  436. int res_nb[3] = { 0, 0, 0 };
  437. int res_Leaf[4] = { 0, 0, 0, 0 };
  438. int res_side[4] = { -1, -1, -1, -1 };
  439. while (res_total < TEST_MAX)
  440. {
  441. for (int k = 0; k < TEST_MAX; k++)
  442. {
  443. if (res_Leaf[k] != LEAF_CURRENT)
  444. {
  445. int result = TestPoint(res_Leaf[k], v[k]);
  446. if (result != LEAF_CURRENT)
  447. {
  448. res_Leaf[k] = m_tree[res_Leaf[k]].m_leaves[result];
  449. res_side[k] = result;
  450. if (res_Leaf[k] == LEAF_CURRENT)
  451. {
  452. res_total++;
  453. res_nb[result]++;
  454. }
  455. }
  456. else
  457. {
  458. res_Leaf[k] = LEAF_CURRENT;
  459. res_side[k] = LEAF_CURRENT;
  460. res_total++;
  461. }
  462. }
  463. }
  464. }
  465. int k = 0;
  466. if (res_nb[LEAF_BACK] && res_nb[LEAF_FRONT])
  467. {
  468. res_total = res_total;
  469. tri_list[i].m1 = LEAF_BACK;
  470. #if 0
  471. tri_to_process.Push( Array< int >(), tri_list[i].m2, tri_list[i].m3, tri_list[i].m4, 0);
  472. tri_to_process.Last().m1.Push(0);
  473. tri_list.Remove(i--);
  474. break;
  475. #endif
  476. }
  477. else
  478. {
  479. for (; k < TEST_MAX; k++)
  480. {
  481. if (res_side[k] != LEAF_CURRENT)
  482. {
  483. tri_list[i].m1 = res_side[k];
  484. break;
  485. }
  486. }
  487. if (k == TEST_MAX)
  488. tri_list[i].m1 = LEAF_FRONT;
  489. }
  490. }
  491. }
  492. if (tri_list.Count() == 1)
  493. return 0;
  494. return 1;
  495. }
  496. } /* namespace lol */