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