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