1ed65f7875f96eb5bbb1ae48dec03e3664bf0f35
[blender.git] / source / blender / editors / space_view3d / view3d_snap.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 /** \file blender/editors/space_view3d/view3d_snap.c
31  *  \ingroup spview3d
32  */
33
34
35 #include <math.h>
36 #include <string.h>
37
38 #include "MEM_guardedalloc.h"
39
40 #include "DNA_armature_types.h"
41 #include "DNA_curve_types.h"
42 #include "DNA_lattice_types.h"
43 #include "DNA_meta_types.h"
44 #include "DNA_scene_types.h"
45 #include "DNA_object_types.h"
46
47 #include "BLI_blenlib.h"
48 #include "BLI_math.h"
49 #include "BLI_editVert.h"
50 #include "BLI_linklist.h"
51 #include "BLI_utildefines.h"
52
53 #include "BKE_armature.h"
54 #include "BKE_context.h"
55 #include "BKE_curve.h"
56 #include "BKE_depsgraph.h"
57 #include "BKE_lattice.h"
58 #include "BKE_main.h"
59 #include "BKE_object.h"
60
61 #include "WM_api.h"
62 #include "WM_types.h"
63
64
65
66 #include "ED_armature.h"
67 #include "ED_mesh.h"
68 #include "ED_screen.h"
69 #include "ED_curve.h" /* for curve_editnurbs */
70
71 #include "view3d_intern.h"
72
73 extern float originmat[3][3];   /* XXX object.c */
74
75 /* ************************************************** */
76 /* ********************* old transform stuff ******** */
77 /* *********** will get replaced with new transform * */
78 /* ************************************************** */
79
80 typedef struct TransVert {
81         float *loc;
82         float oldloc[3], fac;
83         float *val, oldval;
84         int flag;
85         float *nor;
86 } TransVert;
87
88 static TransVert *transvmain=NULL;
89 static int tottrans= 0;
90
91 /* copied from editobject.c, now uses (almost) proper depgraph */
92 static void special_transvert_update(Object *obedit)
93 {
94         
95         if(obedit) {
96                 
97                 DAG_id_tag_update(obedit->data, 0);
98                 
99                 if(obedit->type==OB_MESH) {
100                         Mesh *me= obedit->data;
101                         recalc_editnormals(me->edit_mesh);      // does face centers too
102                 }
103                 else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
104                         Curve *cu= obedit->data;
105                         ListBase *nurbs= curve_editnurbs(cu);
106                         Nurb *nu= nurbs->first;
107
108                         while(nu) {
109                                 /* keep handles' vectors unchanged */
110                                 if(nu->bezt) {
111                                         int a= nu->pntsu;
112                                         TransVert *tv= transvmain;
113                                         BezTriple *bezt= nu->bezt;
114
115                                         while(a--) {
116                                                 if(bezt->f1 & SELECT) tv++;
117
118                                                 if(bezt->f2 & SELECT) {
119                                                         float v[3];
120
121                                                         if(bezt->f1 & SELECT) {
122                                                                 sub_v3_v3v3(v, (tv-1)->oldloc, tv->oldloc);
123                                                                 add_v3_v3v3(bezt->vec[0], bezt->vec[1], v);
124                                                         }
125
126                                                         if(bezt->f3 & SELECT) {
127                                                                 sub_v3_v3v3(v, (tv+1)->oldloc, tv->oldloc);
128                                                                 add_v3_v3v3(bezt->vec[2], bezt->vec[1], v);
129                                                         }
130
131                                                         tv++;
132                                                 }
133
134                                                 if(bezt->f3 & SELECT) tv++;
135
136                                                 bezt++;
137                                         }
138                                 }
139
140                                 test2DNurb(nu);
141                                 testhandlesNurb(nu); /* test for bezier too */
142                                 nu= nu->next;
143                         }
144                 }
145                 else if(obedit->type==OB_ARMATURE){
146                         bArmature *arm= obedit->data;
147                         EditBone *ebo;
148                         TransVert *tv= transvmain;
149                         int a=0;
150                         
151                         /* Ensure all bone tails are correctly adjusted */
152                         for (ebo= arm->edbo->first; ebo; ebo=ebo->next) {
153                                 /* adjust tip if both ends selected */
154                                 if ((ebo->flag & BONE_ROOTSEL) && (ebo->flag & BONE_TIPSEL)) {
155                                         if (tv) {
156                                                 float diffvec[3];
157                                                 
158                                                 sub_v3_v3v3(diffvec, tv->loc, tv->oldloc);
159                                                 add_v3_v3(ebo->tail, diffvec);
160                                                 
161                                                 a++;
162                                                 if (a<tottrans) tv++;
163                                         }
164                                 }
165                         }
166                         
167                         /* Ensure all bones are correctly adjusted */
168                         for (ebo= arm->edbo->first; ebo; ebo=ebo->next) {
169                                 if ((ebo->flag & BONE_CONNECTED) && ebo->parent){
170                                         /* If this bone has a parent tip that has been moved */
171                                         if (ebo->parent->flag & BONE_TIPSEL){
172                                                 VECCOPY (ebo->head, ebo->parent->tail);
173                                         }
174                                         /* If this bone has a parent tip that has NOT been moved */
175                                         else{
176                                                 VECCOPY (ebo->parent->tail, ebo->head);
177                                         }
178                                 }
179                         }
180                         if(arm->flag & ARM_MIRROR_EDIT) 
181                                 transform_armature_mirror_update(obedit);
182                 }
183                 else if(obedit->type==OB_LATTICE) {
184                         Lattice *lt= obedit->data;
185                         
186                         if(lt->editlatt->latt->flag & LT_OUTSIDE)
187                                 outside_lattice(lt->editlatt->latt);
188                 }
189         }
190 }
191
192 /* copied from editobject.c, needs to be replaced with new transform code still */
193 /* mode flags: */
194 #define TM_ALL_JOINTS           1 /* all joints (for bones only) */
195 #define TM_SKIP_HANDLES         2 /* skip handles when control point is selected (for curves only) */
196 static void make_trans_verts(Object *obedit, float *min, float *max, int mode)  
197 {
198         Nurb *nu;
199         BezTriple *bezt;
200         BPoint *bp;
201         TransVert *tv=NULL;
202         MetaElem *ml;
203         EditVert *eve;
204         EditBone        *ebo;
205         float total, center[3], centroid[3];
206         int a;
207
208         tottrans= 0; // global!
209         
210         INIT_MINMAX(min, max);
211         centroid[0]=centroid[1]=centroid[2]= 0.0;
212         
213         if(obedit->type==OB_MESH) {
214                 Mesh *me= obedit->data;
215                 EditMesh *em= me->edit_mesh;
216                 
217                 // transform now requires awareness for select mode, so we tag the f1 flags in verts
218                 tottrans= 0;
219                 if(em->selectmode & SCE_SELECT_VERTEX) {
220                         for(eve= em->verts.first; eve; eve= eve->next) {
221                                 if(eve->h==0 && (eve->f & SELECT)) {
222                                         eve->f1= SELECT;
223                                         tottrans++;
224                                 }
225                                 else eve->f1= 0;
226                         }
227                 }
228                 else if(em->selectmode & SCE_SELECT_EDGE) {
229                         EditEdge *eed;
230                         for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
231                         for(eed= em->edges.first; eed; eed= eed->next) {
232                                 if(eed->h==0 && (eed->f & SELECT)) eed->v1->f1= eed->v2->f1= SELECT;
233                         }
234                         for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++;
235                 }
236                 else {
237                         EditFace *efa;
238                         for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
239                         for(efa= em->faces.first; efa; efa= efa->next) {
240                                 if(efa->h==0 && (efa->f & SELECT)) {
241                                         efa->v1->f1= efa->v2->f1= efa->v3->f1= SELECT;
242                                         if(efa->v4) efa->v4->f1= SELECT;
243                                 }
244                         }
245                         for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++;
246                 }
247                 
248                 /* and now make transverts */
249                 if(tottrans) {
250                         tv=transvmain= MEM_callocN(tottrans*sizeof(TransVert), "maketransverts");
251
252                         for(eve= em->verts.first; eve; eve= eve->next) {
253                                 if(eve->f1) {
254                                         VECCOPY(tv->oldloc, eve->co);
255                                         tv->loc= eve->co;
256                                         if(eve->no[0] != 0.0f || eve->no[1] != 0.0f ||eve->no[2] != 0.0f)
257                                                 tv->nor= eve->no; // note this is a hackish signal (ton)
258                                         tv->flag= eve->f1 & SELECT;
259                                         tv++;
260                                 }
261                         }
262                 }
263         }
264         else if (obedit->type==OB_ARMATURE){
265                 bArmature *arm= obedit->data;
266                 int totmalloc= BLI_countlist(arm->edbo);
267
268                 totmalloc *= 2;  /* probably overkill but bones can have 2 trans verts each */
269
270                 tv=transvmain= MEM_callocN(totmalloc*sizeof(TransVert), "maketransverts armature");
271                 
272                 for (ebo= arm->edbo->first; ebo; ebo=ebo->next){
273                         if(ebo->layer & arm->layer) {
274                                 short tipsel= (ebo->flag & BONE_TIPSEL);
275                                 short rootsel= (ebo->flag & BONE_ROOTSEL);
276                                 short rootok= (!(ebo->parent && (ebo->flag & BONE_CONNECTED) && ebo->parent->flag & BONE_TIPSEL));
277                                 
278                                 if ((tipsel && rootsel) || (rootsel)) {
279                                         /* Don't add the tip (unless mode & TM_ALL_JOINTS, for getting all joints),
280                                          * otherwise we get zero-length bones as tips will snap to the same
281                                          * location as heads. 
282                                          */
283                                         if (rootok) {
284                                                 VECCOPY (tv->oldloc, ebo->head);
285                                                 tv->loc= ebo->head;
286                                                 tv->nor= NULL;
287                                                 tv->flag= 1;
288                                                 tv++;
289                                                 tottrans++;
290                                         }       
291                                         
292                                         if ((mode & TM_ALL_JOINTS) && (tipsel)) {
293                                                 VECCOPY (tv->oldloc, ebo->tail);
294                                                 tv->loc= ebo->tail;
295                                                 tv->nor= NULL;
296                                                 tv->flag= 1;
297                                                 tv++;
298                                                 tottrans++;
299                                         }                                       
300                                 }
301                                 else if (tipsel) {
302                                         VECCOPY (tv->oldloc, ebo->tail);
303                                         tv->loc= ebo->tail;
304                                         tv->nor= NULL;
305                                         tv->flag= 1;
306                                         tv++;
307                                         tottrans++;
308                                 }
309                         }                       
310                 }
311         }
312         else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
313                 Curve *cu= obedit->data;
314                 int totmalloc= 0;
315                 ListBase *nurbs= curve_editnurbs(cu);
316
317                 for(nu= nurbs->first; nu; nu= nu->next) {
318                         if(nu->type == CU_BEZIER)
319                                 totmalloc += 3*nu->pntsu;
320                         else
321                                 totmalloc += nu->pntsu*nu->pntsv;
322                 }
323                 tv=transvmain= MEM_callocN(totmalloc*sizeof(TransVert), "maketransverts curve");
324
325                 nu= nurbs->first;
326                 while(nu) {
327                         if(nu->type == CU_BEZIER) {
328                                 a= nu->pntsu;
329                                 bezt= nu->bezt;
330                                 while(a--) {
331                                         if(bezt->hide==0) {
332                                                 int skip_handle= 0;
333                                                 if(bezt->f2 & SELECT)
334                                                         skip_handle= mode & TM_SKIP_HANDLES;
335
336                                                 if((bezt->f1 & SELECT) && !skip_handle) {
337                                                         VECCOPY(tv->oldloc, bezt->vec[0]);
338                                                         tv->loc= bezt->vec[0];
339                                                         tv->flag= bezt->f1 & SELECT;
340                                                         tv++;
341                                                         tottrans++;
342                                                 }
343                                                 if(bezt->f2 & SELECT) {
344                                                         VECCOPY(tv->oldloc, bezt->vec[1]);
345                                                         tv->loc= bezt->vec[1];
346                                                         tv->val= &(bezt->alfa);
347                                                         tv->oldval= bezt->alfa;
348                                                         tv->flag= bezt->f2 & SELECT;
349                                                         tv++;
350                                                         tottrans++;
351                                                 }
352                                                 if((bezt->f3 & SELECT) && !skip_handle) {
353                                                         VECCOPY(tv->oldloc, bezt->vec[2]);
354                                                         tv->loc= bezt->vec[2];
355                                                         tv->flag= bezt->f3 & SELECT;
356                                                         tv++;
357                                                         tottrans++;
358                                                 }
359                                         }
360                                         bezt++;
361                                 }
362                         }
363                         else {
364                                 a= nu->pntsu*nu->pntsv;
365                                 bp= nu->bp;
366                                 while(a--) {
367                                         if(bp->hide==0) {
368                                                 if(bp->f1 & SELECT) {
369                                                         VECCOPY(tv->oldloc, bp->vec);
370                                                         tv->loc= bp->vec;
371                                                         tv->val= &(bp->alfa);
372                                                         tv->oldval= bp->alfa;
373                                                         tv->flag= bp->f1 & SELECT;
374                                                         tv++;
375                                                         tottrans++;
376                                                 }
377                                         }
378                                         bp++;
379                                 }
380                         }
381                         nu= nu->next;
382                 }
383         }
384         else if(obedit->type==OB_MBALL) {
385                 MetaBall *mb= obedit->data;
386                 int totmalloc= BLI_countlist(mb->editelems);
387                 
388                 tv=transvmain= MEM_callocN(totmalloc*sizeof(TransVert), "maketransverts mball");
389                 
390                 ml= mb->editelems->first;
391                 while(ml) {
392                         if(ml->flag & SELECT) {
393                                 tv->loc= &ml->x;
394                                 copy_v3_v3(tv->oldloc, tv->loc);
395                                 tv->val= &(ml->rad);
396                                 tv->oldval= ml->rad;
397                                 tv->flag= 1;
398                                 tv++;
399                                 tottrans++;
400                         }
401                         ml= ml->next;
402                 }
403         }
404         else if(obedit->type==OB_LATTICE) {
405                 Lattice *lt= obedit->data;
406                 
407                 bp= lt->editlatt->latt->def;
408                 
409                 a= lt->editlatt->latt->pntsu*lt->editlatt->latt->pntsv*lt->editlatt->latt->pntsw;
410                 
411                 tv=transvmain= MEM_callocN(a*sizeof(TransVert), "maketransverts latt");
412                 
413                 while(a--) {
414                         if(bp->f1 & SELECT) {
415                                 if(bp->hide==0) {
416                                         copy_v3_v3(tv->oldloc, bp->vec);
417                                         tv->loc= bp->vec;
418                                         tv->flag= bp->f1 & SELECT;
419                                         tv++;
420                                         tottrans++;
421                                 }
422                         }
423                         bp++;
424                 }
425         }
426         
427         if(!tottrans && transvmain) {
428                 /* prevent memory leak. happens for curves/latticies due to */
429                 /* difficult condition of adding points to trans data */
430                 MEM_freeN(transvmain);
431                 transvmain= NULL;
432         }
433
434         /* cent etc */
435         tv= transvmain;
436         total= 0.0;
437         for(a=0; a<tottrans; a++, tv++) {
438                 if(tv->flag & SELECT) {
439                         add_v3_v3(centroid, tv->oldloc);
440                         total += 1.0f;
441                         DO_MINMAX(tv->oldloc, min, max);
442                 }
443         }
444         if(total != 0.0f) {
445                 mul_v3_fl(centroid, 1.0f/total);
446         }
447
448         mid_v3_v3v3(center, min, max);
449 }
450
451 /* *********************** operators ******************** */
452
453 static int snap_sel_to_grid(bContext *C, wmOperator *UNUSED(op))
454 {
455         Main *bmain= CTX_data_main(C);
456         Object *obedit= CTX_data_edit_object(C);
457         Scene *scene= CTX_data_scene(C);
458         RegionView3D *rv3d= CTX_wm_region_data(C);
459         TransVert *tv;
460         float gridf, imat[3][3], bmat[3][3], vec[3];
461         int a;
462
463         gridf= rv3d->gridview;
464
465         if(obedit) {
466                 tottrans= 0;
467                 
468                 if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
469                         make_trans_verts(obedit, bmat[0], bmat[1], 0);
470                 if(tottrans==0) return OPERATOR_CANCELLED;
471                 
472                 copy_m3_m4(bmat, obedit->obmat);
473                 invert_m3_m3(imat, bmat);
474                 
475                 tv= transvmain;
476                 for(a=0; a<tottrans; a++, tv++) {
477                         
478                         VECCOPY(vec, tv->loc);
479                         mul_m3_v3(bmat, vec);
480                         add_v3_v3(vec, obedit->obmat[3]);
481                         vec[0]= gridf*floorf(0.5f+ vec[0]/gridf);
482                         vec[1]= gridf*floorf(0.5f+ vec[1]/gridf);
483                         vec[2]= gridf*floorf(0.5f+ vec[2]/gridf);
484                         sub_v3_v3(vec, obedit->obmat[3]);
485                         
486                         mul_m3_v3(imat, vec);
487                         VECCOPY(tv->loc, vec);
488                 }
489                 
490                 special_transvert_update(obedit);
491                 
492                 MEM_freeN(transvmain);
493                 transvmain= NULL;
494         
495         }
496         else {
497
498                 CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
499                         if(ob->mode & OB_MODE_POSE) {
500                                 bPoseChannel *pchan;
501                                 bArmature *arm= ob->data;
502                                 
503                                 for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
504                                         if(pchan->bone->flag & BONE_SELECTED) {
505                                                 if(pchan->bone->layer & arm->layer) {
506                                                         if((pchan->bone->flag & BONE_CONNECTED)==0) { 
507                                                                 float vecN[3], nLoc[3]; 
508                                                                 
509                                                                 /* get nearest grid point to snap to */
510                                                                 VECCOPY(nLoc, pchan->pose_mat[3]);
511                                                                 vec[0]= gridf * (float)(floor(0.5f+ nLoc[0]/gridf));
512                                                                 vec[1]= gridf * (float)(floor(0.5f+ nLoc[1]/gridf));
513                                                                 vec[2]= gridf * (float)(floor(0.5f+ nLoc[2]/gridf));
514                                                                 
515                                                                 /* get bone-space location of grid point */
516                                                                 armature_loc_pose_to_bone(pchan, vec, vecN);
517                                                                 
518                                                                 /* adjust location */
519                                                                 if ((pchan->protectflag & OB_LOCK_LOCX)==0)     
520                                                                         pchan->loc[0]= vecN[0];
521                                                                 if ((pchan->protectflag & OB_LOCK_LOCY)==0)     
522                                                                         pchan->loc[0]= vecN[1];
523                                                                 if ((pchan->protectflag & OB_LOCK_LOCZ)==0)     
524                                                                         pchan->loc[0]= vecN[2];
525                                                         }
526                                                         /* if the bone has a parent and is connected to the parent, 
527                                                          * don't do anything - will break chain unless we do auto-ik. 
528                                                          */
529                                                 }
530                                         }
531                                 }
532                                 ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
533                                 
534                                 /* auto-keyframing */
535 // XXX                          autokeyframe_pose_cb_func(ob, TFM_TRANSLATION, 0);
536                                 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
537                         }
538                         else {
539                                 ob->recalc |= OB_RECALC_OB;
540                                 
541                                 vec[0]= -ob->obmat[3][0]+gridf*floorf(0.5f+ ob->obmat[3][0]/gridf);
542                                 vec[1]= -ob->obmat[3][1]+gridf*floorf(0.5f+ ob->obmat[3][1]/gridf);
543                                 vec[2]= -ob->obmat[3][2]+gridf*floorf(0.5f+ ob->obmat[3][2]/gridf);
544                                 
545                                 if(ob->parent) {
546                                         where_is_object(scene, ob);
547                                         
548                                         invert_m3_m3(imat, originmat);
549                                         mul_m3_v3(imat, vec);
550                                 }
551                                 if ((ob->protectflag & OB_LOCK_LOCX)==0)
552                                         ob->loc[0]+= vec[0];
553                                 if ((ob->protectflag & OB_LOCK_LOCY)==0)
554                                         ob->loc[1]+= vec[1];
555                                 if ((ob->protectflag & OB_LOCK_LOCZ)==0)
556                                         ob->loc[2]+= vec[2];
557                                 
558                                 /* auto-keyframing */
559 // XXX                          autokeyframe_ob_cb_func(ob, TFM_TRANSLATION);
560                         }
561                 }
562                 CTX_DATA_END;
563         }
564
565         DAG_ids_flush_update(bmain, 0);
566         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
567         
568         return OPERATOR_FINISHED;
569 }
570
571 void VIEW3D_OT_snap_selected_to_grid(wmOperatorType *ot)
572 {
573         
574         /* identifiers */
575         ot->name= "Snap Selection to Grid";
576         ot->description= "Snap selected item(s) to nearest grid node";
577         ot->idname= "VIEW3D_OT_snap_selected_to_grid";
578         
579         /* api callbacks */
580         ot->exec= snap_sel_to_grid;
581         ot->poll= ED_operator_region_view3d_active;
582         
583         /* flags */
584         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
585 }
586
587 /* *************************************************** */
588
589 static int snap_sel_to_curs(bContext *C, wmOperator *UNUSED(op))
590 {
591         Main *bmain= CTX_data_main(C);
592         Object *obedit= CTX_data_edit_object(C);
593         Scene *scene= CTX_data_scene(C);
594         View3D *v3d= CTX_wm_view3d(C);
595         TransVert *tv;
596         float *curs, imat[3][3], bmat[3][3], vec[3];
597         int a;
598
599         curs= give_cursor(scene, v3d);
600
601         if(obedit) {
602                 tottrans= 0;
603                 
604                 if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
605                         make_trans_verts(obedit, bmat[0], bmat[1], 0);
606                 if(tottrans==0) return OPERATOR_CANCELLED;
607                 
608                 copy_m3_m4(bmat, obedit->obmat);
609                 invert_m3_m3(imat, bmat);
610                 
611                 tv= transvmain;
612                 for(a=0; a<tottrans; a++, tv++) {
613                         sub_v3_v3v3(vec, curs, obedit->obmat[3]);
614                         mul_m3_v3(imat, vec);
615                         copy_v3_v3(tv->loc, vec);
616                 }
617                 
618                 special_transvert_update(obedit);
619                 
620                 MEM_freeN(transvmain);
621                 transvmain= NULL;
622                 
623         }
624         else {
625                 CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
626                         if(ob->mode & OB_MODE_POSE) {
627                                 bPoseChannel *pchan;
628                                 bArmature *arm= ob->data;
629                                 float cursp[3];
630                                 
631                                 invert_m4_m4(ob->imat, ob->obmat);
632                                 VECCOPY(cursp, curs);
633                                 mul_m4_v3(ob->imat, cursp);
634                                 
635                                 for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
636                                         if(pchan->bone->flag & BONE_SELECTED) {
637                                                 if(pchan->bone->layer & arm->layer) {
638                                                         if((pchan->bone->flag & BONE_CONNECTED)==0) { 
639                                                                 float curspn[3];
640                                                                 
641                                                                 /* get location of cursor in bone-space */
642                                                                 armature_loc_pose_to_bone(pchan, cursp, curspn);
643                                                                 
644                                                                 /* copy new position */
645                                                                 if ((pchan->protectflag & OB_LOCK_LOCX)==0)     
646                                                                         pchan->loc[0]= curspn[0];
647                                                                 if ((pchan->protectflag & OB_LOCK_LOCY)==0)     
648                                                                         pchan->loc[1]= curspn[1];
649                                                                 if ((pchan->protectflag & OB_LOCK_LOCZ)==0)     
650                                                                         pchan->loc[2]= curspn[2];
651                                                         }
652                                                         /* if the bone has a parent and is connected to the parent, 
653                                                          * don't do anything - will break chain unless we do auto-ik. 
654                                                          */
655                                                 }
656                                         }
657                                 }
658                                 ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
659                                 
660                                 /* auto-keyframing */
661 // XXX                          autokeyframe_pose_cb_func(ob, TFM_TRANSLATION, 0);
662                                 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
663                         }
664                         else {
665                                 ob->recalc |= OB_RECALC_OB;
666                                 
667                                 vec[0]= -ob->obmat[3][0] + curs[0];
668                                 vec[1]= -ob->obmat[3][1] + curs[1];
669                                 vec[2]= -ob->obmat[3][2] + curs[2];
670                                 
671                                 if(ob->parent) {
672                                         where_is_object(scene, ob);
673                                         
674                                         invert_m3_m3(imat, originmat);
675                                         mul_m3_v3(imat, vec);
676                                 }
677                                 if ((ob->protectflag & OB_LOCK_LOCX)==0)
678                                         ob->loc[0]+= vec[0];
679                                 if ((ob->protectflag & OB_LOCK_LOCY)==0)
680                                         ob->loc[1]+= vec[1];
681                                 if ((ob->protectflag & OB_LOCK_LOCZ)==0)
682                                         ob->loc[2]+= vec[2];
683                                 
684                                 /* auto-keyframing */
685 // XXX                          autokeyframe_ob_cb_func(ob, TFM_TRANSLATION);
686                         }
687                 }
688                 CTX_DATA_END;
689         }
690
691         DAG_ids_flush_update(bmain, 0);
692         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
693         
694         return OPERATOR_FINISHED;
695 }
696
697 void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot)
698 {
699         
700         /* identifiers */
701         ot->name= "Snap Selection to Cursor";
702         ot->description= "Snap selected item(s) to cursor";
703         ot->idname= "VIEW3D_OT_snap_selected_to_cursor";
704         
705         /* api callbacks */
706         ot->exec= snap_sel_to_curs;
707         ot->poll= ED_operator_view3d_active;
708         
709         /* flags */
710         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
711 }
712
713 /* *************************************************** */
714
715 static int snap_curs_to_grid(bContext *C, wmOperator *UNUSED(op))
716 {
717         Scene *scene= CTX_data_scene(C);
718         RegionView3D *rv3d= CTX_wm_region_data(C);
719         View3D *v3d= CTX_wm_view3d(C);
720         float gridf, *curs;
721
722         gridf= rv3d->gridview;
723         curs= give_cursor(scene, v3d);
724
725         curs[0]= gridf*floorf(0.5f+curs[0]/gridf);
726         curs[1]= gridf*floorf(0.5f+curs[1]/gridf);
727         curs[2]= gridf*floorf(0.5f+curs[2]/gridf);
728         
729         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);        // hrm
730         
731         return OPERATOR_FINISHED;
732 }
733
734 void VIEW3D_OT_snap_cursor_to_grid(wmOperatorType *ot)
735 {
736         
737         /* identifiers */
738         ot->name= "Snap Cursor to Grid";
739         ot->description= "Snap cursor to nearest grid node";
740         ot->idname= "VIEW3D_OT_snap_cursor_to_grid";
741         
742         /* api callbacks */
743         ot->exec= snap_curs_to_grid;
744         ot->poll= ED_operator_region_view3d_active;
745         
746         /* flags */
747         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
748 }
749
750 /* **************************************************** */
751
752 static int snap_curs_to_sel(bContext *C, wmOperator *UNUSED(op))
753 {
754         Object *obedit= CTX_data_edit_object(C);
755         Scene *scene= CTX_data_scene(C);
756         View3D *v3d= CTX_wm_view3d(C);
757         TransVert *tv;
758         float *curs, bmat[3][3], vec[3], min[3], max[3], centroid[3];
759         int count, a;
760
761         curs= give_cursor(scene, v3d);
762
763         count= 0;
764         INIT_MINMAX(min, max);
765         centroid[0]= centroid[1]= centroid[2]= 0.0;
766
767         if(obedit) {
768                 tottrans=0;
769                 
770                 if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
771                         make_trans_verts(obedit, bmat[0], bmat[1], TM_ALL_JOINTS|TM_SKIP_HANDLES);
772                 if(tottrans==0) return OPERATOR_CANCELLED;
773                 
774                 copy_m3_m4(bmat, obedit->obmat);
775                 
776                 tv= transvmain;
777                 for(a=0; a<tottrans; a++, tv++) {
778                         VECCOPY(vec, tv->loc);
779                         mul_m3_v3(bmat, vec);
780                         add_v3_v3(vec, obedit->obmat[3]);
781                         add_v3_v3(centroid, vec);
782                         DO_MINMAX(vec, min, max);
783                 }
784                 
785                 if(v3d->around==V3D_CENTROID) {
786                         mul_v3_fl(centroid, 1.0f/(float)tottrans);
787                         VECCOPY(curs, centroid);
788                 }
789                 else {
790                         mid_v3_v3v3(curs, min, max);
791                 }
792                 MEM_freeN(transvmain);
793                 transvmain= NULL;
794         }
795         else {
796                 Object *obact= CTX_data_active_object(C);
797                 
798                 if(obact && (obact->mode & OB_MODE_POSE)) {
799                         bArmature *arm= obact->data;
800                         bPoseChannel *pchan;
801                         for (pchan = obact->pose->chanbase.first; pchan; pchan=pchan->next) {
802                                 if(arm->layer & pchan->bone->layer) {
803                                         if(pchan->bone->flag & BONE_SELECTED) {
804                                                 VECCOPY(vec, pchan->pose_head);
805                                                 mul_m4_v3(obact->obmat, vec);
806                                                 add_v3_v3(centroid, vec);
807                                                 DO_MINMAX(vec, min, max);
808                                                 count++;
809                                         }
810                                 }
811                         }
812                 }
813                 else {
814                         CTX_DATA_BEGIN(C, Object*, ob, selected_objects) {
815                                 VECCOPY(vec, ob->obmat[3]);
816                                 add_v3_v3(centroid, vec);
817                                 DO_MINMAX(vec, min, max);
818                                 count++;
819                         }
820                         CTX_DATA_END;
821                 }
822                 if(count) {
823                         if(v3d->around==V3D_CENTROID) {
824                                 mul_v3_fl(centroid, 1.0f/(float)count);
825                                 VECCOPY(curs, centroid);
826                         }
827                         else {
828                                 mid_v3_v3v3(curs, min, max);
829                         }
830                 }
831         }
832         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
833         
834         return OPERATOR_FINISHED;
835 }
836
837 void VIEW3D_OT_snap_cursor_to_selected(wmOperatorType *ot)
838 {
839         
840         /* identifiers */
841         ot->name= "Snap Cursor to Selected";
842         ot->description= "Snap cursor to center of selected item(s)"; 
843         ot->idname= "VIEW3D_OT_snap_cursor_to_selected";
844         
845         /* api callbacks */
846         ot->exec= snap_curs_to_sel;
847         ot->poll= ED_operator_view3d_active;
848         
849         /* flags */
850         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
851 }
852
853 /* ********************************************** */
854
855 static int snap_curs_to_active(bContext *C, wmOperator *UNUSED(op))
856 {
857         Object *obedit= CTX_data_edit_object(C);
858         Object *obact= CTX_data_active_object(C);
859         Scene *scene= CTX_data_scene(C);
860         View3D *v3d= CTX_wm_view3d(C);
861         float *curs;
862         
863         curs = give_cursor(scene, v3d);
864
865         if (obedit)  {
866                 if (obedit->type == OB_MESH) {
867                         /* check active */
868                         Mesh *me= obedit->data;
869                         EditSelection ese;
870                         
871                         if (EM_get_actSelection(me->edit_mesh, &ese)) {
872                                 EM_editselection_center(curs, &ese);
873                         }
874                         
875                         mul_m4_v3(obedit->obmat, curs);
876                 }
877         }
878         else {
879                 if (obact) {
880                         VECCOPY(curs, obact->obmat[3]);
881                 }
882         }
883         
884         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
885         return OPERATOR_FINISHED;
886 }
887
888 void VIEW3D_OT_snap_cursor_to_active(wmOperatorType *ot)
889 {
890         
891         /* identifiers */
892         ot->name= "Snap Cursor to Active";
893         ot->description= "Snap cursor to active item";
894         ot->idname= "VIEW3D_OT_snap_cursor_to_active";
895         
896         /* api callbacks */
897         ot->exec= snap_curs_to_active;
898         ot->poll= ED_operator_view3d_active;
899         
900         /* flags */
901         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
902 }
903
904 /* **************************************************** */
905 /*New Code - Snap Cursor to Center -*/
906 static int snap_curs_to_center(bContext *C, wmOperator *UNUSED(op))
907 {
908         Scene *scene= CTX_data_scene(C);
909         View3D *v3d= CTX_wm_view3d(C);
910         float *curs;
911         curs= give_cursor(scene, v3d);
912
913         curs[0]= 0.0;
914         curs[1]= 0.0;
915         curs[2]= 0.0;
916         
917         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
918         
919         return OPERATOR_FINISHED;
920 }
921
922 void VIEW3D_OT_snap_cursor_to_center(wmOperatorType *ot)
923 {
924         
925         /* identifiers */
926         ot->name= "Snap Cursor to Center";
927         ot->description= "Snap cursor to the Center";
928         ot->idname= "VIEW3D_OT_snap_cursor_to_center";
929         
930         /* api callbacks */ 
931         ot->exec= snap_curs_to_center;
932         ot->poll= ED_operator_view3d_active;
933         
934         /* flags */
935            ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
936 }
937
938 /* **************************************************** */
939
940
941 int minmax_verts(Object *obedit, float *min, float *max)
942 {
943         TransVert *tv;
944         float centroid[3], vec[3], bmat[3][3];
945         int a;
946
947         tottrans=0;
948         if ELEM5(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE) 
949                 make_trans_verts(obedit, bmat[0], bmat[1], TM_ALL_JOINTS);
950         
951         if(tottrans==0) return 0;
952
953         copy_m3_m4(bmat, obedit->obmat);
954         
955         tv= transvmain;
956         for(a=0; a<tottrans; a++, tv++) {               
957                 VECCOPY(vec, tv->loc);
958                 mul_m3_v3(bmat, vec);
959                 add_v3_v3(vec, obedit->obmat[3]);
960                 add_v3_v3(centroid, vec);
961                 DO_MINMAX(vec, min, max);               
962         }
963         
964         MEM_freeN(transvmain);
965         transvmain= NULL;
966         
967         return 1;
968 }
969