forked from bartvdbraak/blender
New Mesh tool: "Rip".
http://www.blender3d.org/cms/Mesh_Ripping.712.0.html This tool allows to insert gaps/seams in a Mesh, based on the selection (1 vertex or a row of edges) and the position of the mouse (to indicate the part that gets grabbed). Shortcut: Vkey. Special Orange request!
This commit is contained in:
parent
7d325f1ed4
commit
dc611a7575
@ -188,7 +188,7 @@ extern void mesh_set_smooth_faces(short event);
|
||||
void edge_rotate_selected(int dir);
|
||||
int EdgeSlide(short immediate, float imperc);
|
||||
void EdgeLoopDelete(void);
|
||||
|
||||
void mesh_rip(void);
|
||||
|
||||
struct EditVert *editedge_getOtherVert(struct EditEdge *eed, struct EditVert *ev);
|
||||
struct EditVert *editedge_getSharedVert(struct EditEdge *eed, struct EditEdge *eed2);
|
||||
|
@ -831,7 +831,7 @@ static int unified_findnearest(EditVert **eve, EditEdge **eed, EditFace **efa)
|
||||
|
||||
/* selects quads in loop direction of indicated edge */
|
||||
/* only flush over edges with valence <= 2 */
|
||||
static void faceloop_select(EditEdge *startedge, int select)
|
||||
void faceloop_select(EditEdge *startedge, int select)
|
||||
{
|
||||
EditMesh *em = G.editMesh;
|
||||
EditEdge *eed;
|
||||
@ -893,8 +893,10 @@ static void faceloop_select(EditEdge *startedge, int select)
|
||||
}
|
||||
|
||||
/* (de)select the faces */
|
||||
for(efa= em->faces.first; efa; efa= efa->next) {
|
||||
if(efa->f1) EM_select_face(efa, select);
|
||||
if(select!=2) {
|
||||
for(efa= em->faces.first; efa; efa= efa->next) {
|
||||
if(efa->f1) EM_select_face(efa, select);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5901,3 +5901,210 @@ void mesh_set_smooth_faces(short event)
|
||||
else if(event==0) BIF_undo_push("Set Solid");
|
||||
}
|
||||
|
||||
/* helper to find edge for edge_rip */
|
||||
static float mesh_rip_edgedist(float mat[][4], float *co1, float *co2, short *mval)
|
||||
{
|
||||
float vec1[3], vec2[3], mvalf[2];
|
||||
|
||||
view3d_project_float(curarea, co1, vec1, mat);
|
||||
view3d_project_float(curarea, co2, vec2, mat);
|
||||
mvalf[0]= (float)mval[0];
|
||||
mvalf[1]= (float)mval[1];
|
||||
|
||||
return PdistVL2Dfl(mvalf, vec1, vec2);
|
||||
}
|
||||
|
||||
/* helper for below */
|
||||
static void mesh_rip_setface(EditFace *sefa)
|
||||
{
|
||||
/* put new vertices & edges in best face */
|
||||
if(sefa->v1->vn) sefa->v1= sefa->v1->vn;
|
||||
if(sefa->v2->vn) sefa->v2= sefa->v2->vn;
|
||||
if(sefa->v3->vn) sefa->v3= sefa->v3->vn;
|
||||
if(sefa->v4 && sefa->v4->vn) sefa->v4= sefa->v4->vn;
|
||||
|
||||
sefa->e1= addedgelist(sefa->v1, sefa->v2, sefa->e1);
|
||||
sefa->e2= addedgelist(sefa->v2, sefa->v3, sefa->e2);
|
||||
if(sefa->v4) {
|
||||
sefa->e3= addedgelist(sefa->v3, sefa->v4, sefa->e3);
|
||||
sefa->e4= addedgelist(sefa->v4, sefa->v1, sefa->e4);
|
||||
}
|
||||
else
|
||||
sefa->e3= addedgelist(sefa->v3, sefa->v1, sefa->e3);
|
||||
|
||||
}
|
||||
|
||||
/* based on mouse cursor position, it defines how is being ripped */
|
||||
void mesh_rip(void)
|
||||
{
|
||||
extern void faceloop_select(EditEdge *startedge, int select);
|
||||
EditMesh *em = G.editMesh;
|
||||
EditVert *eve;
|
||||
EditEdge *eed, *seed= NULL;
|
||||
EditFace *efa, *sefa= NULL;
|
||||
float projectMat[4][4], viewMat[4][4], vec[3], dist, mindist;
|
||||
short doit= 1, mval[2];
|
||||
|
||||
/* select flush... vertices are important */
|
||||
EM_selectmode_set();
|
||||
|
||||
getmouseco_areawin(mval);
|
||||
view3d_get_object_project_mat(curarea, G.obedit, projectMat, viewMat);
|
||||
|
||||
/* find best face, exclude triangles and break on face select or faces with 2 edges select */
|
||||
mindist= 1000000.0f;
|
||||
for(efa= em->faces.first; efa; efa=efa->next) {
|
||||
if( efa->f & 1)
|
||||
break;
|
||||
if(efa->v4 && faceselectedOR(efa, SELECT) ) {
|
||||
int totsel;
|
||||
|
||||
if(efa->e1->f & SELECT) totsel++;
|
||||
if(efa->e2->f & SELECT) totsel++;
|
||||
if(efa->e3->f & SELECT) totsel++;
|
||||
if(efa->e4->f & SELECT) totsel++;
|
||||
|
||||
if(totsel>1)
|
||||
break;
|
||||
view3d_project_float(curarea, efa->cent, vec, projectMat);
|
||||
dist= sqrt( (vec[0]-mval[0])*(vec[0]-mval[0]) + (vec[1]-mval[1])*(vec[1]-mval[1]) );
|
||||
if(dist<mindist) {
|
||||
mindist= dist;
|
||||
sefa= efa;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(efa) {
|
||||
error("Can't perform ripping with faces selected this way");
|
||||
return;
|
||||
}
|
||||
if(sefa==NULL) {
|
||||
error("No proper selection or triangles included");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* duplicate vertices, new vertices get selected */
|
||||
for(eve = em->verts.last; eve; eve= eve->prev) {
|
||||
eve->vn= NULL;
|
||||
if(eve->f & SELECT) {
|
||||
eve->vn= addvertlist(eve->co);
|
||||
eve->f &= ~SELECT;
|
||||
eve->vn->f |= SELECT;
|
||||
}
|
||||
}
|
||||
|
||||
/* find the best candidate edge */
|
||||
/* or one of sefa edges is selected... */
|
||||
if(sefa->e1->f & SELECT) seed= sefa->e2;
|
||||
if(sefa->e2->f & SELECT) seed= sefa->e1;
|
||||
if(sefa->e3->f & SELECT) seed= sefa->e2;
|
||||
if(sefa->e4 && sefa->e4->f & SELECT) seed= sefa->e3;
|
||||
|
||||
/* or we do the distance trick */
|
||||
if(seed==NULL) {
|
||||
mindist= 1000000.0f;
|
||||
if(sefa->e1->v1->vn || sefa->e1->v2->vn) {
|
||||
dist= mesh_rip_edgedist(projectMat, sefa->e1->v1->co, sefa->e1->v2->co, mval);
|
||||
if(dist<mindist) {
|
||||
seed= sefa->e1;
|
||||
mindist= dist;
|
||||
}
|
||||
}
|
||||
if(sefa->e2->v1->vn || sefa->e2->v2->vn) {
|
||||
dist= mesh_rip_edgedist(projectMat, sefa->e2->v1->co, sefa->e2->v2->co, mval);
|
||||
if(dist<mindist) {
|
||||
seed= sefa->e2;
|
||||
mindist= dist;
|
||||
}
|
||||
}
|
||||
if(sefa->e3->v1->vn || sefa->e3->v2->vn) {
|
||||
dist= mesh_rip_edgedist(projectMat, sefa->e3->v1->co, sefa->e3->v2->co, mval);
|
||||
if(dist<mindist) {
|
||||
seed= sefa->e3;
|
||||
mindist= dist;
|
||||
}
|
||||
}
|
||||
if(sefa->e4 && (sefa->e4->v1->vn || sefa->e4->v2->vn)) {
|
||||
dist= mesh_rip_edgedist(projectMat, sefa->e4->v1->co, sefa->e4->v2->co, mval);
|
||||
if(dist<mindist) {
|
||||
seed= sefa->e4;
|
||||
mindist= dist;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(seed==NULL) { // never happens?
|
||||
error("No proper edge found to start");
|
||||
return;
|
||||
}
|
||||
|
||||
faceloop_select(seed, 2); // tmp abuse for finding all edges that need duplicated, returns OK faces with f1
|
||||
|
||||
/* duplicate edges in the loop, with at least 1 vertex selected, needed for selection flip */
|
||||
for(eed = em->edges.last; eed; eed= eed->prev) {
|
||||
eed->vn= NULL;
|
||||
if((eed->v1->vn) || (eed->v2->vn)) {
|
||||
EditEdge *newed;
|
||||
|
||||
newed= addedgelist(eed->v1->vn?eed->v1->vn:eed->v1, eed->v2->vn?eed->v2->vn:eed->v2, eed);
|
||||
if(eed->f & SELECT) {
|
||||
eed->f &= ~SELECT;
|
||||
newed->f |= SELECT;
|
||||
}
|
||||
eed->vn= (EditVert *)newed;
|
||||
}
|
||||
}
|
||||
|
||||
/* first clear edges to help finding neighbours */
|
||||
for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0;
|
||||
|
||||
/* put new vertices & edges && flag in best face */
|
||||
mesh_rip_setface(sefa);
|
||||
|
||||
/* starting with neighbours of best face, we loop over the seam */
|
||||
sefa->f1= 2;
|
||||
doit= 1;
|
||||
while(doit) {
|
||||
doit= 0;
|
||||
|
||||
for(efa= em->faces.first; efa; efa=efa->next) {
|
||||
/* new vert in face */
|
||||
if(efa->v1->vn || efa->v2->vn || efa->v3->vn || (efa->v4 && efa->v4->vn)) {
|
||||
/* face is tagged with loop */
|
||||
if(efa->f1==1) {
|
||||
mesh_rip_setface(efa);
|
||||
efa->f1= 2;
|
||||
doit= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* remove loose edges */
|
||||
for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0;
|
||||
for(efa= em->faces.first; efa; efa=efa->next) {
|
||||
efa->e1->f1= 1;
|
||||
efa->e2->f1= 1;
|
||||
efa->e3->f1= 1;
|
||||
if(efa->e4) efa->e4->f1= 1;
|
||||
}
|
||||
|
||||
for(eed = em->edges.last; eed; eed= seed) {
|
||||
seed= eed->prev;
|
||||
if(eed->f1==0) {
|
||||
if(eed->v1->f | eed->v2->f | SELECT) {
|
||||
remedge(eed);
|
||||
free_editedge(eed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
countall(); // apparently always needed when adding stuff, derived mesh
|
||||
|
||||
BIF_TransformSetUndo("Rip");
|
||||
initTransform(TFM_TRANSLATION, 0);
|
||||
Transform();
|
||||
}
|
||||
|
||||
|
@ -1717,7 +1717,10 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
|
||||
image_aspect();
|
||||
else if (G.qual==0){
|
||||
if(G.obedit) {
|
||||
if(G.obedit->type==OB_CURVE) {
|
||||
if(G.obedit->type==OB_MESH) {
|
||||
mesh_rip();
|
||||
}
|
||||
else if(G.obedit->type==OB_CURVE) {
|
||||
sethandlesNurb(2);
|
||||
DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
|
||||
allqueue(REDRAWVIEW3D, 0);
|
||||
|
Loading…
Reference in New Issue
Block a user