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