Destruct Mesh.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************/
  5. #define CC4_DSTR CC4('D','S','T','R')
  6. /******************************************************************************/
  7. Cache<DestructMesh> DestructMeshes("Destruct Mesh");
  8. /******************************************************************************/
  9. // MANAGE
  10. /******************************************************************************/
  11. Bool DestructMesh::Part::create(Mesh &src, Int vtx_limit)
  12. {
  13. // optimize
  14. mesh.create(src).triToQuad().weldCoplanarFaces(EPS_COL_COS, -1, false).setAutoTanBin().setRender();
  15. // phys
  16. if(!vtx_limit)phys.del();else
  17. {
  18. MeshBase temp; temp.createPhys(mesh); if(vtx_limit>0)temp.createConvex(temp.vtx.pos(), temp.vtxs(), vtx_limit);
  19. phys.createConvexTry(temp); if(!phys.is())return false;
  20. }
  21. mesh.delBase();
  22. return true;
  23. }
  24. /******************************************************************************/
  25. static void SelectNeighbors(Index &vtx_vtx, Memc<Bool> &vtxs, Int vtx)
  26. {
  27. if(InRange(vtx, vtxs) && !vtxs[vtx]) // if not yet added
  28. {
  29. vtxs[vtx]=true; // add vertex to selection
  30. IndexGroup &ig=vtx_vtx.group[vtx]; REPA(ig)SelectNeighbors(vtx_vtx, vtxs, ig[i]); // process all neighbors
  31. }
  32. }
  33. DestructMesh& DestructMesh::del()
  34. {
  35. _parts .del();
  36. _joints.del();
  37. return T;
  38. }
  39. DestructMesh& DestructMesh::create(Mesh &mesh, Int cuts, C MaterialPtr &material, Flt tex_scale, Int phys_vtx_limit, Bool cut_affects_biggest_part, Bool simple_cuts)
  40. {
  41. del();
  42. UInt flag_and=(VTX_POS|VTX_NRM_TAN_BIN|VTX_TEX_ALL|VTX_COLOR|VTX_MATERIAL|VTX_SIZE);
  43. Bool cur=false;
  44. Memb<Mesh> temp[2]; // use Memb so 'New' will not change memory address of previous elements
  45. FREP(cuts) // order is important
  46. {
  47. Plane clip_plane(Random(mesh.ext), Random(Ball(1), false));
  48. if(!i) // first step
  49. {
  50. if(simple_cuts)SplitMesh (mesh, null, temp[cur].New(), temp[cur].New(), clip_plane, flag_and);
  51. else SplitMeshSolid(mesh, null, temp[cur].New(), temp[cur].New(), clip_plane, material, tex_scale, flag_and);
  52. }else
  53. {
  54. const bool size_by_surface=true;
  55. if(cut_affects_biggest_part)
  56. {
  57. Int biggest=-1;
  58. Flt size;
  59. Vec center;
  60. REPA(temp[cur])
  61. {
  62. C Mesh &mesh=temp[cur][i];
  63. Vec c;
  64. Flt s=(size_by_surface ? mesh.area(&c) : mesh.ext.volume());
  65. if(biggest<0 || s>size){biggest=i; size=s; center=c;}
  66. }
  67. if(biggest>=0)
  68. {
  69. Mesh &mesh=temp[cur][biggest];
  70. clip_plane.pos=(size_by_surface ? center : Random(mesh.ext));
  71. if(simple_cuts)SplitMesh (mesh, null, mesh, temp[cur].New(), clip_plane, flag_and);
  72. else SplitMeshSolid(mesh, null, mesh, temp[cur].New(), clip_plane, material, tex_scale, flag_and);
  73. }
  74. }else
  75. {
  76. REPA(temp[cur]) // order is important
  77. {
  78. if(simple_cuts)SplitMesh (temp[cur][i], null, temp[!cur].New(), temp[!cur].New(), clip_plane, flag_and);
  79. else SplitMeshSolid(temp[cur][i], null, temp[!cur].New(), temp[!cur].New(), clip_plane, material, tex_scale, flag_and);
  80. }
  81. temp[cur].del(); cur^=1;
  82. }
  83. }
  84. REPA(temp[cur])if(!temp[cur][i].is())temp[cur].remove(i); // remove empty meshes
  85. }
  86. // separate mesh parts which aren't physically connected
  87. FREPA(temp[cur]) // order important
  88. {
  89. Mesh &src=temp[cur][i];
  90. if( src.lods()==1)
  91. {
  92. MeshBase joined ; joined.create(src, ~0, true).setVtxDup(); // create 1 part from all parts (and keep id as index of the part)
  93. Index vtx_vtx; joined.linkVtxVtxOnFace(vtx_vtx); // link all vertexes together
  94. Memc<Bool> vtxs ; vtxs .setNumZero(joined.vtxs()); // array of selected vertexes
  95. SelectNeighbors(vtx_vtx, vtxs, 0); // select 0-th vertex and all its neighbors
  96. // set connected triangles and quads
  97. Memt<Bool> tris, quads; tris.setNum(joined.tris()); quads.setNum(joined.quads());
  98. Int tri_count=0, quad_count=0;
  99. FREPA(joined.tri ){VecI ind=joined.tri .ind(i); ind.remap(joined.vtx.dup()); if(tris [i]=(vtxs[ind.x] || vtxs[ind.y] || vtxs[ind.z] )) tri_count++;}
  100. FREPA(joined.quad){VecI4 ind=joined.quad.ind(i); ind.remap(joined.vtx.dup()); if(quads[i]=(vtxs[ind.x] || vtxs[ind.y] || vtxs[ind.z] || vtxs[ind.w]))quad_count++;}
  101. if(tri_count!=joined.tris() || quad_count!=joined.quads()) // if connected faces don't cover the full mesh, then we should split it
  102. {
  103. MeshBase connected; joined.splitFaces(connected, null, tris, quads); // move the connected faces into 'connected'
  104. // convert back to meshes
  105. Mesh connected_mesh, unknown_mesh;
  106. connected.copyId(connected_mesh); connected_mesh.MeshLod::copyParams(src); FREP(Min(src.parts.elms(), connected_mesh.parts.elms()))connected_mesh.parts[i].keepOnly(src.parts[i].base.flag()).copyParams(src.parts[i]);
  107. joined .copyId( unknown_mesh); unknown_mesh.MeshLod::copyParams(src); FREP(Min(src.parts.elms(), unknown_mesh.parts.elms())) unknown_mesh.parts[i].keepOnly(src.parts[i].base.flag()).copyParams(src.parts[i]);
  108. // remove empty parts
  109. REPA(connected_mesh)if(!connected_mesh.parts[i].is())connected_mesh.remove(i, false);
  110. REPA( unknown_mesh)if(! unknown_mesh.parts[i].is()) unknown_mesh.remove(i, false);
  111. // put them into the processing container
  112. Swap(src , connected_mesh); // connected is processed so we can set it back
  113. Swap(temp[cur].New(), unknown_mesh); // unknown needs to be added to the array for checking
  114. }
  115. }
  116. }
  117. // put meshes into the right container
  118. FREPA(temp[cur])if(temp[cur][i].is())if(!_parts.New().create(temp[cur][i], phys_vtx_limit))_parts.removeLast();
  119. // create joints
  120. Memc<MeshBase> phys; FREPA(_parts)phys.New().create(_parts[i].phys).quadToTri().setFaceNormals(); // create mesh from phys convex body
  121. REPAD(a, _parts) // iterate through all pairs of parts
  122. {
  123. REPD(b, a)
  124. {
  125. if(Cuts(Extent(_parts[a].mesh.ext).extend(0.1f), _parts[b].mesh.ext))
  126. {
  127. MeshBase &phys_a=phys[a],
  128. &phys_b=phys[b];
  129. REPA(phys_a.tri)
  130. {
  131. VecI ind=phys_a.tri.ind(i);
  132. Tri tri_a(phys_a.vtx.pos(ind.x), phys_a.vtx.pos(ind.y), phys_a.vtx.pos(ind.z), &phys_a.tri.nrm(i));
  133. Vec tri_a_center=tri_a.center();
  134. REPA(phys_b.tri)
  135. {
  136. Vec &tri_nrm_b=phys_b.tri.nrm(i);
  137. if(Abs(Dot(tri_a.n, tri_nrm_b))>=0.97f) // parallel
  138. {
  139. VecI ind=phys_b.tri.ind(i);
  140. if(Abs(DistPointPlane(phys_b.vtx.pos(ind.x), tri_a))<=0.03f) // on the same plane
  141. {
  142. Tri tri_b(phys_b.vtx.pos(ind.x), phys_b.vtx.pos(ind.y), phys_b.vtx.pos(ind.z), &phys_b.tri.nrm(i));
  143. Vec tri_b_center =tri_b.center();
  144. Tri tri_a_smaller=(tri_a-tri_a_center)*0.9f+tri_a_center,
  145. tri_b_smaller=(tri_b-tri_b_center)*0.9f+tri_b_center;
  146. if(Dist(tri_a_smaller, tri_b_smaller)<=0.01f) // distance between triangles
  147. {
  148. _joints.New().set(a, b);
  149. goto next_part;
  150. }
  151. }
  152. }
  153. }
  154. }
  155. }
  156. next_part:;
  157. }
  158. }
  159. return T;
  160. }
  161. /******************************************************************************/
  162. // OPERATIONS
  163. /******************************************************************************/
  164. Bool DestructMesh::adjustStorage (Bool universal, Bool physx, Bool bullet, Bool *changed) {if(changed)*changed=false; Bool ok=true, c; REPA (_parts){ok&=_parts[i].phys.adjustStorage (universal, physx, bullet, &c); if(changed)*changed|=c;} return ok;}
  165. DestructMesh& DestructMesh::freeHelperData( ) { REPAO(_parts) .phys.freeHelperData( ); return T ;}
  166. void DestructMesh::setShader ( ) { REPAO(_parts) .mesh.setShader ( ); }
  167. /******************************************************************************/
  168. // DRAW
  169. /******************************************************************************/
  170. void DestructMesh::drawMesh(Int highlight_part)C
  171. {
  172. Flt scale=(Sin(Time.appTime()*1)*0.5f+0.5f)*1;
  173. REPA(_parts)
  174. {
  175. Matrix m; m.setPos(_parts[i].mesh.ext.pos*scale);
  176. if(i==highlight_part)SetHighlight(RED);else REPAD(j, _joints)if((_joints[j].a==i || _joints[j].b==i) && (_joints[j].a==highlight_part || _joints[j].b==highlight_part))SetHighlight(BLUE);
  177. _parts[i].mesh.draw(m);
  178. SetHighlight();
  179. }
  180. }
  181. void DestructMesh::drawPhys()C
  182. {
  183. Flt scale=(Sin(Time.appTime()*1)*0.5f+0.5f)*1;
  184. REPA(_parts)
  185. {
  186. Matrix m; m.setPos(_parts[i].mesh.ext.pos*scale);
  187. SetMatrix(m); _parts[i].phys.draw(WHITE);
  188. }
  189. }
  190. /******************************************************************************/
  191. // IO
  192. /******************************************************************************/
  193. void DestructMesh::Part::del()
  194. {
  195. mesh.del();
  196. phys.del();
  197. }
  198. Bool DestructMesh::Part::save(File &f)C
  199. {
  200. if(mesh.save(f))
  201. if(phys.save(f))
  202. return f.ok();
  203. return false;
  204. }
  205. Bool DestructMesh::Part::load(File &f)
  206. {
  207. if(mesh.load(f))
  208. if(phys.load(f))
  209. if(f.ok())return true;
  210. del(); return false;
  211. }
  212. Bool DestructMesh::save(C Str &name)
  213. {
  214. File f; if(f.writeTry(name))
  215. {
  216. f.putUInt (CC4_DSTR);
  217. f.cmpUIntV(0); // version
  218. if(_parts .save (f))
  219. if(_joints.saveRaw(f))
  220. if(f.flushOK())return true;
  221. f.del(); FDelFile(name);
  222. }
  223. return false;
  224. }
  225. Bool DestructMesh::load(C Str &name)
  226. {
  227. File f; if(f.readTry(name) && f.getUInt()==CC4_DSTR)switch(f.decUIntV())
  228. {
  229. case 0:
  230. {
  231. if(_parts .load (f))
  232. if(_joints.loadRaw(f))
  233. if(f.ok())return true;
  234. }break;
  235. }
  236. del(); return false;
  237. }
  238. /******************************************************************************/
  239. }
  240. /******************************************************************************/