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