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