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.
 
 
 

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