svn merge -r41638:41648 ^/trunk/blender
[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 #include "BKE_tessmesh.h"
59 #include "BKE_DerivedMesh.h"
60 #include "BKE_tracking.h"
61
62 #include "WM_api.h"
63 #include "WM_types.h"
64
65
66
67 #include "ED_armature.h"
68 #include "ED_mesh.h"
69 #include "ED_keyframing.h"
70 #include "ED_screen.h"
71 #include "ED_curve.h" /* for curve_editnurbs */
72
73 #include "view3d_intern.h"
74
75 extern float originmat[3][3];   /* XXX object.c */
76
77 /* ************************************************** */
78 /* ********************* old transform stuff ******** */
79 /* *********** will get replaced with new transform * */
80 /* ************************************************** */
81
82 typedef struct TransVert {
83         float *loc;
84         float oldloc[3], maploc[3], fac;
85         float *val, oldval;
86         int flag;
87         float *nor;
88         int f1;
89 } TransVert;
90
91 static TransVert *transvmain=NULL;
92 static int tottrans= 0;
93
94 /* copied from editobject.c, now uses (almost) proper depgraph */
95 static void special_transvert_update(Object *obedit)
96 {
97         
98         if(obedit) {
99                 
100                 DAG_id_tag_update(obedit->data, 0);
101                 
102                 if(obedit->type==OB_MESH) {
103                         Mesh *me= obedit->data;
104                         BM_Compute_Normals(me->edit_btmesh->bm);        // does face centers too
105                 }
106                 else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
107                         Curve *cu= obedit->data;
108                         ListBase *nurbs= curve_editnurbs(cu);
109                         Nurb *nu= nurbs->first;
110
111                         while(nu) {
112                                 /* keep handles' vectors unchanged */
113                                 if(nu->bezt) {
114                                         int a= nu->pntsu;
115                                         TransVert *tv= transvmain;
116                                         BezTriple *bezt= nu->bezt;
117
118                                         while(a--) {
119                                                 if(bezt->f1 & SELECT) tv++;
120
121                                                 if(bezt->f2 & SELECT) {
122                                                         float v[3];
123
124                                                         if(bezt->f1 & SELECT) {
125                                                                 sub_v3_v3v3(v, (tv-1)->oldloc, tv->oldloc);
126                                                                 add_v3_v3v3(bezt->vec[0], bezt->vec[1], v);
127                                                         }
128
129                                                         if(bezt->f3 & SELECT) {
130                                                                 sub_v3_v3v3(v, (tv+1)->oldloc, tv->oldloc);
131                                                                 add_v3_v3v3(bezt->vec[2], bezt->vec[1], v);
132                                                         }
133
134                                                         tv++;
135                                                 }
136
137                                                 if(bezt->f3 & SELECT) tv++;
138
139                                                 bezt++;
140                                         }
141                                 }
142
143                                 test2DNurb(nu);
144                                 testhandlesNurb(nu); /* test for bezier too */
145                                 nu= nu->next;
146                         }
147                 }
148                 else if(obedit->type==OB_ARMATURE){
149                         bArmature *arm= obedit->data;
150                         EditBone *ebo;
151                         TransVert *tv= transvmain;
152                         int a=0;
153                         
154                         /* Ensure all bone tails are correctly adjusted */
155                         for (ebo= arm->edbo->first; ebo; ebo=ebo->next) {
156                                 /* adjust tip if both ends selected */
157                                 if ((ebo->flag & BONE_ROOTSEL) && (ebo->flag & BONE_TIPSEL)) {
158                                         if (tv) {
159                                                 float diffvec[3];
160                                                 
161                                                 sub_v3_v3v3(diffvec, tv->loc, tv->oldloc);
162                                                 add_v3_v3(ebo->tail, diffvec);
163                                                 
164                                                 a++;
165                                                 if (a<tottrans) tv++;
166                                         }
167                                 }
168                         }
169                         
170                         /* Ensure all bones are correctly adjusted */
171                         for (ebo= arm->edbo->first; ebo; ebo=ebo->next) {
172                                 if ((ebo->flag & BONE_CONNECTED) && ebo->parent){
173                                         /* If this bone has a parent tip that has been moved */
174                                         if (ebo->parent->flag & BONE_TIPSEL){
175                                                 copy_v3_v3(ebo->head, ebo->parent->tail);
176                                         }
177                                         /* If this bone has a parent tip that has NOT been moved */
178                                         else{
179                                                 copy_v3_v3(ebo->parent->tail, ebo->head);
180                                         }
181                                 }
182                         }
183                         if(arm->flag & ARM_MIRROR_EDIT) 
184                                 transform_armature_mirror_update(obedit);
185                 }
186                 else if(obedit->type==OB_LATTICE) {
187                         Lattice *lt= obedit->data;
188                         
189                         if(lt->editlatt->latt->flag & LT_OUTSIDE)
190                                 outside_lattice(lt->editlatt->latt);
191                 }
192         }
193 }
194
195 static void set_mapped_co(void *vuserdata, int index, float *co, float *UNUSED(no), short *UNUSED(no_s))
196 {
197         void ** userdata = vuserdata;
198         BMEditMesh *em = userdata[0];
199         TransVert *tv = userdata[1];
200         BMVert *eve = EDBM_get_vert_for_index(em, index);
201         
202         if (BM_GetIndex(eve) != -1 && !tv[BM_GetIndex(eve)].f1) {
203                 copy_v3_v3(tv[BM_GetIndex(eve)].maploc, co);
204                 tv[BM_GetIndex(eve)].f1 = 1;
205         }
206 }
207
208 /* copied from editobject.c, needs to be replaced with new transform code still */
209 /* mode flags: */
210 #define TM_ALL_JOINTS           1 /* all joints (for bones only) */
211 #define TM_SKIP_HANDLES         2 /* skip handles when control point is selected (for curves only) */
212 static void make_trans_verts(Object *obedit, float *min, float *max, int mode)  
213 {
214         Nurb *nu;
215         BezTriple *bezt;
216         BPoint *bp;
217         TransVert *tv=NULL;
218         MetaElem *ml;
219         BMVert *eve;
220         EditBone        *ebo;
221         float total, center[3], centroid[3];
222         int a;
223
224         tottrans= 0; // global!
225         
226         INIT_MINMAX(min, max);
227         centroid[0]=centroid[1]=centroid[2]= 0.0;
228         
229         if(obedit->type==OB_MESH) {
230                 Mesh *me= obedit->data;
231                 BMEditMesh *em= me->edit_btmesh;
232                 BMesh *bm = em->bm;
233                 BMIter iter;
234                 void *userdata[2] = {em, NULL};
235                 /*int proptrans= 0; */ /*UNUSED*/
236                 
237                 // transform now requires awareness for select mode, so we tag the f1 flags in verts
238                 tottrans= 0;
239                 if(em->selectmode & SCE_SELECT_VERTEX) {
240                         BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
241                                 if(!BM_TestHFlag(eve, BM_HIDDEN) && BM_TestHFlag(eve, BM_SELECT)) {
242                                         BM_SetIndex(eve, 1);
243                                         tottrans++;
244                                 }
245                                 else BM_SetIndex(eve, 0);
246                         }
247                 }
248                 else if(em->selectmode & SCE_SELECT_EDGE) {
249                         BMEdge *eed;
250
251                         BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL)
252                                 BM_SetIndex(eve, 0);
253
254                         BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
255                                 if(!BM_TestHFlag(eed, BM_HIDDEN) && BM_TestHFlag(eed, BM_SELECT))
256                                         BM_SetIndex(eed->v1, 1), BM_SetIndex(eed->v2, 1);
257                         }
258
259                         BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL)
260                                 if(BM_GetIndex(eve)) tottrans++;
261                 }
262                 else {
263                         BMFace *efa;
264
265                         BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL)
266                                 BM_SetIndex(eve, 0);
267
268                         BM_ITER(efa, &iter, bm, BM_FACES_OF_MESH, NULL) {
269                                 if(!BM_TestHFlag(efa, BM_HIDDEN) && BM_TestHFlag(efa, BM_SELECT)) {
270                                         BMIter liter;
271                                         BMLoop *l;
272                                         
273                                         BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, efa) {
274                                                 BM_SetIndex(l->v, 1);
275                                         }
276                                 }
277                         }
278
279                         BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL)
280                                 if(BM_GetIndex(eve)) tottrans++;
281                 }
282                 
283                 /* and now make transverts */
284                 if(tottrans) {
285                         tv=transvmain= MEM_callocN(tottrans*sizeof(TransVert), "maketransverts");
286                 
287                         a = 0;
288                         BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
289                                 if(BM_GetIndex(eve)) {
290                                         BM_SetIndex(eve, a);
291                                         copy_v3_v3(tv->oldloc, eve->co);
292                                         tv->loc= eve->co;
293                                         if(eve->no[0] != 0.0f || eve->no[1] != 0.0f ||eve->no[2] != 0.0f)
294                                                 tv->nor= eve->no; // note this is a hackish signal (ton)
295                                         tv->flag= BM_GetIndex(eve) & SELECT;
296                                         tv++;
297                                         a++;
298                                 } else BM_SetIndex(eve, -1);
299                         }
300                         
301                         userdata[1] = transvmain;
302                 }
303                 
304                 if (transvmain && em->derivedCage) {
305                         EDBM_init_index_arrays(em, 1, 0, 0);
306                         em->derivedCage->foreachMappedVert(em->derivedCage, set_mapped_co, userdata);
307                         EDBM_free_index_arrays(em);
308                 } else if (transvmain) {
309                         tv = transvmain;
310                         for (a=0; a<tottrans; a++, tv++) {
311                                 copy_v3_v3(tv->maploc, tv->loc);
312                         }
313                 }
314         }
315         else if (obedit->type==OB_ARMATURE){
316                 bArmature *arm= obedit->data;
317                 int totmalloc= BLI_countlist(arm->edbo);
318
319                 totmalloc *= 2;  /* probably overkill but bones can have 2 trans verts each */
320
321                 tv=transvmain= MEM_callocN(totmalloc*sizeof(TransVert), "maketransverts armature");
322                 
323                 for (ebo= arm->edbo->first; ebo; ebo=ebo->next){
324                         if(ebo->layer & arm->layer) {
325                                 short tipsel= (ebo->flag & BONE_TIPSEL);
326                                 short rootsel= (ebo->flag & BONE_ROOTSEL);
327                                 short rootok= (!(ebo->parent && (ebo->flag & BONE_CONNECTED) && ebo->parent->flag & BONE_TIPSEL));
328                                 
329                                 if ((tipsel && rootsel) || (rootsel)) {
330                                         /* Don't add the tip (unless mode & TM_ALL_JOINTS, for getting all joints),
331                                          * otherwise we get zero-length bones as tips will snap to the same
332                                          * location as heads. 
333                                          */
334                                         if (rootok) {
335                                                 copy_v3_v3(tv->oldloc, ebo->head);
336                                                 tv->loc= ebo->head;
337                                                 tv->nor= NULL;
338                                                 tv->flag= 1;
339                                                 tv++;
340                                                 tottrans++;
341                                         }       
342                                         
343                                         if ((mode & TM_ALL_JOINTS) && (tipsel)) {
344                                                 copy_v3_v3(tv->oldloc, ebo->tail);
345                                                 tv->loc= ebo->tail;
346                                                 tv->nor= NULL;
347                                                 tv->flag= 1;
348                                                 tv++;
349                                                 tottrans++;
350                                         }                                       
351                                 }
352                                 else if (tipsel) {
353                                         copy_v3_v3(tv->oldloc, ebo->tail);
354                                         tv->loc= ebo->tail;
355                                         tv->nor= NULL;
356                                         tv->flag= 1;
357                                         tv++;
358                                         tottrans++;
359                                 }
360                         }                       
361                 }
362         }
363         else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
364                 Curve *cu= obedit->data;
365                 int totmalloc= 0;
366                 ListBase *nurbs= curve_editnurbs(cu);
367
368                 for(nu= nurbs->first; nu; nu= nu->next) {
369                         if(nu->type == CU_BEZIER)
370                                 totmalloc += 3*nu->pntsu;
371                         else
372                                 totmalloc += nu->pntsu*nu->pntsv;
373                 }
374                 tv=transvmain= MEM_callocN(totmalloc*sizeof(TransVert), "maketransverts curve");
375
376                 nu= nurbs->first;
377                 while(nu) {
378                         if(nu->type == CU_BEZIER) {
379                                 a= nu->pntsu;
380                                 bezt= nu->bezt;
381                                 while(a--) {
382                                         if(bezt->hide==0) {
383                                                 int skip_handle= 0;
384                                                 if(bezt->f2 & SELECT)
385                                                         skip_handle= mode & TM_SKIP_HANDLES;
386
387                                                 if((bezt->f1 & SELECT) && !skip_handle) {
388                                                         copy_v3_v3(tv->oldloc, bezt->vec[0]);
389                                                         tv->loc= bezt->vec[0];
390                                                         tv->flag= bezt->f1 & SELECT;
391                                                         tv++;
392                                                         tottrans++;
393                                                 }
394                                                 if(bezt->f2 & SELECT) {
395                                                         copy_v3_v3(tv->oldloc, bezt->vec[1]);
396                                                         tv->loc= bezt->vec[1];
397                                                         tv->val= &(bezt->alfa);
398                                                         tv->oldval= bezt->alfa;
399                                                         tv->flag= bezt->f2 & SELECT;
400                                                         tv++;
401                                                         tottrans++;
402                                                 }
403                                                 if((bezt->f3 & SELECT) && !skip_handle) {
404                                                         copy_v3_v3(tv->oldloc, bezt->vec[2]);
405                                                         tv->loc= bezt->vec[2];
406                                                         tv->flag= bezt->f3 & SELECT;
407                                                         tv++;
408                                                         tottrans++;
409                                                 }
410                                         }
411                                         bezt++;
412                                 }
413                         }
414                         else {
415                                 a= nu->pntsu*nu->pntsv;
416                                 bp= nu->bp;
417                                 while(a--) {
418                                         if(bp->hide==0) {
419                                                 if(bp->f1 & SELECT) {
420                                                         copy_v3_v3(tv->oldloc, bp->vec);
421                                                         tv->loc= bp->vec;
422                                                         tv->val= &(bp->alfa);
423                                                         tv->oldval= bp->alfa;
424                                                         tv->flag= bp->f1 & SELECT;
425                                                         tv++;
426                                                         tottrans++;
427                                                 }
428                                         }
429                                         bp++;
430                                 }
431                         }
432                         nu= nu->next;
433                 }
434         }
435         else if(obedit->type==OB_MBALL) {
436                 MetaBall *mb= obedit->data;
437                 int totmalloc= BLI_countlist(mb->editelems);
438                 
439                 tv=transvmain= MEM_callocN(totmalloc*sizeof(TransVert), "maketransverts mball");
440                 
441                 ml= mb->editelems->first;
442                 while(ml) {
443                         if(ml->flag & SELECT) {
444                                 tv->loc= &ml->x;
445                                 copy_v3_v3(tv->oldloc, tv->loc);
446                                 tv->val= &(ml->rad);
447                                 tv->oldval= ml->rad;
448                                 tv->flag= 1;
449                                 tv++;
450                                 tottrans++;
451                         }
452                         ml= ml->next;
453                 }
454         }
455         else if(obedit->type==OB_LATTICE) {
456                 Lattice *lt= obedit->data;
457                 
458                 bp= lt->editlatt->latt->def;
459                 
460                 a= lt->editlatt->latt->pntsu*lt->editlatt->latt->pntsv*lt->editlatt->latt->pntsw;
461                 
462                 tv=transvmain= MEM_callocN(a*sizeof(TransVert), "maketransverts latt");
463                 
464                 while(a--) {
465                         if(bp->f1 & SELECT) {
466                                 if(bp->hide==0) {
467                                         copy_v3_v3(tv->oldloc, bp->vec);
468                                         tv->loc= bp->vec;
469                                         tv->flag= bp->f1 & SELECT;
470                                         tv++;
471                                         tottrans++;
472                                 }
473                         }
474                         bp++;
475                 }
476         }
477         
478         if(!tottrans && transvmain) {
479                 /* prevent memory leak. happens for curves/latticies due to */
480                 /* difficult condition of adding points to trans data */
481                 MEM_freeN(transvmain);
482                 transvmain= NULL;
483         }
484
485         /* cent etc */
486         tv= transvmain;
487         total= 0.0;
488         for(a=0; a<tottrans; a++, tv++) {
489                 if(tv->flag & SELECT) {
490                         add_v3_v3(centroid, tv->oldloc);
491                         total += 1.0f;
492                         DO_MINMAX(tv->oldloc, min, max);
493                 }
494         }
495         if(total != 0.0f) {
496                 mul_v3_fl(centroid, 1.0f/total);
497         }
498
499         mid_v3_v3v3(center, min, max);
500 }
501
502 /* *********************** operators ******************** */
503
504 static int snap_sel_to_grid(bContext *C, wmOperator *UNUSED(op))
505 {
506         Main *bmain= CTX_data_main(C);
507         Object *obedit= CTX_data_edit_object(C);
508         Scene *scene= CTX_data_scene(C);
509         RegionView3D *rv3d= CTX_wm_region_data(C);
510         TransVert *tv;
511         float gridf, imat[3][3], bmat[3][3], vec[3];
512         int a;
513
514         gridf= rv3d->gridview;
515
516         if(obedit) {
517                 tottrans= 0;
518                 
519                 if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
520                         make_trans_verts(obedit, bmat[0], bmat[1], 0);
521                 if(tottrans==0) return OPERATOR_CANCELLED;
522                 
523                 copy_m3_m4(bmat, obedit->obmat);
524                 invert_m3_m3(imat, bmat);
525                 
526                 tv= transvmain;
527                 for(a=0; a<tottrans; a++, tv++) {
528                         
529                         copy_v3_v3(vec, tv->loc);
530                         mul_m3_v3(bmat, vec);
531                         add_v3_v3(vec, obedit->obmat[3]);
532                         vec[0]= gridf*floorf(0.5f+ vec[0]/gridf);
533                         vec[1]= gridf*floorf(0.5f+ vec[1]/gridf);
534                         vec[2]= gridf*floorf(0.5f+ vec[2]/gridf);
535                         sub_v3_v3(vec, obedit->obmat[3]);
536                         
537                         mul_m3_v3(imat, vec);
538                         copy_v3_v3(tv->loc, vec);
539                 }
540                 
541                 special_transvert_update(obedit);
542                 
543                 MEM_freeN(transvmain);
544                 transvmain= NULL;
545         
546         }
547         else {
548                 struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
549
550                 CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
551                         if(ob->mode & OB_MODE_POSE) {
552                                 bPoseChannel *pchan;
553                                 bArmature *arm= ob->data;
554                                 
555                                 for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
556                                         if(pchan->bone->flag & BONE_SELECTED) {
557                                                 if(pchan->bone->layer & arm->layer) {
558                                                         if((pchan->bone->flag & BONE_CONNECTED)==0) { 
559                                                                 float vecN[3], nLoc[3]; 
560                                                                 
561                                                                 /* get nearest grid point to snap to */
562                                                                 copy_v3_v3(nLoc, pchan->pose_mat[3]);
563                                                                 vec[0]= gridf * (float)(floor(0.5f+ nLoc[0]/gridf));
564                                                                 vec[1]= gridf * (float)(floor(0.5f+ nLoc[1]/gridf));
565                                                                 vec[2]= gridf * (float)(floor(0.5f+ nLoc[2]/gridf));
566                                                                 
567                                                                 /* get bone-space location of grid point */
568                                                                 armature_loc_pose_to_bone(pchan, vec, vecN);
569                                                                 
570                                                                 /* adjust location */
571                                                                 if ((pchan->protectflag & OB_LOCK_LOCX)==0)     
572                                                                         pchan->loc[0]= vecN[0];
573                                                                 if ((pchan->protectflag & OB_LOCK_LOCY)==0)     
574                                                                         pchan->loc[0]= vecN[1];
575                                                                 if ((pchan->protectflag & OB_LOCK_LOCZ)==0)     
576                                                                         pchan->loc[0]= vecN[2];
577
578                                                                 /* auto-keyframing */
579                                                                 ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
580                                                         }
581                                                         /* if the bone has a parent and is connected to the parent, 
582                                                          * don't do anything - will break chain unless we do auto-ik. 
583                                                          */
584                                                 }
585                                         }
586                                 }
587                                 ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
588                                 
589                                 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
590                         }
591                         else {
592                                 ob->recalc |= OB_RECALC_OB;
593                                 
594                                 vec[0]= -ob->obmat[3][0]+gridf*floorf(0.5f+ ob->obmat[3][0]/gridf);
595                                 vec[1]= -ob->obmat[3][1]+gridf*floorf(0.5f+ ob->obmat[3][1]/gridf);
596                                 vec[2]= -ob->obmat[3][2]+gridf*floorf(0.5f+ ob->obmat[3][2]/gridf);
597                                 
598                                 if(ob->parent) {
599                                         where_is_object(scene, ob);
600                                         
601                                         invert_m3_m3(imat, originmat);
602                                         mul_m3_v3(imat, vec);
603                                 }
604                                 if ((ob->protectflag & OB_LOCK_LOCX)==0)
605                                         ob->loc[0]+= vec[0];
606                                 if ((ob->protectflag & OB_LOCK_LOCY)==0)
607                                         ob->loc[1]+= vec[1];
608                                 if ((ob->protectflag & OB_LOCK_LOCZ)==0)
609                                         ob->loc[2]+= vec[2];
610                                 
611                                 /* auto-keyframing */
612                                 ED_autokeyframe_object(C, scene, ob, ks);
613                         }
614                 }
615                 CTX_DATA_END;
616         }
617
618         DAG_ids_flush_update(bmain, 0);
619         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
620         
621         return OPERATOR_FINISHED;
622 }
623
624 void VIEW3D_OT_snap_selected_to_grid(wmOperatorType *ot)
625 {
626         
627         /* identifiers */
628         ot->name= "Snap Selection to Grid";
629         ot->description= "Snap selected item(s) to nearest grid node";
630         ot->idname= "VIEW3D_OT_snap_selected_to_grid";
631         
632         /* api callbacks */
633         ot->exec= snap_sel_to_grid;
634         ot->poll= ED_operator_region_view3d_active;
635         
636         /* flags */
637         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
638 }
639
640 /* *************************************************** */
641
642 static int snap_sel_to_curs(bContext *C, wmOperator *UNUSED(op))
643 {
644         Main *bmain= CTX_data_main(C);
645         Object *obedit= CTX_data_edit_object(C);
646         Scene *scene= CTX_data_scene(C);
647         View3D *v3d= CTX_wm_view3d(C);
648         TransVert *tv;
649         float *curs, imat[3][3], bmat[3][3], vec[3];
650         int a;
651
652         curs= give_cursor(scene, v3d);
653
654         if(obedit) {
655                 tottrans= 0;
656                 
657                 if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
658                         make_trans_verts(obedit, bmat[0], bmat[1], 0);
659                 if(tottrans==0) return OPERATOR_CANCELLED;
660                 
661                 copy_m3_m4(bmat, obedit->obmat);
662                 invert_m3_m3(imat, bmat);
663                 
664                 tv= transvmain;
665                 for(a=0; a<tottrans; a++, tv++) {
666                         sub_v3_v3v3(vec, curs, obedit->obmat[3]);
667                         mul_m3_v3(imat, vec);
668                         copy_v3_v3(tv->loc, vec);
669                 }
670                 
671                 special_transvert_update(obedit);
672                 
673                 MEM_freeN(transvmain);
674                 transvmain= NULL;
675                 
676         }
677         else {
678                 struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
679
680                 CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
681                         if(ob->mode & OB_MODE_POSE) {
682                                 bPoseChannel *pchan;
683                                 bArmature *arm= ob->data;
684                                 float cursp[3];
685                                 
686                                 invert_m4_m4(ob->imat, ob->obmat);
687                                 copy_v3_v3(cursp, curs);
688                                 mul_m4_v3(ob->imat, cursp);
689                                 
690                                 for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
691                                         if(pchan->bone->flag & BONE_SELECTED) {
692                                                 if(pchan->bone->layer & arm->layer) {
693                                                         if((pchan->bone->flag & BONE_CONNECTED)==0) { 
694                                                                 float curspn[3];
695                                                                 
696                                                                 /* get location of cursor in bone-space */
697                                                                 armature_loc_pose_to_bone(pchan, cursp, curspn);
698                                                                 
699                                                                 /* copy new position */
700                                                                 if ((pchan->protectflag & OB_LOCK_LOCX)==0)     
701                                                                         pchan->loc[0]= curspn[0];
702                                                                 if ((pchan->protectflag & OB_LOCK_LOCY)==0)     
703                                                                         pchan->loc[1]= curspn[1];
704                                                                 if ((pchan->protectflag & OB_LOCK_LOCZ)==0)     
705                                                                         pchan->loc[2]= curspn[2];
706
707                                                                 /* auto-keyframing */
708                                                                 ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
709                                                         }
710                                                         /* if the bone has a parent and is connected to the parent, 
711                                                          * don't do anything - will break chain unless we do auto-ik. 
712                                                          */
713                                                 }
714                                         }
715                                 }
716                                 ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
717                                 
718                                 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
719                         }
720                         else {
721                                 ob->recalc |= OB_RECALC_OB;
722                                 
723                                 vec[0]= -ob->obmat[3][0] + curs[0];
724                                 vec[1]= -ob->obmat[3][1] + curs[1];
725                                 vec[2]= -ob->obmat[3][2] + curs[2];
726                                 
727                                 if(ob->parent) {
728                                         where_is_object(scene, ob);
729                                         
730                                         invert_m3_m3(imat, originmat);
731                                         mul_m3_v3(imat, vec);
732                                 }
733                                 if ((ob->protectflag & OB_LOCK_LOCX)==0)
734                                         ob->loc[0]+= vec[0];
735                                 if ((ob->protectflag & OB_LOCK_LOCY)==0)
736                                         ob->loc[1]+= vec[1];
737                                 if ((ob->protectflag & OB_LOCK_LOCZ)==0)
738                                         ob->loc[2]+= vec[2];
739
740                                 /* auto-keyframing */
741                                 ED_autokeyframe_object(C, scene, ob, ks);
742                         }
743                 }
744                 CTX_DATA_END;
745         }
746
747         DAG_ids_flush_update(bmain, 0);
748         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
749         
750         return OPERATOR_FINISHED;
751 }
752
753 void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot)
754 {
755         
756         /* identifiers */
757         ot->name= "Snap Selection to Cursor";
758         ot->description= "Snap selected item(s) to cursor";
759         ot->idname= "VIEW3D_OT_snap_selected_to_cursor";
760         
761         /* api callbacks */
762         ot->exec= snap_sel_to_curs;
763         ot->poll= ED_operator_view3d_active;
764         
765         /* flags */
766         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
767 }
768
769 /* *************************************************** */
770
771 static int snap_curs_to_grid(bContext *C, wmOperator *UNUSED(op))
772 {
773         Scene *scene= CTX_data_scene(C);
774         RegionView3D *rv3d= CTX_wm_region_data(C);
775         View3D *v3d= CTX_wm_view3d(C);
776         float gridf, *curs;
777
778         gridf= rv3d->gridview;
779         curs= give_cursor(scene, v3d);
780
781         curs[0]= gridf*floorf(0.5f+curs[0]/gridf);
782         curs[1]= gridf*floorf(0.5f+curs[1]/gridf);
783         curs[2]= gridf*floorf(0.5f+curs[2]/gridf);
784         
785         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);        // hrm
786         
787         return OPERATOR_FINISHED;
788 }
789
790 void VIEW3D_OT_snap_cursor_to_grid(wmOperatorType *ot)
791 {
792         
793         /* identifiers */
794         ot->name= "Snap Cursor to Grid";
795         ot->description= "Snap cursor to nearest grid node";
796         ot->idname= "VIEW3D_OT_snap_cursor_to_grid";
797         
798         /* api callbacks */
799         ot->exec= snap_curs_to_grid;
800         ot->poll= ED_operator_region_view3d_active;
801         
802         /* flags */
803         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
804 }
805
806 /* **************************************************** */
807
808 static void bundle_midpoint(Scene *scene, Object *ob, float vec[3])
809 {
810         MovieTrackingTrack *track;
811         MovieClip *clip= object_get_movieclip(scene, ob, 0);
812         int ok= 0;
813         float min[3], max[3], mat[4][4], pos[3];
814
815         if(!clip)
816                 return;
817
818         BKE_get_tracking_mat(scene, ob, mat);
819
820         INIT_MINMAX(min, max);
821
822         track= clip->tracking.tracks.first;
823         while(track) {
824                 int selected= (track->flag&SELECT) || (track->pat_flag&SELECT) || (track->search_flag&SELECT);
825                 if((track->flag&TRACK_HAS_BUNDLE) && selected) {
826                         ok= 1;
827                         mul_v3_m4v3(pos, mat, track->bundle_pos);
828                         DO_MINMAX(pos, min, max);
829                 }
830
831                 track= track->next;
832         }
833
834         if(ok) {
835                 mid_v3_v3v3(vec, min, max);
836         }
837 }
838
839 static int snap_curs_to_sel(bContext *C, wmOperator *UNUSED(op))
840 {
841         Object *obedit= CTX_data_edit_object(C);
842         Scene *scene= CTX_data_scene(C);
843         View3D *v3d= CTX_wm_view3d(C);
844         TransVert *tv;
845         float *curs, bmat[3][3], vec[3], min[3], max[3], centroid[3];
846         int count, a;
847
848         curs= give_cursor(scene, v3d);
849
850         count= 0;
851         INIT_MINMAX(min, max);
852         centroid[0]= centroid[1]= centroid[2]= 0.0;
853
854         if(obedit) {
855                 tottrans=0;
856                 
857                 if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
858                         make_trans_verts(obedit, bmat[0], bmat[1], TM_ALL_JOINTS|TM_SKIP_HANDLES);
859                 if(tottrans==0) return OPERATOR_CANCELLED;
860                 
861                 copy_m3_m4(bmat, obedit->obmat);
862                 
863                 tv= transvmain;
864                 for(a=0; a<tottrans; a++, tv++) {
865                         copy_v3_v3(vec, tv->loc);
866                         mul_m3_v3(bmat, vec);
867                         add_v3_v3(vec, obedit->obmat[3]);
868                         add_v3_v3(centroid, vec);
869                         DO_MINMAX(vec, min, max);
870                 }
871                 
872                 if(v3d->around==V3D_CENTROID) {
873                         mul_v3_fl(centroid, 1.0f/(float)tottrans);
874                         copy_v3_v3(curs, centroid);
875                 }
876                 else {
877                         mid_v3_v3v3(curs, min, max);
878                 }
879                 MEM_freeN(transvmain);
880                 transvmain= NULL;
881         }
882         else {
883                 Object *obact= CTX_data_active_object(C);
884                 
885                 if(obact && (obact->mode & OB_MODE_POSE)) {
886                         bArmature *arm= obact->data;
887                         bPoseChannel *pchan;
888                         for (pchan = obact->pose->chanbase.first; pchan; pchan=pchan->next) {
889                                 if(arm->layer & pchan->bone->layer) {
890                                         if(pchan->bone->flag & BONE_SELECTED) {
891                                                 copy_v3_v3(vec, pchan->pose_head);
892                                                 mul_m4_v3(obact->obmat, vec);
893                                                 add_v3_v3(centroid, vec);
894                                                 DO_MINMAX(vec, min, max);
895                                                 count++;
896                                         }
897                                 }
898                         }
899                 }
900                 else {
901                         CTX_DATA_BEGIN(C, Object*, ob, selected_objects) {
902                                 copy_v3_v3(vec, ob->obmat[3]);
903
904                                 /* special case for camera -- snap to bundles */
905                                 if(ob->type==OB_CAMERA) {
906                                         /* snap to bundles should happen only when bundles are visible */
907                                         if(v3d->flag2&V3D_SHOW_RECONSTRUCTION) {
908                                                 bundle_midpoint(scene, ob, vec);
909                                         }
910                                 }
911
912                                 add_v3_v3(centroid, vec);
913                                 DO_MINMAX(vec, min, max);
914                                 count++;
915                         }
916                         CTX_DATA_END;
917                 }
918                 if(count) {
919                         if(v3d->around==V3D_CENTROID) {
920                                 mul_v3_fl(centroid, 1.0f/(float)count);
921                                 copy_v3_v3(curs, centroid);
922                         }
923                         else {
924                                 mid_v3_v3v3(curs, min, max);
925                         }
926                 }
927         }
928         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
929         
930         return OPERATOR_FINISHED;
931 }
932
933 void VIEW3D_OT_snap_cursor_to_selected(wmOperatorType *ot)
934 {
935         
936         /* identifiers */
937         ot->name= "Snap Cursor to Selected";
938         ot->description= "Snap cursor to center of selected item(s)"; 
939         ot->idname= "VIEW3D_OT_snap_cursor_to_selected";
940         
941         /* api callbacks */
942         ot->exec= snap_curs_to_sel;
943         ot->poll= ED_operator_view3d_active;
944         
945         /* flags */
946         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
947 }
948
949 /* ********************************************** */
950
951 static int snap_curs_to_active(bContext *C, wmOperator *UNUSED(op))
952 {
953         Object *obedit= CTX_data_edit_object(C);
954         Object *obact= CTX_data_active_object(C);
955         Scene *scene= CTX_data_scene(C);
956         View3D *v3d= CTX_wm_view3d(C);
957         float *curs;
958         
959         curs = give_cursor(scene, v3d);
960
961         if (obedit)  {
962                 if (obedit->type == OB_MESH) {
963                         /* check active */
964                         Mesh *me= obedit->data;
965                         BMEditSelection ese;
966                         
967                         if (EDBM_get_actSelection(me->edit_btmesh, &ese)) {
968                                 EDBM_editselection_center(me->edit_btmesh, curs, &ese);
969                         }
970                         
971                         mul_m4_v3(obedit->obmat, curs);
972                 }
973         }
974         else {
975                 if (obact) {
976                         copy_v3_v3(curs, obact->obmat[3]);
977                 }
978         }
979         
980         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
981         return OPERATOR_FINISHED;
982 }
983
984 void VIEW3D_OT_snap_cursor_to_active(wmOperatorType *ot)
985 {
986         
987         /* identifiers */
988         ot->name= "Snap Cursor to Active";
989         ot->description= "Snap cursor to active item";
990         ot->idname= "VIEW3D_OT_snap_cursor_to_active";
991         
992         /* api callbacks */
993         ot->exec= snap_curs_to_active;
994         ot->poll= ED_operator_view3d_active;
995         
996         /* flags */
997         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
998 }
999
1000 /* **************************************************** */
1001 /*New Code - Snap Cursor to Center -*/
1002 static int snap_curs_to_center(bContext *C, wmOperator *UNUSED(op))
1003 {
1004         Scene *scene= CTX_data_scene(C);
1005         View3D *v3d= CTX_wm_view3d(C);
1006         float *curs;
1007         curs= give_cursor(scene, v3d);
1008
1009         curs[0]= 0.0;
1010         curs[1]= 0.0;
1011         curs[2]= 0.0;
1012         
1013         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
1014         
1015         return OPERATOR_FINISHED;
1016 }
1017
1018 void VIEW3D_OT_snap_cursor_to_center(wmOperatorType *ot)
1019 {
1020         
1021         /* identifiers */
1022         ot->name= "Snap Cursor to Center";
1023         ot->description= "Snap cursor to the Center";
1024         ot->idname= "VIEW3D_OT_snap_cursor_to_center";
1025         
1026         /* api callbacks */ 
1027         ot->exec= snap_curs_to_center;
1028         ot->poll= ED_operator_view3d_active;
1029         
1030         /* flags */
1031            ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1032 }
1033
1034 /* **************************************************** */
1035
1036
1037 int minmax_verts(Object *obedit, float *min, float *max)
1038 {
1039         TransVert *tv;
1040         float centroid[3], vec[3], bmat[3][3];
1041         int a;
1042
1043         tottrans=0;
1044         if ELEM5(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE) 
1045                 make_trans_verts(obedit, bmat[0], bmat[1], TM_ALL_JOINTS);
1046         
1047         if(tottrans==0) return 0;
1048
1049         copy_m3_m4(bmat, obedit->obmat);
1050         
1051         tv= transvmain;
1052         for(a=0; a<tottrans; a++, tv++) {               
1053                 copy_v3_v3(vec, tv->maploc);
1054                 mul_m3_v3(bmat, vec);
1055                 add_v3_v3(vec, obedit->obmat[3]);
1056                 add_v3_v3(centroid, vec);
1057                 DO_MINMAX(vec, min, max);               
1058         }
1059         
1060         MEM_freeN(transvmain);
1061         transvmain= NULL;
1062         
1063         return 1;
1064 }