*/}}

la_tns_mesh.c 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876
  1. /*
  2. * LaGUI: A graphical application framework.
  3. * Copyright (C) 2022-2023 Wu Yiming
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "la_5.h"
  19. #include <math.h>
  20. extern tnsMain *T;
  21. void tnsMMeshClearFirstLastSelection(tnsMeshObject* mo);
  22. void tnsPrintMeshTopology(tnsMeshObject*mo){
  23. for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ printf("%d ",mv->i); } printf("\n");
  24. for(tnsMEdge* me=mo->me.pFirst;me;me=me->Item.pNext){ printf("%d-%d ",me->vl->i,me->vr->i); } printf("\n");
  25. for(tnsMFace* mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){ printf("%d-[",mf->looplen);
  26. for(laListItemPointer* lip=mf->l.pFirst;lip;lip=lip->pNext){ tnsMEdge*ie=lip->p;
  27. printf("%d%s%d ",ie->vl->i,(ie->fl&&ie->fr)?":":(ie->fl?"l":(ie->fr?"r":"-")),ie->vr->i); }
  28. printf("] ");
  29. }printf("\n");
  30. }
  31. tnsEdgeHash* tnsCreateEdgeHash(int OptionalInitialVertCount){
  32. tnsEdgeHash*eh=memAcquireSimple(sizeof(tnsEdgeHash));
  33. eh->max=OptionalInitialVertCount;
  34. if(eh->max<16) eh->max=16;
  35. arrInitLength(&eh->vl,eh->max,&eh->max, sizeof(tnsEdgeHashVert));
  36. return eh;
  37. }
  38. void tnsDestroyEdgeHash(tnsEdgeHash* eh){
  39. for(int i=0;i<eh->max;i++){
  40. tnsEdgeHashVert* ehv=&eh->vl[i];
  41. if(ehv->e) free(ehv->e);
  42. }
  43. if(eh->vl) free(eh->vl);
  44. memFree(eh);
  45. }
  46. void tnsEdgeHashAddVertPair(tnsEdgeHash* eh, int v1, int v2){
  47. if(v1==v2) return; if(v1>v2) LA_SWAP(int, v1,v2); if(v1>=eh->max) return;
  48. tnsEdgeHashVert* ehv=&eh->vl[v1];
  49. if(!ehv->e) arrInitLength(&ehv->e,1,&ehv->max, sizeof(tnsEdgeHashEdge));
  50. else arrEnsureLength(&ehv->e, ehv->next, &ehv->max, sizeof(tnsEdgeHashEdge));
  51. for(int i=0;i<ehv->next;i++){ if(ehv->e[i].tv==v2) return; }
  52. ehv->e[ehv->next].tv=v2;
  53. ehv->next++;
  54. }
  55. tnsEdgeHashEdge* tnsEdgeHashGetEdge(tnsEdgeHash* eh, int v1, int v2){
  56. if(v1==v2) return 0; if(v1>v2) LA_SWAP(int, v1,v2); if(v1>=eh->max) return 0;
  57. tnsEdgeHashVert* ehv=&eh->vl[v1];
  58. for(int i=0;i<ehv->next;i++){ if(ehv->e[i].tv==v2) return &ehv->e[i]; }
  59. return 0;
  60. }
  61. void tnsInitMesh(tnsMeshObject* mo, int Initialv, int Initiale, int Initialf){
  62. arrInitLength(&mo->v, Initialv, &mo->maxv, sizeof(tnsVert));
  63. arrInitLength(&mo->e, Initiale, &mo->maxe, sizeof(tnsEdge));
  64. arrInitLength(&mo->f, Initialf, &mo->maxf, sizeof(tnsFace));
  65. }
  66. tnsVert* tnsFillVertI(tnsMeshObject* mo, int index, real x, real y, real z){
  67. arrEnsureLength(&mo->v, index, &mo->maxv, sizeof(tnsVert));
  68. mo->v[index].p[0]=x;
  69. mo->v[index].p[1]=y;
  70. mo->v[index].p[2]=z;
  71. return &mo->v[index];
  72. }
  73. tnsVert* tnsFillVert(tnsMeshObject* mo, real x, real y, real z){
  74. int index=mo->totv; mo->totv++;
  75. return tnsFillVertI(mo, index, x,y,z);
  76. }
  77. tnsFace* tnsFillFace(tnsMeshObject* mo, int vertcount, ...){
  78. arrEnsureLength(&mo->f, mo->totf, &mo->maxf, sizeof(tnsFace));
  79. arrInitLength(&mo->f[mo->totf].loop, vertcount, &mo->f[mo->totf].looplen, sizeof(int));
  80. va_list list; va_start(list, vertcount); int id=va_arg(list, int); if(id==-1){ va_end(list); mo->totf++; return &mo->f[mo->totf-1]; }
  81. for(int i=0;i<vertcount;i++){ mo->f[mo->totf].loop[i]=id; id=va_arg(list, int); }
  82. va_end(list);
  83. mo->totf++; return &mo->f[mo->totf-1];
  84. }
  85. void tnsFillFaceLoop(tnsFace* f, int i, int v){ f->loop[i]=v; }
  86. void tnsFillFaceNormal(tnsFace* f, real* normal){ tnsVectorSet3v(f->n, normal); }
  87. void tnsFillVertNormal(tnsVert* v, real* normal){ tnsVectorSet3v(v->n, normal); }
  88. int tnsMergeMeshObjects(tnsMeshObject* into, tnsMeshObject* mo){
  89. if(into->Base.Type!=TNS_OBJECT_MESH||mo->Base.Type!=TNS_OBJECT_MESH) return 0;
  90. if(!mo->totv){ tnsDestroyObject(mo); return 1; }
  91. tnsVector3d v,vf; tnsMatrix44d inv; tnsInverse44d(inv, into->Base.GlobalTransform);
  92. for(int i=0;i<mo->totv;i++){
  93. tnsVectorSet3v(v,mo->v[i].p); tnsApplyTransform43d(vf, mo->Base.GlobalTransform, v);
  94. tnsApplyTransform43d(v, inv, vf); tnsVectorSet3v(mo->v[i].p,v);
  95. }
  96. for(int i=0;i<mo->tote;i++){ mo->e[i].l+=into->totv; mo->e[i].r+=into->totv; }
  97. for(int i=0;i<mo->totf;i++){ for(int l=0;l<mo->f[i].looplen;l++){ mo->f[i].loop[l]+=into->totv; } }
  98. int origv=into->totv, orige=into->tote, origf=into->totf;
  99. into->maxv=into->totv; into->maxe=into->tote; into->maxf=into->totf;
  100. into->totv+=mo->totv; into->tote+=mo->tote; into->totf+=mo->totf;
  101. arrEnsureLength(&into->v, into->totv, &into->maxv, sizeof(tnsVert)); if(mo->totv) memcpy(&into->v[origv],mo->v,sizeof(tnsVert)*mo->totv);
  102. arrEnsureLength(&into->e, into->tote, &into->maxe, sizeof(tnsEdge)); if(mo->tote) memcpy(&into->e[orige],mo->e,sizeof(tnsEdge)*mo->tote);
  103. arrEnsureLength(&into->f, into->totf, &into->maxf, sizeof(tnsFace)); if(mo->totf){ memcpy(&into->f[origf],mo->f,sizeof(tnsFace)*mo->totf);
  104. for(int i=origf;i<into->totf;i++){ into->f[i].loop=0; arrInitLength(&into->f[i].loop, into->f[i].looplen, &into->f[i].looplen, sizeof(int));
  105. for(int l=0;l<into->f[i].looplen;l++){ into->f[i].loop[l]=mo->f[i-origf].loop[l]; }
  106. }
  107. }
  108. tnsDestroyObject(mo); return 1;
  109. }
  110. tnsMeshObject* tnsDuplicateMeshObject(tnsMeshObject* from){
  111. if(from->Base.Type!=TNS_OBJECT_MESH) return 0;
  112. tnsMeshObject* to = memAcquireHyper(sizeof(tnsMeshObject));
  113. tnsInitObjectBase(to, from->Base.ParentObject?from->Base.ParentObject:from->Base.InRoot, from->Base.Name->Ptr, TNS_OBJECT_MESH,0,0,0,0,0,0,0,0,1);
  114. tnsCopyObjectTransformationsLocal(to,from);
  115. tnsMaterialSlot* new_current=0;
  116. for(tnsMaterialSlot* ms=from->Materials.pFirst;ms;ms=ms->Item.pNext){
  117. tnsMaterialSlot* nms=tnsNewMaterialSlot(to); nms->Index=ms->Index;
  118. memAssignRef(nms,&nms->Material,ms->Material);
  119. if(ms==from->CurrentMaterial) new_current=nms;
  120. }
  121. memAssignRef(to,&to->CurrentMaterial,new_current);
  122. if(!from->totv){ return to; }
  123. to->totv=from->totv; to->tote=from->tote; to->totf=from->totf;
  124. arrInitLength(&to->v, to->totv, &to->maxv, sizeof(tnsVert)); if(from->totv) memcpy(to->v,from->v,sizeof(tnsVert)*from->totv);
  125. arrInitLength(&to->e, to->tote, &to->maxe, sizeof(tnsEdge)); if(from->tote) memcpy(to->e,from->e,sizeof(tnsEdge)*from->tote);
  126. arrInitLength(&to->f, to->totf, &to->maxf, sizeof(tnsFace)); if(from->totf) memcpy(to->f,from->f,sizeof(tnsFace)*from->totf);
  127. for(int i=0;i<to->totf;i++){ to->f[i].loop=0; arrInitLength(&to->f[i].loop, to->f[i].looplen, &to->f[i].looplen, sizeof(int));
  128. for(int l=0;l<to->f[i].looplen;l++){ to->f[i].loop[l]=from->f[i].loop[l]; } to->f[i].mat=from->f[i].mat;
  129. }
  130. return to;
  131. }
  132. void tnsInitMeshPlane(tnsMeshObject* mo, real size){
  133. tnsInitMesh(mo, 4,0,1);
  134. tnsFillVert(mo, size, size,0); tnsFillVert(mo,-size, size,0);
  135. tnsFillVert(mo,-size,-size,0); tnsFillVert(mo, size,-size,0);
  136. tnsFace* f=tnsFillFace(mo, 4, 0,1,2,3); tnsVector3d n={0,0,1}; tnsFillFaceNormal(f,n);
  137. mo->v[0].flags|=TNS_MESH_FLAG_SELECTED;
  138. mo->v[1].flags|=TNS_MESH_FLAG_SELECTED;
  139. mo->v[2].flags|=TNS_MESH_FLAG_SELECTED;
  140. mo->v[3].flags|=TNS_MESH_FLAG_SELECTED;
  141. tnsMMeshEnsureSelectionFromVerts(mo);
  142. }
  143. void tnsAddMMeshPlane(tnsMeshObject* mo, real size){
  144. tnsMVert *mv1,*mv2,*mv3,*mv4;
  145. mv1=tnsMMeshNewVert(mo); mv1->p[0]=size; mv1->p[1]=size; mv1->flags|=TNS_MESH_FLAG_SELECTED;
  146. mv2=tnsMMeshNewVert(mo); mv2->p[0]=-size; mv2->p[1]=size; mv2->flags|=TNS_MESH_FLAG_SELECTED;
  147. mv3=tnsMMeshNewVert(mo); mv3->p[0]=-size; mv3->p[1]=-size; mv3->flags|=TNS_MESH_FLAG_SELECTED;
  148. mv4=tnsMMeshNewVert(mo); mv4->p[0]=size; mv4->p[1]=-size; mv4->flags|=TNS_MESH_FLAG_SELECTED;
  149. tnsMMeshMakeFace4v(mo,mv1,mv2,mv3,mv4);
  150. }
  151. void tnsTrangulateFaceSimple(tnsMeshObject* mo, int fi, tnsFace* f, int* ebuf){
  152. for(int i=0;i<f->looplen-2;i++){
  153. ebuf[i*3]=f->loop[i];
  154. ebuf[i*3+1]=f->loop[i+1];
  155. ebuf[i*3+2]=fi+mo->totv; //f->loop[i+2];
  156. }
  157. }
  158. void tnsTrangulateFaceSimpleM(tnsMeshObject* mo, int fi, tnsMFace* mf, int* ebuf){
  159. tnsMVert* mv=0,*mvs; int i=0;
  160. for(laListItemPointer* lip=mf->l.pFirst;lip;lip=lip->pNext){
  161. laListItemPointer* next=lip->pNext; if(!next) next=mf->l.pFirst; tnsMEdge* me0=lip->p, *me1=next->p;
  162. if(next==mf->l.pLast){ break; }
  163. mvs=tnsMMeshEdgeStartingVert(me0,me1);
  164. if(!mv) mv=mvs;
  165. ebuf[i*3]=mvs->i; tnsMVert*mm=tnsMMeshEdgeAnotherVert(me0,mvs);
  166. ebuf[i*3+1]=mm->i;
  167. ebuf[i*3+2]=fi+mo->totmv; /*tnsMMeshEdgeAnotherVert(me1,mm)->i;*/ i++;
  168. }
  169. }
  170. tnsMVert* tnsGetMFaceLastVert(tnsMFace* mf){
  171. laListItemPointer* lip=mf->l.pLast; laListItemPointer* next=mf->l.pFirst; tnsMEdge* me0=lip->p, *me1=next->p;
  172. return tnsMMeshEdgeStartingVert(me0,me1);
  173. }
  174. int* tnsGetTriangulatedBatch(tnsMeshObject* mo, int* totelem, int mat){
  175. int tottri=0; int filter=1; if(mat<0){ filter=0; }
  176. if(mo->Mode==TNS_MESH_OBJECT_MODE){
  177. for(int i=0;i<mo->totf;i++){ if(filter && (mo->f[i].mat!=mat)) continue; tottri+=(mo->f[i].looplen-2); }
  178. }else{ for(tnsMFace* mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){
  179. if(filter && (mf->mat!=mat)) continue; tottri+=mf->looplen-2; }
  180. }
  181. if(!tottri) return 0;
  182. int* ebuf=calloc(1,sizeof(int)*tottri*3); int* pebuf=ebuf;
  183. if(mo->Mode==TNS_MESH_OBJECT_MODE){
  184. for(int i=0;i<mo->totf;i++){ if(filter && (mo->f[i].mat!=mat)) continue;
  185. tnsTrangulateFaceSimple(mo, i, &mo->f[i], pebuf); pebuf+=(mo->f[i].looplen-2)*3;
  186. }
  187. }else{ int i=0; for(tnsMFace* mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){
  188. if(filter && (mf->mat!=mat)){ i++; continue; }
  189. tnsTrangulateFaceSimpleM(mo, i, mf, pebuf); pebuf+=(mf->looplen-2)*3; i++; }
  190. }
  191. *totelem = tottri;
  192. return ebuf;
  193. }
  194. float* tnsGetDrawingVertArray(tnsMeshObject* mo, int* r_tot_render_v, float** r_normals, float** idcolors, float** editcolors, int** edgeelems, int* r_tote){
  195. if(!mo->totv&&!mo->totmv) return 0;
  196. int objmode=mo->Mode==TNS_MESH_OBJECT_MODE;
  197. int totv=objmode?mo->totv:mo->totmv;
  198. int tote=objmode?mo->tote:mo->totme; *r_tote=tote;
  199. int totf=objmode?mo->totf:mo->totmf;
  200. int extraverts=objmode?mo->totf:(mo->totme*2+mo->totmf);
  201. float* p=calloc(1,(totv+extraverts)*3*sizeof(float)); *r_tot_render_v=(totv+extraverts);
  202. float* n=calloc(1,(totv+extraverts)*3*sizeof(float)); *r_normals = n;
  203. if(objmode){
  204. for(int i=0;i<totv;i++){ tnsVectorSet3v(&p[i*3],mo->v[i].p); tnsVectorSet3v(&n[i*3],mo->v[i].n); }
  205. int start=mo->totv*3; for(int i=0;i<totf;i++){
  206. tnsVectorSet3v(&p[start+i*3],mo->v[mo->f[i].loop[mo->f[i].looplen-1]].p); tnsVectorSet3v(&n[start+i*3],mo->f[i].n);
  207. }
  208. }else{
  209. (*idcolors)=calloc(1,(totv+extraverts)*3*sizeof(float));
  210. if(extraverts){
  211. (*edgeelems)=calloc(1,(extraverts)*2*sizeof(int));
  212. (*editcolors)=calloc(1,totv*4*sizeof(float)*extraverts);
  213. }
  214. for(tnsMVert*mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ int i=mv->i;
  215. tnsVectorSet3v(&p[i*3],mv->p); tnsVectorSet3v(&n[i*3],mv->n);
  216. int id=(i+1); real r=(real)((id & 0x000000FF)>>0)/255.0; real g=(real)((id & 0x0000FF00)>>8)/255.0; real b=(real)((id & 0x00FF0000)>>16)/255.0;
  217. (*idcolors)[i*3]=r; (*idcolors)[i*3+1]=g; (*idcolors)[i*3+2]=b;
  218. real* c=(mv->flags&TNS_MESH_FLAG_SELECTED)?laAccentColor(LA_BT_SVERTEX):laAccentColor(LA_BT_VERTEX);
  219. if(extraverts){ (*editcolors)[i*4]=c[0]; (*editcolors)[i*4+1]=c[1]; (*editcolors)[i*4+2]=c[2]; (*editcolors)[i*4+3]=c[3];}
  220. }
  221. if(extraverts){
  222. for(tnsMEdge*me=mo->me.pFirst;me;me=me->Item.pNext){ int ei=me->i;
  223. (*edgeelems)[ei*2]=mo->totmv+mo->totmf+ei*2; (*edgeelems)[ei*2+1]=mo->totmv+mo->totmf+ei*2+1;
  224. float* eidcolor1=&(*idcolors)[(*edgeelems)[ei*2]*3], *eidcolor2=&(*idcolors)[(*edgeelems)[ei*2+1]*3];
  225. int id=((ei+1)|TNS_MMESH_EDGE_BIT); real r=(real)((id & 0x000000FF)>>0)/255.0; real g=(real)((id & 0x0000FF00)>>8)/255.0; real b=(real)((id & 0x00FF0000)>>16)/255.0;
  226. tnsVectorSet3(eidcolor1,r,g,b); tnsVectorSet3(eidcolor2,r,g,b);
  227. int se1=(*edgeelems)[ei*2]; tnsVectorSet3v(&p[se1*3],me->vl->p);
  228. int se2=(*edgeelems)[ei*2+1]; tnsVectorSet3v(&p[se2*3],me->vr->p);
  229. float* eedcolor1=&(*editcolors)[(*edgeelems)[ei*2]*4], *eedcolor2=&(*editcolors)[(*edgeelems)[ei*2+1]*4];
  230. real* c=(me->flags&TNS_MESH_FLAG_SELECTED)?laAccentColor(LA_BT_SEDGE):laAccentColor(LA_BT_EDGE);
  231. tnsVectorSet4v(eedcolor1,c); tnsVectorSet4v(eedcolor2,c);
  232. }
  233. }
  234. int start=mo->totmv*3; int fi=0; for(tnsMFace*mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){
  235. tnsMVert* sv=tnsGetMFaceLastVert(mf); tnsVectorSet3v(&p[start+fi*3],sv->p); tnsVectorSet3v(&n[start+fi*3],mf->n); fi++;
  236. }
  237. }
  238. return p;
  239. }
  240. int* tnsGetEdgeBatch(tnsMeshObject* mo){
  241. if(!mo->totme) return 0;
  242. int* ebuf=calloc(1,sizeof(int)*mo->totme*2); int* pebuf=ebuf; int i=0;
  243. for(tnsMEdge* me=mo->me.pFirst;me;me=me->Item.pNext){ ebuf[i*2]=me->vl->i; ebuf[i*2+1]=me->vr->i; i++; }
  244. return ebuf;
  245. }
  246. void tnsInvalidateMeshBatch(tnsMeshObject* mo){
  247. if(mo->Base.Type!=TNS_OBJECT_MESH) return;
  248. if(mo->Batch) tnsDeleteBatch(mo->Batch); mo->Batch=0;
  249. if(mo->Base.PlayDuplicate){ tnsMeshObject*pmo=mo->Base.PlayDuplicate; pmo->Batch=0; }
  250. }
  251. void tnsRegenerateMeshBatch(tnsMeshObject* mo){
  252. if(!mo) return;
  253. if(mo->Batch) tnsDeleteBatch(mo->Batch); mo->Batch=0;
  254. real meshcolor[4]={0.8,0.8,0.8,1.0};
  255. int tottri; int* elem = tnsGetTriangulatedBatch(mo, &tottri,-1);
  256. float* idcolors=0,*editcolors=0; int docolors=mo->Mode==TNS_MESH_EDIT_MODE;
  257. int totv,tote; int* eelems=0; float* n=0;
  258. float* v = tnsGetDrawingVertArray(mo,&totv,&n,&idcolors,&editcolors,&eelems,&tote);
  259. if(!v){ if(elem){free(elem);} if(eelems){free(eelems);} return; }
  260. mo->Batch = tnsCreateBatch(totv, 3, v, 3, n, 4, editcolors);
  261. tnsBatchCommand*c;
  262. if(elem){
  263. c=tnsCreateCommand(mo->Batch, "body", tottri, 3, GL_TRIANGLES, elem, 0);
  264. tnsCommandUseUniformColor(c,meshcolor);
  265. for(tnsMaterialSlot* ms=mo->Materials.pFirst;ms;ms=ms->Item.pNext){
  266. int* melem,mtot; melem=tnsGetTriangulatedBatch(mo, &mtot, ms->Index);
  267. if(melem){
  268. c=tnsCreateCommand(mo->Batch, "mat", mtot, 3, GL_TRIANGLES, melem, 0);
  269. tnsCommandUseUniformColor(c,ms->Material?ms->Material->Color:meshcolor);
  270. if(ms->Material){ tnsCommandUseMaterial(c,ms->Material); }
  271. free(melem);
  272. }
  273. }
  274. }
  275. free(elem); free(v); free(n);
  276. if(mo->Mode==TNS_MESH_EDIT_MODE){
  277. elem=tnsGetEdgeBatch(mo); if(elem) {
  278. c= tnsCreateCommand(mo->Batch, "lines", mo->totme, 2, GL_LINES, elem, 1); free(elem);
  279. //tnsCommandUseUniformColor(c, laAccentColor(LA_BT_EDGE));
  280. }
  281. c= tnsCreateCommand(mo->Batch, "verts", mo->totmv, 3, GL_POINTS, 0, 1);
  282. c= tnsCreateCommand(mo->Batch, "verts_select", mo->totmv, 3, GL_POINTS, 0, 1);
  283. tnsCommandOverrideColorArray(c, mo->Batch->NumVert, 3, idcolors);
  284. if(eelems){
  285. c= tnsCreateCommand(mo->Batch, "edges_select", mo->totme, 2, GL_LINES, eelems, 1);
  286. tnsCommandOverrideColorArray(c, mo->Batch->NumVert, 3, idcolors);
  287. c= tnsCreateCommand(mo->Batch, "edges", mo->totme, 2, GL_LINES, eelems, 1);
  288. tnsCommandOverrideColorArray(c, mo->Batch->NumVert, 4, editcolors);
  289. }
  290. //for(int i=0;i<mo->totme*2;i++){ printf("%d ",eelems[i]); } printf("\n");
  291. }
  292. if(idcolors) free(idcolors); if(editcolors) free(editcolors); if(eelems) free(eelems);
  293. if(mo->Base.PlayDuplicate){ tnsMeshObject*pmo=mo->Base.PlayDuplicate; pmo->Batch=mo->Batch; }
  294. }
  295. void tnsEnsureMeshBatch(tnsMeshObject* mo){
  296. if(mo->Base.Type!=TNS_OBJECT_MESH) return;
  297. if(mo->Batch) return;
  298. tnsRegenerateMeshBatch(mo);
  299. }
  300. void tnsDrawMeshObjectEdit(tnsMeshObject* mo, int MeshSelectionType){
  301. tnsUniformUseOffset(T->immShader,1);
  302. glPointSize(6); glLineWidth(3);
  303. if(MeshSelectionType==LA_CANVAS_SELECT_MODE_VERTS){
  304. tnsDrawBatch(mo->Batch,"verts",0,0); tnsDrawBatch(mo->Batch,"lines",0,0);
  305. }else{
  306. tnsDrawBatch(mo->Batch,"edges",0,0);
  307. }
  308. glPointSize(1); glLineWidth(1);
  309. tnsUniformUseOffset(T->immShader,0);
  310. }
  311. void tnsDrawMeshObjectOverlay(tnsEvaluatedInstance* ei, la3DObjectDrawExtra* de){
  312. tnsEnsureMeshBatch(ei->Object);
  313. tnsDrawMeshObjectEdit(ei->Object, de?de->MeshEditType:LA_CANVAS_SELECT_MODE_VERTS);
  314. if(((tnsMeshObject*)ei->Object)->ExtraBatch){ tnsDrawBatch(((tnsMeshObject*)ei->Object)->ExtraBatch,0,0,0); }
  315. }
  316. void tnsDrawMeshObjectSelectionID(tnsEvaluatedInstance* ei, void* unused){
  317. tnsEnsureMeshBatch(ei->Object);
  318. int i=ei->InstanceSelectionID; real color[4]={0,0,0,1}; TNS_ID_TO_COLOR(color,i);
  319. tnsDrawBatch(((tnsMeshObject*)ei->Object)->Batch,"body",color,0);
  320. }
  321. void tnsDrawMeshObjectOutline(tnsEvaluatedInstance* ei, void* unused){
  322. real* color=(ei->IsActive)?laAccentColor(LA_BT_TEXT):laAccentColor(LA_BT_NORMAL);
  323. tnsDrawBatch(((tnsMeshObject*)ei->Object)->Batch, "body", color, 0);
  324. }
  325. void tnsDrawMeshObject(tnsEvaluatedInstance* ei, la3DObjectDrawExtra* de){
  326. tnsMeshObject* mo=ei->Object;
  327. if((!mo->totv) && (!mo->totmv)){ tnsDrawSingleObjectOrigin(mo); return; }
  328. tnsEnsureMeshBatch(ei->Object); tnsUseNormal(1);
  329. if(de->DisplayMode==LA_CANVAS_DISPLAY_MATERIAL){
  330. if(!tnsDrawBatch(mo->Batch,"mat",0,0)){
  331. tnsDrawBatch(mo->Batch,"body",0,0);
  332. }
  333. }else{
  334. tnsDrawBatch(mo->Batch,"body",0,0);
  335. }
  336. tnsUseNormal(0);
  337. }
  338. void tnsEvaluateMeshObject(tnsMeshObject* mo, tnsEvaluateData* ed){
  339. tnsEnsureMeshBatch(mo);
  340. tnsAddEvaluatedInstance(ed,mo,tnsDrawMeshObject,TNS_EVAL_LAYER_SOLID,0,0,0);
  341. if(ed->FillOutline && (!ed->OverrideID)){
  342. if((mo->Base.Flags&TNS_OBJECT_FLAGS_SELECTED) && (mo->Mode!=TNS_MESH_EDIT_MODE)){
  343. tnsAddEvaluatedInstance(ed,mo,tnsDrawMeshObjectOutline,TNS_EVAL_LAYER_OUTLINE,ed->Active==mo,0,0);
  344. }
  345. }
  346. if(ed->FillSelectionID){
  347. tnsAddEvaluatedInstance(ed,mo,tnsDrawMeshObjectSelectionID,TNS_EVAL_LAYER_SELECTION,0,1,mo->Base.SelectID);
  348. }
  349. if(mo->Mode==TNS_MESH_EDIT_MODE && (!ed->OverrideID)){
  350. tnsAddEvaluatedInstance(ed,mo,tnsDrawMeshObjectOverlay,TNS_EVAL_LAYER_OVERLAY,0,0,0);
  351. }
  352. }
  353. tnsMFace* tnsMMeshNewFace(tnsMeshObject* mo){ tnsMFace* mf=memAcquireSimple(sizeof(tnsMFace)); mf->i=mo->totmf; mo->totmf++; lstAppendItem(&mo->mf,mf); return mf; }
  354. tnsMEdge* tnsMMeshNewEdge(tnsMeshObject* mo){ tnsMEdge* me=memAcquireSimple(sizeof(tnsMEdge)); me->i=mo->totme; mo->totme++; lstAppendItem(&mo->me,me); return me; }
  355. tnsMVert* tnsMMeshNewVert(tnsMeshObject* mo){ tnsMVert* mv=memAcquireSimple(sizeof(tnsMVert)); mv->i=mo->totmv; mo->totmv++; lstAppendItem(&mo->mv,mv); return mv; }
  356. void tnsMMeshCalculateNormalFrom(tnsMFace* mf){
  357. tnsVector3d accum={0}; tnsVector3d d0,d1; tnsVector3d naccum={0},nn={0};if(mf->flags&TNS_MESH_FLAG_PICKED) return;
  358. for(laListItemPointer* lip=mf->l.pFirst;lip;lip=lip->pNext){
  359. laListItemPointer* next=lip->pNext; if(!next) next=mf->l.pFirst; tnsMEdge* me0=lip->p, *me1=next->p;
  360. tnsMVert* v0=tnsMMeshEdgeStartingVert(me0,me1); tnsMVert* v1=tnsMMeshEdgeShareVert(me0,me1); tnsMVert* v2=tnsMMeshEdgeAnotherVert(me1, v1);
  361. tnsVectorAccum3d(accum, v0->p); tnsVectorAccum3d(accum, v1->p); tnsVectorAccum3d(accum, v2->p);
  362. tnsVectorMinus3d(d0,v0->p,v1->p); tnsVectorMinus3d(d1,v2->p,v1->p); real len=tnsVectorCross3d(nn,d0,d1); tnsVectorMultiSelf3d(nn, len);
  363. tnsVectorAccum3d(naccum, nn);
  364. //if(v0==me0->vr){ me0->flags|=TNS_MESH_FLAG_LOOP_REVERSE; } // TODO: consistency not implemented.
  365. }
  366. tnsNormalize3d(mf->n, naccum); tnsVectorMulti3d(mf->c, accum, 1.0/(mf->looplen+2));
  367. mf->flags|=TNS_MESH_FLAG_PICKED;
  368. if(mf->flags&TNS_MESH_FLAG_SELECTED){
  369. for(laListItemPointer* lip=mf->l.pFirst;lip;lip=lip->pNext){
  370. tnsMEdge* me=lip->p; tnsMFace* of=((mf==me->fl)?me->fr:me->fl);
  371. if(of) tnsMMeshCalculateNormalFrom(of);
  372. }
  373. }
  374. }
  375. void tnsMMeshCalculateFaceVertNormal(tnsMFace* mf){
  376. tnsVector3d accum={0};
  377. for(laListItemPointer* lip=mf->l.pFirst;lip;lip=lip->pNext){
  378. laListItemPointer* next=lip->pNext; if(!next) next=mf->l.pFirst; tnsMEdge* me0=lip->p, *me1=next->p;
  379. tnsMVert* mv=tnsMMeshEdgeStartingVert(me0,me1); int fcount=0;
  380. for(laListItemPointer* el=mv->elink.pFirst;el;el=el->pNext){ tnsMEdge* ve=lip->p;
  381. if(ve->fl){ tnsVectorAccum3d(accum, ve->fl->n); fcount++; }
  382. if(ve->fr){ tnsVectorAccum3d(accum, ve->fr->n); fcount++; }
  383. }
  384. if(!fcount) accum[2]=1; else tnsNormalizeSelf3d(accum);
  385. tnsVectorSet3v(mv->n, accum);
  386. }
  387. }
  388. int tnsMMeshCalculateNormal(tnsMeshObject* mo){
  389. tnsMMeshClearExtraFlags(mo); int ran=0;
  390. for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ if(!(mv->flags&TNS_MESH_FLAG_SELECTED)) continue;
  391. for(laListItemPointer* lip=mv->elink.pFirst; lip;lip=lip->pNext){
  392. tnsMEdge*me=lip->p; if((!me->fl) && (!me->fr)) continue;
  393. if(me->fl) tnsMMeshCalculateNormalFrom(me->fl); if(me->fr) tnsMMeshCalculateNormalFrom(me->fr); ran=1;
  394. }
  395. }
  396. //for(tnsMFace* mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){ if((!(mf->flags&TNS_MESH_FLAG_SELECTED))||(mf->flags&TNS_MESH_FLAG_PICKED)) continue;
  397. // tnsMMeshCalculateNormalFrom(mf); ran=1;
  398. //}
  399. for(tnsMFace* mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){ if(!(mf->flags&TNS_MESH_FLAG_PICKED)) continue;
  400. tnsMMeshCalculateFaceVertNormal(mf); ran=1;
  401. }
  402. return ran;
  403. }
  404. void tnsMMeshEdgeAssignVerts(tnsMEdge* me,tnsMVert* mv1,tnsMVert* mv2){
  405. if(me->vl||me->vr){ return; } //if((me->vl==mv1&&me->vr=mv2) || (me->vl==mv2&&me->vr=mv1))
  406. me->vl=mv1; me->vr=mv2;
  407. lstAppendPointer(&me->vl->elink,me); lstAppendPointer(&me->vr->elink,me);
  408. }
  409. tnsMEdge* tnsMMeshVertsShareEdge(tnsMVert* mv0, tnsMVert* mv1){
  410. for(laListItemPointer*lip=mv0->elink.pFirst;lip;lip=lip->pNext){ tnsMEdge* me=lip->p; if(tnsMMeshEdgeAnotherVert(me, mv0)==mv1) return me; } return 0;
  411. }
  412. int tnsMMeshEdgeHasVert(tnsMEdge* me, tnsMVert* mv){
  413. if(me->vl==mv || me->vr==mv) return 1; return 0;
  414. }
  415. tnsMFace* tnsMMeshEdgeShareFace(tnsMEdge* me0, tnsMEdge* me1){
  416. if(me0->fl==me1->fl || me0->fl==me1->fr) return me0->fl;
  417. if(me0->fr==me1->fl || me0->fr==me1->fr) return me0->fr;
  418. return 0;
  419. }
  420. tnsMVert* tnsMMeshEdgeShareVert(tnsMEdge* me0, tnsMEdge* me1){
  421. if(me0->vl==me1->vl || me0->vl==me1->vr) return me0->vl;
  422. if(me0->vr==me1->vl || me0->vr==me1->vr) return me0->vr;
  423. return 0;
  424. }
  425. tnsMVert* tnsMMeshEdgeAnotherVert(tnsMEdge* me, tnsMVert* v){
  426. if(me->vl==v) return me->vr; if(me->vr==v) return me->vl;
  427. return 0;
  428. }
  429. tnsMVert* tnsMMeshEdgeStartingVert(tnsMEdge* me0, tnsMEdge* me1){
  430. tnsMVert* sv=tnsMMeshEdgeShareVert(me0,me1); if(!sv) return 0;
  431. return tnsMMeshEdgeAnotherVert(me0, sv);
  432. }
  433. void tnsMMeshFaceAddEdge(tnsMFace* mf, tnsMEdge* me){
  434. lstAppendPointer(&mf->l, me); mf->looplen++;
  435. if(!me->fl) me->fl=mf; elif(!me->fr) me->fr=mf;
  436. }
  437. void tnsMMeshFaceAddEdgeReplaceFace(tnsMFace* mf, tnsMEdge* me, tnsMFace* to_be_replaced){
  438. lstAppendPointer(&mf->l, me); mf->looplen++;
  439. if(me->fl==to_be_replaced) me->fl=mf; elif(me->fr==to_be_replaced) me->fr=mf;
  440. elif(!me->fl) me->fl=mf; elif(!me->fr) me->fr=mf;
  441. }
  442. tnsMFace* tnsMMeshFaceHasVert(tnsMFace* mf, tnsMVert* mv){
  443. if(!mf||!mv) return 0; for(laListItemPointer*lip=mf->l.pFirst;lip;lip=lip->pNext){ if(tnsMMeshEdgeAnotherVert(lip->p, mv)) return mf; }
  444. return 0;
  445. }
  446. tnsMFace* tnsMMeshVertsShareFace(tnsMVert* v1, tnsMVert* v2){
  447. tnsMFace* mf=0; for(laListItemPointer*lip=v1->elink.pFirst;lip;lip=lip->pNext){
  448. tnsMEdge* me=lip->p; if((mf=tnsMMeshFaceHasVert(me->fl, v2)) || (mf=tnsMMeshFaceHasVert(me->fr, v2))) return mf;
  449. } return 0;
  450. }
  451. int tnsMMeshSplitFace(tnsMeshObject* mo, tnsMFace* mf, tnsMEdge* me, tnsMFace** r_f1, tnsMFace** r_f2){
  452. tnsMEdge* NextE; laListItemPointer* NextLip, *StartLip=0, *EndLip=0; int guard=0;
  453. for(laListItemPointer*lip=mf->l.pFirst;lip;lip=NextLip){
  454. NextLip=lip->pNext?lip->pNext:mf->l.pFirst; NextE=NextLip->p;
  455. if(tnsMMeshEdgeHasVert(me,tnsMMeshEdgeShareVert(NextE,lip->p))){
  456. if(!StartLip) StartLip=NextLip;
  457. else{EndLip=NextLip; break;} }
  458. guard++; if(guard>mf->looplen) return 0; // me is not across mf.
  459. }
  460. tnsMFace* f1=tnsMMeshNewFace(mo);
  461. for(laListItemPointer*lip=StartLip;lip;lip=NextLip){ NextLip=lip->pNext?lip->pNext:mf->l.pFirst;
  462. if(lip==EndLip){ tnsMMeshFaceAddEdgeReplaceFace(f1, me, mf); break; } tnsMMeshFaceAddEdgeReplaceFace(f1, lip->p, mf);
  463. }
  464. tnsMFace* f2=tnsMMeshNewFace(mo);
  465. for(laListItemPointer*lip=EndLip;lip;lip=NextLip){ NextLip=lip->pNext?lip->pNext:mf->l.pFirst;
  466. if(lip==StartLip){ tnsMMeshFaceAddEdgeReplaceFace(f2, me, mf); break; } tnsMMeshFaceAddEdgeReplaceFace(f2, lip->p, mf);
  467. }
  468. tnsMMeshRemoveFaceOnly(mo, mf);
  469. if(r_f1){ *r_f1=f1; } if(r_f2){ *r_f2=f2; }
  470. //tnsPrintMeshTopology(mo);
  471. return 1;
  472. }
  473. tnsMEdge* tnsMMeshMakeEdge(tnsMeshObject* mo, tnsMVert* v1, tnsMVert* v2){
  474. for(laListItemPointer*lip=v1->elink.pFirst;lip;lip=lip->pNext){ if(tnsMMeshEdgeAnotherVert(lip->p, v1)==v2) return lip->p; }
  475. // for(laListItemPointer*lip=v2->elink.pFirst;lip;lip=lip->pNext){ if(tnsMMeshEdgeAnotherVert(lip->p, v2)==v1) return lip->p; } shouldn't need.
  476. tnsMFace* mf=tnsMMeshVertsShareFace(v1,v2);
  477. tnsMEdge* me=tnsMMeshNewEdge(mo); tnsMMeshEdgeAssignVerts(me, v1, v2);
  478. if(mf){ tnsMMeshSplitFace(mo, mf, me, 0,0); }
  479. return me;
  480. }
  481. int tnsMMeshFaceMatchesN(tnsMFace* mf, int ecount, laListHandle* eip){
  482. if(!mf||mf->looplen!=ecount) return 0; laListItemPointer* lipe=eip->pFirst;
  483. for(int i=0;i<ecount;i++){
  484. tnsMEdge* me=lipe->p; int found=0; lipe=lipe->pNext;
  485. for(laListItemPointer* lip=mf->l.pFirst;lip;lip=lip->pNext){
  486. if(lip->p==me){ found=1; break; }
  487. }
  488. if(!found){ return 0; }
  489. }
  490. return 1;
  491. }
  492. int tnsMMeshFaceMatches(tnsMFace* mf, int ecount, ...){
  493. if(!mf||mf->looplen!=ecount) return 0;
  494. va_list list; va_start(list, ecount);
  495. for(int i=0;i<ecount;i++){
  496. tnsMEdge* me=va_arg(list, tnsMEdge*); int found=0;
  497. for(laListItemPointer* lip=mf->l.pFirst;lip;lip=lip->pNext){
  498. if(lip->p==me){ found=1; break; }
  499. }
  500. if(!found){ va_end(list); return 0; }
  501. }
  502. va_end(list); return 1;
  503. }
  504. tnsMFace* tnsMMeshMakeFaceN(tnsMeshObject* mo, int count, laListHandle* vip, tnsMEdge** r_fallback_me){
  505. if(count<2){ return 0; }
  506. if(count==2){ tnsMEdge* me=tnsMMeshMakeEdge(mo,((laListItemPointer*)vip->pFirst)->p,((laListItemPointer*)vip->pLast)->p); if(r_fallback_me)*r_fallback_me=me; return 0; }
  507. laListHandle el={0};
  508. for(laListItemPointer*lip=vip->pFirst;lip;lip=lip->pNext){
  509. tnsMVert* mv=lip->p; laListItemPointer*nlip=lip->pNext?((laListItemPointer*)lip->pNext):vip->pFirst; tnsMVert* nextmv=nlip->p;
  510. lstAppendPointer(&el,tnsMMeshMakeEdge(mo,mv,nextmv));
  511. }
  512. tnsMEdge* e1=((laListItemPointer*)el.pFirst)->p;
  513. if(tnsMMeshFaceMatchesN(e1->fl, count, &el))return e1->fl; if(tnsMMeshFaceMatchesN(e1->fr, count, &el))return e1->fr;
  514. for(laListItemPointer* lip=el.pFirst;lip;lip=lip->pNext){ tnsMEdge*me=lip->p; if(me->fl&&me->fr) return 0; }
  515. tnsMFace* mf=tnsMMeshNewFace(mo);
  516. for(laListItemPointer* lip=el.pFirst;lip;lip=lip->pNext){ tnsMEdge*me=lip->p; tnsMMeshFaceAddEdge(mf, me); }
  517. while(lstPopPointer(&el));
  518. return mf;
  519. }
  520. tnsMFace* tnsMMeshMakeFace4v(tnsMeshObject* mo, tnsMVert* v1,tnsMVert* v2,tnsMVert* v3,tnsMVert* v4){
  521. tnsMEdge* e1=tnsMMeshMakeEdge(mo,v1,v2); tnsMEdge* e2=tnsMMeshMakeEdge(mo,v2,v3);
  522. tnsMEdge* e3=tnsMMeshMakeEdge(mo,v3,v4); tnsMEdge* e4=tnsMMeshMakeEdge(mo,v4,v1);
  523. if(tnsMMeshFaceMatches(e1->fl,4,e1,e2,e3,e4)) return e1->fl; if(tnsMMeshFaceMatches(e1->fr,4,e1,e2,e3,e4)) return e1->fr; //should not need more
  524. if((e1->fl&&e1->fr) || (e2->fl&&e2->fr) || (e3->fl&&e3->fr) || (e4->fl&&e4->fr)) return 0;
  525. tnsMFace* mf=tnsMMeshNewFace(mo);
  526. tnsMMeshFaceAddEdge(mf,e1); tnsMMeshFaceAddEdge(mf,e2);
  527. tnsMMeshFaceAddEdge(mf,e3); tnsMMeshFaceAddEdge(mf,e4);
  528. return mf;
  529. }
  530. int tnsMMeshLoopIsInverted(laListItemPointer* l){
  531. tnsMEdge* me=l->p; if(l->pNext){ tnsMEdge*next=((laListItemPointer*)l->pNext)->p; if(me->vr==tnsMMeshEdgeShareVert(me,next))return 0; return 1; }
  532. else{ tnsMEdge*prev=((laListItemPointer*)l->pPrev)->p; if(me->vl==tnsMMeshEdgeShareVert(prev,me))return 0; return 1; }
  533. }
  534. int tnsMMeshEdgeInsertVert(tnsMeshObject* mo, tnsMEdge* me, tnsMVert* mv, tnsMVert* ref_e1v_optional, tnsMEdge** r_e1, tnsMEdge** r_e2){
  535. if(mv->elink.pFirst||mv->elink.pLast||me->vl==mv||me->vl==mv) return 0;
  536. tnsMEdge* me1=tnsMMeshNewEdge(mo),*me2=tnsMMeshNewEdge(mo);
  537. me1->fl=me2->fl=me->fl; me1->fr=me2->fr=me->fr;
  538. tnsMMeshEdgeAssignVerts(me1,me->vl,mv); tnsMMeshEdgeAssignVerts(me2,mv,me->vr);
  539. laListItemPointer* lipa1=memAcquireSimple(sizeof(laListItemPointer)),*lipa2=memAcquireSimple(sizeof(laListItemPointer)); lipa1->p=me1; lipa2->p=me2;
  540. laListItemPointer* lipb1=memAcquireSimple(sizeof(laListItemPointer)),*lipb2=memAcquireSimple(sizeof(laListItemPointer)); lipb1->p=me1; lipb2->p=me2;
  541. if(me->fl) for(laListItemPointer* lip=me->fl->l.pFirst;lip;lip=lip->pNext){
  542. tnsMEdge*ie=lip->p; if(ie!=me) continue; if(tnsMMeshLoopIsInverted(lip)){ LA_SWAP(laListItemPointer*,lipa1,lipa2); }
  543. lstInsertItemBefore(&me->fl->l,lipa1,lip); lstInsertItemBefore(&me->fl->l,lipa2,lip); lstRemoveItem(&me->fl->l, lip); memLeave(lip); me->fl->looplen++;
  544. }
  545. if(me->fr) for(laListItemPointer* lip=me->fr->l.pFirst;lip;lip=lip->pNext){
  546. tnsMEdge*ie=lip->p; if(ie!=me) continue; if(tnsMMeshLoopIsInverted(lip)){ LA_SWAP(laListItemPointer*,lipb1,lipb2); }
  547. lstInsertItemBefore(&me->fr->l,lipb1,lip); lstInsertItemBefore(&me->fr->l,lipb2,lip); lstRemoveItem(&me->fr->l, lip); memLeave(lip); me->fr->looplen++;
  548. }
  549. me->fl=me->fr=0; tnsMMeshRemoveEdgeFace(mo,me);
  550. if(ref_e1v_optional&&tnsMMeshEdgeShareVert(me1, ref_e1v_optional)){ if(r_e1)*r_e1=me1; if(r_e2)*r_e2=me2; }else{ if(r_e1)*r_e1=me2; if(r_e2)*r_e2=me1; }
  551. //tnsPrintMeshTopology(mo);
  552. return 1;
  553. }
  554. tnsMVert* tnsMMeshEdgeInsertVertAt(tnsMeshObject* mo, tnsMEdge* me, real at, tnsMVert* ref_e1v_optional, tnsMEdge** r_e1, tnsMEdge** r_e2){
  555. if(!me||at<=0||at>=1) return 0; tnsMVert* mv=tnsMMeshNewVert(mo);
  556. tnsInterpolate3dv(me->vl->p, me->vr->p, at, mv->p);
  557. if(tnsMMeshEdgeInsertVert(mo,me,mv,ref_e1v_optional,r_e1,r_e2)) return mv; return 0;
  558. }
  559. void tnsMMeshRemoveFaceOnly(tnsMeshObject* mo, tnsMFace* mf){
  560. if(!mf) return; tnsMEdge* me;
  561. while(me=lstPopPointerLeave(&mf->l)){ if(me->fl==mf) me->fl=0; elif(me->fr==mf) me->fr=0; }
  562. lstRemoveItem(&mo->mf,mf); memLeave(mf); mo->totmf--;
  563. tnsMMeshClearFirstLastSelection(mo);
  564. }
  565. void tnsMMeshRemoveEdgeFace(tnsMeshObject* mo, tnsMEdge* me){
  566. if(!me) return;
  567. tnsMMeshRemoveFaceOnly(mo, me->fl); tnsMMeshRemoveFaceOnly(mo, me->fr);
  568. lstRemovePointerLeave(&me->vl->elink, me); lstRemovePointerLeave(&me->vr->elink, me);
  569. lstRemoveItem(&mo->me,me); memLeave(me); mo->totme--;
  570. tnsMMeshClearFirstLastSelection(mo);
  571. }
  572. void tnsMMeshRemoveVertEdgeFace(tnsMeshObject* mo, tnsMVert* mv){
  573. if(!mv) return; tnsMEdge* me;
  574. while(me=lstPopPointerLeave(&mv->elink)){ tnsMMeshRemoveEdgeFace(mo,me); }
  575. lstRemoveItem(&mo->mv,mv); memLeave(mv); mo->totmv--;
  576. tnsMMeshClearFirstLastSelection(mo);
  577. }
  578. void tnsMMeshRefreshIndex(tnsMeshObject* mo){
  579. int i;
  580. i=0; for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ mv->i=i; i++; } mo->totmv=i;
  581. i=0; for(tnsMEdge* me=mo->me.pFirst;me;me=me->Item.pNext){ me->i=i; i++; } mo->totme=i;
  582. i=0; for(tnsMFace* mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){ mf->i=i; i++; } mo->totmf=i;
  583. }
  584. void tnsClearMesh(tnsMeshObject* mo){
  585. arrFree(&mo->v, &mo->maxv); mo->totv=0;
  586. arrFree(&mo->e, &mo->maxe); mo->tote=0;
  587. if(mo->f) for(int i=0;i<mo->totf;i++){ if(mo->f[i].loop) free(mo->f[i].loop); }
  588. arrFree(&mo->f, &mo->maxf); mo->totf=0;
  589. }
  590. void tnsClearMMesh(tnsMeshObject* mo){
  591. tnsMFace* mf; tnsMEdge* me; tnsMVert* mv;
  592. while(mf=lstPopItem(&mo->mf)){ while(lstPopPointerLeave(&mf->l)); memLeave(mf); }
  593. while(me=lstPopItem(&mo->me)){ memLeave(me); }
  594. while(mv=lstPopItem(&mo->mv)){ while(lstPopPointerLeave(&mv->elink)); memLeave(mv); }
  595. mo->totmv=mo->totme=mo->totmf=0;
  596. }
  597. void tnsMMeshFromMesh(tnsMeshObject* mo){
  598. tnsClearMMesh(mo);
  599. tnsEdgeHash* eh=tnsCreateEdgeHash(mo->totv); //mo->totmv=mo->totv; mo->totme=mo->tote; mo->totmf=mo->totf;
  600. for(int i=0;i<mo->totf;i++){
  601. tnsFace* f=&mo->f[i];
  602. for(int j=0;j<f->looplen-1;j++){ tnsEdgeHashAddVertPair(eh, f->loop[j], f->loop[j+1]); }
  603. tnsEdgeHashAddVertPair(eh, f->loop[f->looplen-1], f->loop[0]);
  604. }
  605. for(int i=0;i<eh->max;i++){
  606. tnsEdgeHashVert* ehv=&eh->vl[i];
  607. for(int j=0;j<ehv->next;j++){ tnsMEdge*me=tnsMMeshNewEdge(mo); ehv->e[j].me=me; }
  608. }
  609. for(int i=0;i<mo->totv;i++){ tnsVert*v=&mo->v[i]; tnsMVert*mv=tnsMMeshNewVert(mo); eh->vl[i].mv=mv;
  610. tnsVectorSet3v(mv->p,mo->v[i].p); mv->flags=mo->v[i].flags; tnsVectorSet3v(mv->n,v->n); }
  611. for(int i=0;i<mo->totf;i++){
  612. tnsFace* f=&mo->f[i]; tnsMFace* mf=tnsMMeshNewFace(mo); mf->flags=f->flags;
  613. for(int j=0;j<f->looplen;j++){ int v2=j+1; if(j==f->looplen-1) v2=0;
  614. tnsEdgeHashEdge* ehe=tnsEdgeHashGetEdge(eh,f->loop[j],f->loop[v2]);
  615. tnsMEdge* me=ehe->me; tnsMMeshEdgeAssignVerts(me,eh->vl[f->loop[j]].mv,eh->vl[f->loop[v2]].mv);
  616. tnsMMeshFaceAddEdge(mf,me); tnsVectorSet3v(mf->n,f->n); mf->mat=f->mat;
  617. }
  618. }
  619. tnsMMeshEnsureSelectionFromVerts(mo);
  620. tnsDestroyEdgeHash(eh);
  621. }
  622. void tnsMeshFromMMesh(tnsMeshObject* mo){
  623. tnsClearMesh(mo);
  624. tnsInitMesh(mo, mo->totmv, 0, mo->totmf); int i=0;
  625. /* Vertex index should already correct. */
  626. //for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ mv->i=i; i++; }
  627. for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ tnsVert* v=tnsFillVert(mo, LA_COLOR3(mv->p)); tnsFillVertNormal(v,mv->n); v->flags=mv->flags; }
  628. for(tnsMFace* mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){ tnsFace* f=tnsFillFace(mo, mf->looplen, -1); f->flags=mf->flags;
  629. int j=0; for(laListItemPointer* lip=mf->l.pFirst;lip;lip=lip->pNext){
  630. laListItemPointer* next=lip->pNext; if(!next) next=mf->l.pFirst; tnsMEdge* me0=lip->p, *me1=next->p;
  631. tnsFillFaceLoop(f, j, tnsMMeshEdgeStartingVert(me0,me1)->i); j++;
  632. }
  633. tnsFillFaceNormal(f,mf->n); f->mat=mf->mat;
  634. }
  635. mo->totv=mo->totmv; mo->totf=mo->totmf;
  636. mo->maxv=mo->totv; mo->maxe=mo->tote; mo->maxf=mo->totf;
  637. if((!mo->maxv) && mo->v) arrFree(&mo->v, &mo->maxv);
  638. if((!mo->maxe) && mo->e) arrFree(&mo->e, &mo->maxe);
  639. if((!mo->maxf) && mo->f) arrFree(&mo->f, &mo->maxf);
  640. tnsClearMMesh(mo);
  641. }
  642. void tnsMeshEnterEditMode(tnsMeshObject* mo){
  643. if(mo->Mode==TNS_MESH_EDIT_MODE) return;
  644. tnsMMeshFromMesh(mo);
  645. mo->Mode = TNS_MESH_EDIT_MODE;
  646. tnsInvalidateMeshBatch(mo);
  647. tnsInvalidateEvaluation(mo);
  648. }
  649. void tnsMeshLeaveEditMode(tnsMeshObject* mo){
  650. if(mo->Mode==TNS_MESH_OBJECT_MODE) return;
  651. tnsMeshFromMMesh(mo);
  652. mo->Mode = TNS_MESH_OBJECT_MODE;
  653. tnsInvalidateMeshBatch(mo);
  654. tnsInvalidateEvaluation(mo);
  655. }
  656. void tnsMMeshClearFirstLastSelection(tnsMeshObject* mo){
  657. mo->FirstSelectE=mo->FirstSelectV=mo->LastSelectE=mo->LastSelectV=0;
  658. }
  659. int tnsMMeshAnySelected(tnsMeshObject* mo){
  660. for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ if(mv->flags&TNS_MESH_FLAG_SELECTED) return 1; }
  661. for(tnsMEdge* me=mo->me.pFirst;me;me=me->Item.pNext){ if(me->flags&TNS_MESH_FLAG_SELECTED) return 1; }
  662. for(tnsMFace* mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){ if(mf->flags&TNS_MESH_FLAG_SELECTED) return 1; } return 0;
  663. }
  664. void tnsMMeshClearExtraFlags(tnsMeshObject* mo){
  665. for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ mv->flags&=(~TNS_MESH_FLAG_PICKED); }
  666. for(tnsMEdge* me=mo->me.pFirst;me;me=me->Item.pNext){ me->flags&=(~TNS_MESH_FLAG_PICKED); /*me->flags&=(~TNS_MESH_FLAG_LOOP_REVERSE);*/ }
  667. for(tnsMFace* mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){ mf->flags&=(~TNS_MESH_FLAG_PICKED); }
  668. }
  669. void tnsMMeshDeselectAll(tnsMeshObject* mo){
  670. for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ mv->flags&=(~TNS_MESH_FLAG_SELECTED); }
  671. for(tnsMEdge* me=mo->me.pFirst;me;me=me->Item.pNext){ me->flags&=(~TNS_MESH_FLAG_SELECTED); }
  672. for(tnsMFace* mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){ mf->flags&=(~TNS_MESH_FLAG_SELECTED); }
  673. tnsMMeshClearFirstLastSelection(mo);
  674. }
  675. void tnsMMeshSelectAll(tnsMeshObject* mo){
  676. for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ mv->flags|=TNS_MESH_FLAG_SELECTED; }
  677. for(tnsMEdge* me=mo->me.pFirst;me;me=me->Item.pNext){ me->flags|=TNS_MESH_FLAG_SELECTED; }
  678. for(tnsMFace* mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){ mf->flags|=TNS_MESH_FLAG_SELECTED; }
  679. }
  680. void tnsMMeshSelectVert(tnsMeshObject* mo, tnsMVert* mv, int select, int toggle){
  681. if(!mo) return;
  682. if(toggle) tnsMMeshSelectVert(mo,mv,(mv->flags&TNS_MESH_FLAG_SELECTED?0:1),0);
  683. elif(select) mv->flags|=TNS_MESH_FLAG_SELECTED; else mv->flags&=(~TNS_MESH_FLAG_SELECTED);
  684. if(!mo->FirstSelectV) mo->FirstSelectV=mv; mo->LastSelectV=mv;
  685. }
  686. void tnsMMeshSelectEdge(tnsMeshObject* mo, tnsMEdge* me, int select, int toggle){
  687. if(!mo) return;
  688. if(toggle) tnsMMeshSelectEdge(mo,me,(me->flags&TNS_MESH_FLAG_SELECTED?0:1),0);
  689. elif(select) me->flags|=TNS_MESH_FLAG_SELECTED; else me->flags&=(~TNS_MESH_FLAG_SELECTED);
  690. if(!mo->FirstSelectE) mo->FirstSelectE=me; mo->LastSelectE=me;
  691. }
  692. void tnsMMeshEnsureSelectionFromVerts(tnsMeshObject* mo){
  693. for(tnsMEdge* me=mo->me.pFirst;me;me=me->Item.pNext){ me->flags&=(~TNS_MESH_FLAG_SELECTED);
  694. if(me->vl->flags&me->vr->flags&TNS_MESH_FLAG_SELECTED) me->flags|=TNS_MESH_FLAG_SELECTED;
  695. }
  696. for(tnsMFace* mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){ int sel=1; mf->flags&=(~TNS_MESH_FLAG_SELECTED);
  697. for(laListItemPointer* lip=mf->l.pFirst;lip;lip=lip->pNext){ tnsMEdge*me=lip->p; if(!(me->flags&TNS_MESH_FLAG_SELECTED)){ sel=0; break; } }
  698. if(sel){ mf->flags|=TNS_MESH_FLAG_SELECTED; }
  699. }
  700. }
  701. void tnsMMeshEnsureSelectionFromEdges(tnsMeshObject* mo){
  702. for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ mv->flags&=(~TNS_MESH_FLAG_SELECTED);
  703. for(laListItemPointer* lip=mv->elink.pFirst;lip;lip=lip->pNext){ tnsMEdge*me=lip->p; if(me->flags&TNS_MESH_FLAG_SELECTED){ mv->flags|=TNS_MESH_FLAG_SELECTED; break; } }
  704. }
  705. for(tnsMFace* mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){ int sel=1; mf->flags&=(~TNS_MESH_FLAG_SELECTED);
  706. for(laListItemPointer* lip=mf->l.pFirst;lip;lip=lip->pNext){ tnsMEdge*me=lip->p; if(!(me->flags&TNS_MESH_FLAG_SELECTED)){ sel=0; break; } }
  707. if(sel){ mf->flags|=TNS_MESH_FLAG_SELECTED; }
  708. }
  709. }
  710. void tnsMMeshEnsureSelection(tnsMeshObject* mo, int SelectMode){
  711. if(SelectMode==LA_CANVAS_SELECT_MODE_VERTS){ tnsMMeshEnsureSelectionFromVerts(mo); }
  712. elif(SelectMode==LA_CANVAS_SELECT_MODE_EDGES){ tnsMMeshEnsureSelectionFromEdges(mo); }
  713. }
  714. tnsMEdge* tnsMMeshGetRingEdge(tnsMEdge* me, int from_right){
  715. tnsMEdge* candidate=0; tnsMVert* VL=from_right?me->vr:me->vl, *VR=from_right?me->vl:me->vr;
  716. for(laListItemPointer* lip=VL->elink.pFirst;lip;lip=lip->pNext){
  717. tnsMEdge* te=lip->p; if(te==me || (te->flags&TNS_MESH_FLAG_PICKED)){ continue; }
  718. if((!te->fl) || (!te->fr)){ candidate=te; break; }
  719. }
  720. if(candidate){ candidate->flags|=TNS_MESH_FLAG_PICKED; return candidate; }
  721. if(lstCountElements(&VL->elink)!=4) return 0;
  722. tnsMFace* f1=0,*f2=0;
  723. for(laListItemPointer* lip=VL->elink.pFirst;lip;lip=lip->pNext){
  724. tnsMEdge* te=lip->p; if(te==me || (te->flags&TNS_MESH_FLAG_PICKED)){ continue; }
  725. if(tnsMMeshFaceHasVert(te->fl,VR) || tnsMMeshFaceHasVert(te->fr,VR)){ continue; }
  726. else{ te->flags|=TNS_MESH_FLAG_PICKED; return te; }
  727. }
  728. return 0;
  729. }
  730. void tnsMMeshExpandRingList(tnsMeshObject* mo, tnsMEdge* me, laListHandle* lst){
  731. tnsMEdge* el,*er;
  732. int flc=0,frc=0; if(me->fl) flc=me->fl->looplen; if(me->fr) frc=me->fr->looplen;
  733. if(TNS_MAX2(flc,frc)>4){
  734. if(flc>frc){ for(laListItemPointer* lip=me->fl->l.pFirst;lip;lip=lip->pNext){ lstAppendPointer(lst,lip->p); } return; }
  735. elif(flc<frc){ for(laListItemPointer* lip=me->fr->l.pFirst;lip;lip=lip->pNext){ lstAppendPointer(lst,lip->p); } return; }
  736. }
  737. if(el=tnsMMeshGetRingEdge(me,0)){ lstAppendPointer(lst,el); tnsMMeshExpandRingList(mo,el,lst); }
  738. if(er=tnsMMeshGetRingEdge(me,1)){ lstAppendPointer(lst,er); tnsMMeshExpandRingList(mo,er,lst); }
  739. }
  740. tnsMEdge* tnsMMeshGetBandEdge(tnsMEdge* me, int from_right){
  741. tnsMFace* FL=from_right?me->fl:me->fr; if(!FL) return 0;
  742. if(FL->looplen!=4){ return 0;}
  743. for(laListItemPointer* lip=FL->l.pFirst;lip;lip=lip->pNext){
  744. tnsMEdge* te=lip->p; if((!(te->flags&TNS_MESH_FLAG_PICKED)) && (!tnsMMeshEdgeShareVert(te,me))){
  745. te->flags|=TNS_MESH_FLAG_PICKED; return te;
  746. }
  747. }
  748. return 0;
  749. }
  750. void tnsMMeshExpandBandList(tnsMeshObject* mo, tnsMEdge* me, laListHandle* lst){
  751. tnsMEdge* el,*er;
  752. if(el=tnsMMeshGetBandEdge(me,0)){ lstAppendPointer(lst,el); tnsMMeshExpandBandList(mo,el,lst); }
  753. if(er=tnsMMeshGetBandEdge(me,1)){ lstAppendPointer(lst,er); tnsMMeshExpandBandList(mo,er,lst); }
  754. }
  755. int tnsMMeshSelectRingBandFrom(tnsMeshObject* mo, tnsMEdge* me, int ring_band, int select, int toggle){
  756. if(!ring_band) return 0;
  757. tnsMMeshClearExtraFlags(mo);
  758. laListHandle lst={0}; lstAppendPointer(&lst,me); me->flags|=TNS_MESH_FLAG_PICKED;
  759. if(ring_band==1) tnsMMeshExpandRingList(mo,me,&lst);
  760. elif(ring_band==2) tnsMMeshExpandBandList(mo,me,&lst);
  761. if(lst.pFirst==lst.pLast){ while(lstPopPointer(&lst)); return 0; }
  762. int has_idle=0;
  763. if(toggle){
  764. for(laListItemPointer* lip=lst.pFirst;lip;lip=lip->pNext){
  765. tnsMEdge* te=lip->p; if(te!=me && (!(te->flags&TNS_MESH_FLAG_SELECTED))) has_idle=1;
  766. if(has_idle){ break; }
  767. }
  768. if(has_idle){ select=1; }else{ select=0; }
  769. }
  770. for(laListItemPointer* lip=lst.pFirst;lip;lip=lip->pNext){
  771. tnsMEdge* te=lip->p;
  772. if(select){ te->flags|=TNS_MESH_FLAG_SELECTED; te->vl->flags|=TNS_MESH_FLAG_SELECTED; te->vr->flags|=TNS_MESH_FLAG_SELECTED; }
  773. else{ te->flags&=(~TNS_MESH_FLAG_SELECTED); te->vl->flags&=(~TNS_MESH_FLAG_SELECTED); te->vr->flags&=(~TNS_MESH_FLAG_SELECTED); }
  774. }
  775. while(lstPopPointer(&lst)); return 1;
  776. }
  777. void tnsMMeshSelectLinkedRecursive(tnsMeshObject* mo, tnsMVert* mv){
  778. for(laListItemPointer* lip=mv->elink.pFirst;lip;lip=lip->pNext){ tnsMEdge* me=lip->p;
  779. if(!(me->vl->flags&TNS_MESH_FLAG_SELECTED)){ me->vl->flags|=TNS_MESH_FLAG_SELECTED;tnsMMeshSelectLinkedRecursive(mo,me->vl); }
  780. if(!(me->vr->flags&TNS_MESH_FLAG_SELECTED)){ me->vr->flags|=TNS_MESH_FLAG_SELECTED;tnsMMeshSelectLinkedRecursive(mo,me->vr); }
  781. }
  782. }
  783. void tnsMMeshSelectLinked(tnsMeshObject* mo){
  784. if((!mo) || (mo->Mode!=TNS_MESH_EDIT_MODE)){ return; }
  785. for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){
  786. if(mv->flags&TNS_MESH_FLAG_SELECTED){ tnsMMeshSelectLinkedRecursive(mo,mv); }
  787. }
  788. tnsMMeshEnsureSelectionFromVerts(mo);
  789. }
  790. void tnsMMeshReduceFaceEdge(tnsMeshObject* mo, tnsMFace* mf, tnsMEdge* me){
  791. lstRemovePointerLeave(&mf->l,me); mf->looplen--;
  792. }
  793. void tnsMMeshFaceReplaceEdgeWith(tnsMFace* mf, tnsMEdge* to_be_replaced, tnsMEdge* as){
  794. if(!mf) return; for(laListItemPointer* lip=mf->l.pFirst;lip;lip=lip->pNext){
  795. if(lip->p==to_be_replaced){ lip->p=as; return; }
  796. }
  797. }
  798. void tnsMMeshReduceZippedFace(tnsMeshObject* mo, tnsMFace* mf){
  799. if(mf->looplen>2) return; if(mf->looplen<2){ printf("mf->looplen < 2 ?\n");return; }
  800. tnsMEdge* me1=((laListItemPointer*)mf->l.pFirst)->p,*me2=((laListItemPointer*)mf->l.pLast)->p;
  801. tnsMVert* vl=me1->vl; tnsMVert*vr=me1->vr;
  802. lstRemovePointerLeave(&vl->elink,me2); lstRemovePointerLeave(&vr->elink,me2);
  803. tnsMMeshFaceReplaceEdgeWith(me1->fl,me2,me1); tnsMMeshFaceReplaceEdgeWith(me1->fr,me2,me1);
  804. tnsMMeshFaceReplaceEdgeWith(me2->fl,me2,me1); tnsMMeshFaceReplaceEdgeWith(me2->fr,me2,me1);
  805. if(me1->fl==mf){ me1->fl=((me2->fl==mf)?me2->fr:me2->fl); }elif(me1->fr==mf){ me1->fr=((me2->fl==mf)?me2->fr:me2->fl); }
  806. lstRemoveItem(&mo->me,me2); mo->totme--; memLeave(me2);
  807. lstRemoveItem(&mo->mf,mf); mo->totmf--; memLeave(mf);
  808. tnsMMeshClearFirstLastSelection(mo);
  809. }
  810. int tnsMMeshVertsCanMerge(tnsMeshObject* mo, tnsMVert* into, tnsMVert* mv){
  811. for(laListItemPointer* lip=into->elink.pFirst;lip;lip=lip->pNext){ tnsMEdge* me=lip->p;
  812. for(laListItemPointer* lip2=mv->elink.pFirst;lip2;lip2=lip2->pNext){ tnsMEdge* me2=lip2->p; if(me==me2) continue;
  813. tnsMVert* mvs=tnsMMeshEdgeShareVert(me,me2); if((!mvs)||mvs==mv||mvs==into) continue; int count=0;
  814. if(me->fl) count++; if(me->fr) count++; if(me2->fl) count++; if(me2->fr) count++;
  815. tnsMFace* sf=tnsMMeshEdgeShareFace(me,me2); if(sf){count--;}
  816. if ((sf==me->fl && me->fr && (me->fr==me2->fl||me->fr==me2->fr))||
  817. (sf==me->fr && me->fl && (me->fl==me2->fl||me->fl==me2->fr))){ return 0; }
  818. if((sf && count>3) || (!sf && count>2)){ return 0; }
  819. }
  820. }
  821. return 1;
  822. }
  823. int tnsMMeshMergeVerts(tnsMeshObject* mo, tnsMVert* into, tnsMVert* mv){
  824. if(!tnsMMeshVertsCanMerge(mo,into,mv)) return 0;
  825. tnsMEdge* me=tnsMMeshMakeEdge(mo,into,mv);
  826. if(me->fl){ tnsMMeshReduceFaceEdge(mo,me->fl,me); }
  827. if(me->fr){ tnsMMeshReduceFaceEdge(mo,me->fr,me); }
  828. tnsMEdge* me2; while(me2=lstPopPointerLeave(&mv->elink)){
  829. if(me2==me) continue; lstAppendPointer(&into->elink,me2);
  830. if(me2->vl==mv){ me2->vl=into; }elif(me2->vr==mv){ me2->vr=into; }
  831. }
  832. if(me->fl){ tnsMMeshReduceZippedFace(mo,me->fl); }
  833. if(me->fr){ tnsMMeshReduceZippedFace(mo,me->fr); }
  834. lstRemovePointerLeave(&into->elink,me);
  835. lstRemoveItem(&mo->mv,mv); memLeave(mv); mo->totmv--;
  836. lstRemoveItem(&mo->me,me); memLeave(me); mo->totme--;
  837. tnsMMeshClearFirstLastSelection(mo);
  838. //tnsPrintMeshTopology(mo);
  839. return 1;
  840. }
  841. tnsMeshObject *tnsCreateMeshEmpty(tnsObject *under, char *Name, real AtX, real AtY, real AtZ){
  842. tnsMeshObject *mo = memAcquireHyper(sizeof(tnsMeshObject));
  843. tnsInitObjectBase(&mo->Base, under, Name, TNS_OBJECT_MESH, AtX, AtY, AtZ, 0, 0, 0, 1.0f, TNS_ROTATION_XYZ_EULER, 1.0f);
  844. return mo;
  845. }
  846. tnsMeshObject *tnsCreateMeshPlane(tnsObject *under, char *Name, real AtX, real AtY, real AtZ, real size){
  847. tnsMeshObject *mo=tnsCreateMeshEmpty(under, Name, AtX, AtY, AtZ);
  848. tnsInitMeshPlane(mo, size);
  849. tnsInvalidateMeshBatch(mo);
  850. return mo;
  851. }