e9aca8d4640b1de40e93f0c65f8cfa7e403cf936
[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 *curs, imat[3][3], bmat[3][3], vec[3];
680         int a;
681
682         curs = give_cursor(scene, v3d);
683
684         if (obedit) {
685                 tottrans = 0;
686                 
687                 if (ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL))
688                         make_trans_verts(obedit, bmat[0], bmat[1], 0);
689                 if (tottrans == 0) return OPERATOR_CANCELLED;
690                 
691                 copy_m3_m4(bmat, obedit->obmat);
692                 invert_m3_m3(imat, bmat);
693                 
694                 tv = transvmain;
695                 for (a = 0; a < tottrans; a++, tv++) {
696                         sub_v3_v3v3(vec, curs, obedit->obmat[3]);
697                         mul_m3_v3(imat, vec);
698                         copy_v3_v3(tv->loc, vec);
699                 }
700                 
701                 special_transvert_update(obedit);
702                 
703                 MEM_freeN(transvmain);
704                 transvmain = NULL;
705         }
706         else {
707                 struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
708
709                 CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
710                 {
711                         if (ob->mode & OB_MODE_POSE) {
712                                 bPoseChannel *pchan;
713                                 bArmature *arm = ob->data;
714                                 
715                                 invert_m4_m4(ob->imat, ob->obmat);
716                                 copy_v3_v3(vec, curs);
717                                 mul_m4_v3(ob->imat, vec);
718                                 
719                                 for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
720                                         if (pchan->bone->flag & BONE_SELECTED) {
721                                                 if (pchan->bone->layer & arm->layer) {
722                                                         if ((pchan->bone->flag & BONE_CONNECTED) == 0) {
723                                                                 /* Get position in pchan (pose) space. */
724                                                                 BKE_armature_loc_pose_to_bone(pchan, vec, vec);
725
726                                                                 /* copy new position */
727                                                                 if ((pchan->protectflag & OB_LOCK_LOCX) == 0)
728                                                                         pchan->loc[0] = vec[0];
729                                                                 if ((pchan->protectflag & OB_LOCK_LOCY) == 0)
730                                                                         pchan->loc[1] = vec[1];
731                                                                 if ((pchan->protectflag & OB_LOCK_LOCZ) == 0)
732                                                                         pchan->loc[2] = vec[2];
733
734                                                                 /* auto-keyframing */
735                                                                 ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
736                                                         }
737                                                         /* if the bone has a parent and is connected to the parent,
738                                                          * don't do anything - will break chain unless we do auto-ik.
739                                                          */
740                                                 }
741                                         }
742                                 }
743                                 ob->pose->flag |= (POSE_LOCKED | POSE_DO_UNLOCK);
744                                 
745                                 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
746                         }
747                         else {
748                                 vec[0] = -ob->obmat[3][0] + curs[0];
749                                 vec[1] = -ob->obmat[3][1] + curs[1];
750                                 vec[2] = -ob->obmat[3][2] + curs[2];
751                                 
752                                 if (ob->parent) {
753                                         float originmat[3][3];
754                                         BKE_object_where_is_calc_ex(scene, NULL, ob, originmat);
755                                         
756                                         invert_m3_m3(imat, originmat);
757                                         mul_m3_v3(imat, vec);
758                                 }
759                                 if ((ob->protectflag & OB_LOCK_LOCX) == 0)
760                                         ob->loc[0] += vec[0];
761                                 if ((ob->protectflag & OB_LOCK_LOCY) == 0)
762                                         ob->loc[1] += vec[1];
763                                 if ((ob->protectflag & OB_LOCK_LOCZ) == 0)
764                                         ob->loc[2] += vec[2];
765
766                                 /* auto-keyframing */
767                                 ED_autokeyframe_object(C, scene, ob, ks);
768
769                                 DAG_id_tag_update(&ob->id, OB_RECALC_OB);
770                         }
771                 }
772                 CTX_DATA_END;
773         }
774
775         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
776         
777         return OPERATOR_FINISHED;
778 }
779
780 void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot)
781 {
782         /* identifiers */
783         ot->name = "Snap Selection to Cursor";
784         ot->description = "Snap selected item(s) to cursor";
785         ot->idname = "VIEW3D_OT_snap_selected_to_cursor";
786         
787         /* api callbacks */
788         ot->exec = snap_sel_to_curs;
789         ot->poll = ED_operator_view3d_active;
790         
791         /* flags */
792         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
793 }
794
795 /* *************************************************** */
796
797 static int snap_curs_to_grid(bContext *C, wmOperator *UNUSED(op))
798 {
799         Scene *scene = CTX_data_scene(C);
800         RegionView3D *rv3d = CTX_wm_region_data(C);
801         View3D *v3d = CTX_wm_view3d(C);
802         float gridf, *curs;
803
804         gridf = rv3d->gridview;
805         curs = give_cursor(scene, v3d);
806
807         curs[0] = gridf * floorf(0.5f + curs[0] / gridf);
808         curs[1] = gridf * floorf(0.5f + curs[1] / gridf);
809         curs[2] = gridf * floorf(0.5f + curs[2] / gridf);
810         
811         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);  /* hrm */
812
813         return OPERATOR_FINISHED;
814 }
815
816 void VIEW3D_OT_snap_cursor_to_grid(wmOperatorType *ot)
817 {
818         /* identifiers */
819         ot->name = "Snap Cursor to Grid";
820         ot->description = "Snap cursor to nearest grid node";
821         ot->idname = "VIEW3D_OT_snap_cursor_to_grid";
822         
823         /* api callbacks */
824         ot->exec = snap_curs_to_grid;
825         ot->poll = ED_operator_region_view3d_active;
826         
827         /* flags */
828         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
829 }
830
831 /* **************************************************** */
832
833 static void bundle_midpoint(Scene *scene, Object *ob, float vec[3])
834 {
835         MovieClip *clip = BKE_object_movieclip_get(scene, ob, 0);
836         MovieTracking *tracking;
837         MovieTrackingObject *object;
838         int ok = 0;
839         float min[3], max[3], mat[4][4], pos[3], cammat[4][4] = MAT4_UNITY;
840
841         if (!clip)
842                 return;
843
844         tracking = &clip->tracking;
845
846         copy_m4_m4(cammat, ob->obmat);
847
848         BKE_tracking_get_camera_object_matrix(scene, ob, mat);
849
850         INIT_MINMAX(min, max);
851
852         for (object = tracking->objects.first; object; object = object->next) {
853                 ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
854                 MovieTrackingTrack *track = tracksbase->first;
855                 float obmat[4][4];
856
857                 if (object->flag & TRACKING_OBJECT_CAMERA) {
858                         copy_m4_m4(obmat, mat);
859                 }
860                 else {
861                         float imat[4][4];
862
863                         BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, scene->r.cfra, imat);
864                         invert_m4(imat);
865
866                         mul_m4_m4m4(obmat, cammat, imat);
867                 }
868
869                 while (track) {
870                         if ((track->flag & TRACK_HAS_BUNDLE) && TRACK_SELECTED(track)) {
871                                 ok = 1;
872                                 mul_v3_m4v3(pos, obmat, track->bundle_pos);
873                                 minmax_v3v3_v3(min, max, pos);
874                         }
875
876                         track = track->next;
877                 }
878         }
879
880         if (ok) {
881                 mid_v3_v3v3(vec, min, max);
882         }
883 }
884
885 static int snap_curs_to_sel(bContext *C, wmOperator *UNUSED(op))
886 {
887         Object *obedit = CTX_data_edit_object(C);
888         Scene *scene = CTX_data_scene(C);
889         View3D *v3d = CTX_wm_view3d(C);
890         TransVert *tv;
891         float *curs, bmat[3][3], vec[3], min[3], max[3], centroid[3];
892         int count, a;
893
894         curs = give_cursor(scene, v3d);
895
896         count = 0;
897         INIT_MINMAX(min, max);
898         zero_v3(centroid);
899
900         if (obedit) {
901                 tottrans = 0;
902                 
903                 if (ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL))
904                         make_trans_verts(obedit, bmat[0], bmat[1], TM_ALL_JOINTS | TM_SKIP_HANDLES);
905                 if (tottrans == 0) return OPERATOR_CANCELLED;
906                 
907                 copy_m3_m4(bmat, obedit->obmat);
908                 
909                 tv = transvmain;
910                 for (a = 0; a < tottrans; a++, tv++) {
911                         copy_v3_v3(vec, tv->loc);
912                         mul_m3_v3(bmat, vec);
913                         add_v3_v3(vec, obedit->obmat[3]);
914                         add_v3_v3(centroid, vec);
915                         minmax_v3v3_v3(min, max, vec);
916                 }
917                 
918                 if (v3d->around == V3D_CENTROID) {
919                         mul_v3_fl(centroid, 1.0f / (float)tottrans);
920                         copy_v3_v3(curs, centroid);
921                 }
922                 else {
923                         mid_v3_v3v3(curs, min, max);
924                 }
925                 MEM_freeN(transvmain);
926                 transvmain = NULL;
927         }
928         else {
929                 Object *obact = CTX_data_active_object(C);
930                 
931                 if (obact && (obact->mode & OB_MODE_POSE)) {
932                         bArmature *arm = obact->data;
933                         bPoseChannel *pchan;
934                         for (pchan = obact->pose->chanbase.first; pchan; pchan = pchan->next) {
935                                 if (arm->layer & pchan->bone->layer) {
936                                         if (pchan->bone->flag & BONE_SELECTED) {
937                                                 copy_v3_v3(vec, pchan->pose_head);
938                                                 mul_m4_v3(obact->obmat, vec);
939                                                 add_v3_v3(centroid, vec);
940                                                 minmax_v3v3_v3(min, max, vec);
941                                                 count++;
942                                         }
943                                 }
944                         }
945                 }
946                 else {
947                         CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
948                         {
949                                 copy_v3_v3(vec, ob->obmat[3]);
950
951                                 /* special case for camera -- snap to bundles */
952                                 if (ob->type == OB_CAMERA) {
953                                         /* snap to bundles should happen only when bundles are visible */
954                                         if (v3d->flag2 & V3D_SHOW_RECONSTRUCTION) {
955                                                 bundle_midpoint(scene, ob, vec);
956                                         }
957                                 }
958
959                                 add_v3_v3(centroid, vec);
960                                 minmax_v3v3_v3(min, max, vec);
961                                 count++;
962                         }
963                         CTX_DATA_END;
964                 }
965                 if (count) {
966                         if (v3d->around == V3D_CENTROID) {
967                                 mul_v3_fl(centroid, 1.0f / (float)count);
968                                 copy_v3_v3(curs, centroid);
969                         }
970                         else {
971                                 mid_v3_v3v3(curs, min, max);
972                         }
973                 }
974         }
975         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
976         
977         return OPERATOR_FINISHED;
978 }
979
980 void VIEW3D_OT_snap_cursor_to_selected(wmOperatorType *ot)
981 {
982         /* identifiers */
983         ot->name = "Snap Cursor to Selected";
984         ot->description = "Snap cursor to center of selected item(s)";
985         ot->idname = "VIEW3D_OT_snap_cursor_to_selected";
986         
987         /* api callbacks */
988         ot->exec = snap_curs_to_sel;
989         ot->poll = ED_operator_view3d_active;
990         
991         /* flags */
992         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
993 }
994
995 /* ********************************************** */
996
997 static int snap_curs_to_active(bContext *C, wmOperator *UNUSED(op))
998 {
999         Object *obedit = CTX_data_edit_object(C);
1000         Object *obact = CTX_data_active_object(C);
1001         Scene *scene = CTX_data_scene(C);
1002         View3D *v3d = CTX_wm_view3d(C);
1003         float *curs;
1004         
1005         curs = give_cursor(scene, v3d);
1006
1007         if (obedit) {
1008                 if (obedit->type == OB_MESH) {
1009                         BMEditMesh *em = BKE_editmesh_from_object(obedit);
1010                         /* check active */
1011                         BMEditSelection ese;
1012                         
1013                         if (BM_select_history_active_get(em->bm, &ese)) {
1014                                 BM_editselection_center(&ese, curs);
1015                         }
1016                         
1017                         mul_m4_v3(obedit->obmat, curs);
1018                 }
1019                 else if (obedit->type == OB_LATTICE) {
1020                         BPoint *actbp = BKE_lattice_active_point_get(obedit->data);
1021
1022                         if (actbp) {
1023                                 copy_v3_v3(curs, actbp->vec);
1024                                 mul_m4_v3(obedit->obmat, curs);
1025                         }
1026                 }
1027         }
1028         else {
1029                 if (obact) {
1030                         copy_v3_v3(curs, obact->obmat[3]);
1031                 }
1032         }
1033         
1034         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
1035         return OPERATOR_FINISHED;
1036 }
1037
1038 void VIEW3D_OT_snap_cursor_to_active(wmOperatorType *ot)
1039 {
1040         /* identifiers */
1041         ot->name = "Snap Cursor to Active";
1042         ot->description = "Snap cursor to active item";
1043         ot->idname = "VIEW3D_OT_snap_cursor_to_active";
1044         
1045         /* api callbacks */
1046         ot->exec = snap_curs_to_active;
1047         ot->poll = ED_operator_view3d_active;
1048         
1049         /* flags */
1050         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1051 }
1052
1053 /* **************************************************** */
1054 /*New Code - Snap Cursor to Center -*/
1055 static int snap_curs_to_center(bContext *C, wmOperator *UNUSED(op))
1056 {
1057         Scene *scene = CTX_data_scene(C);
1058         View3D *v3d = CTX_wm_view3d(C);
1059         float *curs;
1060         curs = give_cursor(scene, v3d);
1061
1062         zero_v3(curs);
1063         
1064         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
1065         
1066         return OPERATOR_FINISHED;
1067 }
1068
1069 void VIEW3D_OT_snap_cursor_to_center(wmOperatorType *ot)
1070 {
1071         /* identifiers */
1072         ot->name = "Snap Cursor to Center";
1073         ot->description = "Snap cursor to the Center";
1074         ot->idname = "VIEW3D_OT_snap_cursor_to_center";
1075         
1076         /* api callbacks */
1077         ot->exec = snap_curs_to_center;
1078         ot->poll = ED_operator_view3d_active;
1079         
1080         /* flags */
1081         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1082 }
1083
1084 /* **************************************************** */
1085
1086
1087 bool ED_view3d_minmax_verts(Object *obedit, float min[3], float max[3])
1088 {
1089         TransVert *tv;
1090         float centroid[3], vec[3], bmat[3][3];
1091         int a;
1092
1093         /* metaballs are an exception */
1094         if (obedit->type == OB_MBALL) {
1095                 float ob_min[3], ob_max[3];
1096                 bool change;
1097
1098                 change = BKE_mball_minmax_ex(obedit->data, ob_min, ob_max, obedit->obmat, SELECT);
1099                 if (change) {
1100                         minmax_v3v3_v3(min, max, ob_min);
1101                         minmax_v3v3_v3(min, max, ob_max);
1102                 }
1103                 return change;
1104         }
1105
1106         tottrans = 0;
1107         if (ELEM5(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE))
1108                 make_trans_verts(obedit, bmat[0], bmat[1], TM_ALL_JOINTS);
1109         
1110         if (tottrans == 0) return false;
1111
1112         copy_m3_m4(bmat, obedit->obmat);
1113         
1114         tv = transvmain;
1115         for (a = 0; a < tottrans; a++, tv++) {
1116                 copy_v3_v3(vec, (tv->flag & TX_VERT_USE_MAPLOC) ? tv->maploc : tv->loc);
1117                 mul_m3_v3(bmat, vec);
1118                 add_v3_v3(vec, obedit->obmat[3]);
1119                 add_v3_v3(centroid, vec);
1120                 minmax_v3v3_v3(min, max, vec);
1121         }
1122         
1123         MEM_freeN(transvmain);
1124         transvmain = NULL;
1125         
1126         return true;
1127 }