Mesh Lod.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************/
  5. // MANAGE
  6. /******************************************************************************/
  7. void MeshLod::zero() {dist2=0;}
  8. MeshLod::MeshLod() {zero();}
  9. MeshLod& MeshLod::delBase () {REPAO(parts).delBase (); return T;}
  10. MeshLod& MeshLod::delRender() {REPAO(parts).delRender(); return T;}
  11. MeshLod& MeshLod::del ()
  12. {
  13. parts.del();
  14. zero(); return T;
  15. }
  16. MeshLod& MeshLod::create(Int num)
  17. {
  18. del();
  19. parts.setNum(num);
  20. return T;
  21. }
  22. MeshLod& MeshLod::create(C MeshLod &src, UInt flag_and)
  23. {
  24. if(this==&src)keepOnly(flag_and);else
  25. {
  26. create(src.parts.elms()); copyParams(src); FREPAO(parts).create(src.parts[i], flag_and);
  27. }
  28. return T;
  29. }
  30. void MeshLod::copyParams(C MeshLod &src)
  31. {
  32. if(this!=&src)
  33. {
  34. dist2=src.dist2;
  35. }
  36. }
  37. void MeshLod::scaleParams(Flt scale)
  38. {
  39. dist2*=Sqr(scale);
  40. }
  41. MeshLod& MeshLod::include (UInt flag) {REPAO(parts).include (flag); return T;}
  42. MeshLod& MeshLod::exclude (UInt flag) {REPAO(parts).exclude (flag); return T;}
  43. MeshLod& MeshLod::keepOnly(UInt flag) {REPAO(parts).keepOnly(flag); return T;}
  44. /******************************************************************************/
  45. // GET
  46. /******************************************************************************/
  47. UInt MeshLod::flag ()C {UInt flag =0; REPA(T)flag |=parts[i].flag (); return flag ;}
  48. UInt MeshLod::memUsage ()C {UInt size =0; REPA(T)size +=parts[i].memUsage (); return size ;}
  49. Int MeshLod::vtxs ()C {Int vtxs =0; REPA(T)vtxs +=parts[i].vtxs (); return vtxs ;}
  50. Int MeshLod::edges ()C {Int edges=0; REPA(T)edges+=parts[i].edges (); return edges;}
  51. Int MeshLod::tris ()C {Int tris =0; REPA(T)tris +=parts[i].tris (); return tris ;}
  52. Int MeshLod::quads ()C {Int quads=0; REPA(T)quads+=parts[i].quads (); return quads;}
  53. Int MeshLod::faces ()C {Int faces=0; REPA(T)faces+=parts[i].faces (); return faces;}
  54. Int MeshLod::trisTotal()C {Int tris =0; REPA(T)tris +=parts[i].trisTotal(); return tris ;}
  55. Flt MeshLod::area (Vec *center)C
  56. {
  57. if(center)center->zero();
  58. Flt area=0;
  59. REPA(T)
  60. {
  61. Vec c;
  62. Flt a=parts[i].area(center ? &c : null);
  63. area +=a;
  64. if(center)*center+=a*c;
  65. }
  66. if(center && area)*center/=area;
  67. return area;
  68. }
  69. Bool MeshLod::getBox(Box &box, Bool skip_hidden_parts)C
  70. {
  71. Bool found=false; Box temp; REPA(T)
  72. {
  73. C MeshPart &part=parts[i];
  74. if(!skip_hidden_parts || !(part.part_flag&MSHP_HIDDEN))
  75. if(part.getBox(temp))
  76. {
  77. if(!found){found=true; box=temp;}else box|=temp;
  78. }
  79. }
  80. if(!found)box.zero(); return found;
  81. }
  82. /******************************************************************************/
  83. // have to use SB functions for special case of -0
  84. Flt MeshLod::dist()C
  85. {
  86. Flt dist; if(NegativeSB(dist2)){dist=SqrtFast(-dist2); CHSSB(dist);}else dist=SqrtFast(dist2);
  87. return dist;
  88. }
  89. MeshLod& MeshLod::dist(Flt dist)
  90. {
  91. dist2=Sqr(dist); if(NegativeSB(dist))CHSSB(dist2);
  92. return T;
  93. }
  94. /******************************************************************************/
  95. Bool MeshLod::hasDrawGroup ( Int draw_group_index)C {REPA(parts)if( parts[i].drawGroup()==draw_group_index)return true; return false;}
  96. Bool MeshLod::hasDrawGroupMask(UInt draw_group_mask )C {REPA(parts)if((1<<parts[i].drawGroup())&draw_group_mask )return true; return false;}
  97. /******************************************************************************/
  98. // SET
  99. /******************************************************************************/
  100. MeshLod& MeshLod::setEdgeNormals(Bool flag ) {REPAO(parts).base.setEdgeNormals(flag ); return T;}
  101. MeshLod& MeshLod::setFaceNormals( ) {REPAO(parts).base.setFaceNormals( ); return T;}
  102. MeshLod& MeshLod::setNormals2D (Bool flag ) {REPAO(parts).base.setNormals2D (flag ); return T;}
  103. MeshLod& MeshLod::setNormals ( ) {REPAO(parts).base.setNormals ( ); return T;}
  104. MeshLod& MeshLod::setTangents ( ) {REPAO(parts).base.setTangents ( ); return T;}
  105. MeshLod& MeshLod::setBinormals ( ) {REPAO(parts).base.setBinormals ( ); return T;}
  106. MeshLod& MeshLod::setAutoTanBin ( ) {REPAO(parts). setAutoTanBin ( ); return T;}
  107. MeshLod& MeshLod::setVtxDup2D (UInt flag, Flt pos_eps, Flt nrm_cos) {REPAO(parts).base.setVtxDup2D (flag, pos_eps, nrm_cos); return T;}
  108. MeshLod& MeshLod::setVtxDup (UInt flag, Flt pos_eps, Flt nrm_cos) {REPAO(parts).base.setVtxDup (flag, pos_eps, nrm_cos); return T;}
  109. MeshLod& MeshLod::setAdjacencies(Bool faces, Bool edges ) {REPAO(parts).base.setAdjacencies(faces, edges ); return T;}
  110. MeshLod& MeshLod::setVtxColorAlphaAsTesselationIntensity(Bool tesselate_edges)
  111. {
  112. Box box; if(!getBox(box))return T;
  113. struct VtxDupIndex : VtxDup
  114. {
  115. VecI2 index;
  116. Bool freeze;
  117. };
  118. // create vertex array
  119. Int vtx_num=0; REPA(parts)vtx_num+=parts[i].base.vtxs(); // do not use T.vtxs() as it includes 'MeshRender'
  120. Memc<VtxDupIndex> vtxs; vtxs.setNum(vtx_num); vtx_num=0;
  121. REPAD(p, T)
  122. {
  123. MeshBase &mshb=parts[p].base;
  124. REPA(mshb.vtx)
  125. {
  126. VtxDupIndex &vtx=vtxs[vtx_num++];
  127. vtx.pos=mshb.vtx.pos(i);
  128. vtx.index.set(i, p);
  129. vtx.freeze=false;
  130. }
  131. }
  132. // get vtx dup
  133. SetVtxDup(SCAST(Memc<VtxDup>, vtxs), box, EPSD);
  134. // set freeze
  135. REPA(vtxs)
  136. {
  137. VtxDupIndex &vi=vtxs[i]; if(vi.dup!=i)
  138. {
  139. VtxDupIndex &vd=vtxs[vi.dup];
  140. if(!parts[vi.index.y].base.vtx.nrm()
  141. || !parts[vd.index.y].base.vtx.nrm())vtxs[vi.dup].freeze=true;else
  142. {
  143. C Vec &nrm1=parts[vi.index.y].base.vtx.nrm(vi.index.x),
  144. &nrm2=parts[vd.index.y].base.vtx.nrm(vd.index.x);
  145. if(Dot(nrm1, nrm2)<0.995f)vtxs[vi.dup].freeze=true;
  146. }
  147. }
  148. }
  149. // set color
  150. REPA(vtxs)
  151. {
  152. VtxDupIndex &vi=vtxs[i]; if(vtxs[vi.dup].freeze) // if the main should be frozen, then all duplicates also should be frozen
  153. {
  154. MeshBase &base=parts[vi.index.y].base;
  155. if(base.vtx.nrm())
  156. {
  157. if(!base.vtx.color()){base.include(VTX_COLOR); REPA(base.vtx)base.vtx.color(i)=WHITE;} // create vtx colors
  158. base.vtx.color(vi.index.x).a=0; // set alpha to zero
  159. }
  160. }
  161. }
  162. return T;
  163. }
  164. /******************************************************************************/
  165. MeshLod& MeshLod::setRenderSS( ) {REPAO(parts).setRenderEx(false , false, 0 ); return T;}
  166. MeshLod& MeshLod::setBase (Bool only_if_empty ) {REPAO(parts).setBase (only_if_empty ); return T;}
  167. MeshLod& MeshLod::setRender (Bool optimize , Int lod_index) {REPAO(parts).setRender (optimize, lod_index); return T;}
  168. MeshLod& MeshLod::setShader ( Int lod_index) {REPAO(parts).setShader ( lod_index); return T;}
  169. MeshLod& MeshLod::material (C MaterialPtr &material, Int lod_index) {REPAO(parts).material (material, lod_index); return T;}
  170. /******************************************************************************/
  171. // JOIN
  172. /******************************************************************************/
  173. MeshLod& MeshLod::join(Int i0, Int i1, Flt weld_pos_eps)
  174. {
  175. if(i0!=i1 && InRange(i0, T) && InRange(i1, T))
  176. {
  177. MeshPart &part=parts[i0];
  178. part+=parts[i1];
  179. if(weld_pos_eps>=0)
  180. {
  181. Bool base=part.base.is();
  182. part.setBase().base.weldVtx(VTX_ALL, weld_pos_eps, EPS_COL_COS, -1); // there are no degenerate faces
  183. if(part.render.is())part.setRender();
  184. if( !base)part.delBase();
  185. }
  186. parts.remove(i1, true);
  187. }
  188. return T;
  189. }
  190. MeshLod& MeshLod::joinAll(Bool test_material, Bool test_draw_group, Bool test_name, UInt test_vtx_flag, Flt weld_pos_eps)
  191. {
  192. if(parts.elms()>1) // if has some parts to merge
  193. {
  194. Bool base_is=false, render_is=false; REPA(T){if(parts[i].base.is())base_is=true; if(parts[i].render.is())render_is=true;} // detect what is present in the mesh
  195. if(test_material || test_draw_group || test_name || test_vtx_flag)
  196. {
  197. MemtN< Int , 256> similar;
  198. Memb < MeshBase > temp; // use 'Memb' because we're storing pointers to elms
  199. MemtN<C MeshBase*, 256> mesh_ptr;
  200. MemtN< MeshPart , 16> joined;
  201. FREPA(T) // iterate through all parts, preserve order
  202. {
  203. MeshPart &part=parts[i]; if(part.is())
  204. {
  205. Int draw_group=part.drawGroup();
  206. UInt part_vtx_flag=(part.flag()&test_vtx_flag);
  207. similar.add(i); // add self before others, so order is preserved
  208. for(Int j=i+1; j<parts.elms(); j++) // find matching, preserve order
  209. {
  210. C MeshPart &test=parts[j]; if(test.is())
  211. {
  212. if(test_material && !test.sameMaterials(part) )continue;
  213. if(test_draw_group && test.drawGroup()!=draw_group)continue;
  214. if(test_name && !Equal(test.name, part.name) )continue;
  215. if(test_vtx_flag && (test.flag()&test_vtx_flag)!=part_vtx_flag)continue;
  216. similar.add(j);
  217. }
  218. }
  219. if(similar.elms()>1) // if detected any similar parts
  220. {
  221. // list similar parts
  222. FREPA(similar) // preserve order
  223. {
  224. C MeshPart &test=parts[similar[i]];
  225. if(!(test.part_flag&MSHP_HIDDEN))FlagDisable(part.part_flag, MSHP_HIDDEN); // if at least one part is visible then set all as visible
  226. if(test.render.is() && !test.base.is())mesh_ptr.add(&temp.New().create(test.render)); // MeshBase needs to be created
  227. else mesh_ptr.add(& test.base ); // point to original MeshBase
  228. }
  229. part.base.create(mesh_ptr.data(), mesh_ptr.elms());
  230. if(weld_pos_eps>=0)part.base.weldVtx(VTX_ALL, weld_pos_eps, EPS_COL_COS, -1); // there are no degenerate faces
  231. if(render_is )part.setRender();
  232. if( !base_is )part.base.del ();
  233. temp.clear();
  234. mesh_ptr.clear();
  235. }
  236. Swap(joined.New(), part);
  237. REPA(similar)parts[similar[i]].del(); // delete joined parts, so they won't be processed again
  238. similar.clear();
  239. }
  240. }
  241. parts.setNum(joined.elms()); REPA(parts)Swap(parts[i], joined[i]);
  242. }else
  243. {
  244. MeshPart &first=parts[0];
  245. REPA(T)if(!(parts[i].part_flag&MSHP_HIDDEN)){FlagDisable(first.part_flag, MSHP_HIDDEN); break;} // if at least one part is visible then set all as visible
  246. first.base.create(T); // create from all
  247. parts.setNum(1); // set only one part
  248. if(weld_pos_eps>=0)weldVtx(VTX_ALL, weld_pos_eps, EPS_COL_COS, -1); // there are no degenerate faces
  249. if(render_is )setRender();
  250. if( !base_is )delBase ();
  251. }
  252. }
  253. return T;
  254. }
  255. /******************************************************************************/
  256. MeshPart* MeshLod::splitVtxs(Int i, C MemPtr<Bool> &vtx_is)
  257. {
  258. MeshPart *part=null; if(InRange(i, T) && vtx_is.elms())
  259. {
  260. MeshBase &base=parts[i].base; // !! don't use this later as creating New Part invalidates this reference !!
  261. Int vtxs=CountIs(vtx_is);
  262. if(vtxs && vtxs!=base.vtxs())
  263. {
  264. part=&parts.NewAt(i+1);
  265. MeshBase &old=parts[i].base; old.splitVtxs(part->base, vtx_is);
  266. if(old.is())
  267. {
  268. part->copyParams(parts[i]);
  269. }else // 'old' may be empty for 'splitVtxs' because we had to select neighbor vertexes which could've resulted in entire mesh being copied
  270. {
  271. Swap(old, part->base); // bring back to the old
  272. parts.removeData(part, true); part=null; // remove the newly created part
  273. }
  274. }
  275. }
  276. return part;
  277. }
  278. MeshPart* MeshLod::splitFaces(Int i, C MemPtr<Bool> &edge_is, C MemPtr<Bool> &tri_is, C MemPtr<Bool> &quad_is)
  279. {
  280. MeshPart *part=null; if(InRange(i, T) && (edge_is.elms() || tri_is.elms() || quad_is.elms()))
  281. {
  282. MeshBase &base =parts[i].base; // !! don't use this later as creating New Part invalidates this reference !!
  283. Int edges=CountIs(edge_is),
  284. tris=CountIs( tri_is),
  285. quads=CountIs(quad_is);
  286. if((edges!= 0 || tris!= 0 || quads!=0 ) // if want to copy something
  287. && (edges!=base.edges() || tris!=base.tris() || quads!=base.quads())) // and not everything
  288. {
  289. part=&parts.NewAt(i+1); parts[i].base.splitFaces(part->base, edge_is, tri_is, quad_is); // !! can't access 'base' anymore because 'New' could've changed its mem address !!
  290. part->copyParams(parts[i]);
  291. }
  292. }
  293. return part;
  294. }
  295. MeshPart* MeshLod::splitBone(Int i, Int bone, C Skeleton *skeleton)
  296. {
  297. MeshPart *part=null; if(InRange(i, T) && parts[i].base.vtx.matrix())
  298. {
  299. part=&parts.NewAt(i+1); parts[i].base.splitBone(part->base, bone);
  300. if(part->is())
  301. {
  302. part->copyParams(parts[i]); if(skeleton && InRange(bone, skeleton->bones))Set(part->name, skeleton->bones[bone].name);
  303. }else
  304. {
  305. parts.removeData(part, true); part=null;
  306. }
  307. }
  308. return part;
  309. }
  310. MeshPart* MeshLod::splitVtxs(Int i, C MemPtr<Int> &vtxs)
  311. {
  312. if(vtxs.elms())if(MeshPart *part=parts.addr(i))
  313. {
  314. Memt<Bool> vtx_is; CreateIs(vtx_is, vtxs, part->base.vtxs()); return splitVtxs(i, vtx_is);
  315. }
  316. return null;
  317. }
  318. MeshPart* MeshLod::splitFaces(Int i, C MemPtr<Int> &faces)
  319. {
  320. if(faces.elms())if(MeshPart *part=parts.addr(i))
  321. {
  322. Memt<Bool> tri_is, quad_is; CreateFaceIs(tri_is, quad_is, faces, part->base.tris(), part->base.quads());
  323. return splitFaces(i, null, tri_is, quad_is);
  324. }
  325. return null;
  326. }
  327. MeshPart* MeshLod::splitFaces(Int i, C MemPtr<Int> &edges, C MemPtr<Int> &tris, C MemPtr<Int> &quads)
  328. {
  329. if(edges.elms() || tris.elms() || quads.elms())if(MeshPart *part=parts.addr(i))
  330. {
  331. Memt<Bool> edge_is; CreateIs(edge_is, edges, part->base.edges());
  332. Memt<Bool> tri_is; CreateIs( tri_is, tris, part->base. tris());
  333. Memt<Bool> quad_is; CreateIs(quad_is, quads, part->base.quads());
  334. return splitFaces(i, edge_is, tri_is, quad_is);
  335. }
  336. return null;
  337. }
  338. /*
  339. MeshLod& splitFloor(Flt y, Int i=-1 ); // split i-th(-1=all) part faces if face.normal.y>=y
  340. MeshLod& MeshLod::splitFloor(Flt y, Int i)
  341. {
  342. REPD(m, parts())if((i==-1 || i==m) && base(m).is()) // order is important
  343. {
  344. MeshBase &mshb=base(m);
  345. if((mshb.tris () && !mshb.tri .nrm())
  346. || (mshb.quads() && !mshb.quad.nrm()))mshb.setFaceNormals();
  347. Vec *nrm;
  348. Bool * tri_is=Alloc<Bool>(mshb.tris ()); Int tris=0; nrm=mshb.tri .nrm(); REPA(mshb.tri )if( tri_is[i]=(nrm[i].y>=y)) tris++;
  349. Bool *quad_is=Alloc<Bool>(mshb.quads()); Int quads=0; nrm=mshb.quad.nrm(); REPA(mshb.quad)if(quad_is[i]=(nrm[i].y>=y))quads++;
  350. if(tris || quads)
  351. {
  352. if(tris==mshb.tris() && quads==mshb.quads())part(m).part_flag|=MSHP_FLOOR;
  353. else split(m,null,tri_is,quad_is).part_flag|=MSHP_FLOOR;
  354. }
  355. Free( tri_is);
  356. Free(quad_is);
  357. }
  358. return T;
  359. }
  360. /******************************************************************************/
  361. // TEXTURE TRANSFORM
  362. /******************************************************************************/
  363. MeshLod& MeshLod::texMove (C Vec2 &move , Byte tex_index) {REPAO(parts).texMove (move , tex_index); return T;}
  364. MeshLod& MeshLod::texScale (C Vec2 &scale, Byte tex_index) {REPAO(parts).texScale (scale, tex_index); return T;}
  365. MeshLod& MeshLod::texRotate( Flt angle, Byte tex_index) {REPAO(parts).texRotate(angle, tex_index); return T;}
  366. /******************************************************************************/
  367. // TEXTURIZE
  368. /******************************************************************************/
  369. MeshLod& MeshLod::texMap( Flt scale , Byte tex_index) {REPAO(parts).base.texMap(scale , tex_index); return T;}
  370. MeshLod& MeshLod::texMap(C Matrix &matrix, Byte tex_index) {REPAO(parts).base.texMap(matrix, tex_index); return T;}
  371. MeshLod& MeshLod::texMap(C Plane &plane , Byte tex_index) {REPAO(parts).base.texMap(plane , tex_index); return T;}
  372. MeshLod& MeshLod::texMap(C Ball &ball , Byte tex_index) {REPAO(parts).base.texMap(ball , tex_index); return T;}
  373. MeshLod& MeshLod::texMap(C Tube &tube , Byte tex_index) {REPAO(parts).base.texMap(tube , tex_index); return T;}
  374. /******************************************************************************/
  375. // TRANSFORM
  376. /******************************************************************************/
  377. MeshLod& MeshLod::move ( C Vec &move ) { REPAO(parts). move ( move); return T;}
  378. MeshLod& MeshLod::scale (C Vec &scale ) { REPAO(parts). scale (scale ); scaleParams( Abs(scale).max ()); return T;}
  379. MeshLod& MeshLod::scaleMove (C Vec &scale, C Vec &move ) { REPAO(parts). scaleMove (scale, move); scaleParams( Abs(scale).max ()); return T;}
  380. MeshLod& MeshLod::scaleMoveBase(C Vec &scale, C Vec &move ) { REPAO(parts). scaleMoveBase(scale, move); scaleParams( Abs(scale).max ()); return T;}
  381. MeshLod& MeshLod::transform (C Matrix3 &matrix ) { REPAO(parts). transform (matrix ); scaleParams( matrix .maxScale()); return T;}
  382. MeshLod& MeshLod::transform (C Matrix &matrix ) { REPAO(parts). transform (matrix ); scaleParams( matrix .maxScale()); return T;}
  383. MeshLod& MeshLod::animate (C MemPtrN<Matrix, 256> &matrixes) {if(matrixes.elms()){REPAO(parts). animate (matrixes ); scaleParams( matrixes[0].maxScale());} return T;}
  384. MeshLod& MeshLod::animate (C AnimatedSkeleton &skel ) { REPAO(parts). animate (skel ); scaleParams(skel.matrix ( ).maxScale()); return T;}
  385. MeshLod& MeshLod::mirrorX ( ) { REPAO(parts).base.mirrorX ( ); return T;}
  386. MeshLod& MeshLod::mirrorY ( ) { REPAO(parts).base.mirrorY ( ); return T;}
  387. MeshLod& MeshLod::mirrorZ ( ) { REPAO(parts).base.mirrorZ ( ); return T;}
  388. MeshLod& MeshLod::rightToLeft ( ) { REPAO(parts).base.rightToLeft ( ); return T;}
  389. MeshLod& MeshLod::reverse ( ) { REPAO(parts).base.reverse ( ); return T;}
  390. /******************************************************************************/
  391. // OPERATIONS
  392. /******************************************************************************/
  393. MeshLod& MeshLod::weldVtx2D (UInt flag, Flt pos_eps, Flt nrm_cos, Flt remove_degenerate_faces_eps) {REPA(T)parts[i].base.weldVtx2D(flag, pos_eps, nrm_cos, remove_degenerate_faces_eps); return T;}
  394. MeshLod& MeshLod::weldVtx (UInt flag, Flt pos_eps, Flt nrm_cos, Flt remove_degenerate_faces_eps) {REPA(T)parts[i].base.weldVtx (flag, pos_eps, nrm_cos, remove_degenerate_faces_eps); return T;}
  395. MeshLod& MeshLod::weldVtxValues(UInt flag, Flt pos_eps, Flt nrm_cos, Flt remove_degenerate_faces_eps)
  396. {
  397. flag&=T.flag();
  398. if(flag&(VTX_POS|VTX_NRM_TAN_BIN|VTX_HLP|VTX_TEX_ALL|VTX_COLOR|VTX_MATERIAL|VTX_SKIN|VTX_SIZE))
  399. {
  400. struct VtxDupIndex : VtxDupNrm
  401. {
  402. VecI2 index;
  403. Int count;
  404. VecI4 color;
  405. };
  406. Box box; if(!getBox(box))return T;
  407. // create vertex array
  408. Int vtx_num=0; REPA(parts)vtx_num+=parts[i].base.vtxs(); // do not use T.vtxs() as it includes MeshRender
  409. Memc<VtxDupIndex> vtxs; vtxs.setNum(vtx_num); vtx_num=0;
  410. REPAD(p, T)
  411. {
  412. MeshBase &mshb=parts[p].base;
  413. C Vec *nrm =mshb.vtx.nrm();
  414. REPA(mshb.vtx)
  415. {
  416. VtxDupIndex &vtx=vtxs[vtx_num++];
  417. vtx.pos=mshb.vtx.pos(i);
  418. vtx.nrm=(nrm ? nrm[i] : VecZero);
  419. vtx.index.set(i, p);
  420. vtx.count=0;
  421. vtx.color.zero();
  422. }
  423. }
  424. // get vtx dup
  425. SetVtxDup(SCAST(Memc<VtxDupNrm>, vtxs), box, pos_eps, nrm_cos);
  426. // weldVtx
  427. REPA(vtxs)
  428. {
  429. VtxDupIndex &vn=vtxs[i]; vtxs[vn.dup].count++; if(vn.dup!=i)
  430. {
  431. VtxDupIndex &vd=vtxs[vn.dup];
  432. if(flag&VTX_POS )parts[vn.index.y].base.vtx.pos (vn.index.x) =parts[vd.index.y].base.vtx.pos (vd.index.x);
  433. if(flag&VTX_MATERIAL)parts[vn.index.y].base.vtx.material(vn.index.x) =parts[vd.index.y].base.vtx.material(vd.index.x); // !! sum must be equal to 255 !!
  434. if(flag&VTX_MATRIX )parts[vn.index.y].base.vtx.matrix (vn.index.x) =parts[vd.index.y].base.vtx.matrix (vd.index.x);
  435. if(flag&VTX_BLEND )parts[vn.index.y].base.vtx.blend (vn.index.x) =parts[vd.index.y].base.vtx.blend (vd.index.x); // !! sum must be equal to 255 !!
  436. if(flag&VTX_NRM )parts[vd.index.y].base.vtx.nrm (vd.index.x)+=parts[vn.index.y].base.vtx.nrm (vn.index.x);
  437. if(flag&VTX_TAN )parts[vd.index.y].base.vtx.tan (vd.index.x)+=parts[vn.index.y].base.vtx.tan (vn.index.x);
  438. if(flag&VTX_BIN )parts[vd.index.y].base.vtx.bin (vd.index.x)+=parts[vn.index.y].base.vtx.bin (vn.index.x);
  439. if(flag&VTX_HLP )parts[vd.index.y].base.vtx.hlp (vd.index.x)+=parts[vn.index.y].base.vtx.hlp (vn.index.x);
  440. if(flag&VTX_TEX0 )parts[vd.index.y].base.vtx.tex0 (vd.index.x)+=parts[vn.index.y].base.vtx.tex0 (vn.index.x);
  441. if(flag&VTX_TEX1 )parts[vd.index.y].base.vtx.tex1 (vd.index.x)+=parts[vn.index.y].base.vtx.tex1 (vn.index.x);
  442. if(flag&VTX_TEX2 )parts[vd.index.y].base.vtx.tex2 (vd.index.x)+=parts[vn.index.y].base.vtx.tex2 (vn.index.x);
  443. if(flag&VTX_SIZE )parts[vd.index.y].base.vtx.size (vd.index.x)+=parts[vn.index.y].base.vtx.size (vn.index.x);
  444. }
  445. if(flag&VTX_COLOR)vtxs[vn.dup].color+=parts[vn.index.y].base.vtx.color(vn.index.x).v4;
  446. }
  447. // first calculate the average values, then set those values
  448. if(flag&VTX_NRM ){REPA(vtxs){VtxDupIndex &vn=vtxs[i]; if(vn.dup==i)parts[vn.index.y].base.vtx.nrm (vn.index.x).normalize();} REPA(vtxs){VtxDupIndex &vn=vtxs[i], &vd=vtxs[vn.dup]; parts[vn.index.y].base.vtx.nrm (vn.index.x)=parts[vd.index.y].base.vtx.nrm (vd.index.x);}}
  449. if(flag&VTX_TAN ){REPA(vtxs){VtxDupIndex &vn=vtxs[i]; if(vn.dup==i)parts[vn.index.y].base.vtx.tan (vn.index.x).normalize();} REPA(vtxs){VtxDupIndex &vn=vtxs[i], &vd=vtxs[vn.dup]; parts[vn.index.y].base.vtx.tan (vn.index.x)=parts[vd.index.y].base.vtx.tan (vd.index.x);}}
  450. if(flag&VTX_BIN ){REPA(vtxs){VtxDupIndex &vn=vtxs[i]; if(vn.dup==i)parts[vn.index.y].base.vtx.bin (vn.index.x).normalize();} REPA(vtxs){VtxDupIndex &vn=vtxs[i], &vd=vtxs[vn.dup]; parts[vn.index.y].base.vtx.bin (vn.index.x)=parts[vd.index.y].base.vtx.bin (vd.index.x);}}
  451. if(flag&VTX_HLP ){REPA(vtxs){VtxDupIndex &vn=vtxs[i]; if(vn.dup==i)parts[vn.index.y].base.vtx.hlp (vn.index.x)/=vn.count ;} REPA(vtxs){VtxDupIndex &vn=vtxs[i], &vd=vtxs[vn.dup]; parts[vn.index.y].base.vtx.hlp (vn.index.x)=parts[vd.index.y].base.vtx.hlp (vd.index.x);}}
  452. if(flag&VTX_TEX0 ){REPA(vtxs){VtxDupIndex &vn=vtxs[i]; if(vn.dup==i)parts[vn.index.y].base.vtx.tex0 (vn.index.x)/=vn.count ;} REPA(vtxs){VtxDupIndex &vn=vtxs[i], &vd=vtxs[vn.dup]; parts[vn.index.y].base.vtx.tex0(vn.index.x)=parts[vd.index.y].base.vtx.tex0(vd.index.x);}}
  453. if(flag&VTX_TEX1 ){REPA(vtxs){VtxDupIndex &vn=vtxs[i]; if(vn.dup==i)parts[vn.index.y].base.vtx.tex1 (vn.index.x)/=vn.count ;} REPA(vtxs){VtxDupIndex &vn=vtxs[i], &vd=vtxs[vn.dup]; parts[vn.index.y].base.vtx.tex1(vn.index.x)=parts[vd.index.y].base.vtx.tex1(vd.index.x);}}
  454. if(flag&VTX_TEX2 ){REPA(vtxs){VtxDupIndex &vn=vtxs[i]; if(vn.dup==i)parts[vn.index.y].base.vtx.tex2 (vn.index.x)/=vn.count ;} REPA(vtxs){VtxDupIndex &vn=vtxs[i], &vd=vtxs[vn.dup]; parts[vn.index.y].base.vtx.tex2(vn.index.x)=parts[vd.index.y].base.vtx.tex2(vd.index.x);}}
  455. if(flag&VTX_SIZE ){REPA(vtxs){VtxDupIndex &vn=vtxs[i]; if(vn.dup==i)parts[vn.index.y].base.vtx.size (vn.index.x)/=vn.count ;} REPA(vtxs){VtxDupIndex &vn=vtxs[i], &vd=vtxs[vn.dup]; parts[vn.index.y].base.vtx.size(vn.index.x)=parts[vd.index.y].base.vtx.size(vd.index.x);}}
  456. if(flag&VTX_COLOR){REPA(vtxs){VtxDupIndex &vn=vtxs[i]; if(vn.dup==i)parts[vn.index.y].base.vtx.color(vn.index.x).set(DivRound(vn.color.x, vn.count), DivRound(vn.color.y, vn.count), DivRound(vn.color.z, vn.count), DivRound(vn.color.w, vn.count));}
  457. REPA(vtxs){VtxDupIndex &vn=vtxs[i], &vd=vtxs[vn.dup]; parts[vn.index.y].base.vtx.color(vn.index.x)=parts[vd.index.y].base.vtx.color(vd.index.x);}
  458. }
  459. // remove degenerate faces
  460. if((flag&VTX_POS) && remove_degenerate_faces_eps>=0)removeDegenerateFaces(remove_degenerate_faces_eps);
  461. }
  462. return T;
  463. }
  464. MeshLod& MeshLod::weldEdge () {REPAO(parts).base.weldEdge (); return T;}
  465. MeshLod& MeshLod::tesselate() {REPAO(parts).base.tesselate(); return T;}
  466. MeshLod& MeshLod::subdivide() {REPAO(parts).base.subdivide(); return T;}
  467. MeshLod& MeshLod::boneRemap(C MemPtr<Byte, 256> &old_to_new) {REPAO(parts).boneRemap (old_to_new); return T;}
  468. void MeshLod::includeUsedBones(Bool (&bones)[256] )C {REPAO(parts).includeUsedBones(bones);}
  469. void MeshLod:: setUsedBones(Bool (&bones)[256] )C {Zero(bones); includeUsedBones(bones);}
  470. MeshLod& MeshLod::freeOpenGLESData() {REPAO(parts).freeOpenGLESData(); return T;}
  471. /******************************************************************************/
  472. // FIX
  473. /******************************************************************************/
  474. MeshLod& MeshLod::fixTexOffset (Byte tex_index) {REPA(T)parts[i].base.fixTexOffset (tex_index); return T;}
  475. MeshLod& MeshLod::fixTexWrapping(Byte tex_index) {REPA(T)parts[i].base.fixTexWrapping(tex_index); return T;}
  476. /******************************************************************************/
  477. // CONVERT
  478. /******************************************************************************/
  479. MeshLod& MeshLod::edgeToDepth(Bool tex_align) {REPA(T)parts[i].base.edgeToDepth(tex_align); return T;}
  480. MeshLod& MeshLod::edgeToTri (Bool set_id ) {REPA(T)parts[i].base.edgeToTri (set_id ); return T;}
  481. MeshLod& MeshLod::triToQuad (Flt cos ) {REPA(T)parts[i].base.triToQuad (cos ); return T;}
  482. MeshLod& MeshLod::quadToTri (Flt cos ) {REPA(T)parts[i].base.quadToTri (cos ); return T;}
  483. /******************************************************************************/
  484. // ADD / REMOVE
  485. /******************************************************************************/
  486. MeshLod& MeshLod::add(C MeshBase &src)
  487. {
  488. MeshBase temp; temp.create(src); // create in 'temp' in case 'src' belongs to this (and 'New' would change its memory address)
  489. Swap(parts.New().base, temp);
  490. return T;
  491. }
  492. MeshLod& MeshLod::add(C MeshPart &src)
  493. {
  494. MeshPart temp; temp.create(src); // create in 'temp' in case 'src' belongs to this (and 'New' would change its memory address)
  495. Swap(parts.New(), temp);
  496. return T;
  497. }
  498. MeshLod& MeshLod::add(C MeshLod &src, C Mesh *src_mesh, C Mesh *this_mesh)
  499. {
  500. if(&src==this)
  501. {
  502. Int num=parts.elms();
  503. FREP(num)
  504. {
  505. MeshPart &dest=parts.New(); dest.create(parts[i]); // don't put New into create(..) (because of memory address issues)
  506. }
  507. }else
  508. {
  509. if(!is())copyParams(src); // if this is empty, then copy params from src
  510. FREPA(src)
  511. {
  512. MeshPart &dest=parts.New().create(src.parts[i]);
  513. if(src_mesh && this_mesh)dest.variationRemap(*src_mesh, *this_mesh);
  514. }
  515. }
  516. return T;
  517. }
  518. /******************************************************************************/
  519. // OPTIMIZE
  520. /******************************************************************************/
  521. MeshLod& MeshLod::removeDoubleEdges ( ) { REPA(T) parts[i].base.removeDoubleEdges ( ); return T;}
  522. MeshLod& MeshLod::removeDegenerateFaces(Flt eps ) { REPA(T) parts[i].base.removeDegenerateFaces(eps ); return T;}
  523. Bool MeshLod::removeUnusedVtxs (Bool include_edge_references ) {Bool changed=false; REPA(T)changed|=parts[i].base.removeUnusedVtxs (include_edge_references ); return changed;}
  524. MeshLod& MeshLod::removeSingleFaces (Flt fraction ) { REPA(T) parts[i].base.removeSingleFaces (fraction ); return T;}
  525. MeshLod& MeshLod::weldInlineEdges (Flt cos_edge, Flt cos_vtx, Bool z_test ) { REPA(T) parts[i].base.weldInlineEdges (cos_edge, cos_vtx, z_test ); return T;}
  526. MeshLod& MeshLod::weldCoplanarFaces (Flt cos_face, Flt cos_vtx, Bool safe, Flt max_face_length) { REPA(T) parts[i].base.weldCoplanarFaces (cos_face, cos_vtx, safe, max_face_length); return T;}
  527. static Bool HasMaterial(MeshPart &part, Material *mtrl)
  528. {
  529. return part.multiMaterial(0)==mtrl
  530. || part.multiMaterial(1)==mtrl
  531. || part.multiMaterial(2)==mtrl
  532. || part.multiMaterial(3)==mtrl;
  533. }
  534. struct MaterialIndex
  535. {
  536. CChar *name;
  537. Byte index;
  538. static Int Compare(C MaterialIndex &a, C MaterialIndex &b)
  539. {
  540. return ComparePath(b.name, a.name); // the order is swapped intentionally so null materials are at the end
  541. }
  542. MaterialIndex(C MaterialPtr &material, Byte index) {T.name=material.name(); T.index=index;}
  543. };
  544. MeshLod& MeshLod::sortByMaterials()
  545. {
  546. // first sort multi materials by universal comparison (best are paths to file)
  547. FREPA(T)
  548. {
  549. MeshPart &p=parts[i];
  550. if(p.multiMaterial(1) || p.multiMaterial(2) || p.multiMaterial(3))
  551. {
  552. MaterialIndex m[4]=
  553. {
  554. MaterialIndex(p.multiMaterial(0), 0),
  555. MaterialIndex(p.multiMaterial(1), 1),
  556. MaterialIndex(p.multiMaterial(2), 2),
  557. MaterialIndex(p.multiMaterial(3), 3),
  558. };
  559. Sort(m, Elms(m), MaterialIndex::Compare);
  560. Byte new_index[4]={m[0].index, m[1].index, m[2].index, m[3].index};
  561. p.remapMaterials(new_index);
  562. }
  563. }
  564. // now sort parts, so the same materials would be close to each other
  565. FREPA(T)
  566. {
  567. MeshPart &p=parts[i];
  568. Int best_match=-1, matching_materials=0;
  569. for(Int j=i+1; j<parts.elms(); j++)
  570. {
  571. MeshPart &t =parts[j];
  572. Int mtrls=0;
  573. if(p.multiMaterial(0) && HasMaterial(t, p.multiMaterial(0)()))mtrls++;
  574. if(p.multiMaterial(1) && HasMaterial(t, p.multiMaterial(1)()))mtrls++;
  575. if(p.multiMaterial(2) && HasMaterial(t, p.multiMaterial(2)()))mtrls++;
  576. if(p.multiMaterial(3) && HasMaterial(t, p.multiMaterial(3)()))mtrls++;
  577. if(mtrls>matching_materials){best_match=j; matching_materials=mtrls;}
  578. }
  579. if(best_match>=0 && best_match!=i+1)Swap(parts[i+1], parts[best_match]);
  580. }
  581. return T;
  582. }
  583. /******************************************************************************/
  584. }
  585. /******************************************************************************/