|
@@ -86,7 +86,8 @@ int OPINV_ToggleEdit(laOperator *a, laEvent *e){
|
|
|
STRUCTURE(MSelectData){
|
|
|
tnsOffscreen* FBO;
|
|
|
tnsTexture* Color;
|
|
|
- void** Refs; int next,max;
|
|
|
+ void** RefsV; int nextV,maxV;
|
|
|
+ void** RefsE; int nextE,maxE;
|
|
|
};
|
|
|
MSelectData* la_InitSelectData(int w, int h, tnsCamera* camera){
|
|
|
MSelectData* sd=memAcquireSimple(sizeof(MSelectData));
|
|
@@ -100,16 +101,16 @@ MSelectData* la_InitSelectData(int w, int h, tnsCamera* camera){
|
|
|
void la_AssignObjectSelectIDRecursive(tnsObject* root, MSelectData* sd){
|
|
|
for(laListItemPointer*lip=root->ChildObjects.pFirst;lip;lip=lip->pNext){
|
|
|
tnsObject* o=lip->p; if(!o) continue;
|
|
|
- arrEnsureLength(&sd->Refs, sd->next, &sd->max, sizeof(tnsObject*));
|
|
|
- sd->Refs[sd->next]=o; o->SelectID=sd->next; sd->next++;
|
|
|
+ arrEnsureLength(&sd->RefsV, sd->nextV, &sd->maxV, sizeof(tnsObject*));
|
|
|
+ sd->RefsV[sd->nextV]=o; o->SelectID=sd->nextV; sd->nextV++;
|
|
|
if(o->ChildObjects.pFirst){ la_AssignObjectSelectIDRecursive(o,sd); }
|
|
|
}
|
|
|
}
|
|
|
void la_PopulateSelectDataObjects(MSelectData* sd, tnsObject* root, tnsCamera* camera){
|
|
|
- arrEnsureLength(&sd->Refs,0,&sd->max,sizeof(tnsObject*));
|
|
|
- sd->next++; // starting from 1;
|
|
|
+ arrEnsureLength(&sd->RefsV,0,&sd->maxV,sizeof(tnsObject*));
|
|
|
+ sd->nextV++; // starting from 1;
|
|
|
la_AssignObjectSelectIDRecursive(root, sd);
|
|
|
- if(sd->next==1) return; int w=sd->Color->Width, h=sd->Color->Height;
|
|
|
+ if(sd->nextV==1) return; int w=sd->Color->Width, h=sd->Color->Height;
|
|
|
tnsUnbindTexture(); tnsUniformUseTexture(T->immShader,0,0); tnsUseMultiplyColor(0);
|
|
|
tnsEnableShaderv(T->SelectionShader);
|
|
|
glDisableVertexAttribArray(T->SelectionShader->iColor); glVertexAttrib4f(T->SelectionShader->iColor,0,0,0,0);
|
|
@@ -121,26 +122,28 @@ void la_PopulateSelectDataObjects(MSelectData* sd, tnsObject* root, tnsCamera* c
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
}
|
|
|
void la_PopulateSelectVerts(MSelectData* sd, tnsMeshObject* mo){
|
|
|
- arrEnsureLength(&sd->Refs,0,&sd->max,sizeof(tnsMVert*));
|
|
|
+ arrEnsureLength(&sd->RefsV,0,&sd->maxV,sizeof(tnsMVert*));
|
|
|
if(mo->Base.Type!=TNS_OBJECT_MESH||!mo->mv.pFirst){ return; }
|
|
|
for(tnsMVert* v=mo->mv.pFirst;v;v=v->Item.pNext){
|
|
|
- arrEnsureLength(&sd->Refs, v->i, &sd->max, sizeof(tnsObject*));
|
|
|
- sd->Refs[v->i]=v; sd->next=TNS_MAX2(v->i, sd->next);
|
|
|
+ arrEnsureLength(&sd->RefsV, v->i, &sd->maxV, sizeof(tnsObject*));
|
|
|
+ sd->RefsV[v->i]=v; sd->nextV=TNS_MAX2(v->i, sd->nextV);
|
|
|
}
|
|
|
- sd->next++;
|
|
|
+ sd->nextV++;
|
|
|
}
|
|
|
void la_PopulateSelectEdges(MSelectData* sd, tnsMeshObject* mo){
|
|
|
- arrEnsureLength(&sd->Refs,0,&sd->max,sizeof(tnsMEdge*));
|
|
|
+ arrEnsureLength(&sd->RefsE,0,&sd->maxE,sizeof(tnsMEdge*));
|
|
|
if(mo->Base.Type!=TNS_OBJECT_MESH||!mo->mv.pFirst){ return; }
|
|
|
for(tnsMEdge* e=mo->me.pFirst;e;e=e->Item.pNext){
|
|
|
- arrEnsureLength(&sd->Refs, e->i, &sd->max, sizeof(tnsObject*));
|
|
|
- sd->Refs[e->i]=e; sd->next=TNS_MAX2(e->i, sd->next);
|
|
|
+ arrEnsureLength(&sd->RefsE, e->i, &sd->maxE, sizeof(tnsObject*));
|
|
|
+ sd->RefsE[e->i]=e; sd->nextE=TNS_MAX2(e->i, sd->nextE);
|
|
|
}
|
|
|
- sd->next++;
|
|
|
+ sd->nextE++;
|
|
|
}
|
|
|
void la_PopulateSelectDataPrimitives(MSelectData* sd, tnsMeshObject* mo, tnsCamera* camera, int WhatPrim){
|
|
|
- if(WhatPrim==LA_CANVAS_SELECT_MODE_VERTS){ la_PopulateSelectVerts(sd,mo); }
|
|
|
- elif(WhatPrim==LA_CANVAS_SELECT_MODE_EDGES){ la_PopulateSelectEdges(sd,mo); }
|
|
|
+ int DoVerts=(WhatPrim==LA_CANVAS_SELECT_MODE_VERTS),DoEdges=(WhatPrim==LA_CANVAS_SELECT_MODE_EDGES);
|
|
|
+ int Knife=(WhatPrim==LA_CANVAS_SELECT_MODE_KNIFE);
|
|
|
+ if(DoVerts || Knife){ la_PopulateSelectVerts(sd,mo); }
|
|
|
+ if(DoEdges || Knife){ la_PopulateSelectEdges(sd,mo); }
|
|
|
int w=sd->Color->Width, h=sd->Color->Height;
|
|
|
tnsUnbindTexture(); tnsUniformUseTexture(T->immShader,0,0); tnsUseMultiplyColor(0);
|
|
|
tnsEnableShaderv(T->SelectionShader);
|
|
@@ -149,7 +152,10 @@ void la_PopulateSelectDataPrimitives(MSelectData* sd, tnsMeshObject* mo, tnsCame
|
|
|
glClearColor(0,0,0,0); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
tnsPushMatrix(); tnsApplyObjectMatrix(mo);
|
|
|
- tnsDrawBatch(mo->Batch, (WhatPrim==LA_CANVAS_SELECT_MODE_VERTS)?"verts_select":"edges_select",0,0);
|
|
|
+ if(Knife){ glPointSize(10); }
|
|
|
+ if(DoEdges || Knife){ tnsDrawBatch(mo->Batch, "edges_select",0,0); }
|
|
|
+ if(DoVerts || Knife){ tnsDrawBatch(mo->Batch, "verts_select",0,0); }
|
|
|
+ if(Knife){ glPointSize(1); }
|
|
|
tnsPopMatrix();
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
}
|
|
@@ -196,18 +202,19 @@ uint8_t* la_ReadSelectionBox(MSelectData* sd, int uix, int uiy, int uix2, int ui
|
|
|
la_PadSelectionBuffer(buf, w, h, _startx-startx, _starty-starty, endx-_endx, endy-_endy,_endx);
|
|
|
return buf;
|
|
|
}
|
|
|
-int la_SelectGetClosest(MSelectData* sd, int uix, int uiy, int radius){
|
|
|
- uint8_t* buf=la_ReadSelectionRadius(sd, uix, uiy, radius); if(!buf) return 0;
|
|
|
- int w=radius*2; int MinD=INT_MAX; int MinID=0, d;
|
|
|
+int la_SelectGetClosest(MSelectData* sd, int uix, int uiy, int radius, int *ElemType){
|
|
|
+ *ElemType=0; uint8_t* buf=la_ReadSelectionRadius(sd, uix, uiy, radius); if(!buf) return 0;
|
|
|
+ int w=radius*2; int MinD=INT_MAX; int MinID=0, d, elemtype=0;
|
|
|
for(int i=0;i<w;i++){
|
|
|
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; }
|
|
|
+ uint8_t* p=&buf[(i*w+j)*4]; int id=(p[0])|(p[1]<<8)|((p[2]<<16)&(~TNS_MMESH_TYPE_BIT));
|
|
|
+ if(id && (d=tnsDistIdv2(i,j, radius, radius))<MinD ){ MinD=d; MinID=id; elemtype=((p[2]<<16)&TNS_MMESH_TYPE_BIT); }
|
|
|
//printf("%d ",buf[(i*w+j)*4]);
|
|
|
}
|
|
|
//printf("\n");
|
|
|
}
|
|
|
free(buf);
|
|
|
+ *ElemType=elemtype;
|
|
|
return MinID;
|
|
|
}
|
|
|
int* la_SelectGetBox(MSelectData* sd, int uix, int uiy, int uix2, int uiy2, int* r_length){
|
|
@@ -220,7 +227,7 @@ int* la_SelectGetBox(MSelectData* sd, int uix, int uiy, int uix2, int uiy2, int*
|
|
|
arrEnsureLength(&ids, next, &max, sizeof(int));
|
|
|
for(int i=0;i<h;i++){
|
|
|
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);
|
|
|
+ uint8_t* p=&buf[(i*w+j)*4]; int id=(p[0])|(p[1]<<8)|((p[2]<<16)&(~TNS_MMESH_TYPE_BIT));
|
|
|
if(id){ int found=0;
|
|
|
for(int a=0;a<next;a++){ if(ids[a]==id){ found=1; break; } }
|
|
|
if(!found){
|
|
@@ -234,9 +241,15 @@ int* la_SelectGetBox(MSelectData* sd, int uix, int uiy, int uix2, int uiy2, int*
|
|
|
}
|
|
|
void la_FreeSelectData(MSelectData* sd){
|
|
|
tnsDelete2DOffscreen(sd->FBO);
|
|
|
- free(sd->Refs);
|
|
|
+ free(sd->RefsV);
|
|
|
+ free(sd->RefsE);
|
|
|
memFree(sd);
|
|
|
}
|
|
|
+void* la_SelectGetRef(MSelectData* sd, int id, int elemtype){
|
|
|
+ if(!elemtype){ if(id>=0 && id<sd->nextV){ return sd->RefsV[id]; } }
|
|
|
+ elif(elemtype==TNS_MMESH_EDGE_BIT){ if(id>=0 && id<sd->nextE){ return sd->RefsE[id]; } }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
int OPCHK_ViewportAndSceneExists(laPropPack *This, laStringSplitor *ss){
|
|
|
if(!This || !This->EndInstance){ return 0; } laCanvasExtra* ex=This->EndInstance;
|
|
@@ -262,6 +275,9 @@ STRUCTURE(MSelectExtra){
|
|
|
tnsCamera* cam;
|
|
|
int Mode;
|
|
|
int InSelect;
|
|
|
+
|
|
|
+ laListHandle KnifeElements;
|
|
|
+ void* PendingElem; int PendingElemType, BatchDirty;
|
|
|
};
|
|
|
|
|
|
int OPINV_Select(laOperator *a, laEvent *e){
|
|
@@ -294,8 +310,8 @@ int OPINV_Select(laOperator *a, laEvent *e){
|
|
|
ex->OnX=e->x; ex->OnX=e->y;
|
|
|
a->CustomData=se; se->sd=sd; se->Mode=LA_SELECT_MODE_BOX; se->mo=mo; se->cam=c; ex->DrawCursor=1; se->root=root; return LA_RUNNING;
|
|
|
}
|
|
|
- int id=la_SelectGetClosest(sd, e->x-ui->L, e->y-ui->U, LA_RH)-1;
|
|
|
- void* p; if(id>=0 && id<sd->next){ p=sd->Refs[id]; }
|
|
|
+ int elemtype,id=la_SelectGetClosest(sd, e->x-ui->L, e->y-ui->U, LA_RH,&elemtype)-1;
|
|
|
+ void* p=la_SelectGetRef(sd,id,elemtype); printf("%d %d\n",id,elemtype);
|
|
|
la_DoMeshSelect(mo, p, ex->SelectMode, DeselectAll, 1, 1); tnsMMeshEnsureSelection(mo,ex->SelectMode);
|
|
|
tnsInvalidateMeshBatch(mo);
|
|
|
laNotifyUsers("tns.world"); laRecordAndPush(0,"tns.world","Mesh selection",TNS_HINT_GEOMETRY);
|
|
@@ -306,8 +322,8 @@ int OPINV_Select(laOperator *a, laEvent *e){
|
|
|
ex->OnX=e->x; ex->OnX=e->y;
|
|
|
a->CustomData=se; se->sd=sd; se->Mode=LA_SELECT_MODE_BOX; se->cam=c; ex->DrawCursor=1; se->root=root; return LA_RUNNING;
|
|
|
}
|
|
|
- int id=la_SelectGetClosest(sd, e->x-ui->L, e->y-ui->U, LA_RH*2);
|
|
|
- if(id && id<sd->next){ la_DoObjectSelect(root, sd->Refs[id], ex, DeselectAll, 1, 1); }
|
|
|
+ int elemtype,id=la_SelectGetClosest(sd, e->x-ui->L, e->y-ui->U, LA_RH*2,&elemtype); printf("%d\n",elemtype);
|
|
|
+ void* p=la_SelectGetRef(sd,id,elemtype); if(p){ la_DoObjectSelect(root, p, ex, DeselectAll, 1, 1); }
|
|
|
else{ la_DoObjectSelect(root, 0, ex, DeselectAll, 1, 1); }
|
|
|
laNotifyUsers("tns.world"); laRecordAndPush(0,"tns.world","Object selection",TNS_HINT_TRANSFORM);
|
|
|
}
|
|
@@ -326,7 +342,7 @@ int OPMOD_Select(laOperator *a, laEvent *e){
|
|
|
if(e->Type==LA_L_MOUSE_DOWN){ se->InSelect=1; ex->DrawCursor=2; ex->ClickedX=e->x; ex->ClickedY=e->y; laRedrawCurrentPanel(); }
|
|
|
if(e->Type&LA_MOUSE_EVENT){ ex->OnX=e->x; ex->OnY=e->y; laRedrawCurrentPanel(); }
|
|
|
if(e->Type==LA_R_MOUSE_DOWN || (e->Type == LA_KEY_DOWN && e->key==LA_KEY_ESCAPE)){
|
|
|
- ex->DrawCursor=0; la_FreeSelectData(se->sd); laNotifyUsers("tns.world"); return LA_FINISHED;
|
|
|
+ ex->DrawCursor=0; la_FreeSelectData(se->sd); memFree(se); laNotifyUsers("tns.world"); return LA_FINISHED;
|
|
|
}
|
|
|
|
|
|
int DeselectAll=1;
|
|
@@ -339,7 +355,7 @@ int OPMOD_Select(laOperator *a, laEvent *e){
|
|
|
la_DoMeshSelect(mo, 0, ex->SelectMode, DeselectAll, 0, 0);
|
|
|
int len; int* ids=la_SelectGetBox(se->sd, ex->ClickedX-ui->L, ex->ClickedY-ui->U, e->x-ui->L, e->y-ui->U, &len);
|
|
|
for(int i=0;i<len;i++){
|
|
|
- int id=ids[i]-1; void* p; if(id>=0 && id<se->sd->next){ p=se->sd->Refs[id]; }
|
|
|
+ int id=ids[i]-1; void* p=la_SelectGetRef(se->sd,id,ex->SelectMode==LA_CANVAS_SELECT_MODE_EDGES?TNS_MMESH_EDGE_BIT:0);
|
|
|
la_DoMeshSelect(mo, p, ex->SelectMode, 0, !Remove, 0);
|
|
|
}
|
|
|
tnsMMeshEnsureSelection(mo,ex->SelectMode);
|
|
@@ -348,12 +364,13 @@ int OPMOD_Select(laOperator *a, laEvent *e){
|
|
|
la_DoObjectSelect(se->root, 0, ex, DeselectAll, 0, 0);
|
|
|
int len; int* ids=la_SelectGetBox(se->sd, ex->ClickedX, ex->ClickedY, e->x-ui->L, e->y-ui->U, &len);
|
|
|
for(int i=0;i<len;i++){
|
|
|
- int id=ids[i]; if(id && id<se->sd->next){ la_DoObjectSelect(se->root, se->sd->Refs[id], ex, 0, !Remove, 0); }
|
|
|
+ int id=ids[i]; void* p=la_SelectGetRef(se->sd,id,0);
|
|
|
+ if(p){ la_DoObjectSelect(se->root, p, ex, 0, !Remove, 0); }
|
|
|
}
|
|
|
}
|
|
|
laNotifyUsers("tns.world"); laRecordAndPush(0,"tns.world","Box selection",is_geo?TNS_HINT_GEOMETRY:TNS_HINT_TRANSFORM);
|
|
|
ex->DrawCursor=0;
|
|
|
- la_FreeSelectData(se->sd);
|
|
|
+ la_FreeSelectData(se->sd); memFree(se);
|
|
|
laRedrawCurrentPanel();
|
|
|
return LA_FINISHED;
|
|
|
}
|
|
@@ -1039,7 +1056,10 @@ tnsMFace* la_MakeFacesFrom1Vert(tnsMeshObject* mo, tnsMVert* mv){
|
|
|
} 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, 0); while(lstPopPointer(&vl)); return f;
|
|
|
+ tnsMFace* f=tnsMMeshMakeFaceN(mo, 3, &vl, 0);
|
|
|
+ ov1->flags|=TNS_MESH_FLAG_SELECTED;ov2->flags|=TNS_MESH_FLAG_SELECTED; mv->flags&=(~TNS_MESH_FLAG_SELECTED);
|
|
|
+ tnsMMeshEnsureSelectionFromVerts(mo);
|
|
|
+ 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;
|
|
@@ -1054,7 +1074,8 @@ tnsMFace* la_MakeFacesFrom2Verts(tnsMeshObject* mo, tnsMVert* mv1, tnsMVert* mv2
|
|
|
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, 0); while(lstPopPointer(&vl)); return f;
|
|
|
+ tnsMFace* f=tnsMMeshMakeFaceN(mo, 4, &vl, 0); tnsMMeshEnsureSelectionFromVerts(mo);
|
|
|
+ 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;
|
|
@@ -1272,6 +1293,124 @@ int OPINV_RecalculateNormals(laOperator *a, laEvent *e){
|
|
|
return LA_FINISHED;
|
|
|
}
|
|
|
|
|
|
+STRUCTURE(MKnifeElement){
|
|
|
+ laListItem Item;
|
|
|
+ void* p;
|
|
|
+ int Type;
|
|
|
+};
|
|
|
+void la_KnifeUpdateToolBatch(MSelectExtra* se,tnsObject* o){
|
|
|
+ if(se->root->ExtraBatch) tnsDeleteBatch(se->root->ExtraBatch); se->root->ExtraBatch=0;
|
|
|
+ int count=lstCountElements(&se->KnifeElements); if((!count) && (!se->PendingElem)) return;
|
|
|
+ float* points=calloc((count+1)*3,sizeof(real));
|
|
|
+ float* p=points; real tmp[3],trans[4];
|
|
|
+ for(MKnifeElement* ke=se->KnifeElements.pFirst;ke;ke=ke->Item.pNext){
|
|
|
+ if(ke->Type==TNS_MMESH_EDGE_BIT){ tnsMEdge* me=ke->p; tnsVectorSet3v(tmp,me->vl->p); tnsVectorAccum3d(tmp,me->vr->p);
|
|
|
+ tnsVectorMultiSelf3d(tmp,0.5); tnsApplyTransform43d(trans,o->GlobalTransform,tmp); tnsVectorSet3v(p,trans); }
|
|
|
+ else{ tnsMVert* mv=ke->p; tnsApplyTransform43d(trans,o->GlobalTransform,mv->p); tnsVectorSet3v(p,trans); }
|
|
|
+ p+=3;
|
|
|
+ }
|
|
|
+ if(se->PendingElem){
|
|
|
+ if(se->PendingElemType==TNS_MMESH_EDGE_BIT){ tnsMEdge* me=se->PendingElem; tnsVectorSet3v(tmp,me->vl->p); tnsVectorAccum3d(tmp,me->vr->p);
|
|
|
+ tnsVectorMultiSelf3d(tmp,0.5); tnsApplyTransform43d(trans,o->GlobalTransform,tmp); tnsVectorSet3v(p,trans); }
|
|
|
+ else{ tnsMVert* mv=se->PendingElem; tnsApplyTransform43d(trans,o->GlobalTransform,mv->p); tnsVectorSet3v(p,trans); }
|
|
|
+ }elif(count){
|
|
|
+ tnsVectorSet3v(p,p-3);
|
|
|
+ }
|
|
|
+ uint32_t elem=count;
|
|
|
+ tnsBatch* batch=tnsCreateBatch(count+1,3,points,0,0,0,0); tnsBatchCommand*c;
|
|
|
+ c=tnsCreateCommand(batch, "hovering_point", 1, 3, GL_POINTS, &elem, 0);
|
|
|
+ tnsCommandUseUniformColor(c,laAccentColor(LA_BT_SVERTEX));
|
|
|
+ if(count){
|
|
|
+ c=tnsCreateCommand(batch, "edges", count+1, 3, GL_LINE_STRIP, 0, 0);
|
|
|
+ tnsCommandUseUniformColor(c,laAccentColor(LA_BT_NORMAL));
|
|
|
+ c=tnsCreateCommand(batch, "points", count+1, 3, GL_POINTS, 0, 0);
|
|
|
+ tnsCommandUseUniformColor(c,laAccentColor(LA_BT_NORMAL));
|
|
|
+ }
|
|
|
+ se->root->ExtraBatch=batch;
|
|
|
+ free(points);
|
|
|
+}
|
|
|
+int la_KnifeIsDuplicated(MSelectExtra* se, void* ref){
|
|
|
+ for(MKnifeElement* ke=se->KnifeElements.pFirst;ke;ke=ke->Item.pNext){
|
|
|
+ if(ke->Type==TNS_MMESH_EDGE_BIT && ke->p==ref){ return 1; }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+void la_KnifeAppendCut(MSelectExtra* se){
|
|
|
+ MKnifeElement* ke=lstAppendPointerSized(&se->KnifeElements,se->PendingElem,sizeof(MKnifeElement));
|
|
|
+ ke->Type=se->PendingElemType;
|
|
|
+}
|
|
|
+int la_KnifeRegisterCuts(MSelectExtra* se, tnsMeshObject* mo){
|
|
|
+ if(!mo || mo->Base.Type!=TNS_OBJECT_MESH || mo->Mode!=TNS_MESH_EDIT_MODE) return 0;
|
|
|
+ if(!se->KnifeElements.pFirst) return 0;
|
|
|
+ tnsMVert* lastv=0,*newv=0; tnsMEdge* newme=0; int changed=0;
|
|
|
+ for(MKnifeElement* ke=se->KnifeElements.pFirst;ke;ke=ke->Item.pNext){
|
|
|
+ if(ke->Type==TNS_MMESH_EDGE_BIT){
|
|
|
+ newv=tnsMMeshEdgeInsertVertAt(mo,ke->p,0.5,0,0,0); changed=1;
|
|
|
+ }
|
|
|
+ else{ newv=ke->p; }
|
|
|
+ if(lastv){ if(tnsMMeshVertsShareFace(lastv,newv)) newme=tnsMMeshMakeEdge(mo, lastv, newv); changed=1; }
|
|
|
+ lastv=newv; newv->flags|=TNS_MESH_FLAG_SELECTED; if(newme){ newme->flags|=TNS_MESH_FLAG_SELECTED; }
|
|
|
+ }
|
|
|
+ if(changed){ tnsMMeshRefreshIndex(mo); tnsMMeshCalculateNormal(mo); }
|
|
|
+ return changed;
|
|
|
+}
|
|
|
+void la_KnifeFinish(MSelectExtra* se, tnsObject*o){
|
|
|
+ if(o->ExtraBatch) tnsDeleteBatch(o->ExtraBatch); o->ExtraBatch=0;
|
|
|
+ while(lstPopPointer(&se->KnifeElements));
|
|
|
+ la_FreeSelectData(se->sd); memFree(se);
|
|
|
+}
|
|
|
+int OPINV_Knife(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 LA_CANCELED;
|
|
|
+ tnsMeshObject* mo=root->Active; int ran=0;
|
|
|
+
|
|
|
+ if(!mo || mo->Base.Type!=TNS_OBJECT_MESH || mo->Mode!=TNS_MESH_EDIT_MODE){ return LA_CANCELED; }
|
|
|
+
|
|
|
+ MSelectExtra* se=memAcquire(sizeof(MSelectExtra));
|
|
|
+ MSelectData* sd=la_InitSelectData(ex->OffScr->pColor[0]->Width, ex->OffScr->pColor[0]->Height, c);
|
|
|
+ a->CustomData=se; se->sd=sd; se->root=root;
|
|
|
+ la_PopulateSelectDataPrimitives(sd,mo,c,LA_CANVAS_SELECT_MODE_KNIFE);
|
|
|
+
|
|
|
+ strSafeSet(&a->RuntimeHint, "◧ Set cut ◨ Cancel ⮨ Confirm");
|
|
|
+
|
|
|
+ return LA_RUNNING;
|
|
|
+}
|
|
|
+int OPMOD_Knife(laOperator *a, laEvent *e){
|
|
|
+ if(!a->This || !a->This->EndInstance || !a->CustomData){ 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;
|
|
|
+ MSelectExtra* se=a->CustomData;
|
|
|
+ tnsMeshObject* mo=root->Active;
|
|
|
+ int changed=0;
|
|
|
+
|
|
|
+ if(e->Type==LA_R_MOUSE_DOWN || (e->Type == LA_KEY_DOWN && e->key==LA_KEY_ESCAPE)){
|
|
|
+ la_KnifeFinish(se,root); laNotifyUsers("tns.world"); return LA_FINISHED;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(e->Type&LA_MOUSE_EVENT){
|
|
|
+ int elemtype,id=la_SelectGetClosest(se->sd, e->x-ui->L, e->y-ui->U, LA_RH,&elemtype)-1;
|
|
|
+ void* p=la_SelectGetRef(se->sd,id,elemtype); if(la_KnifeIsDuplicated(se,p)) p=0;
|
|
|
+ if(se->PendingElem!=p){ changed=1; }
|
|
|
+ se->PendingElem=p; se->PendingElemType=elemtype;
|
|
|
+ if(e->Type==LA_L_MOUSE_DOWN && p){ la_KnifeAppendCut(se); changed=1; }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(e->Type==LA_KEY_DOWN && e->key==LA_KEY_ENTER){
|
|
|
+ if(la_KnifeRegisterCuts(se,mo)){ tnsMMeshEnsureSelection(mo,ex->SelectMode);
|
|
|
+ tnsInvalidateMeshBatch(mo); laRecordAndPush(0,"tns.world","Knife Cut",TNS_HINT_GEOMETRY);laNotifyUsers("tns.world");
|
|
|
+ }
|
|
|
+ la_KnifeFinish(se,root); return LA_FINISHED;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(changed){
|
|
|
+ la_KnifeUpdateToolBatch(se,mo); laRedrawCurrentPanel();
|
|
|
+ }
|
|
|
+
|
|
|
+ return LA_RUNNING;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
void la_RegisterModellingOperators(){
|
|
|
laPropContainer *pc; laProp *p;
|
|
|
laOperatorType *at;
|
|
@@ -1299,4 +1438,6 @@ void la_RegisterModellingOperators(){
|
|
|
laCreateOperatorType("M_combine", "Combine", "Combine mesh objects", 0, 0, 0, OPINV_Combine, 0, 0, 0);
|
|
|
laCreateOperatorType("M_duplicate", "Duplicate", "Duplicate objects", 0, 0, 0, OPINV_Duplicate, OPMOD_Transformation, 0, 0);
|
|
|
laCreateOperatorType("M_recalculate_normals", "Recalculate Normals", "Recalculate normals", 0, 0, 0, OPINV_RecalculateNormals, 0, 0, 0);
|
|
|
+ laCreateOperatorType("M_knife", "Knife", "Cut through edges", OPCHK_ViewportAndSceneExists, 0, 0, OPINV_Knife, OPMOD_Knife, 0, LA_EXTRA_TO_PANEL);
|
|
|
+
|
|
|
}
|