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