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.

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