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