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