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