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