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.
 
 
 

542 lines
23 KiB

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