|
@@ -199,25 +199,29 @@ float* tnsGetDrawingVertArray(tnsMeshObject* mo, int* r_tot_render_v, float** r_
|
|
|
}
|
|
|
}else{
|
|
|
(*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;
|
|
|
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;
|
|
|
(*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);
|
|
|
- (*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){
|
|
|
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; }
|
|
|
|
|
|
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);
|
|
|
|
|
|
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_select", mo->totmv, 3, GL_POINTS, 0, 1);
|
|
|
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");
|
|
|
}
|
|
|
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;
|
|
|
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;
|
|
|
}
|
|
|
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;
|
|
|
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;
|
|
|
return 0;
|
|
|
}
|
|
@@ -482,7 +491,7 @@ tnsMFace* tnsMMeshMakeFaceN(tnsMeshObject* mo, int count, laListHandle* vip, tns
|
|
|
while(lstPopPointer(&el));
|
|
|
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* 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
|
|
@@ -525,17 +534,20 @@ void tnsMMeshRemoveFaceOnly(tnsMeshObject* mo, tnsMFace* mf){
|
|
|
if(!mf) return; tnsMEdge* me;
|
|
|
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--;
|
|
|
+ tnsMMeshClearFirstLastSelection(mo);
|
|
|
}
|
|
|
void tnsMMeshRemoveEdgeFace(tnsMeshObject* mo, tnsMEdge* me){
|
|
|
if(!me) return;
|
|
|
tnsMMeshRemoveFaceOnly(mo, me->fl); tnsMMeshRemoveFaceOnly(mo, me->fr);
|
|
|
lstRemovePointerLeave(&me->vl->elink, me); lstRemovePointerLeave(&me->vr->elink, me);
|
|
|
lstRemoveItem(&mo->me,me); memLeave(me); mo->totme--;
|
|
|
+ tnsMMeshClearFirstLastSelection(mo);
|
|
|
}
|
|
|
void tnsMMeshRemoveVertEdgeFace(tnsMeshObject* mo, tnsMVert* mv){
|
|
|
if(!mv) return; tnsMEdge* me;
|
|
|
while(me=lstPopPointerLeave(&mv->elink)){ tnsMMeshRemoveEdgeFace(mo,me); }
|
|
|
lstRemoveItem(&mo->mv,mv); memLeave(mv); mo->totmv--;
|
|
|
+ tnsMMeshClearFirstLastSelection(mo);
|
|
|
}
|
|
|
|
|
|
void tnsMMeshRefreshIndex(tnsMeshObject* mo){
|
|
@@ -618,6 +630,9 @@ void tnsMeshLeaveEditMode(tnsMeshObject* mo){
|
|
|
tnsInvalidateMeshBatch(mo);
|
|
|
}
|
|
|
|
|
|
+void tnsMMeshClearFirstLastSelection(tnsMeshObject* mo){
|
|
|
+ mo->FirstSelectE=mo->FirstSelectV=mo->LastSelectE=mo->LastSelectV=0;
|
|
|
+}
|
|
|
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(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(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); }
|
|
|
+ tnsMMeshClearFirstLastSelection(mo);
|
|
|
}
|
|
|
void tnsMMeshSelectAll(tnsMeshObject* mo){
|
|
|
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(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);
|
|
|
+ if(!mo->FirstSelectV) mo->FirstSelectV=mv; mo->LastSelectV=mv;
|
|
|
}
|
|
|
void tnsMMeshSelectEdge(tnsMeshObject* mo, tnsMEdge* me, int select, int toggle){
|
|
|
if(!mo) return;
|
|
|
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);
|
|
|
+ if(!mo->FirstSelectE) mo->FirstSelectE=me; mo->LastSelectE=me;
|
|
|
}
|
|
|
void tnsMMeshEnsureSelectionFromVerts(tnsMeshObject* mo){
|
|
|
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;
|
|
|
}
|
|
|
|
|
|
+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 *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);
|