diff options
-rw-r--r-- | source/blender/editors/include/ED_mesh.h | 3 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/space_view3d.c | 1 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/view3d_edit.c | 3 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/view3d_intern.h | 11 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/view3d_ops.c | 10 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/view3d_snap.c | 1148 |
6 files changed, 1174 insertions, 2 deletions
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index e32243fc28f..0353fb8c28d 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -120,11 +120,12 @@ void EM_selectmode_set(struct EditMesh *em); void EM_select_flush(struct EditMesh *em); void EM_convertsel(struct EditMesh *em, short oldmode, short selectmode); void EM_validate_selections(struct EditMesh *em); - + /* exported to transform */ int EM_get_actSelection(struct EditMesh *em, struct EditSelection *ese); void EM_editselection_normal(float *normal, struct EditSelection *ese); void EM_editselection_plane(float *plane, struct EditSelection *ese); +void EM_editselection_center(float *center, struct EditSelection *ese); struct UvVertMap *EM_make_uv_vert_map(struct EditMesh *em, int selected, int do_face_idx_array, float *limit); struct UvMapVert *EM_get_uv_map_vert(struct UvVertMap *vmap, unsigned int v); diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 0b0c48891d4..1ca6fa1e841 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -324,6 +324,7 @@ static void view3d_main_area_listener(ARegion *ar, wmNotifier *wmn) switch(wmn->category) { case NC_SCENE: switch(wmn->data) { + case ND_TRANSFORM: case ND_FRAME: case ND_OB_ACTIVE: case ND_OB_SELECT: diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 03f8e65e547..6313fe73cd1 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -956,7 +956,7 @@ static int viewcenter_exec(bContext *C, wmOperator *op) /* like a localview with if(obedit) { -// XXX ok = minmax_verts(min, max); /* only selected */ + ok = minmax_verts(obedit, min, max); /* only selected */ } else if(ob && (ob->flag & OB_POSEMODE)) { if(ob->pose) { @@ -1042,6 +1042,7 @@ static int viewcenter_exec(bContext *C, wmOperator *op) /* like a localview with return OPERATOR_FINISHED; } + void VIEW3D_OT_viewcenter(wmOperatorType *ot) { diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 2f5914905eb..5322f18c02d 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -144,6 +144,17 @@ void VIEW3D_OT_properties(struct wmOperatorType *ot); void view3d_buttons_area_defbuts(const struct bContext *C, ARegion *ar); +/* view3d_snap.c */ +int minmax_verts(Object *obedit, float *min, float *max); + +void VIEW3D_OT_snap_selected_to_grid(struct wmOperatorType *ot); +void VIEW3D_OT_snap_selected_to_cursor(struct wmOperatorType *ot); +void VIEW3D_OT_snap_selected_to_center(struct wmOperatorType *ot); +void VIEW3D_OT_snap_cursor_to_grid(struct wmOperatorType *ot); +void VIEW3D_OT_snap_cursor_to_selected(struct wmOperatorType *ot); +void VIEW3D_OT_snap_cursor_to_active(struct wmOperatorType *ot); +void VIEW3D_OT_snap_menu(struct wmOperatorType *ot); + /* space_view3d.c */ ARegion *view3d_has_buttons_region(ScrArea *sa); diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index f0af4c745fe..645dadcd275 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -92,6 +92,14 @@ void view3d_operatortypes(void) WM_operatortype_append(VIEW3D_OT_editmesh_face_toolbox); WM_operatortype_append(VIEW3D_OT_properties); WM_operatortype_append(VIEW3D_OT_localview); + + WM_operatortype_append(VIEW3D_OT_snap_selected_to_grid); + WM_operatortype_append(VIEW3D_OT_snap_selected_to_cursor); + WM_operatortype_append(VIEW3D_OT_snap_selected_to_center); + WM_operatortype_append(VIEW3D_OT_snap_cursor_to_grid); + WM_operatortype_append(VIEW3D_OT_snap_cursor_to_selected); + WM_operatortype_append(VIEW3D_OT_snap_cursor_to_active); + WM_operatortype_append(VIEW3D_OT_snap_menu); transform_operatortypes(); } @@ -181,6 +189,8 @@ void view3d_keymap(wmWindowManager *wm) WM_keymap_add_item(keymap, "VIEW3D_OT_set_camera_to_view", PAD0, KM_PRESS, KM_ALT|KM_CTRL, 0); + WM_keymap_add_item(keymap, "VIEW3D_OT_snap_menu", SKEY, KM_PRESS, KM_SHIFT, 0); + /* radial control */ RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_radial_control", FKEY, KM_PRESS, 0, 0)->ptr, "mode", WM_RADIALCONTROL_SIZE); RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", WM_RADIALCONTROL_STRENGTH); diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c new file mode 100644 index 00000000000..ad9d3f85538 --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_snap.c @@ -0,0 +1,1148 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <math.h> +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_action_types.h" +#include "DNA_armature_types.h" +#include "DNA_curve_types.h" +#include "DNA_group_types.h" +#include "DNA_ipo_types.h" +#include "DNA_lattice_types.h" +#include "DNA_meta_types.h" +#include "DNA_mesh_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_screen_types.h" +#include "DNA_scene_types.h" +#include "DNA_space_types.h" +#include "DNA_view3d_types.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_editVert.h" +#include "BLI_linklist.h" + +#include "BKE_action.h" +#include "BKE_anim.h" +#include "BKE_context.h" +#include "BKE_armature.h" +#include "BKE_curve.h" +#include "BKE_depsgraph.h" +#include "BKE_DerivedMesh.h" +#include "BKE_displist.h" +#include "BKE_global.h" +#include "BKE_lattice.h" +#include "BKE_mesh.h" +#include "BKE_modifier.h" +#include "BKE_object.h" +#include "BKE_utildefines.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "UI_interface.h" + +#include "ED_anim_api.h" +#include "ED_armature.h" +#include "ED_mesh.h" +#include "ED_screen.h" +#include "ED_view3d.h" + +#include "view3d_intern.h" + + +/* ************************************************** */ +/* ********************* old transform stuff ******** */ +/* *********** will get replaced with new transform * */ +/* ************************************************** */ + +typedef struct TransVert { + float *loc; + float oldloc[3], fac; + float *val, oldval; + int flag; + float *nor; +} TransVert; + +static TransVert *transvmain=NULL; +static int tottrans= 0; + +/* copied from editobject.c, now uses (almost) proper depgraph */ +static void special_transvert_update(Scene *scene, Object *obedit) +{ + + if(obedit) { + + DAG_object_flush_update(scene, obedit, 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); + } + } +} + +/* copied from editobject.c, needs to be replaced with new transform code still */ +/* mode: 1 = proportional, 2 = all joints (for bones only) */ +static void make_trans_verts(Object *obedit, float *min, float *max, int mode) +{ + Nurb *nu; + BezTriple *bezt; + BPoint *bp; + TransVert *tv=NULL; + MetaElem *ml; + EditVert *eve; + EditBone *ebo; + float total, center[3], centroid[3]; + int a; + + tottrans= 0; // global! + + INIT_MINMAX(min, max); + centroid[0]=centroid[1]=centroid[2]= 0.0; + + if(obedit->type==OB_MESH) { + Mesh *me= obedit->data; + EditMesh *em= me->edit_mesh; + int proptrans= 0; + + // transform now requires awareness for select mode, so we tag the f1 flags in verts + tottrans= 0; + if(em->selectmode & SCE_SELECT_VERTEX) { + for(eve= em->verts.first; eve; eve= eve->next) { + if(eve->h==0 && (eve->f & SELECT)) { + eve->f1= SELECT; + tottrans++; + } + else eve->f1= 0; + } + } + else if(em->selectmode & SCE_SELECT_EDGE) { + EditEdge *eed; + for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; + for(eed= em->edges.first; eed; eed= eed->next) { + if(eed->h==0 && (eed->f & SELECT)) eed->v1->f1= eed->v2->f1= SELECT; + } + for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++; + } + else { + EditFace *efa; + for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; + for(efa= em->faces.first; efa; efa= efa->next) { + if(efa->h==0 && (efa->f & SELECT)) { + efa->v1->f1= efa->v2->f1= efa->v3->f1= SELECT; + if(efa->v4) efa->v4->f1= SELECT; + } + } + for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++; + } + + /* proportional edit exception... */ + if((mode & 1) && tottrans) { + for(eve= em->verts.first; eve; eve= eve->next) { + if(eve->h==0) { + eve->f1 |= 2; + proptrans++; + } + } + if(proptrans>tottrans) tottrans= proptrans; + } + + /* and now make transverts */ + if(tottrans) { + tv=transvmain= MEM_callocN(tottrans*sizeof(TransVert), "maketransverts"); + + for(eve= em->verts.first; eve; eve= eve->next) { + if(eve->f1) { + VECCOPY(tv->oldloc, eve->co); + tv->loc= eve->co; + if(eve->no[0]!=0.0 || eve->no[1]!=0.0 ||eve->no[2]!=0.0) + tv->nor= eve->no; // note this is a hackish signal (ton) + tv->flag= eve->f1 & SELECT; + tv++; + } + } + } + } + else if (obedit->type==OB_ARMATURE){ + bArmature *arm= obedit->data; + int totmalloc= BLI_countlist(arm->edbo); + + tv=transvmain= MEM_callocN(totmalloc*sizeof(TransVert), "maketransverts armature"); + + for (ebo= arm->edbo->first; ebo; ebo=ebo->next){ + if(ebo->layer & arm->layer) { + short tipsel= (ebo->flag & BONE_TIPSEL); + short rootsel= (ebo->flag & BONE_ROOTSEL); + short rootok= (!(ebo->parent && (ebo->flag & BONE_CONNECTED) && ebo->parent->flag & BONE_TIPSEL)); + + if ((tipsel && rootsel) || (rootsel)) { + /* Don't add the tip (unless mode & 2, for getting all joints), + * otherwise we get zero-length bones as tips will snap to the same + * location as heads. + */ + if (rootok) { + VECCOPY (tv->oldloc, ebo->head); + tv->loc= ebo->head; + tv->nor= NULL; + tv->flag= 1; + tv++; + tottrans++; + } + + if ((mode & 2) && (tipsel)) { + VECCOPY (tv->oldloc, ebo->tail); + tv->loc= ebo->tail; + tv->nor= NULL; + tv->flag= 1; + tv++; + tottrans++; + } + } + else if (tipsel) { + VECCOPY (tv->oldloc, ebo->tail); + tv->loc= ebo->tail; + tv->nor= NULL; + tv->flag= 1; + tv++; + tottrans++; + } + } + } + } + else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) { + Curve *cu= obedit->data; + int totmalloc= 0; + + for(nu= cu->editnurb->first; nu; nu= nu->next) { + if((nu->type & 7)==CU_BEZIER) + totmalloc += 3*nu->pntsu; + else + totmalloc += nu->pntsu*nu->pntsv; + } + tv=transvmain= MEM_callocN(totmalloc*sizeof(TransVert), "maketransverts curve"); + + nu= cu->editnurb->first; + while(nu) { + if((nu->type & 7)==CU_BEZIER) { + a= nu->pntsu; + bezt= nu->bezt; + while(a--) { + if(bezt->hide==0) { + if((mode & 1) || (bezt->f1 & SELECT)) { + VECCOPY(tv->oldloc, bezt->vec[0]); + tv->loc= bezt->vec[0]; + tv->flag= bezt->f1 & SELECT; + tv++; + tottrans++; + } + if((mode & 1) || (bezt->f2 & SELECT)) { + VECCOPY(tv->oldloc, bezt->vec[1]); + tv->loc= bezt->vec[1]; + tv->val= &(bezt->alfa); + tv->oldval= bezt->alfa; + tv->flag= bezt->f2 & SELECT; + tv++; + tottrans++; + } + if((mode & 1) || (bezt->f3 & SELECT)) { + VECCOPY(tv->oldloc, bezt->vec[2]); + tv->loc= bezt->vec[2]; + tv->flag= bezt->f3 & SELECT; + tv++; + tottrans++; + } + } + bezt++; + } + } + else { + a= nu->pntsu*nu->pntsv; + bp= nu->bp; + while(a--) { + if(bp->hide==0) { + if((mode & 1) || (bp->f1 & SELECT)) { + VECCOPY(tv->oldloc, bp->vec); + tv->loc= bp->vec; + tv->val= &(bp->alfa); + tv->oldval= bp->alfa; + tv->flag= bp->f1 & SELECT; + tv++; + tottrans++; + } + } + bp++; + } + } + nu= nu->next; + } + } + else if(obedit->type==OB_MBALL) { + MetaBall *mb= obedit->data; + int totmalloc= BLI_countlist(mb->editelems); + + tv=transvmain= MEM_callocN(totmalloc*sizeof(TransVert), "maketransverts mball"); + + ml= mb->editelems->first; + while(ml) { + if(ml->flag & SELECT) { + tv->loc= &ml->x; + VECCOPY(tv->oldloc, tv->loc); + tv->val= &(ml->rad); + tv->oldval= ml->rad; + tv->flag= 1; + tv++; + tottrans++; + } + ml= ml->next; + } + } + else if(obedit->type==OB_LATTICE) { + Lattice *lt= obedit->data; + + bp= lt->editlatt->def; + + a= lt->editlatt->pntsu*lt->editlatt->pntsv*lt->editlatt->pntsw; + + tv=transvmain= MEM_callocN(a*sizeof(TransVert), "maketransverts curve"); + + while(a--) { + if((mode & 1) || (bp->f1 & SELECT)) { + if(bp->hide==0) { + VECCOPY(tv->oldloc, bp->vec); + tv->loc= bp->vec; + tv->flag= bp->f1 & SELECT; + tv++; + tottrans++; + } + } + bp++; + } + } + + /* cent etc */ + tv= transvmain; + total= 0.0; + for(a=0; a<tottrans; a++, tv++) { + if(tv->flag & SELECT) { + centroid[0]+= tv->oldloc[0]; + centroid[1]+= tv->oldloc[1]; + centroid[2]+= tv->oldloc[2]; + total+= 1.0; + DO_MINMAX(tv->oldloc, min, max); + } + } + if(total!=0.0) { + centroid[0]/= total; + centroid[1]/= total; + centroid[2]/= total; + } + + center[0]= (min[0]+max[0])/2.0; + center[1]= (min[1]+max[1])/2.0; + center[2]= (min[2]+max[2])/2.0; + +} + +/* *********************** operators ******************** */ + +static int snap_sel_to_grid(bContext *C, wmOperator *op) +{ + extern float originmat[3][3]; /* XXX object.c */ + Object *obedit= CTX_data_edit_object(C); + Scene *scene= CTX_data_scene(C); + View3D *v3d= CTX_wm_view3d(C); + TransVert *tv; + Object *ob; + float gridf, imat[3][3], bmat[3][3], vec[3]; + int a; + + gridf= v3d->gridview; + + if(obedit) { + tottrans= 0; + + if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) + make_trans_verts(obedit, bmat[0], bmat[1], 0); + if(tottrans==0) return OPERATOR_CANCELLED; + + Mat3CpyMat4(bmat, obedit->obmat); + Mat3Inv(imat, bmat); + + tv= transvmain; + for(a=0; a<tottrans; a++, tv++) { + + VECCOPY(vec, tv->loc); + Mat3MulVecfl(bmat, vec); + VecAddf(vec, vec, obedit->obmat[3]); + vec[0]= v3d->gridview*floor(.5+ vec[0]/gridf); + vec[1]= v3d->gridview*floor(.5+ vec[1]/gridf); + vec[2]= v3d->gridview*floor(.5+ vec[2]/gridf); + VecSubf(vec, vec, obedit->obmat[3]); + + Mat3MulVecfl(imat, vec); + VECCOPY(tv->loc, vec); + } + + special_transvert_update(scene, obedit); + + MEM_freeN(transvmain); + transvmain= NULL; + + } + else { + + CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { + ob= base->object; + + if(ob->flag & OB_POSEMODE) { + bPoseChannel *pchan; + bArmature *arm= ob->data; + + for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { + if(pchan->bone->flag & BONE_SELECTED) { + if(pchan->bone->layer & arm->layer) { + if((pchan->bone->flag & BONE_CONNECTED)==0) { + float vecN[3], nLoc[3]; + + /* get nearest grid point to snap to */ + VECCOPY(nLoc, pchan->pose_mat[3]); + vec[0]= gridf * (float)(floor(.5+ nLoc[0]/gridf)); + vec[1]= gridf * (float)(floor(.5+ nLoc[1]/gridf)); + vec[2]= gridf * (float)(floor(.5+ nLoc[2]/gridf)); + + /* get bone-space location of grid point */ + armature_loc_pose_to_bone(pchan, vec, vecN); + + /* adjust location */ + VECCOPY(pchan->loc, vecN); + } + /* if the bone has a parent and is connected to the parent, + * don't do anything - will break chain unless we do auto-ik. + */ + } + } + } + ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK); + + /* auto-keyframing */ +// XXX autokeyframe_pose_cb_func(ob, TFM_TRANSLATION, 0); + DAG_object_flush_update(scene, ob, OB_RECALC_DATA); + } + else { + ob->recalc |= OB_RECALC_OB; + + vec[0]= -ob->obmat[3][0]+v3d->gridview*floor(.5+ ob->obmat[3][0]/gridf); + vec[1]= -ob->obmat[3][1]+v3d->gridview*floor(.5+ ob->obmat[3][1]/gridf); + vec[2]= -ob->obmat[3][2]+v3d->gridview*floor(.5+ ob->obmat[3][2]/gridf); + + if(ob->parent) { + where_is_object(scene, ob); + + Mat3Inv(imat, originmat); + Mat3MulVecfl(imat, vec); + ob->loc[0]+= vec[0]; + ob->loc[1]+= vec[1]; + ob->loc[2]+= vec[2]; + } + else { + ob->loc[0]+= vec[0]; + ob->loc[1]+= vec[1]; + ob->loc[2]+= vec[2]; + } + + /* auto-keyframing */ +// XXX autokeyframe_ob_cb_func(ob, TFM_TRANSLATION); + } + } + CTX_DATA_END; + } + ED_anim_dag_flush_update(C); + WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL); + + return OPERATOR_FINISHED; +} + +void VIEW3D_OT_snap_selected_to_grid(wmOperatorType *ot) +{ + + /* identifiers */ + ot->name= "Snap Selection to Grid"; + ot->idname= "VIEW3D_OT_snap_selected_to_grid"; + + /* api callbacks */ + ot->exec= snap_sel_to_grid; + ot->poll= ED_operator_view3d_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/* *************************************************** */ + +static int snap_sel_to_curs(bContext *C, wmOperator *op) +{ + extern float originmat[3][3]; /* XXX object.c */ + Object *obedit= CTX_data_edit_object(C); + Scene *scene= CTX_data_scene(C); + View3D *v3d= CTX_wm_view3d(C); + TransVert *tv; + Object *ob; + float *curs, imat[3][3], bmat[3][3], vec[3]; + int a; + + curs= give_cursor(scene, v3d); + + if(obedit) { + tottrans= 0; + + if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) + make_trans_verts(obedit, bmat[0], bmat[1], 0); + if(tottrans==0) return OPERATOR_CANCELLED; + + Mat3CpyMat4(bmat, obedit->obmat); + Mat3Inv(imat, bmat); + + tv= transvmain; + for(a=0; a<tottrans; a++, tv++) { + vec[0]= curs[0]-obedit->obmat[3][0]; + vec[1]= curs[1]-obedit->obmat[3][1]; + vec[2]= curs[2]-obedit->obmat[3][2]; + + Mat3MulVecfl(imat, vec); + VECCOPY(tv->loc, vec); + } + + special_transvert_update(scene, obedit); + + MEM_freeN(transvmain); + transvmain= NULL; + + } + else { + CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { + ob= base->object; + if(ob->flag & OB_POSEMODE) { + bPoseChannel *pchan; + bArmature *arm= ob->data; + float cursp[3]; + + Mat4Invert(ob->imat, ob->obmat); + VECCOPY(cursp, curs); + Mat4MulVecfl(ob->imat, cursp); + + for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) { + if(pchan->bone->flag & BONE_SELECTED) { + if(pchan->bone->layer & arm->layer) { + if((pchan->bone->flag & BONE_CONNECTED)==0) { + float curspn[3]; + + /* get location of cursor in bone-space */ + armature_loc_pose_to_bone(pchan, cursp, curspn); + + /* calculate new position */ + VECCOPY(pchan->loc, curspn); + } + /* if the bone has a parent and is connected to the parent, + * don't do anything - will break chain unless we do auto-ik. + */ + } + } + } + ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK); + + /* auto-keyframing */ +// XXX autokeyframe_pose_cb_func(ob, TFM_TRANSLATION, 0); + DAG_object_flush_update(scene, ob, OB_RECALC_DATA); + } + else { + ob->recalc |= OB_RECALC_OB; + + vec[0]= -ob->obmat[3][0] + curs[0]; + vec[1]= -ob->obmat[3][1] + curs[1]; + vec[2]= -ob->obmat[3][2] + curs[2]; + + if(ob->parent) { + where_is_object(scene, ob); + + Mat3Inv(imat, originmat); + Mat3MulVecfl(imat, vec); + ob->loc[0]+= vec[0]; + ob->loc[1]+= vec[1]; + ob->loc[2]+= vec[2]; + } + else { + ob->loc[0]+= vec[0]; + ob->loc[1]+= vec[1]; + ob->loc[2]+= vec[2]; + } + /* auto-keyframing */ +// XXX autokeyframe_ob_cb_func(ob, TFM_TRANSLATION); + } + } + CTX_DATA_END; + } + ED_anim_dag_flush_update(C); + WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL); + + return OPERATOR_FINISHED; +} + +void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot) +{ + + /* identifiers */ + ot->name= "Snap Selection to Cursor"; + ot->idname= "VIEW3D_OT_snap_selected_to_cursor"; + + /* api callbacks */ + ot->exec= snap_sel_to_curs; + ot->poll= ED_operator_view3d_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/* *************************************************** */ + +static int snap_curs_to_grid(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + View3D *v3d= CTX_wm_view3d(C); + float gridf, *curs; + + gridf= v3d->gridview; + curs= give_cursor(scene, v3d); + + curs[0]= v3d->gridview*floor(.5+curs[0]/gridf); + curs[1]= v3d->gridview*floor(.5+curs[1]/gridf); + curs[2]= v3d->gridview*floor(.5+curs[2]/gridf); + + WM_event_add_notifier(C, NC_SCENE|ND_TRANSFORM, scene); // hrm + + return OPERATOR_FINISHED; +} + +void VIEW3D_OT_snap_cursor_to_grid(wmOperatorType *ot) +{ + + /* identifiers */ + ot->name= "Snap Cursor to Grid"; + ot->idname= "VIEW3D_OT_snap_cursor_to_grid"; + + /* api callbacks */ + ot->exec= snap_curs_to_grid; + ot->poll= ED_operator_view3d_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/* **************************************************** */ + +static int snap_curs_to_sel(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + Scene *scene= CTX_data_scene(C); + View3D *v3d= CTX_wm_view3d(C); + TransVert *tv; + float *curs, bmat[3][3], vec[3], min[3], max[3], centroid[3]; + int count, a; + + curs= give_cursor(scene, v3d); + + count= 0; + INIT_MINMAX(min, max); + centroid[0]= centroid[1]= centroid[2]= 0.0; + + if(obedit) { + tottrans=0; + + if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) + make_trans_verts(obedit, bmat[0], bmat[1], 2); + if(tottrans==0) return OPERATOR_CANCELLED; + + Mat3CpyMat4(bmat, obedit->obmat); + + tv= transvmain; + for(a=0; a<tottrans; a++, tv++) { + VECCOPY(vec, tv->loc); + Mat3MulVecfl(bmat, vec); + VecAddf(vec, vec, obedit->obmat[3]); + VecAddf(centroid, centroid, vec); + DO_MINMAX(vec, min, max); + } + + if(v3d->around==V3D_CENTROID) { + VecMulf(centroid, 1.0/(float)tottrans); + VECCOPY(curs, centroid); + } + else { + curs[0]= (min[0]+max[0])/2; + curs[1]= (min[1]+max[1])/2; + curs[2]= (min[2]+max[2])/2; + } + MEM_freeN(transvmain); + transvmain= NULL; + } + else { + Object *ob= OBACT; + + if(ob && (ob->flag & OB_POSEMODE)) { + bArmature *arm= ob->data; + bPoseChannel *pchan; + for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) { + if(arm->layer & pchan->bone->layer) { + if(pchan->bone->flag & BONE_SELECTED) { + VECCOPY(vec, pchan->pose_head); + Mat4MulVecfl(ob->obmat, vec); + VecAddf(centroid, centroid, vec); + DO_MINMAX(vec, min, max); + count++; + } + } + } + } + else { + CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { + VECCOPY(vec, base->object->obmat[3]); + VecAddf(centroid, centroid, vec); + DO_MINMAX(vec, min, max); + count++; + } + CTX_DATA_END; + } + if(count) { + if(v3d->around==V3D_CENTROID) { + VecMulf(centroid, 1.0/(float)count); + VECCOPY(curs, centroid); + } + else { + curs[0]= (min[0]+max[0])/2; + curs[1]= (min[1]+max[1])/2; + curs[2]= (min[2]+max[2])/2; + } + } + } + WM_event_add_notifier(C, NC_SCENE|ND_TRANSFORM, scene); // hrm + + return OPERATOR_FINISHED; +} + +void VIEW3D_OT_snap_cursor_to_selected(wmOperatorType *ot) +{ + + /* identifiers */ + ot->name= "Snap Cursor to Selected"; + ot->idname= "VIEW3D_OT_snap_cursor_to_selected"; + + /* api callbacks */ + ot->exec= snap_curs_to_sel; + ot->poll= ED_operator_view3d_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/* ********************************************** */ + +static int snap_curs_to_active(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + Scene *scene= CTX_data_scene(C); + View3D *v3d= CTX_wm_view3d(C); + float *curs; + + curs = give_cursor(scene, v3d); + + if (obedit) { + if (obedit->type == OB_MESH) { + /* check active */ + Mesh *me= obedit->data; + EditSelection ese; + + if (EM_get_actSelection(me->edit_mesh, &ese)) { + EM_editselection_center(curs, &ese); + } + + Mat4MulVecfl(obedit->obmat, curs); + } + } + else { + if (BASACT) { + VECCOPY(curs, BASACT->object->obmat[3]); + } + } + + WM_event_add_notifier(C, NC_SCENE|ND_TRANSFORM, scene); + return OPERATOR_FINISHED; +} + +void VIEW3D_OT_snap_cursor_to_active(wmOperatorType *ot) +{ + + /* identifiers */ + ot->name= "Snap Cursor to Active"; + ot->idname= "VIEW3D_OT_snap_cursor_to_active"; + + /* api callbacks */ + ot->exec= snap_curs_to_active; + ot->poll= ED_operator_view3d_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/* ************************************** */ + +static int snap_selected_to_center(bContext *C, wmOperator *op) +{ + extern float originmat[3][3]; /* XXX object.c */ + Object *obedit= CTX_data_edit_object(C); + Scene *scene= CTX_data_scene(C); + View3D *v3d= CTX_wm_view3d(C); + TransVert *tv; + Object *ob; + float snaploc[3], imat[3][3], bmat[3][3], vec[3], min[3], max[3], centroid[3]; + int count, a; + + /*calculate the snaplocation (centerpoint) */ + count= 0; + INIT_MINMAX(min, max); + centroid[0]= centroid[1]= centroid[2]= 0.0f; + snaploc[0]= snaploc[1]= snaploc[2]= 0.0f; + + if(obedit) { + tottrans= 0; + + if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) + make_trans_verts(obedit, bmat[0], bmat[1], 0); + if(tottrans==0) return OPERATOR_CANCELLED; + + Mat3CpyMat4(bmat, obedit->obmat); + Mat3Inv(imat, bmat); + + tv= transvmain; + for(a=0; a<tottrans; a++, tv++) { + VECCOPY(vec, tv->loc); + Mat3MulVecfl(bmat, vec); + VecAddf(vec, vec, obedit->obmat[3]); + VecAddf(centroid, centroid, vec); + DO_MINMAX(vec, min, max); + } + + if(v3d->around==V3D_CENTROID) { + VecMulf(centroid, 1.0/(float)tottrans); + VECCOPY(snaploc, centroid); + } + else { + snaploc[0]= (min[0]+max[0])/2; + snaploc[1]= (min[1]+max[1])/2; + snaploc[2]= (min[2]+max[2])/2; + } + + MEM_freeN(transvmain); + transvmain= NULL; + } + else { + + CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { + ob= base->object; + if(ob->flag & OB_POSEMODE) { + bPoseChannel *pchan; + bArmature *arm= ob->data; + + for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) { + if(pchan->bone->flag & BONE_SELECTED) { + if(pchan->bone->layer & arm->layer) { + VECCOPY(vec, pchan->pose_mat[3]); + VecAddf(centroid, centroid, vec); + DO_MINMAX(vec, min, max); + count++; + } + } + } + } + else { + /* not armature bones (i.e. objects) */ + VECCOPY(vec, base->object->obmat[3]); + VecAddf(centroid, centroid, vec); + DO_MINMAX(vec, min, max); + count++; + } + } + CTX_DATA_END; + + if(count) { + if(v3d->around==V3D_CENTROID) { + VecMulf(centroid, 1.0/(float)count); + VECCOPY(snaploc, centroid); + } + else { + snaploc[0]= (min[0]+max[0])/2; + snaploc[1]= (min[1]+max[1])/2; + snaploc[2]= (min[2]+max[2])/2; + } + } + } + + /* Snap the selection to the snaplocation (duh!) */ + if(obedit) { + tottrans= 0; + + if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) + make_trans_verts(obedit, bmat[0], bmat[1], 0); + if(tottrans==0) return OPERATOR_CANCELLED; + + Mat3CpyMat4(bmat, obedit->obmat); + Mat3Inv(imat, bmat); + + tv= transvmain; + for(a=0; a<tottrans; a++, tv++) { + vec[0]= snaploc[0]-obedit->obmat[3][0]; + vec[1]= snaploc[1]-obedit->obmat[3][1]; + vec[2]= snaploc[2]-obedit->obmat[3][2]; + + Mat3MulVecfl(imat, vec); + VECCOPY(tv->loc, vec); + } + + special_transvert_update(scene, obedit); + + MEM_freeN(transvmain); + transvmain= NULL; + + } + else { + + CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { + ob= base->object; + if(ob->flag & OB_POSEMODE) { + bPoseChannel *pchan; + bArmature *arm= ob->data; + + for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) { + if(pchan->bone->flag & BONE_SELECTED) { + if(pchan->bone->layer & arm->layer) { + if((pchan->bone->flag & BONE_CONNECTED)==0) { + /* get location of cursor in bone-space */ + armature_loc_pose_to_bone(pchan, snaploc, vec); + + /* calculate new position */ + VECCOPY(pchan->loc, vec); + } + /* if the bone has a parent and is connected to the parent, + * don't do anything - will break chain unless we do auto-ik. + */ + } + } + } + + /* auto-keyframing */ + ob->pose->flag |= POSE_DO_UNLOCK; +// XXX autokeyframe_pose_cb_func(ob, TFM_TRANSLATION, 0); + DAG_object_flush_update(scene, ob, OB_RECALC_DATA); + } + else { + ob->recalc |= OB_RECALC_OB; + + vec[0]= -ob->obmat[3][0] + snaploc[0]; + vec[1]= -ob->obmat[3][1] + snaploc[1]; + vec[2]= -ob->obmat[3][2] + snaploc[2]; + + if(ob->parent) { + where_is_object(scene, ob); + + Mat3Inv(imat, originmat); + Mat3MulVecfl(imat, vec); + ob->loc[0]+= vec[0]; + ob->loc[1]+= vec[1]; + ob->loc[2]+= vec[2]; + } + else { + ob->loc[0]+= vec[0]; + ob->loc[1]+= vec[1]; + ob->loc[2]+= vec[2]; + } + /* auto-keyframing */ +// XXX autokeyframe_ob_cb_func(ob, TFM_TRANSLATION); + } + } + CTX_DATA_END; + } + + ED_anim_dag_flush_update(C); + WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL); + + return OPERATOR_FINISHED; +} + +void VIEW3D_OT_snap_selected_to_center(wmOperatorType *ot) +{ + + /* identifiers */ + ot->name= "Snap Selection to Center"; + ot->idname= "VIEW3D_OT_snap_selected_to_center"; + + /* api callbacks */ + ot->exec= snap_selected_to_center; + ot->poll= ED_operator_view3d_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + + +int minmax_verts(Object *obedit, float *min, float *max) +{ + TransVert *tv; + float centroid[3], vec[3], bmat[3][3]; + int a; + + tottrans=0; + if ELEM5(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE) + make_trans_verts(obedit, bmat[0], bmat[1], 2); + + if(tottrans==0) return 0; + + Mat3CpyMat4(bmat, obedit->obmat); + + tv= transvmain; + for(a=0; a<tottrans; a++, tv++) { + VECCOPY(vec, tv->loc); + Mat3MulVecfl(bmat, vec); + VecAddf(vec, vec, obedit->obmat[3]); + VecAddf(centroid, centroid, vec); + DO_MINMAX(vec, min, max); + } + + MEM_freeN(transvmain); + transvmain= NULL; + + return 1; +} + +/* ************************************************* */ + +static int snap_menu_invoke(bContext *C, wmOperator *unused, wmEvent *event) +{ + uiMenuItem *head= uiPupMenuBegin("Snap", 0); + + uiMenuItemO(head, 0, "VIEW3D_OT_snap_selected_to_grid"); + uiMenuItemO(head, 0, "VIEW3D_OT_snap_selected_to_cursor"); + uiMenuItemO(head, 0, "VIEW3D_OT_snap_selected_to_center"); + uiMenuSeparator(head); + uiMenuItemO(head, 0, "VIEW3D_OT_snap_cursor_to_selected"); + uiMenuItemO(head, 0, "VIEW3D_OT_snap_cursor_to_grid"); + uiMenuItemO(head, 0, "VIEW3D_OT_snap_cursor_to_active"); + + uiPupMenuEnd(C, head); + + /* this operator is only for a menu, not used further */ + return OPERATOR_CANCELLED; +} + +/* only used as menu */ +void VIEW3D_OT_snap_menu(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Snap Menu"; + ot->idname= "VIEW3D_OT_snap_menu"; + + /* api callbacks */ + ot->invoke= snap_menu_invoke; + + ot->poll= ED_operator_view3d_active; + + /* flags */ + ot->flag= 0; +} + + |