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