|  | @@ -199,25 +199,29 @@ float* tnsGetDrawingVertArray(tnsMeshObject* mo, int* r_tot_render_v, float** r_
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  |      }else{
 |  |      }else{
 | 
											
												
													
														|  |          (*idcolors)=calloc(1,(totv+extraverts)*3*sizeof(float));
 |  |          (*idcolors)=calloc(1,(totv+extraverts)*3*sizeof(float));
 | 
											
												
													
														|  | -        (*edgeelems)=calloc(1,(extraverts)*2*sizeof(int));
 |  | 
 | 
											
												
													
														|  | -        (*editcolors)=calloc(1,totv*4*sizeof(float)*extraverts);
 |  | 
 | 
											
												
													
														|  | 
 |  | +        if(extraverts){
 | 
											
												
													
														|  | 
 |  | +            (*edgeelems)=calloc(1,(extraverts)*2*sizeof(int));
 | 
											
												
													
														|  | 
 |  | +            (*editcolors)=calloc(1,totv*4*sizeof(float)*extraverts);
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  |          for(tnsMVert*mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ int i=mv->i;
 |  |          for(tnsMVert*mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ int i=mv->i;
 | 
											
												
													
														|  |              tnsVectorSet3v(&p[i*3],mv->p); tnsVectorSet3v(&n[i*3],mv->n);
 |  |              tnsVectorSet3v(&p[i*3],mv->p); tnsVectorSet3v(&n[i*3],mv->n);
 | 
											
												
													
														|  |              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;
 |  |              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;
 | 
											
												
													
														|  |              (*idcolors)[i*3]=r; (*idcolors)[i*3+1]=g; (*idcolors)[i*3+2]=b;
 |  |              (*idcolors)[i*3]=r; (*idcolors)[i*3+1]=g; (*idcolors)[i*3+2]=b;
 | 
											
												
													
														|  |              real* c=(mv->flags&TNS_MESH_FLAG_SELECTED)?laAccentColor(LA_BT_SVERTEX):laAccentColor(LA_BT_VERTEX);
 |  |              real* c=(mv->flags&TNS_MESH_FLAG_SELECTED)?laAccentColor(LA_BT_SVERTEX):laAccentColor(LA_BT_VERTEX);
 | 
											
												
													
														|  | -            (*editcolors)[i*4]=c[0]; (*editcolors)[i*4+1]=c[1]; (*editcolors)[i*4+2]=c[2]; (*editcolors)[i*4+3]=c[3];
 |  | 
 | 
											
												
													
														|  | 
 |  | +            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];}
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  | -        for(tnsMEdge*me=mo->me.pFirst;me;me=me->Item.pNext){ int ei=me->i;
 |  | 
 | 
											
												
													
														|  | -            (*edgeelems)[ei*2]=mo->totmv+mo->totmf+ei*2; (*edgeelems)[ei*2+1]=mo->totmv+mo->totmf+ei*2+1;
 |  | 
 | 
											
												
													
														|  | -            float* eidcolor1=&(*idcolors)[(*edgeelems)[ei*2]*3], *eidcolor2=&(*idcolors)[(*edgeelems)[ei*2+1]*3];
 |  | 
 | 
											
												
													
														|  | -            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;
 |  | 
 | 
											
												
													
														|  | -            tnsVectorSet3(eidcolor1,r,g,b); tnsVectorSet3(eidcolor2,r,g,b);
 |  | 
 | 
											
												
													
														|  | -            int se1=(*edgeelems)[ei*2];   tnsVectorSet3v(&p[se1*3],me->vl->p);
 |  | 
 | 
											
												
													
														|  | -            int se2=(*edgeelems)[ei*2+1]; tnsVectorSet3v(&p[se2*3],me->vr->p);
 |  | 
 | 
											
												
													
														|  | -            float* eedcolor1=&(*editcolors)[(*edgeelems)[ei*2]*4], *eedcolor2=&(*editcolors)[(*edgeelems)[ei*2+1]*4];
 |  | 
 | 
											
												
													
														|  | -            real* c=(me->flags&TNS_MESH_FLAG_SELECTED)?laAccentColor(LA_BT_SEDGE):laAccentColor(LA_BT_EDGE);
 |  | 
 | 
											
												
													
														|  | -            tnsVectorSet4v(eedcolor1,c); tnsVectorSet4v(eedcolor2,c);
 |  | 
 | 
											
												
													
														|  | 
 |  | +        if(extraverts){ 
 | 
											
												
													
														|  | 
 |  | +            for(tnsMEdge*me=mo->me.pFirst;me;me=me->Item.pNext){ int ei=me->i;
 | 
											
												
													
														|  | 
 |  | +                (*edgeelems)[ei*2]=mo->totmv+mo->totmf+ei*2; (*edgeelems)[ei*2+1]=mo->totmv+mo->totmf+ei*2+1;
 | 
											
												
													
														|  | 
 |  | +                float* eidcolor1=&(*idcolors)[(*edgeelems)[ei*2]*3], *eidcolor2=&(*idcolors)[(*edgeelems)[ei*2+1]*3];
 | 
											
												
													
														|  | 
 |  | +                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;
 | 
											
												
													
														|  | 
 |  | +                tnsVectorSet3(eidcolor1,r,g,b); tnsVectorSet3(eidcolor2,r,g,b);
 | 
											
												
													
														|  | 
 |  | +                int se1=(*edgeelems)[ei*2];   tnsVectorSet3v(&p[se1*3],me->vl->p);
 | 
											
												
													
														|  | 
 |  | +                int se2=(*edgeelems)[ei*2+1]; tnsVectorSet3v(&p[se2*3],me->vr->p);
 | 
											
												
													
														|  | 
 |  | +                float* eedcolor1=&(*editcolors)[(*edgeelems)[ei*2]*4], *eedcolor2=&(*editcolors)[(*edgeelems)[ei*2+1]*4];
 | 
											
												
													
														|  | 
 |  | +                real* c=(me->flags&TNS_MESH_FLAG_SELECTED)?laAccentColor(LA_BT_SEDGE):laAccentColor(LA_BT_EDGE);
 | 
											
												
													
														|  | 
 |  | +                tnsVectorSet4v(eedcolor1,c); tnsVectorSet4v(eedcolor2,c);
 | 
											
												
													
														|  | 
 |  | +            }
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  |          int start=mo->totmv*3; int fi=0; for(tnsMFace*mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){
 |  |          int start=mo->totmv*3; int fi=0; for(tnsMFace*mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){
 | 
											
												
													
														|  |              tnsMVert* sv=tnsGetMFaceLastVert(mf); tnsVectorSet3v(&p[start+fi*3],sv->p); tnsVectorSet3v(&n[start+fi*3],mf->n); fi++;
 |  |              tnsMVert* sv=tnsGetMFaceLastVert(mf); tnsVectorSet3v(&p[start+fi*3],sv->p); tnsVectorSet3v(&n[start+fi*3],mf->n); fi++;
 | 
											
										
											
												
													
														|  | @@ -248,8 +252,11 @@ void tnsRegenerateMeshBatch(tnsMeshObject* mo){
 | 
											
												
													
														|  |      if(!v){ if(elem){free(elem);} if(eelems){free(eelems);} return; }
 |  |      if(!v){ if(elem){free(elem);} if(eelems){free(eelems);} return; }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      mo->Batch = tnsCreateBatch(totv, 3, v, 3, n, 4, editcolors);
 |  |      mo->Batch = tnsCreateBatch(totv, 3, v, 3, n, 4, editcolors);
 | 
											
												
													
														|  | -    tnsBatchCommand*c=tnsCreateCommand(mo->Batch, "body", tottri, 3, GL_TRIANGLES, elem, 0);
 |  | 
 | 
											
												
													
														|  | -    tnsCommandUseUniformColor(c,meshcolor);
 |  | 
 | 
											
												
													
														|  | 
 |  | +    tnsBatchCommand*c;
 | 
											
												
													
														|  | 
 |  | +    if(elem){
 | 
											
												
													
														|  | 
 |  | +        c=tnsCreateCommand(mo->Batch, "body", tottri, 3, GL_TRIANGLES, elem, 0);
 | 
											
												
													
														|  | 
 |  | +        tnsCommandUseUniformColor(c,meshcolor);
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  |      free(elem); free(v); free(n);
 |  |      free(elem); free(v); free(n);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      if(mo->Mode==TNS_MESH_EDIT_MODE){
 |  |      if(mo->Mode==TNS_MESH_EDIT_MODE){
 | 
											
										
											
												
													
														|  | @@ -260,10 +267,12 @@ void tnsRegenerateMeshBatch(tnsMeshObject* mo){
 | 
											
												
													
														|  |          c= tnsCreateCommand(mo->Batch, "verts", mo->totmv, 3, GL_POINTS, 0, 1);
 |  |          c= tnsCreateCommand(mo->Batch, "verts", mo->totmv, 3, GL_POINTS, 0, 1);
 | 
											
												
													
														|  |          c= tnsCreateCommand(mo->Batch, "verts_select", mo->totmv, 3, GL_POINTS, 0, 1);
 |  |          c= tnsCreateCommand(mo->Batch, "verts_select", mo->totmv, 3, GL_POINTS, 0, 1);
 | 
											
												
													
														|  |          tnsCommandOverrideColorArray(c, mo->Batch->NumVert, 3, idcolors);
 |  |          tnsCommandOverrideColorArray(c, mo->Batch->NumVert, 3, idcolors);
 | 
											
												
													
														|  | -        c= tnsCreateCommand(mo->Batch, "edges_select", mo->totme, 2, GL_LINES, eelems, 1);
 |  | 
 | 
											
												
													
														|  | -        tnsCommandOverrideColorArray(c, mo->Batch->NumVert, 3, idcolors);
 |  | 
 | 
											
												
													
														|  | -        c= tnsCreateCommand(mo->Batch, "edges", mo->totme, 2, GL_LINES, eelems, 1);
 |  | 
 | 
											
												
													
														|  | -        tnsCommandOverrideColorArray(c, mo->Batch->NumVert, 4, editcolors);
 |  | 
 | 
											
												
													
														|  | 
 |  | +        if(eelems){
 | 
											
												
													
														|  | 
 |  | +            c= tnsCreateCommand(mo->Batch, "edges_select", mo->totme, 2, GL_LINES, eelems, 1);
 | 
											
												
													
														|  | 
 |  | +            tnsCommandOverrideColorArray(c, mo->Batch->NumVert, 3, idcolors);
 | 
											
												
													
														|  | 
 |  | +            c= tnsCreateCommand(mo->Batch, "edges", mo->totme, 2, GL_LINES, eelems, 1);
 | 
											
												
													
														|  | 
 |  | +            tnsCommandOverrideColorArray(c, mo->Batch->NumVert, 4, editcolors);
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  |          //for(int i=0;i<mo->totme*2;i++){ printf("%d ",eelems[i]); } printf("\n");
 |  |          //for(int i=0;i<mo->totme*2;i++){ printf("%d ",eelems[i]); } printf("\n");
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |      if(idcolors) free(idcolors); if(editcolors) free(editcolors); if(eelems) free(eelems);
 |  |      if(idcolors) free(idcolors); if(editcolors) free(editcolors); if(eelems) free(eelems);
 | 
											
										
											
												
													
														|  | @@ -371,7 +380,7 @@ void tnsMMeshEdgeAssignVerts(tnsMEdge* me,tnsMVert* mv1,tnsMVert* mv2){
 | 
											
												
													
														|  |      me->vl=mv1; me->vr=mv2;
 |  |      me->vl=mv1; me->vr=mv2;
 | 
											
												
													
														|  |      lstAppendPointer(&me->vl->elink,me); lstAppendPointer(&me->vr->elink,me);
 |  |      lstAppendPointer(&me->vl->elink,me); lstAppendPointer(&me->vr->elink,me);
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  | -tnsMEdge* tnsMMeshVertShareEdge(tnsMVert* mv0, tnsMVert* mv1){
 |  | 
 | 
											
												
													
														|  | 
 |  | +tnsMEdge* tnsMMeshVertsShareEdge(tnsMVert* mv0, tnsMVert* mv1){
 | 
											
												
													
														|  |      for(laListItemPointer*lip=mv0->elink.pFirst;lip;lip=lip->pNext){ tnsMEdge* me=lip->p; if(tnsMMeshEdgeAnotherVert(me, mv0)==mv1) return me; } return 0;
 |  |      for(laListItemPointer*lip=mv0->elink.pFirst;lip;lip=lip->pNext){ tnsMEdge* me=lip->p; if(tnsMMeshEdgeAnotherVert(me, mv0)==mv1) return me; } return 0;
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  int tnsMMeshEdgeHasVert(tnsMEdge* me, tnsMVert* mv){
 |  |  int tnsMMeshEdgeHasVert(tnsMEdge* me, tnsMVert* mv){
 | 
											
										
											
												
													
														|  | @@ -387,7 +396,7 @@ tnsMVert* tnsMMeshEdgeShareVert(tnsMEdge* me0, tnsMEdge* me1){
 | 
											
												
													
														|  |      if(me0->vr==me1->vl || me0->vr==me1->vr) return me0->vr;
 |  |      if(me0->vr==me1->vl || me0->vr==me1->vr) return me0->vr;
 | 
											
												
													
														|  |      return 0;
 |  |      return 0;
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  | -tnsMVert* tnsMMeshEdgeAnotherVert(tnsMEdge* me, tnsVert* v){
 |  | 
 | 
											
												
													
														|  | 
 |  | +tnsMVert* tnsMMeshEdgeAnotherVert(tnsMEdge* me, tnsMVert* v){
 | 
											
												
													
														|  |      if(me->vl==v) return me->vr; if(me->vr==v) return me->vl;
 |  |      if(me->vl==v) return me->vr; if(me->vr==v) return me->vl;
 | 
											
												
													
														|  |      return 0;
 |  |      return 0;
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
										
											
												
													
														|  | @@ -482,7 +491,7 @@ tnsMFace* tnsMMeshMakeFaceN(tnsMeshObject* mo, int count, laListHandle* vip, tns
 | 
											
												
													
														|  |      while(lstPopPointer(&el));
 |  |      while(lstPopPointer(&el));
 | 
											
												
													
														|  |      return mf;
 |  |      return mf;
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  | -tnsMFace* tnsMMeshMakeFace4v(tnsMeshObject* mo, tnsVert* v1,tnsVert* v2,tnsVert* v3,tnsVert* v4){
 |  | 
 | 
											
												
													
														|  | 
 |  | +tnsMFace* tnsMMeshMakeFace4v(tnsMeshObject* mo, tnsMVert* v1,tnsMVert* v2,tnsMVert* v3,tnsMVert* v4){
 | 
											
												
													
														|  |      tnsMEdge* e1=tnsMMeshMakeEdge(mo,v1,v2); tnsMEdge* e2=tnsMMeshMakeEdge(mo,v2,v3);
 |  |      tnsMEdge* e1=tnsMMeshMakeEdge(mo,v1,v2); tnsMEdge* e2=tnsMMeshMakeEdge(mo,v2,v3);
 | 
											
												
													
														|  |      tnsMEdge* e3=tnsMMeshMakeEdge(mo,v3,v4); tnsMEdge* e4=tnsMMeshMakeEdge(mo,v4,v1);
 |  |      tnsMEdge* e3=tnsMMeshMakeEdge(mo,v3,v4); tnsMEdge* e4=tnsMMeshMakeEdge(mo,v4,v1);
 | 
											
												
													
														|  |      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
 |  |      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
 | 
											
										
											
												
													
														|  | @@ -525,17 +534,20 @@ void tnsMMeshRemoveFaceOnly(tnsMeshObject* mo, tnsMFace* mf){
 | 
											
												
													
														|  |      if(!mf) return; tnsMEdge* me;
 |  |      if(!mf) return; tnsMEdge* me;
 | 
											
												
													
														|  |      while(me=lstPopPointerLeave(&mf->l)){ if(me->fl==mf) me->fl=0; elif(me->fr==mf) me->fr=0; }
 |  |      while(me=lstPopPointerLeave(&mf->l)){ if(me->fl==mf) me->fl=0; elif(me->fr==mf) me->fr=0; }
 | 
											
												
													
														|  |      lstRemoveItem(&mo->mf,mf); memLeave(mf); mo->totmf--;
 |  |      lstRemoveItem(&mo->mf,mf); memLeave(mf); mo->totmf--;
 | 
											
												
													
														|  | 
 |  | +    tnsMMeshClearFirstLastSelection(mo);
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  void tnsMMeshRemoveEdgeFace(tnsMeshObject* mo, tnsMEdge* me){
 |  |  void tnsMMeshRemoveEdgeFace(tnsMeshObject* mo, tnsMEdge* me){
 | 
											
												
													
														|  |      if(!me) return;
 |  |      if(!me) return;
 | 
											
												
													
														|  |      tnsMMeshRemoveFaceOnly(mo, me->fl); tnsMMeshRemoveFaceOnly(mo, me->fr);
 |  |      tnsMMeshRemoveFaceOnly(mo, me->fl); tnsMMeshRemoveFaceOnly(mo, me->fr);
 | 
											
												
													
														|  |      lstRemovePointerLeave(&me->vl->elink, me); lstRemovePointerLeave(&me->vr->elink, me);
 |  |      lstRemovePointerLeave(&me->vl->elink, me); lstRemovePointerLeave(&me->vr->elink, me);
 | 
											
												
													
														|  |      lstRemoveItem(&mo->me,me); memLeave(me); mo->totme--;
 |  |      lstRemoveItem(&mo->me,me); memLeave(me); mo->totme--;
 | 
											
												
													
														|  | 
 |  | +    tnsMMeshClearFirstLastSelection(mo);
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  void tnsMMeshRemoveVertEdgeFace(tnsMeshObject* mo, tnsMVert* mv){
 |  |  void tnsMMeshRemoveVertEdgeFace(tnsMeshObject* mo, tnsMVert* mv){
 | 
											
												
													
														|  |      if(!mv) return; tnsMEdge* me;
 |  |      if(!mv) return; tnsMEdge* me;
 | 
											
												
													
														|  |      while(me=lstPopPointerLeave(&mv->elink)){ tnsMMeshRemoveEdgeFace(mo,me); }
 |  |      while(me=lstPopPointerLeave(&mv->elink)){ tnsMMeshRemoveEdgeFace(mo,me); }
 | 
											
												
													
														|  |      lstRemoveItem(&mo->mv,mv); memLeave(mv); mo->totmv--;
 |  |      lstRemoveItem(&mo->mv,mv); memLeave(mv); mo->totmv--;
 | 
											
												
													
														|  | 
 |  | +    tnsMMeshClearFirstLastSelection(mo);
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  void tnsMMeshRefreshIndex(tnsMeshObject* mo){
 |  |  void tnsMMeshRefreshIndex(tnsMeshObject* mo){
 | 
											
										
											
												
													
														|  | @@ -618,6 +630,9 @@ void tnsMeshLeaveEditMode(tnsMeshObject* mo){
 | 
											
												
													
														|  |      tnsInvalidateMeshBatch(mo);
 |  |      tnsInvalidateMeshBatch(mo);
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | 
 |  | +void tnsMMeshClearFirstLastSelection(tnsMeshObject* mo){
 | 
											
												
													
														|  | 
 |  | +    mo->FirstSelectE=mo->FirstSelectV=mo->LastSelectE=mo->LastSelectV=0;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  |  int tnsMMeshAnySelected(tnsMeshObject* mo){
 |  |  int tnsMMeshAnySelected(tnsMeshObject* mo){
 | 
											
												
													
														|  |      for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ if(mv->flags&TNS_MESH_FLAG_SELECTED) return 1; }
 |  |      for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ if(mv->flags&TNS_MESH_FLAG_SELECTED) return 1; }
 | 
											
												
													
														|  |      for(tnsMEdge* me=mo->me.pFirst;me;me=me->Item.pNext){ if(me->flags&TNS_MESH_FLAG_SELECTED) return 1; }
 |  |      for(tnsMEdge* me=mo->me.pFirst;me;me=me->Item.pNext){ if(me->flags&TNS_MESH_FLAG_SELECTED) return 1; }
 | 
											
										
											
												
													
														|  | @@ -632,6 +647,7 @@ void tnsMMeshDeselectAll(tnsMeshObject* mo){
 | 
											
												
													
														|  |      for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ mv->flags&=(~TNS_MESH_FLAG_SELECTED); }
 |  |      for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ mv->flags&=(~TNS_MESH_FLAG_SELECTED); }
 | 
											
												
													
														|  |      for(tnsMEdge* me=mo->me.pFirst;me;me=me->Item.pNext){ me->flags&=(~TNS_MESH_FLAG_SELECTED); }
 |  |      for(tnsMEdge* me=mo->me.pFirst;me;me=me->Item.pNext){ me->flags&=(~TNS_MESH_FLAG_SELECTED); }
 | 
											
												
													
														|  |      for(tnsMFace* mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){ mf->flags&=(~TNS_MESH_FLAG_SELECTED); }
 |  |      for(tnsMFace* mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){ mf->flags&=(~TNS_MESH_FLAG_SELECTED); }
 | 
											
												
													
														|  | 
 |  | +    tnsMMeshClearFirstLastSelection(mo);
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  void tnsMMeshSelectAll(tnsMeshObject* mo){
 |  |  void tnsMMeshSelectAll(tnsMeshObject* mo){
 | 
											
												
													
														|  |      for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ mv->flags|=TNS_MESH_FLAG_SELECTED; }
 |  |      for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ mv->flags|=TNS_MESH_FLAG_SELECTED; }
 | 
											
										
											
												
													
														|  | @@ -642,11 +658,13 @@ void tnsMMeshSelectVert(tnsMeshObject* mo, tnsMVert* mv, int select, int toggle)
 | 
											
												
													
														|  |      if(!mo) return;
 |  |      if(!mo) return;
 | 
											
												
													
														|  |      if(toggle) tnsMMeshSelectVert(mo,mv,(mv->flags&TNS_MESH_FLAG_SELECTED?0:1),0);
 |  |      if(toggle) tnsMMeshSelectVert(mo,mv,(mv->flags&TNS_MESH_FLAG_SELECTED?0:1),0);
 | 
											
												
													
														|  |      elif(select) mv->flags|=TNS_MESH_FLAG_SELECTED; else mv->flags&=(~TNS_MESH_FLAG_SELECTED);
 |  |      elif(select) mv->flags|=TNS_MESH_FLAG_SELECTED; else mv->flags&=(~TNS_MESH_FLAG_SELECTED);
 | 
											
												
													
														|  | 
 |  | +    if(!mo->FirstSelectV) mo->FirstSelectV=mv; mo->LastSelectV=mv;
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  void tnsMMeshSelectEdge(tnsMeshObject* mo, tnsMEdge* me, int select, int toggle){
 |  |  void tnsMMeshSelectEdge(tnsMeshObject* mo, tnsMEdge* me, int select, int toggle){
 | 
											
												
													
														|  |      if(!mo) return;
 |  |      if(!mo) return;
 | 
											
												
													
														|  |      if(toggle) tnsMMeshSelectEdge(mo,me,(me->flags&TNS_MESH_FLAG_SELECTED?0:1),0);
 |  |      if(toggle) tnsMMeshSelectEdge(mo,me,(me->flags&TNS_MESH_FLAG_SELECTED?0:1),0);
 | 
											
												
													
														|  |      elif(select) me->flags|=TNS_MESH_FLAG_SELECTED; else me->flags&=(~TNS_MESH_FLAG_SELECTED);
 |  |      elif(select) me->flags|=TNS_MESH_FLAG_SELECTED; else me->flags&=(~TNS_MESH_FLAG_SELECTED);
 | 
											
												
													
														|  | 
 |  | +    if(!mo->FirstSelectE) mo->FirstSelectE=me; mo->LastSelectE=me;
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  void tnsMMeshEnsureSelectionFromVerts(tnsMeshObject* mo){
 |  |  void tnsMMeshEnsureSelectionFromVerts(tnsMeshObject* mo){
 | 
											
												
													
														|  |      for(tnsMEdge* me=mo->me.pFirst;me;me=me->Item.pNext){ me->flags&=(~TNS_MESH_FLAG_SELECTED);
 |  |      for(tnsMEdge* me=mo->me.pFirst;me;me=me->Item.pNext){ me->flags&=(~TNS_MESH_FLAG_SELECTED);
 | 
											
										
											
												
													
														|  | @@ -734,6 +752,58 @@ int tnsMMeshSelectRingBandFrom(tnsMeshObject* mo, tnsMEdge* me, int ring_band, i
 | 
											
												
													
														|  |      while(lstPopPointer(&lst)); return 1;
 |  |      while(lstPopPointer(&lst)); return 1;
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | 
 |  | +void tnsMMeshReduceFaceEdge(tnsMeshObject* mo, tnsMFace* mf, tnsMEdge* me){
 | 
											
												
													
														|  | 
 |  | +    lstRemovePointerLeave(&mf->l,me); mf->looplen--;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +void tnsMMeshFaceReplaceEdgeWith(tnsMFace* mf, tnsMEdge* to_be_replaced, tnsMEdge* as){
 | 
											
												
													
														|  | 
 |  | +    if(!mf) return; for(laListItemPointer* lip=mf->l.pFirst;lip;lip=lip->pNext){
 | 
											
												
													
														|  | 
 |  | +        if(lip->p==to_be_replaced){ lip->p=as; return; }
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +void tnsMMeshReduceZippedFace(tnsMeshObject* mo, tnsMFace* mf){
 | 
											
												
													
														|  | 
 |  | +    if(mf->looplen>2) return; if(mf->looplen<2){ printf("mf->looplen < 2 ?\n");return; }
 | 
											
												
													
														|  | 
 |  | +    tnsMEdge* me1=((laListItemPointer*)mf->l.pFirst)->p,*me2=((laListItemPointer*)mf->l.pLast)->p;
 | 
											
												
													
														|  | 
 |  | +    tnsMVert* vl=me1->vl; tnsMVert*vr=me1->vr;
 | 
											
												
													
														|  | 
 |  | +    lstRemovePointerLeave(&vl->elink,me2); lstRemovePointerLeave(&vr->elink,me2);
 | 
											
												
													
														|  | 
 |  | +    tnsMMeshFaceReplaceEdgeWith(me1->fl,me2,me1); tnsMMeshFaceReplaceEdgeWith(me1->fr,me2,me1);
 | 
											
												
													
														|  | 
 |  | +    tnsMMeshFaceReplaceEdgeWith(me2->fl,me2,me1); tnsMMeshFaceReplaceEdgeWith(me2->fr,me2,me1);
 | 
											
												
													
														|  | 
 |  | +    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); }
 | 
											
												
													
														|  | 
 |  | +    lstRemoveItem(&mo->me,me2); mo->totme--; memLeave(me2);
 | 
											
												
													
														|  | 
 |  | +    lstRemoveItem(&mo->mf,mf); mo->totmf--; memLeave(mf);
 | 
											
												
													
														|  | 
 |  | +    tnsMMeshClearFirstLastSelection(mo);
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +int tnsMMeshVertsCanMerge(tnsMeshObject* mo, tnsMVert* into, tnsMVert* mv){
 | 
											
												
													
														|  | 
 |  | +    for(laListItemPointer* lip=into->elink.pFirst;lip;lip=lip->pNext){ tnsMEdge* me=lip->p;
 | 
											
												
													
														|  | 
 |  | +        for(laListItemPointer* lip2=mv->elink.pFirst;lip2;lip2=lip2->pNext){ tnsMEdge* me2=lip2->p; if(me==me2) continue;
 | 
											
												
													
														|  | 
 |  | +            tnsMVert* mvs=tnsMMeshEdgeShareVert(me,me2); if((!mvs)||mvs==mv||mvs==into) continue; int count=0;
 | 
											
												
													
														|  | 
 |  | +                if(me->fl) count++; if(me->fr) count++; if(me2->fl) count++; if(me2->fr) count++;
 | 
											
												
													
														|  | 
 |  | +                tnsMFace* sf=tnsMMeshEdgeShareFace(me,me2); if(sf){count--;}
 | 
											
												
													
														|  | 
 |  | +                if ((sf==me->fl && me->fr && (me->fr==me2->fl||me->fr==me2->fr))||
 | 
											
												
													
														|  | 
 |  | +                    (sf==me->fr && me->fl && (me->fl==me2->fl||me->fl==me2->fr))){ return 0; }
 | 
											
												
													
														|  | 
 |  | +                if((sf && count>3) || (!sf && count>2)){ return 0; }
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +    return 1;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +int tnsMMeshMergeVerts(tnsMeshObject* mo, tnsMVert* into, tnsMVert* mv){
 | 
											
												
													
														|  | 
 |  | +    if(!tnsMMeshVertsCanMerge(mo,into,mv)) return 0;
 | 
											
												
													
														|  | 
 |  | +    tnsMEdge* me=tnsMMeshMakeEdge(mo,into,mv);
 | 
											
												
													
														|  | 
 |  | +    if(me->fl){ tnsMMeshReduceFaceEdge(mo,me->fl,me); }
 | 
											
												
													
														|  | 
 |  | +    if(me->fr){ tnsMMeshReduceFaceEdge(mo,me->fr,me); }
 | 
											
												
													
														|  | 
 |  | +    tnsMEdge* me2; while(me2=lstPopPointerLeave(&mv->elink)){
 | 
											
												
													
														|  | 
 |  | +        if(me2==me) continue; lstAppendPointer(&into->elink,me2);
 | 
											
												
													
														|  | 
 |  | +        if(me2->vl==mv){ me2->vl=into; }elif(me2->vr==mv){ me2->vr=into; }
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +    if(me->fl){ tnsMMeshReduceZippedFace(mo,me->fl); }
 | 
											
												
													
														|  | 
 |  | +    if(me->fr){ tnsMMeshReduceZippedFace(mo,me->fr); }
 | 
											
												
													
														|  | 
 |  | +    lstRemovePointerLeave(&into->elink,me);
 | 
											
												
													
														|  | 
 |  | +    lstRemoveItem(&mo->mv,mv); memLeave(mv); mo->totmv--;
 | 
											
												
													
														|  | 
 |  | +    lstRemoveItem(&mo->me,me); memLeave(me); mo->totme--;
 | 
											
												
													
														|  | 
 |  | +    tnsMMeshClearFirstLastSelection(mo);
 | 
											
												
													
														|  | 
 |  | +    tnsPrintMeshTopology(mo);
 | 
											
												
													
														|  | 
 |  | +    return 1;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |  tnsMeshObject *tnsCreateMeshEmpty(tnsObject *under, char *Name, real AtX, real AtY, real AtZ){
 |  |  tnsMeshObject *tnsCreateMeshEmpty(tnsObject *under, char *Name, real AtX, real AtY, real AtZ){
 | 
											
												
													
														|  |      tnsMeshObject *mo = memAcquireHyper(sizeof(tnsMeshObject));
 |  |      tnsMeshObject *mo = memAcquireHyper(sizeof(tnsMeshObject));
 | 
											
												
													
														|  |      tnsInitObjectBase(&mo->Base, under, Name, TNS_OBJECT_MESH, AtX, AtY, AtZ, 0, 0, 0, 1.0f, TNS_ROTATION_XYZ_EULER, 1.0f);
 |  |      tnsInitObjectBase(&mo->Base, under, Name, TNS_OBJECT_MESH, AtX, AtY, AtZ, 0, 0, 0, 1.0f, TNS_ROTATION_XYZ_EULER, 1.0f);
 |