|
@@ -142,9 +142,9 @@ int la_SelectGetClosest(MSelectData* sd, int uix, int uiy, int radius){
|
|
|
for(int j=0;j<w;j++){
|
|
|
uint8_t* p=&buf[(i*w+j)*4]; int id=(p[0])|(p[1]<<8)|(p[2]<<16);
|
|
|
if(id && (d=tnsDistIdv2(i,j, radius, radius))<MinD ){ MinD=d; MinID=id; }
|
|
|
- printf("%d ",buf[(i*w+j)*4]);
|
|
|
+ //printf("%d ",buf[(i*w+j)*4]);
|
|
|
}
|
|
|
- printf("\n");
|
|
|
+ //printf("\n");
|
|
|
}
|
|
|
free(buf);
|
|
|
return MinID;
|
|
@@ -357,7 +357,7 @@ void la_GetTransformCenter2D(MTransformData* td){
|
|
|
int la_AddTransformObjectsRecursive(MTransformData* td, tnsObject*root){
|
|
|
int any=0; for(laListItemPointer* lip=root->ChildObjects.pFirst;lip;lip=lip->pNext){
|
|
|
tnsObject* o=lip->p; if(o->ChildObjects.pFirst) any+=la_AddTransformObjectsRecursive(td,o);
|
|
|
- if(!o->Flags&TNS_OBJECT_FLAGS_SELECTED) continue;
|
|
|
+ if(!(o->Flags&TNS_OBJECT_FLAGS_SELECTED)) continue;
|
|
|
arrEnsureLength(&td->Originals, td->next, &td->max, sizeof(MTOrigObject));
|
|
|
MTOrigObject* to=arrElement(td->Originals, td->next, sizeof(MTOrigObject)); td->next++; to->o=o;
|
|
|
memcpy(to->Global, o->GlobalTransform, sizeof(tnsMatrix44d));
|
|
@@ -379,13 +379,15 @@ int la_PopulateTransformVerticies(MTransformData* td, tnsMeshObject* mo){
|
|
|
arrEnsureLength(&td->Originals, 0, &td->max, sizeof(MTOrigMVert));
|
|
|
tnsInverse44d(td->obmatinv, mo->Base.GlobalTransform);
|
|
|
for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){
|
|
|
- if(!mv->flags&TNS_MESH_FLAG_SELECTED) continue;
|
|
|
+ if(!(mv->flags&TNS_MESH_FLAG_SELECTED)) continue;
|
|
|
+ printf("v %d ",mv->i);
|
|
|
arrEnsureLength(&td->Originals, td->next, &td->max, sizeof(MTOrigMVert));
|
|
|
MTOrigMVert* to=arrElement(td->Originals, td->next, sizeof(MTOrigMVert)); td->next++; to->mv=mv;
|
|
|
tnsApplyTransform43d(to->p, mo->Base.GlobalTransform, mv->p);
|
|
|
memcpy(to->origp, mv->p, sizeof(tnsVector3d)); any++;
|
|
|
tnsVectorAccum3d(td->TCenter,to->p);
|
|
|
}
|
|
|
+ printf(" [totmv %d]\n",mo->totmv);
|
|
|
tnsVectorMultiSelf3d(td->TCenter, 1.0f/any);
|
|
|
la_GetTransformCenter2D(td);
|
|
|
return any;
|
|
@@ -597,14 +599,14 @@ int OPMOD_Transformation(laOperator *a, laEvent *e){
|
|
|
|
|
|
int la_ParentableRecursive(tnsObject* root, tnsObject* parent){
|
|
|
for(laListItemPointer* lip=root->ChildObjects.pFirst;lip;lip=lip->pNext){
|
|
|
- tnsObject* o=lip->p; if(!o || !o->Flags&TNS_OBJECT_FLAGS_SELECTED || o==parent) continue;
|
|
|
+ tnsObject* o=lip->p; if((!o) || (!(o->Flags&TNS_OBJECT_FLAGS_SELECTED)) || (o==parent)) continue;
|
|
|
if(!tnsCheckParentable(o,parent)) return 0;
|
|
|
if(!la_ParentableRecursive(o,parent)) return 0;
|
|
|
}return 1;
|
|
|
}
|
|
|
void la_MakeParentExecuteRecursive(tnsObject* root, tnsObject* parent, int Unparent, int KeepTransform){
|
|
|
for(laListItemPointer* lip=root->ChildObjects.pFirst;lip;lip=lip->pNext){
|
|
|
- tnsObject* o=lip->p; if(!o || !o->Flags&TNS_OBJECT_FLAGS_SELECTED) continue;
|
|
|
+ tnsObject* o=lip->p; if((!o) || (!(o->Flags&TNS_OBJECT_FLAGS_SELECTED))) continue;
|
|
|
if(Unparent) tnsUnparentObject(o, KeepTransform);
|
|
|
else tnsParentObject(o, parent, KeepTransform);
|
|
|
la_MakeParentExecuteRecursive(o,parent,Unparent,KeepTransform);
|
|
@@ -623,7 +625,7 @@ int OPINV_MakeParent(laOperator *a, laEvent *e){
|
|
|
if(strSame(action,"unparent")){ Unparent=1; }
|
|
|
if(strSame(keep,"false")){ KeepTransform=0; }
|
|
|
|
|
|
- if(!Unparent){ if(!mo || !mo->Flags&TNS_OBJECT_FLAGS_SELECTED) return LA_FINISHED;
|
|
|
+ if(!Unparent){ if((!mo) || (!(mo->Flags&TNS_OBJECT_FLAGS_SELECTED))) return LA_FINISHED;
|
|
|
if(!la_ParentableRecursive(root,mo)) laEnableMessagePanel(0,0,"It didn't work","There are loops in parenting",e->x,e->y,0,e); return LA_FINISHED;
|
|
|
}
|
|
|
|
|
@@ -648,7 +650,7 @@ void laui_Unparent(laUiList *uil, laPropPack *pp, laPropPack *actinst, laColumn
|
|
|
|
|
|
int la_ClearTransformationRecursive(tnsObject* root, int global,int location,int rotation,int scale){
|
|
|
int any=0; for(laListItemPointer* lip=root->ChildObjects.pFirst;lip;lip=lip->pNext){
|
|
|
- tnsObject* o=lip->p; if(!o->Flags&TNS_OBJECT_FLAGS_SELECTED) continue;
|
|
|
+ tnsObject* o=lip->p; if(!(o->Flags&TNS_OBJECT_FLAGS_SELECTED)) continue;
|
|
|
if(location){
|
|
|
if(global){ o->GLocation[0]=o->GLocation[1]=o->GLocation[2]=0;}
|
|
|
else{ o->Location[0]=o->Location[1]=o->Location[2]=0; }
|
|
@@ -922,6 +924,133 @@ void laui_Delete(laUiList *uil, laPropPack *pp, laPropPack *actinst, laColumn *e
|
|
|
laShowItemFull(uil,c,pp,"_this_M_delete",0,"mode=only_faces;text=Only Faces",0,0);
|
|
|
}
|
|
|
|
|
|
+STRUCTURE(MIslandInfo){
|
|
|
+ laListItem Item;
|
|
|
+ laListHandle v,e,f;int numv,nume,numf;
|
|
|
+ int Paired,HasBranches;
|
|
|
+};
|
|
|
+STRUCTURE(MMakeData){
|
|
|
+ laListHandle Islands; int NumIslands;
|
|
|
+};
|
|
|
+
|
|
|
+#define M_SHOULD_INCL_PRIM(m)\
|
|
|
+ ((!(m->flags&TNS_MESH_FLAG_PICKED)) && (m->flags&TNS_MESH_FLAG_SELECTED))
|
|
|
+#define M_SHOULD_USE_OE(oe,sf)\
|
|
|
+ (((!oe->fl)&&(oe->fr!=sf))||((!oe->fr)&&(oe->fl!=sf)))
|
|
|
+
|
|
|
+MIslandInfo* la_NewMIsland(MMakeData* md){ MIslandInfo* ii=memAcquireSimple(sizeof(MIslandInfo)); lstAppendItem(&md->Islands, ii); md->NumIslands++; return ii; }
|
|
|
+void la_FillIslandFromVert(MIslandInfo* ii, tnsMVert* mv, int SelectMode){
|
|
|
+ mv->flags|=TNS_MESH_FLAG_PICKED; lstAppendPointer(&ii->v,mv); ii->numv++; int connections=0;
|
|
|
+ for(laListItemPointer* lip=mv->elink.pFirst;lip;lip=lip->pNext){ tnsMEdge* oe=lip->p; tnsMVert* ov=tnsMMeshEdgeAnotherVert(oe,mv);
|
|
|
+ if(ov->flags&TNS_MESH_FLAG_SELECTED) connections++; else continue;
|
|
|
+ if(SelectMode==LA_CANVAS_SELECT_MODE_EDGES){ if(!(oe->flags&TNS_MESH_FLAG_SELECTED)) continue; }
|
|
|
+ if(M_SHOULD_INCL_PRIM(ov)){ la_FillIslandFromVert(ii,ov,SelectMode); } else { continue; }
|
|
|
+ if(M_SHOULD_INCL_PRIM(oe)){ lstAppendPointer(&ii->e,oe); ii->nume++; oe->flags|=TNS_MESH_FLAG_PICKED; }
|
|
|
+ if(oe->fl&&M_SHOULD_INCL_PRIM(oe->fl)){ lstAppendPointer(&ii->f,oe->fl); ii->numf++; oe->fl->flags|=TNS_MESH_FLAG_PICKED; }
|
|
|
+ if(oe->fr&&M_SHOULD_INCL_PRIM(oe->fr)){ lstAppendPointer(&ii->f,oe->fr); ii->numf++; oe->fr->flags|=TNS_MESH_FLAG_PICKED; }
|
|
|
+ }
|
|
|
+ if(connections>2) ii->HasBranches=1;
|
|
|
+}
|
|
|
+void la_GetSelectionIslands(tnsMeshObject* mo, MMakeData* md, int SelectMode){
|
|
|
+ tnsMMeshClearPickedFlags(mo);
|
|
|
+ for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){
|
|
|
+ if(M_SHOULD_INCL_PRIM(mv)){ MIslandInfo* ii=la_NewMIsland(md); la_FillIslandFromVert(ii,mv,SelectMode); }
|
|
|
+ }
|
|
|
+}
|
|
|
+void la_ClearIslands(MMakeData* md){ MIslandInfo* ii; while(ii=lstPopItem(&md->Islands)){ while(lstPopPointer(&ii->v)); memFree(ii); } }
|
|
|
+tnsMFace* la_MakeFacesFrom1Vert(tnsMeshObject* mo, tnsMVert* mv){
|
|
|
+ tnsMEdge* oe1=0,*oe2=0; tnsMVert* ov1,*ov2;
|
|
|
+ for(laListItemPointer* lip=mv->elink.pFirst;lip;lip=lip->pNext){
|
|
|
+ tnsMEdge* oe=lip->p; if(oe->flags&TNS_MESH_FLAG_SELECTED) continue; if((!oe->fl)||(!oe->fr)){ if(!oe1)oe1=oe;elif(!oe2)oe2=oe;else return 0; /* more than 2 empty edges connected */ }
|
|
|
+ } if(!oe1||!oe2) return 0;
|
|
|
+ ov1=tnsMMeshEdgeAnotherVert(oe1,mv); ov2=tnsMMeshEdgeAnotherVert(oe2,mv);
|
|
|
+ laListHandle vl={0}; lstAppendPointer(&vl,ov1); lstAppendPointer(&vl,mv); lstAppendPointer(&vl,ov2);
|
|
|
+ tnsMFace* f=tnsMMeshMakeFaceN(mo, 3, &vl); while(lstPopPointer(&vl)); return f;
|
|
|
+}
|
|
|
+tnsMFace* la_MakeFacesFrom2Verts(tnsMeshObject* mo, tnsMVert* mv1, tnsMVert* mv2){
|
|
|
+ tnsMEdge* oe1=0,*oe2=0; tnsMVert* ov1,*ov2; tnsMFace* sf=0;
|
|
|
+ tnsMEdge* se=tnsMMeshVertShareEdge(mv1,mv2); if(se->fl && se->fr) return 0; sf=se->fl?se->fl:se->fr;
|
|
|
+ for(laListItemPointer* lip=mv1->elink.pFirst;lip;lip=lip->pNext){
|
|
|
+ tnsMEdge* oe=lip->p; if(oe->flags&TNS_MESH_FLAG_SELECTED) continue; if(M_SHOULD_USE_OE(oe,sf)){ if(!oe1)oe1=oe;else return 0; /* more than 1 empty edge connected */ }
|
|
|
+ }
|
|
|
+ for(laListItemPointer* lip=mv2->elink.pFirst;lip;lip=lip->pNext){
|
|
|
+ tnsMEdge* oe=lip->p; if(oe->flags&TNS_MESH_FLAG_SELECTED) continue; if(M_SHOULD_USE_OE(oe,sf)){ if(!oe2)oe2=oe;else return 0; /* more than 1 empty edge connected */ }
|
|
|
+ }
|
|
|
+ if(!oe1||!oe2) return 0;
|
|
|
+ ov1=tnsMMeshEdgeAnotherVert(oe1,mv1); ov2=tnsMMeshEdgeAnotherVert(oe2,mv2);
|
|
|
+ ov1->flags|=TNS_MESH_FLAG_SELECTED;ov2->flags|=TNS_MESH_FLAG_SELECTED; mv1->flags&=(~TNS_MESH_FLAG_SELECTED);mv2->flags&=(~TNS_MESH_FLAG_SELECTED);
|
|
|
+ laListHandle vl={0}; lstAppendPointer(&vl,ov1); lstAppendPointer(&vl,mv1); lstAppendPointer(&vl,mv2); lstAppendPointer(&vl,ov2);
|
|
|
+ tnsMFace* f=tnsMMeshMakeFaceN(mo, 4, &vl); while(lstPopPointer(&vl)); return f;
|
|
|
+}
|
|
|
+int la_IsEndingVert(tnsMVert* mv){
|
|
|
+ int sel=0; for(laListItemPointer*lip=mv->elink.pFirst;lip;lip=lip->pNext){ tnsMEdge* me=lip->p;
|
|
|
+ if(tnsMMeshEdgeAnotherVert(me,mv)->flags&TNS_MESH_FLAG_SELECTED){ sel++; if(sel>1) return 0; }
|
|
|
+ }
|
|
|
+ if(sel==1) return 1; return 0;
|
|
|
+}
|
|
|
+void la_EnsureIslandVertsSequence(MIslandInfo* ii){
|
|
|
+ laListHandle l={0}; tnsMVert* startv=((laListItemPointer*)ii->v.pFirst)->p; laListItemPointer* nextlip;
|
|
|
+ for(laListItemPointer*lip=ii->v.pFirst;lip;lip=lip->pNext){ if(la_IsEndingVert(lip->p)){ startv=lip->p; break; } } // otherwise a loop, doesn't matter.
|
|
|
+ lstRemovePointer(&ii->v, startv); lstAppendPointer(&l, startv);
|
|
|
+ while(ii->v.pFirst){
|
|
|
+ for(laListItemPointer*lip=ii->v.pFirst;lip;lip=lip->pNext){ nextlip=lip->pNext;
|
|
|
+ if(tnsMMeshVertShareEdge(startv, lip->p)){ startv=lip->p; lstRemoveItem(&ii->v,lip); lstAppendItem(&l, lip); break; }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ memcpy(&ii->v, &l, sizeof(laListHandle));
|
|
|
+}
|
|
|
+MIslandInfo* la_GetNeighborIsland(tnsMVert* from, MMakeData* md){
|
|
|
+ int found=0; real dist=1e10; MIslandInfo* rii=0; for(MIslandInfo* ii=md->Islands.pFirst;ii;ii=ii->Item.pNext){ if(ii->Paired) continue;
|
|
|
+ found=1; tnsMVert* mv1=((laListItemPointer*)ii->v.pFirst)->p,*mv2=((laListItemPointer*)ii->v.pLast)->p;
|
|
|
+ real d1=tnsDist3dv(mv1->p, from->p),d2=tnsDist3dv(mv2->p, from->p);
|
|
|
+ if(d2<d1 && d2<dist){ lstReverse(&ii->v); } if(d1<dist || d2<dist){ rii=ii; }
|
|
|
+ }
|
|
|
+ if(rii) rii->Paired=1;
|
|
|
+ return rii;
|
|
|
+}
|
|
|
+int la_MakeFacesFromIslands(tnsMeshObject* mo, MMakeData* md){
|
|
|
+ int success=0;
|
|
|
+ if(!md->Islands.pFirst) return 0;
|
|
|
+ if(md->Islands.pFirst==md->Islands.pLast){
|
|
|
+ MIslandInfo* ii=md->Islands.pFirst; if(ii->HasBranches) return 0;
|
|
|
+ if(ii->numv==1){ laListItemPointer*lip=ii->v.pFirst; if(la_MakeFacesFrom1Vert(mo,lip->p)) success++; }
|
|
|
+ elif(ii->numv==2){ laListItemPointer*lip=ii->v.pFirst,*lip2=ii->v.pLast; if(la_MakeFacesFrom2Verts(mo,lip->p, lip2->p)) success++; }
|
|
|
+ else{ la_EnsureIslandVertsSequence(ii); if(tnsMMeshMakeFaceN(mo, ii->numv, &ii->v)) success++; }
|
|
|
+ }else{
|
|
|
+ for(MIslandInfo* ii=md->Islands.pFirst;ii;ii=ii->Item.pNext){ if(ii->HasBranches) return 0; la_EnsureIslandVertsSequence(ii); }
|
|
|
+ laListHandle final={0}; int vcount=0;
|
|
|
+ MIslandInfo* ii=md->Islands.pFirst; ii->Paired=1; for(laListItemPointer* lip=ii->v.pFirst;lip;lip=lip->pNext){ lstAppendPointer(&final, lip->p); vcount++; }
|
|
|
+ while((ii=la_GetNeighborIsland(((laListItemPointer*)ii->v.pLast)->p, md))){
|
|
|
+ for(laListItemPointer* lip=ii->v.pFirst;lip;lip=lip->pNext){ lstAppendPointer(&final, lip->p); vcount++; }
|
|
|
+ }
|
|
|
+ if(tnsMMeshMakeFaceN(mo,vcount,&final)) success++;
|
|
|
+ while(lstPopPointer(&final));
|
|
|
+ }
|
|
|
+ return success;
|
|
|
+}
|
|
|
+int OPINV_Make(laOperator *a, laEvent *e){
|
|
|
+ if(!a->This || !a->This->EndInstance){ return 0; }
|
|
|
+ laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
|
|
|
+ tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
|
|
|
+ tnsMeshObject* mo=root->Active;
|
|
|
+
|
|
|
+ if(mo->Base.Type!=TNS_OBJECT_MESH || mo->Mode!=TNS_MESH_EDIT_MODE){ return LA_CANCELED; }
|
|
|
+
|
|
|
+ MMakeData md={0};
|
|
|
+ la_GetSelectionIslands(mo,&md,ex->SelectMode);
|
|
|
+ int success=la_MakeFacesFromIslands(mo,&md);
|
|
|
+ la_ClearIslands(&md);
|
|
|
+
|
|
|
+ //tnsMMeshDeselectAll(mo);
|
|
|
+ tnsMMeshRefreshIndex(mo);
|
|
|
+ tnsMMeshEnsureSelection(mo,ex->SelectMode);
|
|
|
+ tnsInvaliateMeshBatch(mo);
|
|
|
+ if(laRecordInstanceDifferences(mo, "tns_mesh_object")) laPushDifferences("Make primitives", TNS_HINT_GEOMETRY);
|
|
|
+ laNotifyUsers("tns.world");
|
|
|
+
|
|
|
+ return LA_FINISHED;
|
|
|
+}
|
|
|
+
|
|
|
void la_RegisterModellingOperators(){
|
|
|
laPropContainer *pc; laProp *p;
|
|
|
laOperatorType *at;
|
|
@@ -940,5 +1069,6 @@ void la_RegisterModellingOperators(){
|
|
|
laCreateOperatorType("M_extrude", "Extrude", "Extrude parts of the mesh", 0, 0, 0, OPINV_Extrude, OPMOD_Transformation, 0, 0);
|
|
|
at=laCreateOperatorType("M_delete", "Delete", "Delete parts of the mesh", 0, 0, 0, OPINV_Delete, OPMOD_FinishOnData, 0, 0);
|
|
|
at->UiDefine=laui_Delete;
|
|
|
-
|
|
|
+ laCreateOperatorType("M_make", "Make", "Make mesh primitive from selected ones", 0, 0, 0, OPINV_Make, 0, 0, 0);
|
|
|
+
|
|
|
}
|