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