Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.

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