fix for bug snapping multiple pose bones to the cursor (it would apply pose transform...
[blender-staging.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_mesh_types.h"
42 #include "DNA_meta_types.h"
43 #include "DNA_scene_types.h"
44 #include "DNA_object_types.h"
45
46 #include "BLI_blenlib.h"
47 #include "BLI_math.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_mball.h"
58 #include "BKE_object.h"
59 #include "BKE_editmesh.h"
60 #include "BKE_DerivedMesh.h"
61 #include "BKE_scene.h"
62 #include "BKE_tracking.h"
63
64 #include "WM_api.h"
65 #include "WM_types.h"
66
67
68
69 #include "ED_armature.h"
70 #include "ED_mesh.h"
71 #include "ED_keyframing.h"
72 #include "ED_screen.h"
73 #include "ED_curve.h" /* for curve_editnurbs */
74
75 #include "view3d_intern.h"
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];
85         float *val, oldval;
86         int flag;
87 } TransVert;
88
89               /* SELECT == (1 << 0) */
90 #define TX_VERT_USE_MAPLOC (1 << 1)
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                         BMEditMesh *em = BKE_editmesh_from_object(obedit);
103                         BM_mesh_normals_update(em->bm);
104                 }
105                 else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
106                         Curve *cu = obedit->data;
107                         ListBase *nurbs = BKE_curve_editNurbs_get(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                                 BKE_nurb_test2D(nu);
143                                 BKE_nurb_handles_test(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 /* currently only used for bmesh index values */
195 enum {
196         TM_INDEX_ON      =  1,  /* tag to make trans verts */
197         TM_INDEX_OFF     =  0,  /* don't make verts */
198         TM_INDEX_SKIP    = -1   /* dont make verts (when the index values point to trans-verts) */
199 };
200
201 /* copied from editobject.c, needs to be replaced with new transform code still */
202 /* mode flags: */
203 enum {
204         TM_ALL_JOINTS      = 1, /* all joints (for bones only) */
205         TM_SKIP_HANDLES    = 2  /* skip handles when control point is selected (for curves only) */
206 };
207
208 static void set_mapped_co(void *vuserdata, int index, const float co[3],
209                           const float UNUSED(no[3]), const short UNUSED(no_s[3]))
210 {
211         void **userdata = vuserdata;
212         BMEditMesh *em = userdata[0];
213         TransVert *tv = userdata[1];
214         BMVert *eve = EDBM_vert_at_index(em, index);
215         
216         if (BM_elem_index_get(eve) != TM_INDEX_SKIP) {
217                 tv = &tv[BM_elem_index_get(eve)];
218
219                 /* be clever, get the closest vertex to the original,
220                  * behaves most logically when the mirror modifier is used for eg [#33051]*/
221                 if ((tv->flag & TX_VERT_USE_MAPLOC) == 0) {
222                         /* first time */
223                         copy_v3_v3(tv->maploc, co);
224                         tv->flag |= TX_VERT_USE_MAPLOC;
225                 }
226                 else {
227                         /* find best location to use */
228                         if (len_squared_v3v3(eve->co, co) < len_squared_v3v3(eve->co, tv->maploc)) {
229                                 copy_v3_v3(tv->maploc, co);
230                         }
231                 }
232         }
233 }
234
235 static void make_trans_verts(Object *obedit, float min[3], float max[3], int mode)
236 {
237         Nurb *nu;
238         BezTriple *bezt;
239         BPoint *bp;
240         TransVert *tv = NULL;
241         MetaElem *ml;
242         BMVert *eve;
243         EditBone    *ebo;
244         float total, center[3], centroid[3];
245         int a;
246
247         tottrans = 0; /* global! */
248
249         INIT_MINMAX(min, max);
250         zero_v3(centroid);
251         
252         if (obedit->type == OB_MESH) {
253                 BMEditMesh *em = BKE_editmesh_from_object(obedit);
254                 BMesh *bm = em->bm;
255                 BMIter iter;
256                 void *userdata[2] = {em, NULL};
257                 /*int proptrans = 0; */ /*UNUSED*/
258                 
259                 /* abuses vertex index all over, set, just set dirty here,
260                  * perhaps this could use its own array instead? - campbell */
261
262                 /* transform now requires awareness for select mode, so we tag the f1 flags in verts */
263                 tottrans = 0;
264                 if (em->selectmode & SCE_SELECT_VERTEX) {
265                         BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
266                                 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
267                                         BM_elem_index_set(eve, TM_INDEX_ON); /* set_dirty! */
268                                         tottrans++;
269                                 }
270                                 else {
271                                         BM_elem_index_set(eve, TM_INDEX_OFF);  /* set_dirty! */
272                                 }
273                         }
274                 }
275                 else if (em->selectmode & SCE_SELECT_EDGE) {
276                         BMEdge *eed;
277
278                         BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
279                                 BM_elem_index_set(eve, TM_INDEX_OFF);  /* set_dirty! */
280                         }
281
282                         BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
283                                 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
284                                         BM_elem_index_set(eed->v1, TM_INDEX_ON);  /* set_dirty! */
285                                         BM_elem_index_set(eed->v2, TM_INDEX_ON);  /* set_dirty! */
286                                 }
287                         }
288
289                         BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
290                                 if (BM_elem_index_get(eve) == TM_INDEX_ON) tottrans++;
291                         }
292                 }
293                 else {
294                         BMFace *efa;
295
296                         BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
297                                 BM_elem_index_set(eve, TM_INDEX_OFF);  /* set_dirty! */
298                         }
299
300                         BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
301                                 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
302                                         BMIter liter;
303                                         BMLoop *l;
304                                         
305                                         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
306                                                 BM_elem_index_set(l->v, TM_INDEX_ON); /* set_dirty! */
307                                         }
308                                 }
309                         }
310
311                         BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
312                                 if (BM_elem_index_get(eve) == TM_INDEX_ON) tottrans++;
313                         }
314                 }
315                 /* for any of the 3 loops above which all dirty the indices */
316                 bm->elem_index_dirty |= BM_VERT;
317                 
318                 /* and now make transverts */
319                 if (tottrans) {
320                         tv = transvmain = MEM_callocN(tottrans * sizeof(TransVert), "maketransverts");
321                 
322                         a = 0;
323                         BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
324                                 if (BM_elem_index_get(eve)) {
325                                         BM_elem_index_set(eve, a);  /* set_dirty! */
326                                         copy_v3_v3(tv->oldloc, eve->co);
327                                         tv->loc = eve->co;
328                                         tv->flag = (BM_elem_index_get(eve) == TM_INDEX_ON) ? SELECT : 0;
329                                         tv++;
330                                         a++;
331                                 }
332                                 else {
333                                         BM_elem_index_set(eve, TM_INDEX_SKIP);  /* set_dirty! */
334                                 }
335                         }
336                         /* set dirty already, above */
337
338                         userdata[1] = transvmain;
339                 }
340                 
341                 if (transvmain && em->derivedCage) {
342                         EDBM_index_arrays_ensure(em, BM_VERT);
343                         em->derivedCage->foreachMappedVert(em->derivedCage, set_mapped_co, userdata);
344                 }
345         }
346         else if (obedit->type == OB_ARMATURE) {
347                 bArmature *arm = obedit->data;
348                 int totmalloc = BLI_countlist(arm->edbo);
349
350                 totmalloc *= 2;  /* probably overkill but bones can have 2 trans verts each */
351
352                 tv = transvmain = MEM_callocN(totmalloc * sizeof(TransVert), "maketransverts armature");
353                 
354                 for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
355                         if (ebo->layer & arm->layer) {
356                                 short tipsel = (ebo->flag & BONE_TIPSEL);
357                                 short rootsel = (ebo->flag & BONE_ROOTSEL);
358                                 short rootok = (!(ebo->parent && (ebo->flag & BONE_CONNECTED) && (ebo->parent->flag & BONE_TIPSEL)));
359                                 
360                                 if ((tipsel && rootsel) || (rootsel)) {
361                                         /* Don't add the tip (unless mode & TM_ALL_JOINTS, for getting all joints),
362                                          * otherwise we get zero-length bones as tips will snap to the same
363                                          * location as heads.
364                                          */
365                                         if (rootok) {
366                                                 copy_v3_v3(tv->oldloc, ebo->head);
367                                                 tv->loc = ebo->head;
368                                                 tv->flag = SELECT;
369                                                 tv++;
370                                                 tottrans++;
371                                         }
372                                         
373                                         if ((mode & TM_ALL_JOINTS) && (tipsel)) {
374                                                 copy_v3_v3(tv->oldloc, ebo->tail);
375                                                 tv->loc = ebo->tail;
376                                                 tv->flag = SELECT;
377                                                 tv++;
378                                                 tottrans++;
379                                         }
380                                 }
381                                 else if (tipsel) {
382                                         copy_v3_v3(tv->oldloc, ebo->tail);
383                                         tv->loc = ebo->tail;
384                                         tv->flag = SELECT;
385                                         tv++;
386                                         tottrans++;
387                                 }
388                         }
389                 }
390         }
391         else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
392                 Curve *cu = obedit->data;
393                 int totmalloc = 0;
394                 ListBase *nurbs = BKE_curve_editNurbs_get(cu);
395
396                 for (nu = nurbs->first; nu; nu = nu->next) {
397                         if (nu->type == CU_BEZIER)
398                                 totmalloc += 3 * nu->pntsu;
399                         else
400                                 totmalloc += nu->pntsu * nu->pntsv;
401                 }
402                 tv = transvmain = MEM_callocN(totmalloc * sizeof(TransVert), "maketransverts curve");
403
404                 nu = nurbs->first;
405                 while (nu) {
406                         if (nu->type == CU_BEZIER) {
407                                 a = nu->pntsu;
408                                 bezt = nu->bezt;
409                                 while (a--) {
410                                         if (bezt->hide == 0) {
411                                                 int skip_handle = 0;
412                                                 if (bezt->f2 & SELECT)
413                                                         skip_handle = mode & TM_SKIP_HANDLES;
414
415                                                 if ((bezt->f1 & SELECT) && !skip_handle) {
416                                                         copy_v3_v3(tv->oldloc, bezt->vec[0]);
417                                                         tv->loc = bezt->vec[0];
418                                                         tv->flag = bezt->f1 & SELECT;
419                                                         tv++;
420                                                         tottrans++;
421                                                 }
422                                                 if (bezt->f2 & SELECT) {
423                                                         copy_v3_v3(tv->oldloc, bezt->vec[1]);
424                                                         tv->loc = bezt->vec[1];
425                                                         tv->val = &(bezt->alfa);
426                                                         tv->oldval = bezt->alfa;
427                                                         tv->flag = bezt->f2 & SELECT;
428                                                         tv++;
429                                                         tottrans++;
430                                                 }
431                                                 if ((bezt->f3 & SELECT) && !skip_handle) {
432                                                         copy_v3_v3(tv->oldloc, bezt->vec[2]);
433                                                         tv->loc = bezt->vec[2];
434                                                         tv->flag = bezt->f3 & SELECT;
435                                                         tv++;
436                                                         tottrans++;
437                                                 }
438                                         }
439                                         bezt++;
440                                 }
441                         }
442                         else {
443                                 a = nu->pntsu * nu->pntsv;
444                                 bp = nu->bp;
445                                 while (a--) {
446                                         if (bp->hide == 0) {
447                                                 if (bp->f1 & SELECT) {
448                                                         copy_v3_v3(tv->oldloc, bp->vec);
449                                                         tv->loc = bp->vec;
450                                                         tv->val = &(bp->alfa);
451                                                         tv->oldval = bp->alfa;
452                                                         tv->flag = bp->f1 & SELECT;
453                                                         tv++;
454                                                         tottrans++;
455                                                 }
456                                         }
457                                         bp++;
458                                 }
459                         }
460                         nu = nu->next;
461                 }
462         }
463         else if (obedit->type == OB_MBALL) {
464                 MetaBall *mb = obedit->data;
465                 int totmalloc = BLI_countlist(mb->editelems);
466                 
467                 tv = transvmain = MEM_callocN(totmalloc * sizeof(TransVert), "maketransverts mball");
468                 
469                 ml = mb->editelems->first;
470                 while (ml) {
471                         if (ml->flag & SELECT) {
472                                 tv->loc = &ml->x;
473                                 copy_v3_v3(tv->oldloc, tv->loc);
474                                 tv->val = &(ml->rad);
475                                 tv->oldval = ml->rad;
476                                 tv->flag = SELECT;
477                                 tv++;
478                                 tottrans++;
479                         }
480                         ml = ml->next;
481                 }
482         }
483         else if (obedit->type == OB_LATTICE) {
484                 Lattice *lt = obedit->data;
485                 
486                 bp = lt->editlatt->latt->def;
487                 
488                 a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
489                 
490                 tv = transvmain = MEM_callocN(a * sizeof(TransVert), "maketransverts latt");
491                 
492                 while (a--) {
493                         if (bp->f1 & SELECT) {
494                                 if (bp->hide == 0) {
495                                         copy_v3_v3(tv->oldloc, bp->vec);
496                                         tv->loc = bp->vec;
497                                         tv->flag = bp->f1 & SELECT;
498                                         tv++;
499                                         tottrans++;
500                                 }
501                         }
502                         bp++;
503                 }
504         }
505         
506         if (!tottrans && transvmain) {
507                 /* prevent memory leak. happens for curves/latticies due to */
508                 /* difficult condition of adding points to trans data */
509                 MEM_freeN(transvmain);
510                 transvmain = NULL;
511         }
512
513         /* cent etc */
514         tv = transvmain;
515         total = 0.0;
516         for (a = 0; a < tottrans; a++, tv++) {
517                 if (tv->flag & SELECT) {
518                         add_v3_v3(centroid, tv->oldloc);
519                         total += 1.0f;
520                         minmax_v3v3_v3(min, max, tv->oldloc);
521                 }
522         }
523         if (total != 0.0f) {
524                 mul_v3_fl(centroid, 1.0f / total);
525         }
526
527         mid_v3_v3v3(center, min, max);
528 }
529
530 /* *********************** operators ******************** */
531
532 static int snap_sel_to_grid(bContext *C, wmOperator *UNUSED(op))
533 {
534         Object *obedit = CTX_data_edit_object(C);
535         Scene *scene = CTX_data_scene(C);
536         RegionView3D *rv3d = CTX_wm_region_data(C);
537         TransVert *tv;
538         float gridf, imat[3][3], bmat[3][3], vec[3];
539         int a;
540
541         gridf = rv3d->gridview;
542
543         if (obedit) {
544                 tottrans = 0;
545                 
546                 if (ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL))
547                         make_trans_verts(obedit, bmat[0], bmat[1], 0);
548                 if (tottrans == 0) return OPERATOR_CANCELLED;
549                 
550                 copy_m3_m4(bmat, obedit->obmat);
551                 invert_m3_m3(imat, bmat);
552                 
553                 tv = transvmain;
554                 for (a = 0; a < tottrans; a++, tv++) {
555                         copy_v3_v3(vec, tv->loc);
556                         mul_m3_v3(bmat, vec);
557                         add_v3_v3(vec, obedit->obmat[3]);
558                         vec[0] = gridf * floorf(0.5f + vec[0] / gridf);
559                         vec[1] = gridf * floorf(0.5f + vec[1] / gridf);
560                         vec[2] = gridf * floorf(0.5f + vec[2] / gridf);
561                         sub_v3_v3(vec, obedit->obmat[3]);
562                         
563                         mul_m3_v3(imat, vec);
564                         copy_v3_v3(tv->loc, vec);
565                 }
566                 
567                 special_transvert_update(obedit);
568                 
569                 MEM_freeN(transvmain);
570                 transvmain = NULL;
571         }
572         else {
573                 struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
574
575                 CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
576                 {
577                         if (ob->mode & OB_MODE_POSE) {
578                                 bPoseChannel *pchan;
579                                 bArmature *arm = ob->data;
580                                 
581                                 invert_m4_m4(ob->imat, ob->obmat);
582                                 
583                                 for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
584                                         if (pchan->bone->flag & BONE_SELECTED) {
585                                                 if (pchan->bone->layer & arm->layer) {
586                                                         if ((pchan->bone->flag & BONE_CONNECTED) == 0) {
587                                                                 float nLoc[3];
588                                                                 
589                                                                 /* get nearest grid point to snap to */
590                                                                 copy_v3_v3(nLoc, pchan->pose_mat[3]);
591                                                                 /* We must operate in world space! */
592                                                                 mul_m4_v3(ob->obmat, nLoc);
593                                                                 vec[0] = gridf * (float)(floor(0.5f + nLoc[0] / gridf));
594                                                                 vec[1] = gridf * (float)(floor(0.5f + nLoc[1] / gridf));
595                                                                 vec[2] = gridf * (float)(floor(0.5f + nLoc[2] / gridf));
596                                                                 /* Back in object space... */
597                                                                 mul_m4_v3(ob->imat, vec);
598                                                                 
599                                                                 /* Get location of grid point in pose space. */
600                                                                 BKE_armature_loc_pose_to_bone(pchan, vec, vec);
601                                                                 
602                                                                 /* adjust location */
603                                                                 if ((pchan->protectflag & OB_LOCK_LOCX) == 0)
604                                                                         pchan->loc[0] = vec[0];
605                                                                 if ((pchan->protectflag & OB_LOCK_LOCY) == 0)
606                                                                         pchan->loc[1] = vec[1];
607                                                                 if ((pchan->protectflag & OB_LOCK_LOCZ) == 0)
608                                                                         pchan->loc[2] = vec[2];
609
610                                                                 /* auto-keyframing */
611                                                                 ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
612                                                         }
613                                                         /* if the bone has a parent and is connected to the parent,
614                                                          * don't do anything - will break chain unless we do auto-ik.
615                                                          */
616                                                 }
617                                         }
618                                 }
619                                 ob->pose->flag |= (POSE_LOCKED | POSE_DO_UNLOCK);
620                                 
621                                 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
622                         }
623                         else {
624                                 vec[0] = -ob->obmat[3][0] + gridf * floorf(0.5f + ob->obmat[3][0] / gridf);
625                                 vec[1] = -ob->obmat[3][1] + gridf * floorf(0.5f + ob->obmat[3][1] / gridf);
626                                 vec[2] = -ob->obmat[3][2] + gridf * floorf(0.5f + ob->obmat[3][2] / gridf);
627                                 
628                                 if (ob->parent) {
629                                         float originmat[3][3];
630                                         BKE_object_where_is_calc_ex(scene, NULL, ob, originmat);
631                                         
632                                         invert_m3_m3(imat, originmat);
633                                         mul_m3_v3(imat, vec);
634                                 }
635                                 if ((ob->protectflag & OB_LOCK_LOCX) == 0)
636                                         ob->loc[0] += vec[0];
637                                 if ((ob->protectflag & OB_LOCK_LOCY) == 0)
638                                         ob->loc[1] += vec[1];
639                                 if ((ob->protectflag & OB_LOCK_LOCZ) == 0)
640                                         ob->loc[2] += vec[2];
641                                 
642                                 /* auto-keyframing */
643                                 ED_autokeyframe_object(C, scene, ob, ks);
644
645                                 DAG_id_tag_update(&ob->id, OB_RECALC_OB);
646                         }
647                 }
648                 CTX_DATA_END;
649         }
650
651         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
652         
653         return OPERATOR_FINISHED;
654 }
655
656 void VIEW3D_OT_snap_selected_to_grid(wmOperatorType *ot)
657 {
658         /* identifiers */
659         ot->name = "Snap Selection to Grid";
660         ot->description = "Snap selected item(s) to nearest grid node";
661         ot->idname = "VIEW3D_OT_snap_selected_to_grid";
662         
663         /* api callbacks */
664         ot->exec = snap_sel_to_grid;
665         ot->poll = ED_operator_region_view3d_active;
666         
667         /* flags */
668         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
669 }
670
671 /* *************************************************** */
672
673 static int snap_sel_to_curs(bContext *C, wmOperator *UNUSED(op))
674 {
675         Object *obedit = CTX_data_edit_object(C);
676         Scene *scene = CTX_data_scene(C);
677         View3D *v3d = CTX_wm_view3d(C);
678         TransVert *tv;
679         float imat[3][3], bmat[3][3];
680         const float *cursor_global;
681         int a;
682
683         cursor_global = give_cursor(scene, v3d);
684
685         if (obedit) {
686                 float cursor_local[3];
687
688                 tottrans = 0;
689                 
690                 if (ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL))
691                         make_trans_verts(obedit, bmat[0], bmat[1], 0);
692                 if (tottrans == 0) return OPERATOR_CANCELLED;
693                 
694                 copy_m3_m4(bmat, obedit->obmat);
695                 invert_m3_m3(imat, bmat);
696                 
697                 tv = transvmain;
698                 sub_v3_v3v3(cursor_local, cursor_global, obedit->obmat[3]);
699                 mul_m3_v3(imat, cursor_local);
700                 for (a = 0; a < tottrans; a++, tv++) {
701                         copy_v3_v3(tv->loc, cursor_local);
702                 }
703                 
704                 special_transvert_update(obedit);
705                 
706                 MEM_freeN(transvmain);
707                 transvmain = NULL;
708         }
709         else {
710                 struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
711
712                 CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
713                 {
714                         if (ob->mode & OB_MODE_POSE) {
715                                 bPoseChannel *pchan;
716                                 bArmature *arm = ob->data;
717                                 float cursor_local[3];
718                                 
719                                 invert_m4_m4(ob->imat, ob->obmat);
720                                 copy_v3_v3(cursor_local, cursor_global);
721                                 mul_m4_v3(ob->imat, cursor_local);
722                                 
723                                 for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
724                                         if (pchan->bone->flag & BONE_SELECTED) {
725                                                 if (pchan->bone->layer & arm->layer) {
726                                                         if ((pchan->bone->flag & BONE_CONNECTED) == 0) {
727                                                                 /* Get position in pchan (pose) space. */
728                                                                 float cursor_pose[3];
729                                                                 BKE_armature_loc_pose_to_bone(pchan, cursor_local, cursor_pose);
730
731                                                                 /* copy new position */
732                                                                 if ((pchan->protectflag & OB_LOCK_LOCX) == 0)
733                                                                         pchan->loc[0] = cursor_pose[0];
734                                                                 if ((pchan->protectflag & OB_LOCK_LOCY) == 0)
735                                                                         pchan->loc[1] = cursor_pose[1];
736                                                                 if ((pchan->protectflag & OB_LOCK_LOCZ) == 0)
737                                                                         pchan->loc[2] = cursor_pose[2];
738
739                                                                 /* auto-keyframing */
740                                                                 ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
741                                                         }
742                                                         /* if the bone has a parent and is connected to the parent,
743                                                          * don't do anything - will break chain unless we do auto-ik.
744                                                          */
745                                                 }
746                                         }
747                                 }
748                                 ob->pose->flag |= (POSE_LOCKED | POSE_DO_UNLOCK);
749                                 
750                                 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
751                         }
752                         else {
753                                 float cursor_parent[3];  /* parent-relative */
754                                 cursor_parent[0] = -ob->obmat[3][0] + cursor_global[0];
755                                 cursor_parent[1] = -ob->obmat[3][1] + cursor_global[1];
756                                 cursor_parent[2] = -ob->obmat[3][2] + cursor_global[2];
757                                 
758                                 if (ob->parent) {
759                                         float originmat[3][3];
760                                         BKE_object_where_is_calc_ex(scene, NULL, ob, originmat);
761                                         
762                                         invert_m3_m3(imat, originmat);
763                                         mul_m3_v3(imat, cursor_parent);
764                                 }
765                                 if ((ob->protectflag & OB_LOCK_LOCX) == 0)
766                                         ob->loc[0] += cursor_parent[0];
767                                 if ((ob->protectflag & OB_LOCK_LOCY) == 0)
768                                         ob->loc[1] += cursor_parent[1];
769                                 if ((ob->protectflag & OB_LOCK_LOCZ) == 0)
770                                         ob->loc[2] += cursor_parent[2];
771
772                                 /* auto-keyframing */
773                                 ED_autokeyframe_object(C, scene, ob, ks);
774
775                                 DAG_id_tag_update(&ob->id, OB_RECALC_OB);
776                         }
777                 }
778                 CTX_DATA_END;
779         }
780
781         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
782         
783         return OPERATOR_FINISHED;
784 }
785
786 void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot)
787 {
788         /* identifiers */
789         ot->name = "Snap Selection to Cursor";
790         ot->description = "Snap selected item(s) to cursor";
791         ot->idname = "VIEW3D_OT_snap_selected_to_cursor";
792         
793         /* api callbacks */
794         ot->exec = snap_sel_to_curs;
795         ot->poll = ED_operator_view3d_active;
796         
797         /* flags */
798         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
799 }
800
801 /* *************************************************** */
802
803 static int snap_curs_to_grid(bContext *C, wmOperator *UNUSED(op))
804 {
805         Scene *scene = CTX_data_scene(C);
806         RegionView3D *rv3d = CTX_wm_region_data(C);
807         View3D *v3d = CTX_wm_view3d(C);
808         float gridf, *curs;
809
810         gridf = rv3d->gridview;
811         curs = give_cursor(scene, v3d);
812
813         curs[0] = gridf * floorf(0.5f + curs[0] / gridf);
814         curs[1] = gridf * floorf(0.5f + curs[1] / gridf);
815         curs[2] = gridf * floorf(0.5f + curs[2] / gridf);
816         
817         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);  /* hrm */
818
819         return OPERATOR_FINISHED;
820 }
821
822 void VIEW3D_OT_snap_cursor_to_grid(wmOperatorType *ot)
823 {
824         /* identifiers */
825         ot->name = "Snap Cursor to Grid";
826         ot->description = "Snap cursor to nearest grid node";
827         ot->idname = "VIEW3D_OT_snap_cursor_to_grid";
828         
829         /* api callbacks */
830         ot->exec = snap_curs_to_grid;
831         ot->poll = ED_operator_region_view3d_active;
832         
833         /* flags */
834         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
835 }
836
837 /* **************************************************** */
838
839 static void bundle_midpoint(Scene *scene, Object *ob, float vec[3])
840 {
841         MovieClip *clip = BKE_object_movieclip_get(scene, ob, 0);
842         MovieTracking *tracking;
843         MovieTrackingObject *object;
844         int ok = 0;
845         float min[3], max[3], mat[4][4], pos[3], cammat[4][4] = MAT4_UNITY;
846
847         if (!clip)
848                 return;
849
850         tracking = &clip->tracking;
851
852         copy_m4_m4(cammat, ob->obmat);
853
854         BKE_tracking_get_camera_object_matrix(scene, ob, mat);
855
856         INIT_MINMAX(min, max);
857
858         for (object = tracking->objects.first; object; object = object->next) {
859                 ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
860                 MovieTrackingTrack *track = tracksbase->first;
861                 float obmat[4][4];
862
863                 if (object->flag & TRACKING_OBJECT_CAMERA) {
864                         copy_m4_m4(obmat, mat);
865                 }
866                 else {
867                         float imat[4][4];
868
869                         BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, scene->r.cfra, imat);
870                         invert_m4(imat);
871
872                         mul_m4_m4m4(obmat, cammat, imat);
873                 }
874
875                 while (track) {
876                         if ((track->flag & TRACK_HAS_BUNDLE) && TRACK_SELECTED(track)) {
877                                 ok = 1;
878                                 mul_v3_m4v3(pos, obmat, track->bundle_pos);
879                                 minmax_v3v3_v3(min, max, pos);
880                         }
881
882                         track = track->next;
883                 }
884         }
885
886         if (ok) {
887                 mid_v3_v3v3(vec, min, max);
888         }
889 }
890
891 static int snap_curs_to_sel(bContext *C, wmOperator *UNUSED(op))
892 {
893         Object *obedit = CTX_data_edit_object(C);
894         Scene *scene = CTX_data_scene(C);
895         View3D *v3d = CTX_wm_view3d(C);
896         TransVert *tv;
897         float *curs, bmat[3][3], vec[3], min[3], max[3], centroid[3];
898         int count, a;
899
900         curs = give_cursor(scene, v3d);
901
902         count = 0;
903         INIT_MINMAX(min, max);
904         zero_v3(centroid);
905
906         if (obedit) {
907                 tottrans = 0;
908                 
909                 if (ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL))
910                         make_trans_verts(obedit, bmat[0], bmat[1], TM_ALL_JOINTS | TM_SKIP_HANDLES);
911                 if (tottrans == 0) return OPERATOR_CANCELLED;
912                 
913                 copy_m3_m4(bmat, obedit->obmat);
914                 
915                 tv = transvmain;
916                 for (a = 0; a < tottrans; a++, tv++) {
917                         copy_v3_v3(vec, tv->loc);
918                         mul_m3_v3(bmat, vec);
919                         add_v3_v3(vec, obedit->obmat[3]);
920                         add_v3_v3(centroid, vec);
921                         minmax_v3v3_v3(min, max, vec);
922                 }
923                 
924                 if (v3d->around == V3D_CENTROID) {
925                         mul_v3_fl(centroid, 1.0f / (float)tottrans);
926                         copy_v3_v3(curs, centroid);
927                 }
928                 else {
929                         mid_v3_v3v3(curs, min, max);
930                 }
931                 MEM_freeN(transvmain);
932                 transvmain = NULL;
933         }
934         else {
935                 Object *obact = CTX_data_active_object(C);
936                 
937                 if (obact && (obact->mode & OB_MODE_POSE)) {
938                         bArmature *arm = obact->data;
939                         bPoseChannel *pchan;
940                         for (pchan = obact->pose->chanbase.first; pchan; pchan = pchan->next) {
941                                 if (arm->layer & pchan->bone->layer) {
942                                         if (pchan->bone->flag & BONE_SELECTED) {
943                                                 copy_v3_v3(vec, pchan->pose_head);
944                                                 mul_m4_v3(obact->obmat, vec);
945                                                 add_v3_v3(centroid, vec);
946                                                 minmax_v3v3_v3(min, max, vec);
947                                                 count++;
948                                         }
949                                 }
950                         }
951                 }
952                 else {
953                         CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
954                         {
955                                 copy_v3_v3(vec, ob->obmat[3]);
956
957                                 /* special case for camera -- snap to bundles */
958                                 if (ob->type == OB_CAMERA) {
959                                         /* snap to bundles should happen only when bundles are visible */
960                                         if (v3d->flag2 & V3D_SHOW_RECONSTRUCTION) {
961                                                 bundle_midpoint(scene, ob, vec);
962                                         }
963                                 }
964
965                                 add_v3_v3(centroid, vec);
966                                 minmax_v3v3_v3(min, max, vec);
967                                 count++;
968                         }
969                         CTX_DATA_END;
970                 }
971                 if (count) {
972                         if (v3d->around == V3D_CENTROID) {
973                                 mul_v3_fl(centroid, 1.0f / (float)count);
974                                 copy_v3_v3(curs, centroid);
975                         }
976                         else {
977                                 mid_v3_v3v3(curs, min, max);
978                         }
979                 }
980         }
981         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
982         
983         return OPERATOR_FINISHED;
984 }
985
986 void VIEW3D_OT_snap_cursor_to_selected(wmOperatorType *ot)
987 {
988         /* identifiers */
989         ot->name = "Snap Cursor to Selected";
990         ot->description = "Snap cursor to center of selected item(s)";
991         ot->idname = "VIEW3D_OT_snap_cursor_to_selected";
992         
993         /* api callbacks */
994         ot->exec = snap_curs_to_sel;
995         ot->poll = ED_operator_view3d_active;
996         
997         /* flags */
998         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
999 }
1000
1001 /* ********************************************** */
1002
1003 static int snap_curs_to_active(bContext *C, wmOperator *UNUSED(op))
1004 {
1005         Object *obedit = CTX_data_edit_object(C);
1006         Object *obact = CTX_data_active_object(C);
1007         Scene *scene = CTX_data_scene(C);
1008         View3D *v3d = CTX_wm_view3d(C);
1009         float *curs;
1010         
1011         curs = give_cursor(scene, v3d);
1012
1013         if (obedit) {
1014                 if (obedit->type == OB_MESH) {
1015                         BMEditMesh *em = BKE_editmesh_from_object(obedit);
1016                         /* check active */
1017                         BMEditSelection ese;
1018                         
1019                         if (BM_select_history_active_get(em->bm, &ese)) {
1020                                 BM_editselection_center(&ese, curs);
1021                         }
1022                         
1023                         mul_m4_v3(obedit->obmat, curs);
1024                 }
1025                 else if (obedit->type == OB_LATTICE) {
1026                         BPoint *actbp = BKE_lattice_active_point_get(obedit->data);
1027
1028                         if (actbp) {
1029                                 copy_v3_v3(curs, actbp->vec);
1030                                 mul_m4_v3(obedit->obmat, curs);
1031                         }
1032                 }
1033         }
1034         else {
1035                 if (obact) {
1036                         copy_v3_v3(curs, obact->obmat[3]);
1037                 }
1038         }
1039         
1040         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
1041         return OPERATOR_FINISHED;
1042 }
1043
1044 void VIEW3D_OT_snap_cursor_to_active(wmOperatorType *ot)
1045 {
1046         /* identifiers */
1047         ot->name = "Snap Cursor to Active";
1048         ot->description = "Snap cursor to active item";
1049         ot->idname = "VIEW3D_OT_snap_cursor_to_active";
1050         
1051         /* api callbacks */
1052         ot->exec = snap_curs_to_active;
1053         ot->poll = ED_operator_view3d_active;
1054         
1055         /* flags */
1056         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1057 }
1058
1059 /* **************************************************** */
1060 /*New Code - Snap Cursor to Center -*/
1061 static int snap_curs_to_center(bContext *C, wmOperator *UNUSED(op))
1062 {
1063         Scene *scene = CTX_data_scene(C);
1064         View3D *v3d = CTX_wm_view3d(C);
1065         float *curs;
1066         curs = give_cursor(scene, v3d);
1067
1068         zero_v3(curs);
1069         
1070         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
1071         
1072         return OPERATOR_FINISHED;
1073 }
1074
1075 void VIEW3D_OT_snap_cursor_to_center(wmOperatorType *ot)
1076 {
1077         /* identifiers */
1078         ot->name = "Snap Cursor to Center";
1079         ot->description = "Snap cursor to the Center";
1080         ot->idname = "VIEW3D_OT_snap_cursor_to_center";
1081         
1082         /* api callbacks */
1083         ot->exec = snap_curs_to_center;
1084         ot->poll = ED_operator_view3d_active;
1085         
1086         /* flags */
1087         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1088 }
1089
1090 /* **************************************************** */
1091
1092
1093 bool ED_view3d_minmax_verts(Object *obedit, float min[3], float max[3])
1094 {
1095         TransVert *tv;
1096         float centroid[3], vec[3], bmat[3][3];
1097         int a;
1098
1099         /* metaballs are an exception */
1100         if (obedit->type == OB_MBALL) {
1101                 float ob_min[3], ob_max[3];
1102                 bool change;
1103
1104                 change = BKE_mball_minmax_ex(obedit->data, ob_min, ob_max, obedit->obmat, SELECT);
1105                 if (change) {
1106                         minmax_v3v3_v3(min, max, ob_min);
1107                         minmax_v3v3_v3(min, max, ob_max);
1108                 }
1109                 return change;
1110         }
1111
1112         tottrans = 0;
1113         if (ELEM5(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE))
1114                 make_trans_verts(obedit, bmat[0], bmat[1], TM_ALL_JOINTS);
1115         
1116         if (tottrans == 0) return false;
1117
1118         copy_m3_m4(bmat, obedit->obmat);
1119         
1120         tv = transvmain;
1121         for (a = 0; a < tottrans; a++, tv++) {
1122                 copy_v3_v3(vec, (tv->flag & TX_VERT_USE_MAPLOC) ? tv->maploc : tv->loc);
1123                 mul_m3_v3(bmat, vec);
1124                 add_v3_v3(vec, obedit->obmat[3]);
1125                 add_v3_v3(centroid, vec);
1126                 minmax_v3v3_v3(min, max, vec);
1127         }
1128         
1129         MEM_freeN(transvmain);
1130         transvmain = NULL;
1131         
1132         return true;
1133 }