static void addedgeface_mesh(EditMesh *em, wmOperator *op) { EditVert *eve, *neweve[4]; EditEdge *eed; EditFace *efa; short amount=0; /* how many selected ? */ if(em->selectmode & SCE_SELECT_EDGE) { /* in edge mode finding selected vertices means flushing down edge codes... */ /* can't make face with only edge selection info... */ EM_selectmode_set(em); } for(eve= em->verts.first; eve; eve= eve->next) { if(eve->f & SELECT) { amount++; if(amount>4) break; neweve[amount-1]= eve; } } if(amount==2) { eed= addedgelist(em, neweve[0], neweve[1], NULL); EM_select_edge(eed, 1); // XXX DAG_id_tag_update(obedit->data, 0); return; } else if(amount > 4) { addfaces_from_edgenet(em); return; } else if(amount<2) { BKE_report(op->reports, RPT_WARNING, "More vertices are needed to make an edge/face"); return; } efa= NULL; // check later if(amount==3) { if(exist_face_overlaps(em, neweve[0], neweve[1], neweve[2], NULL)==0) { efa= addfacelist(em, neweve[0], neweve[1], neweve[2], 0, NULL, NULL); EM_select_face(efa, 1); } else BKE_report(op->reports, RPT_WARNING, "The selected vertices already form a face"); } else if(amount==4) { /* this test survives when theres 2 triangles */ if(exist_face(em, neweve[0], neweve[1], neweve[2], neweve[3])==0) { int tria= 0; /* remove trias if they exist, 4 cases.... */ if(exist_face(em, neweve[0], neweve[1], neweve[2], NULL)) tria++; if(exist_face(em, neweve[0], neweve[1], neweve[3], NULL)) tria++; if(exist_face(em, neweve[0], neweve[2], neweve[3], NULL)) tria++; if(exist_face(em, neweve[1], neweve[2], neweve[3], NULL)) tria++; if(tria==2) join_triangles(em); else if(exist_face_overlaps(em, neweve[0], neweve[1], neweve[2], neweve[3])==0) { /* If there are 4 Verts, But more selected edges, we need to call addfaces_from_edgenet */ EditEdge *eedcheck; int count; count = 0; for(eedcheck= em->edges.first; eedcheck; eedcheck= eedcheck->next) { if(eedcheck->f & SELECT) { count++; } } if(count++ > 4){ addfaces_from_edgenet(em); return; } else { /* if 4 edges exist, we just create the face, convex or not */ efa= addface_from_edges(em); if(efa==NULL) { /* the order of vertices can be anything, 6 cases to check */ if( convex(neweve[0]->co, neweve[1]->co, neweve[2]->co, neweve[3]->co) ) { efa= addfacelist(em, neweve[0], neweve[1], neweve[2], neweve[3], NULL, NULL); } else if( convex(neweve[0]->co, neweve[2]->co, neweve[3]->co, neweve[1]->co) ) { efa= addfacelist(em, neweve[0], neweve[2], neweve[3], neweve[1], NULL, NULL); } else if( convex(neweve[0]->co, neweve[2]->co, neweve[1]->co, neweve[3]->co) ) { efa= addfacelist(em, neweve[0], neweve[2], neweve[1], neweve[3], NULL, NULL); } else if( convex(neweve[0]->co, neweve[1]->co, neweve[3]->co, neweve[2]->co) ) { efa= addfacelist(em, neweve[0], neweve[1], neweve[3], neweve[2], NULL, NULL); } else if( convex(neweve[0]->co, neweve[3]->co, neweve[2]->co, neweve[1]->co) ) { efa= addfacelist(em, neweve[0], neweve[3], neweve[2], neweve[1], NULL, NULL); } else if( convex(neweve[0]->co, neweve[3]->co, neweve[1]->co, neweve[2]->co) ) { efa= addfacelist(em, neweve[0], neweve[3], neweve[1], neweve[2], NULL, NULL); } else BKE_report(op->reports, RPT_WARNING, "cannot find nice quad from concave set of vertices"); } } } else BKE_report(op->reports, RPT_WARNING, "The selected vertices already form a face"); } else BKE_report(op->reports, RPT_WARNING, "The selected vertices already form a face"); } if(efa) { EM_select_face(efa, 1); fix_new_face(em, efa); recalc_editnormals(em); } }
static int dupli_extrude_cursor(bContext *C, wmOperator *op, wmEvent *event) { ViewContext vc; EditVert *eve; float min[3], max[3]; int done= 0; short use_proj; em_setup_viewcontext(C, &vc); use_proj= (vc.scene->toolsettings->snap_flag & SCE_SNAP) && (vc.scene->toolsettings->snap_mode==SCE_SNAP_MODE_FACE); invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); INIT_MINMAX(min, max); for(eve= vc.em->verts.first; eve; eve= eve->next) { if(eve->f & SELECT) { DO_MINMAX(eve->co, min, max); done= 1; } } /* call extrude? */ if(done) { const short rot_src= RNA_boolean_get(op->ptr, "rotate_source"); EditEdge *eed; float vec[3], cent[3], mat[3][3]; float nor[3]= {0.0, 0.0, 0.0}; /* 2D normal calc */ float mval_f[2]; mval_f[0]= (float)event->mval[0]; mval_f[1]= (float)event->mval[1]; done= 0; /* calculate the normal for selected edges */ for(eed= vc.em->edges.first; eed; eed= eed->next) { if(eed->f & SELECT) { float co1[3], co2[3]; mul_v3_m4v3(co1, vc.obedit->obmat, eed->v1->co); mul_v3_m4v3(co2, vc.obedit->obmat, eed->v2->co); project_float_noclip(vc.ar, co1, co1); project_float_noclip(vc.ar, co2, co2); /* 2D rotate by 90d while adding. * (x, y) = (y, -x) * * accumulate the screenspace normal in 2D, * with screenspace edge length weighting the result. */ if(line_point_side_v2(co1, co2, mval_f) >= 0.0f) { nor[0] += (co1[1] - co2[1]); nor[1] += -(co1[0] - co2[0]); } else { nor[0] += (co2[1] - co1[1]); nor[1] += -(co2[0] - co1[0]); } done= 1; } } if(done) { float view_vec[3], cross[3]; /* convert the 2D nomal into 3D */ mul_mat3_m4_v3(vc.rv3d->viewinv, nor); /* worldspace */ mul_mat3_m4_v3(vc.obedit->imat, nor); /* local space */ /* correct the normal to be aligned on the view plane */ copy_v3_v3(view_vec, vc.rv3d->viewinv[2]); mul_mat3_m4_v3(vc.obedit->imat, view_vec); cross_v3_v3v3(cross, nor, view_vec); cross_v3_v3v3(nor, view_vec, cross); normalize_v3(nor); } /* center */ mid_v3_v3v3(cent, min, max); copy_v3_v3(min, cent); mul_m4_v3(vc.obedit->obmat, min); // view space view3d_get_view_aligned_coordinate(&vc, min, event->mval, TRUE); mul_m4_v3(vc.obedit->imat, min); // back in object space sub_v3_v3(min, cent); /* calculate rotation */ unit_m3(mat); if(done) { float dot; copy_v3_v3(vec, min); normalize_v3(vec); dot= dot_v3v3(vec, nor); if( fabs(dot)<0.999) { float cross[3], si, q1[4]; cross_v3_v3v3(cross, nor, vec); normalize_v3(cross); dot= 0.5f*saacos(dot); /* halve the rotation if its applied twice */ if(rot_src) dot *= 0.5f; si= (float)sin(dot); q1[0]= (float)cos(dot); q1[1]= cross[0]*si; q1[2]= cross[1]*si; q1[3]= cross[2]*si; quat_to_mat3( mat,q1); } } if(rot_src) { rotateflag(vc.em, SELECT, cent, mat); /* also project the source, for retopo workflow */ if(use_proj) EM_project_snap_verts(C, vc.ar, vc.obedit, vc.em); } extrudeflag(vc.obedit, vc.em, SELECT, nor, 0); rotateflag(vc.em, SELECT, cent, mat); translateflag(vc.em, SELECT, min); recalc_editnormals(vc.em); } else if(vc.em->selectmode & SCE_SELECT_VERTEX) { float imat[4][4]; const float *curs= give_cursor(vc.scene, vc.v3d); copy_v3_v3(min, curs); view3d_get_view_aligned_coordinate(&vc, min, event->mval, TRUE); eve= addvertlist(vc.em, 0, NULL); invert_m4_m4(imat, vc.obedit->obmat); mul_v3_m4v3(eve->co, imat, min); eve->f= SELECT; } if(use_proj) EM_project_snap_verts(C, vc.ar, vc.obedit, vc.em); WM_event_add_notifier(C, NC_GEOM|ND_DATA, vc.obedit->data); DAG_id_tag_update(vc.obedit->data, 0); return OPERATOR_FINISHED; }
static void make_prim(Object *obedit, int type, float mat[4][4], int tot, int seg, int subdiv, float dia, float depth, int ext, int fill) { /* * type - for the type of shape * dia - the radius for cone,sphere cylinder etc. * depth - * ext - extrude * fill - end capping, and option to fill in circle * cent[3] - center of the data. * */ EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); EditVert *eve, *v1=NULL, *v2, *v3, *v4=NULL, *vtop, *vdown; float phi, phid, vec[3]; float q[4], cmat[3][3], nor[3]= {0.0, 0.0, 0.0}; short a, b; EM_clear_flag_all(em, SELECT); phid= 2.0f*(float)M_PI/tot; phi= .25f*(float)M_PI; switch(type) { case PRIM_GRID: /* grid */ /* clear flags */ eve= em->verts.first; while(eve) { eve->f= 0; eve= eve->next; } /* one segment first: the X axis */ phi = (2*dia)/(float)(tot-1); phid = (2*dia)/(float)(seg-1); for(a=tot-1;a>=0;a--) { vec[0] = (phi*a) - dia; vec[1]= - dia; vec[2]= 0.0f; eve= addvertlist(em, vec, NULL); eve->f= 1+2+4; if(a < tot -1) addedgelist(em, eve->prev, eve, NULL); } /* extrude and translate */ vec[0]= vec[2]= 0.0; vec[1]= phid; for(a=0;a<seg-1;a++) { extrudeflag_vert(obedit, em, 2, nor, 0); // nor unused translateflag(em, 2, vec); } /* and now do imat */ eve= em->verts.first; while(eve) { if(eve->f & SELECT) { mul_m4_v3(mat,eve->co); } eve= eve->next; } recalc_editnormals(em); break; case PRIM_UVSPHERE: /* UVsphere */ /* clear all flags */ eve= em->verts.first; while(eve) { eve->f= 0; eve= eve->next; } /* one segment first */ phi= 0; phid/=2; for(a=0; a<=tot; a++) { vec[0]= dia*sinf(phi); vec[1]= 0.0; vec[2]= dia*cosf(phi); eve= addvertlist(em, vec, NULL); eve->f= 1+2+4; if(a==0) v1= eve; else addedgelist(em, eve, eve->prev, NULL); phi+= phid; } /* extrude and rotate */ phi= M_PI/seg; q[0]= cos(phi); q[3]= sin(phi); q[1]=q[2]= 0; quat_to_mat3( cmat,q); for(a=0; a<seg; a++) { extrudeflag_vert(obedit, em, 2, nor, 0); // nor unused rotateflag(em, 2, v1->co, cmat); } removedoublesflag(em, 4, 0, 0.0001); /* and now do imat */ eve= em->verts.first; while(eve) { if(eve->f & SELECT) { mul_m4_v3(mat,eve->co); } eve= eve->next; } recalc_editnormals(em); break; case PRIM_ICOSPHERE: /* Icosphere */ { EditVert *eva[12]; EditEdge *eed; /* clear all flags */ eve= em->verts.first; while(eve) { eve->f= 0; eve= eve->next; } dia/=200; for(a=0;a<12;a++) { vec[0]= dia*icovert[a][0]; vec[1]= dia*icovert[a][1]; vec[2]= dia*icovert[a][2]; eva[a]= addvertlist(em, vec, NULL); eva[a]->f= 1+2; } for(a=0;a<20;a++) { EditFace *evtemp; v1= eva[ icoface[a][0] ]; v2= eva[ icoface[a][1] ]; v3= eva[ icoface[a][2] ]; evtemp = addfacelist(em, v1, v2, v3, 0, NULL, NULL); evtemp->e1->f = 1+2; evtemp->e2->f = 1+2; evtemp->e3->f = 1+2; } dia*=200; for(a=1; a<subdiv; a++) esubdivideflag(obedit, em, 2, dia, 0, B_SPHERE,1, SUBDIV_CORNER_PATH, 0); /* and now do imat */ eve= em->verts.first; while(eve) { if(eve->f & 2) { mul_m4_v3(mat,eve->co); } eve= eve->next; } // Clear the flag 2 from the edges for(eed=em->edges.first;eed;eed=eed->next){ if(eed->f & 2){ eed->f &= !2; } } } break; case PRIM_MONKEY: /* Monkey */ { //extern int monkeyo, monkeynv, monkeynf; //extern signed char monkeyf[][4]; //extern signed char monkeyv[][3]; EditVert **tv= MEM_mallocN(sizeof(*tv)*monkeynv*2, "tv"); int i; for (i=0; i<monkeynv; i++) { float v[3]; v[0]= (monkeyv[i][0]+127)/128.0, v[1]= monkeyv[i][1]/128.0, v[2]= monkeyv[i][2]/128.0; tv[i]= addvertlist(em, v, NULL); tv[i]->f |= SELECT; tv[monkeynv+i]= (fabs(v[0]= -v[0])<0.001)?tv[i]:addvertlist(em, v, NULL); tv[monkeynv+i]->f |= SELECT; } for (i=0; i<monkeynf; i++) { addfacelist(em, tv[monkeyf[i][0]+i-monkeyo], tv[monkeyf[i][1]+i-monkeyo], tv[monkeyf[i][2]+i-monkeyo], (monkeyf[i][3]!=monkeyf[i][2])?tv[monkeyf[i][3]+i-monkeyo]:NULL, NULL, NULL); addfacelist(em, tv[monkeynv+monkeyf[i][2]+i-monkeyo], tv[monkeynv+monkeyf[i][1]+i-monkeyo], tv[monkeynv+monkeyf[i][0]+i-monkeyo], (monkeyf[i][3]!=monkeyf[i][2])?tv[monkeynv+monkeyf[i][3]+i-monkeyo]:NULL, NULL, NULL); } MEM_freeN(tv); /* and now do imat */ for(eve= em->verts.first; eve; eve= eve->next) { if(eve->f & SELECT) { mul_m4_v3(mat,eve->co); } } recalc_editnormals(em); } break; default: /* all types except grid, sphere... */ if(type==PRIM_CONE); else if(ext==0) depth= 0.0f; /* first vertex at 0° for circular objects */ if( ELEM3(type, PRIM_CIRCLE,PRIM_CYLINDER,PRIM_CONE) ) phi = 0.0f; vtop= vdown= v1= v2= 0; for(b=0; b<=ext; b++) { for(a=0; a<tot; a++) { vec[0]= dia*sinf(phi); vec[1]= dia*cosf(phi); vec[2]= b?depth:-depth; mul_m4_v3(mat, vec); eve= addvertlist(em, vec, NULL); eve->f= SELECT; if(a==0) { if(b==0) v1= eve; else v2= eve; } phi+=phid; } } /* center vertices */ /* type PRIM_CONE can only have 1 one side filled * if the cone has no capping, dont add vtop */ if(type == PRIM_CONE || (fill && !ELEM(type, PRIM_PLANE, PRIM_CUBE))) { vec[0]= vec[1]= 0.0f; vec[2]= type==PRIM_CONE ? depth : -depth; mul_m4_v3(mat, vec); vdown= addvertlist(em, vec, NULL); if((ext || type==PRIM_CONE) && fill) { vec[0]= vec[1]= 0.0f; vec[2]= type==PRIM_CONE ? -depth : depth; mul_m4_v3(mat,vec); vtop= addvertlist(em, vec, NULL); } } else { vdown= v1; vtop= v2; } if(vtop) vtop->f= SELECT; if(vdown) vdown->f= SELECT; /* top and bottom face */ if(fill || type==PRIM_CONE) { if(tot==4 && ELEM(type, PRIM_PLANE, PRIM_CUBE)) { v3= v1->next->next; if(ext) v4= v2->next->next; addfacelist(em, v3, v1->next, v1, v3->next, NULL, NULL); if(ext) addfacelist(em, v2, v2->next, v4, v4->next, NULL, NULL); } else { v3= v1; v4= v2; for(a=1; a<tot; a++) { addfacelist(em, vdown, v3, v3->next, 0, NULL, NULL); v3= v3->next; if(ext && fill) { addfacelist(em, vtop, v4, v4->next, 0, NULL, NULL); v4= v4->next; } } if(!ELEM(type, PRIM_PLANE, PRIM_CUBE)) { addfacelist(em, vdown, v3, v1, 0, NULL, NULL); if(ext) addfacelist(em, vtop, v4, v2, 0, NULL, NULL); } } } else if(type==PRIM_CIRCLE) { /* we need edges for a circle */ v3= v1; for(a=1;a<tot;a++) { addedgelist(em, v3, v3->next, NULL); v3= v3->next; } addedgelist(em, v3, v1, NULL); } /* side faces */ if(ext) { v3= v1; v4= v2; for(a=1; a<tot; a++) { addfacelist(em, v3, v3->next, v4->next, v4, NULL, NULL); v3= v3->next; v4= v4->next; } addfacelist(em, v3, v1, v2, v4, NULL, NULL); } else if(fill && type==PRIM_CONE) { /* add the bottom flat area of the cone * if capping is disabled dont bother */ v3= v1; for(a=1; a<tot; a++) { addfacelist(em, vtop, v3->next, v3, 0, NULL, NULL); v3= v3->next; } addfacelist(em, vtop, v1, v3, 0, NULL, NULL); } } EM_stats_update(em); /* simple selection flush OK, based on fact it's a single model */ EM_select_flush(em); /* flushes vertex -> edge -> face selection */ if(!ELEM5(type, PRIM_GRID, PRIM_PLANE, PRIM_ICOSPHERE, PRIM_UVSPHERE, PRIM_MONKEY)) EM_recalc_normal_direction(em, FALSE, TRUE); /* otherwise monkey has eyes in wrong direction */ BKE_mesh_end_editmesh(obedit->data, em); }
static void edge_drawflags(Mesh *me, EditMesh *em) { EditVert *eve; EditEdge *eed, *e1, *e2, *e3, *e4; EditFace *efa; /* - count number of times edges are used in faces: 0 en 1 time means draw edge * - edges more than 1 time used: in *tmp.f is pointer to first face * - check all faces, when normal differs to much: draw (flag becomes 1) */ /* later on: added flags for 'cylinder' and 'sphere' intersection tests in old game engine (2.04) */ recalc_editnormals(em); /* init */ eve= em->verts.first; while(eve) { eve->f1= 1; /* during test it's set at zero */ eve= eve->next; } eed= em->edges.first; while(eed) { eed->f2= eed->f1= 0; eed->tmp.f = 0; eed= eed->next; } efa= em->faces.first; while(efa) { e1= efa->e1; e2= efa->e2; e3= efa->e3; e4= efa->e4; if(e1->f2<4) e1->f2+= 1; if(e2->f2<4) e2->f2+= 1; if(e3->f2<4) e3->f2+= 1; if(e4 && e4->f2<4) e4->f2+= 1; if(e1->tmp.f == 0) e1->tmp.f = (void *) efa; if(e2->tmp.f == 0) e2->tmp.f = (void *) efa; if(e3->tmp.f ==0) e3->tmp.f = (void *) efa; if(e4 && (e4->tmp.f == 0)) e4->tmp.f = (void *) efa; efa= efa->next; } if(me->drawflag & ME_ALLEDGES) { efa= em->faces.first; while(efa) { if(efa->e1->f2>=2) efa->e1->f2= 1; if(efa->e2->f2>=2) efa->e2->f2= 1; if(efa->e3->f2>=2) efa->e3->f2= 1; if(efa->e4 && efa->e4->f2>=2) efa->e4->f2= 1; efa= efa->next; } } else { /* handle single-edges for 'test cylinder flag' (old engine) */ eed= em->edges.first; while(eed) { if(eed->f2==1) eed->f1= 1; eed= eed->next; } /* all faces, all edges with flag==2: compare normal */ efa= em->faces.first; while(efa) { if(efa->e1->f2==2) edge_normal_compare(efa->e1, efa); else efa->e1->f2= 1; if(efa->e2->f2==2) edge_normal_compare(efa->e2, efa); else efa->e2->f2= 1; if(efa->e3->f2==2) edge_normal_compare(efa->e3, efa); else efa->e3->f2= 1; if(efa->e4) { if(efa->e4->f2==2) edge_normal_compare(efa->e4, efa); else efa->e4->f2= 1; } efa= efa->next; } /* sphere collision flag */ eed= em->edges.first; while(eed) { if(eed->f1!=1) { eed->v1->f1= eed->v2->f1= 0; } eed= eed->next; } } }
/* is used for both read and write... */ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float lim) { uiBlock *block= (layout)? uiLayoutAbsoluteBlock(layout): NULL; MDeformVert *dvert=NULL; TransformProperties *tfp; float median[6], ve_median[6]; int tot, totw, totweight, totedge, totradius; char defstr[320]; median[0]= median[1]= median[2]= median[3]= median[4]= median[5]= 0.0; tot= totw= totweight= totedge= totradius= 0; defstr[0]= 0; /* make sure we got storage */ if(v3d->properties_storage==NULL) v3d->properties_storage= MEM_callocN(sizeof(TransformProperties), "TransformProperties"); tfp= v3d->properties_storage; if(ob->type==OB_MESH) { Mesh *me= ob->data; EditMesh *em = BKE_mesh_get_editmesh(me); EditVert *eve, *evedef=NULL; EditEdge *eed; eve= em->verts.first; while(eve) { if(eve->f & SELECT) { evedef= eve; tot++; add_v3_v3(median, eve->co); } eve= eve->next; } eed= em->edges.first; while(eed) { if((eed->f & SELECT)) { totedge++; median[3]+= eed->crease; } eed= eed->next; } /* check for defgroups */ if(evedef) dvert= CustomData_em_get(&em->vdata, evedef->data, CD_MDEFORMVERT); if(tot==1 && dvert && dvert->totweight) { bDeformGroup *dg; int i, max=1, init=1; char str[320]; for (i=0; i<dvert->totweight; i++){ dg = BLI_findlink (&ob->defbase, dvert->dw[i].def_nr); if(dg) { max+= BLI_snprintf(str, sizeof(str), "%s %%x%d|", dg->name, dvert->dw[i].def_nr); if(max<320) strcat(defstr, str); } if(tfp->curdef==dvert->dw[i].def_nr) { init= 0; tfp->defweightp= &dvert->dw[i].weight; } } if(init) { // needs new initialized tfp->curdef= dvert->dw[0].def_nr; tfp->defweightp= &dvert->dw[0].weight; } } BKE_mesh_end_editmesh(me, em); } else if(ob->type==OB_CURVE || ob->type==OB_SURF) { Curve *cu= ob->data; Nurb *nu; BPoint *bp; BezTriple *bezt; int a; ListBase *nurbs= ED_curve_editnurbs(cu); nu= nurbs->first; while(nu) { if(nu->type == CU_BEZIER) { bezt= nu->bezt; a= nu->pntsu; while(a--) { if(bezt->f2 & SELECT) { add_v3_v3(median, bezt->vec[1]); tot++; median[4]+= bezt->weight; totweight++; median[5]+= bezt->radius; totradius++; } else { if(bezt->f1 & SELECT) { add_v3_v3(median, bezt->vec[0]); tot++; } if(bezt->f3 & SELECT) { add_v3_v3(median, bezt->vec[2]); tot++; } } bezt++; } } else { bp= nu->bp; a= nu->pntsu*nu->pntsv; while(a--) { if(bp->f1 & SELECT) { add_v3_v3(median, bp->vec); median[3]+= bp->vec[3]; totw++; tot++; median[4]+= bp->weight; totweight++; median[5]+= bp->radius; totradius++; } bp++; } } nu= nu->next; } } else if(ob->type==OB_LATTICE) { Lattice *lt= ob->data; BPoint *bp; int a; a= lt->editlatt->latt->pntsu*lt->editlatt->latt->pntsv*lt->editlatt->latt->pntsw; bp= lt->editlatt->latt->def; while(a--) { if(bp->f1 & SELECT) { add_v3_v3(median, bp->vec); tot++; median[4]+= bp->weight; totweight++; } bp++; } } if(tot==0) { uiDefBut(block, LABEL, 0, "Nothing selected",0, 130, 200, 20, NULL, 0, 0, 0, 0, ""); return; } median[0] /= (float)tot; median[1] /= (float)tot; median[2] /= (float)tot; if(totedge) median[3] /= (float)totedge; else if(totw) median[3] /= (float)totw; if(totweight) median[4] /= (float)totweight; if(totradius) median[5] /= (float)totradius; if(v3d->flag & V3D_GLOBAL_STATS) mul_m4_v3(ob->obmat, median); if(block) { // buttons uiBut *but; memcpy(tfp->ve_median, median, sizeof(tfp->ve_median)); uiBlockBeginAlign(block); if(tot==1) { uiDefBut(block, LABEL, 0, "Vertex:", 0, 130, 200, 20, NULL, 0, 0, 0, 0, ""); uiBlockBeginAlign(block); but= uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "X:", 0, 110, 200, 20, &(tfp->ve_median[0]), -lim, lim, 10, 3, ""); uiButSetUnitType(but, PROP_UNIT_LENGTH); but= uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Y:", 0, 90, 200, 20, &(tfp->ve_median[1]), -lim, lim, 10, 3, ""); uiButSetUnitType(but, PROP_UNIT_LENGTH); but= uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Z:", 0, 70, 200, 20, &(tfp->ve_median[2]), -lim, lim, 10, 3, ""); uiButSetUnitType(but, PROP_UNIT_LENGTH); if(totw==1) { uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "W:", 0, 50, 200, 20, &(tfp->ve_median[3]), 0.01, 100.0, 1, 3, ""); uiBlockBeginAlign(block); uiDefButBitS(block, TOG, V3D_GLOBAL_STATS, B_REDR, "Global", 0, 25, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays global values"); uiDefButBitS(block, TOGN, V3D_GLOBAL_STATS, B_REDR, "Local", 100, 25, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays local values"); uiBlockEndAlign(block); if(totweight) uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Weight:", 0, 0, 200, 20, &(tfp->ve_median[4]), 0.0, 1.0, 1, 3, ""); if(totradius) uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Radius:", 0, 0, 200, 20, &(tfp->ve_median[5]), 0.0, 100.0, 1, 3, "Radius of curve CPs"); } else { uiBlockBeginAlign(block); uiDefButBitS(block, TOG, V3D_GLOBAL_STATS, B_REDR, "Global", 0, 45, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays global values"); uiDefButBitS(block, TOGN, V3D_GLOBAL_STATS, B_REDR, "Local", 100, 45, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays local values"); uiBlockEndAlign(block); if(totweight) uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Weight:", 0, 20, 200, 20, &(tfp->ve_median[4]), 0.0, 1.0, 10, 3, ""); if(totradius) uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Radius:", 0, 20, 200, 20, &(tfp->ve_median[5]), 0.0, 100.0, 10, 3, "Radius of curve CPs"); } } else { uiDefBut(block, LABEL, 0, "Median:", 0, 130, 200, 20, NULL, 0, 0, 0, 0, ""); uiBlockBeginAlign(block); but= uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "X:", 0, 110, 200, 20, &(tfp->ve_median[0]), -lim, lim, 10, 3, ""); uiButSetUnitType(but, PROP_UNIT_LENGTH); but= uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Y:", 0, 90, 200, 20, &(tfp->ve_median[1]), -lim, lim, 10, 3, ""); uiButSetUnitType(but, PROP_UNIT_LENGTH); but= uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Z:", 0, 70, 200, 20, &(tfp->ve_median[2]), -lim, lim, 10, 3, ""); uiButSetUnitType(but, PROP_UNIT_LENGTH); if(totw==tot) { uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "W:", 0, 50, 200, 20, &(tfp->ve_median[3]), 0.01, 100.0, 1, 3, ""); uiBlockEndAlign(block); uiBlockBeginAlign(block); uiDefButBitS(block, TOG, V3D_GLOBAL_STATS, B_REDR, "Global", 0, 25, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays global values"); uiDefButBitS(block, TOGN, V3D_GLOBAL_STATS, B_REDR, "Local", 100, 25, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays local values"); uiBlockEndAlign(block); if(totweight) uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Weight:", 0, 0, 200, 20, &(tfp->ve_median[4]), 0.0, 1.0, 10, 3, "Weight is used for SoftBody Goal"); if(totradius) uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Radius:", 0, 0, 200, 20, &(tfp->ve_median[5]), 0.0, 100.0, 10, 3, "Radius of curve CPs"); uiBlockEndAlign(block); } else { uiBlockBeginAlign(block); uiDefButBitS(block, TOG, V3D_GLOBAL_STATS, B_REDR, "Global", 0, 45, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays global values"); uiDefButBitS(block, TOGN, V3D_GLOBAL_STATS, B_REDR, "Local", 100, 45, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays local values"); uiBlockEndAlign(block); if(totweight) uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Weight:", 0, 20, 200, 20, &(tfp->ve_median[4]), 0.0, 1.0, 1, 3, "Weight is used for SoftBody Goal"); if(totradius) uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Radius:", 0, 0, 200, 20, &(tfp->ve_median[5]), 0.0, 100.0, 1, 3, "Radius of curve CPs"); uiBlockEndAlign(block); } } if(totedge==1) uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Crease:", 0, 20, 200, 20, &(tfp->ve_median[3]), 0.0, 1.0, 1, 3, ""); else if(totedge>1) uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Mean Crease:", 0, 20, 200, 20, &(tfp->ve_median[3]), 0.0, 1.0, 1, 3, ""); } else { // apply memcpy(ve_median, tfp->ve_median, sizeof(tfp->ve_median)); if(v3d->flag & V3D_GLOBAL_STATS) { invert_m4_m4(ob->imat, ob->obmat); mul_m4_v3(ob->imat, median); mul_m4_v3(ob->imat, ve_median); } sub_v3_v3v3(median, ve_median, median); median[3]= ve_median[3]-median[3]; median[4]= ve_median[4]-median[4]; median[5]= ve_median[5]-median[5]; if(ob->type==OB_MESH) { Mesh *me= ob->data; EditMesh *em = BKE_mesh_get_editmesh(me); /* allow for some rounding error becasue of matrix transform */ if(len_v3(median) > 0.000001f) { EditVert *eve; for(eve= em->verts.first; eve; eve= eve->next) { if(eve->f & SELECT) { add_v3_v3(eve->co, median); } } recalc_editnormals(em); } if(median[3] != 0.0f) { EditEdge *eed; const float fixed_crease= (ve_median[3] <= 0.0f ? 0.0f : (ve_median[3] >= 1.0f ? 1.0f : FLT_MAX)); if(fixed_crease != FLT_MAX) { /* simple case */ for(eed= em->edges.first; eed; eed= eed->next) { if(eed->f & SELECT) { eed->crease= fixed_crease; } } } else { /* scale crease to target median */ float median_new= ve_median[3]; float median_orig= ve_median[3] - median[3]; /* previous median value */ /* incase of floating point error */ CLAMP(median_orig, 0.0f, 1.0f); CLAMP(median_new, 0.0f, 1.0f); if(median_new < median_orig) { /* scale down */ const float sca= median_new / median_orig; for(eed= em->edges.first; eed; eed= eed->next) { if(eed->f & SELECT) { eed->crease *= sca; CLAMP(eed->crease, 0.0f, 1.0f); } } } else { /* scale up */ const float sca= (1.0f - median_new) / (1.0f - median_orig); for(eed= em->edges.first; eed; eed= eed->next) { if(eed->f & SELECT) { eed->crease = 1.0f - ((1.0f - eed->crease) * sca); CLAMP(eed->crease, 0.0f, 1.0f); } } } } } BKE_mesh_end_editmesh(me, em); } else if(ob->type==OB_CURVE || ob->type==OB_SURF) { Curve *cu= ob->data; Nurb *nu; BPoint *bp; BezTriple *bezt; int a; ListBase *nurbs= ED_curve_editnurbs(cu); nu= nurbs->first; while(nu) { if(nu->type == CU_BEZIER) { bezt= nu->bezt; a= nu->pntsu; while(a--) { if(bezt->f2 & SELECT) { add_v3_v3(bezt->vec[0], median); add_v3_v3(bezt->vec[1], median); add_v3_v3(bezt->vec[2], median); bezt->weight+= median[4]; bezt->radius+= median[5]; } else { if(bezt->f1 & SELECT) { add_v3_v3(bezt->vec[0], median); } if(bezt->f3 & SELECT) { add_v3_v3(bezt->vec[2], median); } } bezt++; } } else { bp= nu->bp; a= nu->pntsu*nu->pntsv; while(a--) { if(bp->f1 & SELECT) { add_v3_v3(bp->vec, median); bp->vec[3]+= median[3]; bp->weight+= median[4]; bp->radius+= median[5]; } bp++; } } test2DNurb(nu); testhandlesNurb(nu); /* test for bezier too */ nu= nu->next; } } else if(ob->type==OB_LATTICE) { Lattice *lt= ob->data; BPoint *bp; int a; a= lt->editlatt->latt->pntsu*lt->editlatt->latt->pntsv*lt->editlatt->latt->pntsw; bp= lt->editlatt->latt->def; while(a--) { if(bp->f1 & SELECT) { add_v3_v3(bp->vec, median); bp->weight+= median[4]; } bp++; } } // ED_undo_push(C, "Transform properties"); } }
/* copied from editobject.c, now uses (almost) proper depgraph */ static void special_transvert_update(Scene *scene, Object *obedit) { if(obedit) { DAG_id_flush_update(obedit->data, OB_RECALC_DATA); if(obedit->type==OB_MESH) { Mesh *me= obedit->data; recalc_editnormals(me->edit_mesh); // does face centers too } else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) { Curve *cu= obedit->data; Nurb *nu= cu->editnurb->first; while(nu) { test2DNurb(nu); testhandlesNurb(nu); /* test for bezier too */ nu= nu->next; } } else if(obedit->type==OB_ARMATURE){ bArmature *arm= obedit->data; EditBone *ebo; TransVert *tv= transvmain; int a=0; /* Ensure all bone tails are correctly adjusted */ for (ebo= arm->edbo->first; ebo; ebo=ebo->next) { /* adjust tip if both ends selected */ if ((ebo->flag & BONE_ROOTSEL) && (ebo->flag & BONE_TIPSEL)) { if (tv) { float diffvec[3]; VecSubf(diffvec, tv->loc, tv->oldloc); VecAddf(ebo->tail, ebo->tail, diffvec); a++; if (a<tottrans) tv++; } } } /* Ensure all bones are correctly adjusted */ for (ebo= arm->edbo->first; ebo; ebo=ebo->next) { if ((ebo->flag & BONE_CONNECTED) && ebo->parent){ /* If this bone has a parent tip that has been moved */ if (ebo->parent->flag & BONE_TIPSEL){ VECCOPY (ebo->head, ebo->parent->tail); } /* If this bone has a parent tip that has NOT been moved */ else{ VECCOPY (ebo->parent->tail, ebo->head); } } } if(arm->flag & ARM_MIRROR_EDIT) transform_armature_mirror_update(obedit); } else if(obedit->type==OB_LATTICE) { Lattice *lt= obedit->data; if(lt->editlatt->flag & LT_OUTSIDE) outside_lattice(lt->editlatt); } } }