Merge from trunk -r 23000:23968.
[blender.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_arithb.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                                                 VecSubf(diffvec, tv->loc, tv->oldloc);
139                                                 VecAddf(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                 tv=transvmain= MEM_callocN(totmalloc*sizeof(TransVert), "maketransverts armature");
259                 
260                 for (ebo= arm->edbo->first; ebo; ebo=ebo->next){
261                         if(ebo->layer & arm->layer) {
262                                 short tipsel= (ebo->flag & BONE_TIPSEL);
263                                 short rootsel= (ebo->flag & BONE_ROOTSEL);
264                                 short rootok= (!(ebo->parent && (ebo->flag & BONE_CONNECTED) && ebo->parent->flag & BONE_TIPSEL));
265                                 
266                                 if ((tipsel && rootsel) || (rootsel)) {
267                                         /* Don't add the tip (unless mode & 2, for getting all joints), 
268                                          * otherwise we get zero-length bones as tips will snap to the same
269                                          * location as heads. 
270                                          */
271                                         if (rootok) {
272                                                 VECCOPY (tv->oldloc, ebo->head);
273                                                 tv->loc= ebo->head;
274                                                 tv->nor= NULL;
275                                                 tv->flag= 1;
276                                                 tv++;
277                                                 tottrans++;
278                                         }       
279                                         
280                                         if ((mode & 2) && (tipsel)) {
281                                                 VECCOPY (tv->oldloc, ebo->tail);
282                                                 tv->loc= ebo->tail;
283                                                 tv->nor= NULL;
284                                                 tv->flag= 1;
285                                                 tv++;
286                                                 tottrans++;
287                                         }                                       
288                                 }
289                                 else if (tipsel) {
290                                         VECCOPY (tv->oldloc, ebo->tail);
291                                         tv->loc= ebo->tail;
292                                         tv->nor= NULL;
293                                         tv->flag= 1;
294                                         tv++;
295                                         tottrans++;
296                                 }
297                         }                       
298                 }
299         }
300         else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
301                 Curve *cu= obedit->data;
302                 int totmalloc= 0;
303                 
304                 for(nu= cu->editnurb->first; nu; nu= nu->next) {
305                         if(nu->type == CU_BEZIER)
306                                 totmalloc += 3*nu->pntsu;
307                         else
308                                 totmalloc += nu->pntsu*nu->pntsv;
309                 }
310                 tv=transvmain= MEM_callocN(totmalloc*sizeof(TransVert), "maketransverts curve");
311
312                 nu= cu->editnurb->first;
313                 while(nu) {
314                         if(nu->type == CU_BEZIER) {
315                                 a= nu->pntsu;
316                                 bezt= nu->bezt;
317                                 while(a--) {
318                                         if(bezt->hide==0) {
319                                                 if((mode & 1) || (bezt->f1 & SELECT)) {
320                                                         VECCOPY(tv->oldloc, bezt->vec[0]);
321                                                         tv->loc= bezt->vec[0];
322                                                         tv->flag= bezt->f1 & SELECT;
323                                                         tv++;
324                                                         tottrans++;
325                                                 }
326                                                 if((mode & 1) || (bezt->f2 & SELECT)) {
327                                                         VECCOPY(tv->oldloc, bezt->vec[1]);
328                                                         tv->loc= bezt->vec[1];
329                                                         tv->val= &(bezt->alfa);
330                                                         tv->oldval= bezt->alfa;
331                                                         tv->flag= bezt->f2 & SELECT;
332                                                         tv++;
333                                                         tottrans++;
334                                                 }
335                                                 if((mode & 1) || (bezt->f3 & SELECT)) {
336                                                         VECCOPY(tv->oldloc, bezt->vec[2]);
337                                                         tv->loc= bezt->vec[2];
338                                                         tv->flag= bezt->f3 & SELECT;
339                                                         tv++;
340                                                         tottrans++;
341                                                 }
342                                         }
343                                         bezt++;
344                                 }
345                         }
346                         else {
347                                 a= nu->pntsu*nu->pntsv;
348                                 bp= nu->bp;
349                                 while(a--) {
350                                         if(bp->hide==0) {
351                                                 if((mode & 1) || (bp->f1 & SELECT)) {
352                                                         VECCOPY(tv->oldloc, bp->vec);
353                                                         tv->loc= bp->vec;
354                                                         tv->val= &(bp->alfa);
355                                                         tv->oldval= bp->alfa;
356                                                         tv->flag= bp->f1 & SELECT;
357                                                         tv++;
358                                                         tottrans++;
359                                                 }
360                                         }
361                                         bp++;
362                                 }
363                         }
364                         nu= nu->next;
365                 }
366         }
367         else if(obedit->type==OB_MBALL) {
368                 MetaBall *mb= obedit->data;
369                 int totmalloc= BLI_countlist(mb->editelems);
370                 
371                 tv=transvmain= MEM_callocN(totmalloc*sizeof(TransVert), "maketransverts mball");
372                 
373                 ml= mb->editelems->first;
374                 while(ml) {
375                         if(ml->flag & SELECT) {
376                                 tv->loc= &ml->x;
377                                 VECCOPY(tv->oldloc, tv->loc);
378                                 tv->val= &(ml->rad);
379                                 tv->oldval= ml->rad;
380                                 tv->flag= 1;
381                                 tv++;
382                                 tottrans++;
383                         }
384                         ml= ml->next;
385                 }
386         }
387         else if(obedit->type==OB_LATTICE) {
388                 Lattice *lt= obedit->data;
389                 
390                 bp= lt->editlatt->def;
391                 
392                 a= lt->editlatt->pntsu*lt->editlatt->pntsv*lt->editlatt->pntsw;
393                 
394                 tv=transvmain= MEM_callocN(a*sizeof(TransVert), "maketransverts curve");
395                 
396                 while(a--) {
397                         if((mode & 1) || (bp->f1 & SELECT)) {
398                                 if(bp->hide==0) {
399                                         VECCOPY(tv->oldloc, bp->vec);
400                                         tv->loc= bp->vec;
401                                         tv->flag= bp->f1 & SELECT;
402                                         tv++;
403                                         tottrans++;
404                                 }
405                         }
406                         bp++;
407                 }
408         }
409         
410         /* cent etc */
411         tv= transvmain;
412         total= 0.0;
413         for(a=0; a<tottrans; a++, tv++) {
414                 if(tv->flag & SELECT) {
415                         centroid[0]+= tv->oldloc[0];
416                         centroid[1]+= tv->oldloc[1];
417                         centroid[2]+= tv->oldloc[2];
418                         total+= 1.0;
419                         DO_MINMAX(tv->oldloc, min, max);
420                 }
421         }
422         if(total!=0.0) {
423                 centroid[0]/= total;
424                 centroid[1]/= total;
425                 centroid[2]/= total;
426         }
427
428         center[0]= (min[0]+max[0])/2.0;
429         center[1]= (min[1]+max[1])/2.0;
430         center[2]= (min[2]+max[2])/2.0;
431         
432 }
433
434 /* *********************** operators ******************** */
435
436 static int snap_sel_to_grid(bContext *C, wmOperator *op)
437 {
438         extern float originmat[3][3];   /* XXX object.c */
439         Object *obedit= CTX_data_edit_object(C);
440         Scene *scene= CTX_data_scene(C);
441         View3D *v3d= CTX_wm_view3d(C);
442         TransVert *tv;
443         Object *ob;
444         float gridf, imat[3][3], bmat[3][3], vec[3];
445         int a;
446
447         gridf= v3d->gridview;
448
449         if(obedit) {
450                 tottrans= 0;
451                 
452                 if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
453                         make_trans_verts(obedit, bmat[0], bmat[1], 0);
454                 if(tottrans==0) return OPERATOR_CANCELLED;
455                 
456                 Mat3CpyMat4(bmat, obedit->obmat);
457                 Mat3Inv(imat, bmat);
458                 
459                 tv= transvmain;
460                 for(a=0; a<tottrans; a++, tv++) {
461                         
462                         VECCOPY(vec, tv->loc);
463                         Mat3MulVecfl(bmat, vec);
464                         VecAddf(vec, vec, obedit->obmat[3]);
465                         vec[0]= v3d->gridview*floor(.5+ vec[0]/gridf);
466                         vec[1]= v3d->gridview*floor(.5+ vec[1]/gridf);
467                         vec[2]= v3d->gridview*floor(.5+ vec[2]/gridf);
468                         VecSubf(vec, vec, obedit->obmat[3]);
469                         
470                         Mat3MulVecfl(imat, vec);
471                         VECCOPY(tv->loc, vec);
472                 }
473                 
474                 special_transvert_update(scene, obedit);
475                 
476                 MEM_freeN(transvmain);
477                 transvmain= NULL;
478         
479         }
480         else {
481
482                 CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
483                         ob= base->object;
484                         
485                         if(ob->mode & OB_MODE_POSE) {
486                                 bPoseChannel *pchan;
487                                 bArmature *arm= ob->data;
488                                 
489                                 for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
490                                         if(pchan->bone->flag & BONE_SELECTED) {
491                                                 if(pchan->bone->layer & arm->layer) {
492                                                         if((pchan->bone->flag & BONE_CONNECTED)==0) { 
493                                                                 float vecN[3], nLoc[3]; 
494                                                                 
495                                                                 /* get nearest grid point to snap to */
496                                                                 VECCOPY(nLoc, pchan->pose_mat[3]);
497                                                                 vec[0]= gridf * (float)(floor(.5+ nLoc[0]/gridf));
498                                                                 vec[1]= gridf * (float)(floor(.5+ nLoc[1]/gridf));
499                                                                 vec[2]= gridf * (float)(floor(.5+ nLoc[2]/gridf));
500                                                                 
501                                                                 /* get bone-space location of grid point */
502                                                                 armature_loc_pose_to_bone(pchan, vec, vecN);
503                                                                 
504                                                                 /* adjust location */
505                                                                 VECCOPY(pchan->loc, vecN);
506                                                         }
507                                                         /* if the bone has a parent and is connected to the parent, 
508                                                          * don't do anything - will break chain unless we do auto-ik. 
509                                                          */
510                                                 }
511                                         }
512                                 }
513                                 ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
514                                 
515                                 /* auto-keyframing */
516 // XXX                          autokeyframe_pose_cb_func(ob, TFM_TRANSLATION, 0);
517                                 DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
518                         }
519                         else {
520                                 ob->recalc |= OB_RECALC_OB;
521                                 
522                                 vec[0]= -ob->obmat[3][0]+v3d->gridview*floor(.5+ ob->obmat[3][0]/gridf);
523                                 vec[1]= -ob->obmat[3][1]+v3d->gridview*floor(.5+ ob->obmat[3][1]/gridf);
524                                 vec[2]= -ob->obmat[3][2]+v3d->gridview*floor(.5+ ob->obmat[3][2]/gridf);
525                                 
526                                 if(ob->parent) {
527                                         where_is_object(scene, ob);
528                                         
529                                         Mat3Inv(imat, originmat);
530                                         Mat3MulVecfl(imat, vec);
531                                         ob->loc[0]+= vec[0];
532                                         ob->loc[1]+= vec[1];
533                                         ob->loc[2]+= vec[2];
534                                 }
535                                 else {
536                                         ob->loc[0]+= vec[0];
537                                         ob->loc[1]+= vec[1];
538                                         ob->loc[2]+= vec[2];
539                                 }
540                         
541                                 /* auto-keyframing */
542 // XXX                          autokeyframe_ob_cb_func(ob, TFM_TRANSLATION);
543                         }
544                 }
545                 CTX_DATA_END;
546         }
547         ED_anim_dag_flush_update(C);
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         Object *ob;
579         float *curs, imat[3][3], bmat[3][3], vec[3];
580         int a;
581
582         curs= give_cursor(scene, v3d);
583
584         if(obedit) {
585                 tottrans= 0;
586                 
587                 if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
588                         make_trans_verts(obedit, bmat[0], bmat[1], 0);
589                 if(tottrans==0) return OPERATOR_CANCELLED;
590                 
591                 Mat3CpyMat4(bmat, obedit->obmat);
592                 Mat3Inv(imat, bmat);
593                 
594                 tv= transvmain;
595                 for(a=0; a<tottrans; a++, tv++) {
596                         vec[0]= curs[0]-obedit->obmat[3][0];
597                         vec[1]= curs[1]-obedit->obmat[3][1];
598                         vec[2]= curs[2]-obedit->obmat[3][2];
599                         
600                         Mat3MulVecfl(imat, vec);
601                         VECCOPY(tv->loc, vec);
602                 }
603                 
604                 special_transvert_update(scene, obedit);
605                 
606                 MEM_freeN(transvmain);
607                 transvmain= NULL;
608                 
609         }
610         else {
611                 CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
612                         ob= base->object;
613                         if(ob->mode & OB_MODE_POSE) {
614                                 bPoseChannel *pchan;
615                                 bArmature *arm= ob->data;
616                                 float cursp[3];
617                                 
618                                 Mat4Invert(ob->imat, ob->obmat);
619                                 VECCOPY(cursp, curs);
620                                 Mat4MulVecfl(ob->imat, cursp);
621                                 
622                                 for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
623                                         if(pchan->bone->flag & BONE_SELECTED) {
624                                                 if(pchan->bone->layer & arm->layer) {
625                                                         if((pchan->bone->flag & BONE_CONNECTED)==0) { 
626                                                                 float curspn[3];
627                                                                 
628                                                                 /* get location of cursor in bone-space */
629                                                                 armature_loc_pose_to_bone(pchan, cursp, curspn);
630                                                                 
631                                                                 /* calculate new position */
632                                                                 VECCOPY(pchan->loc, curspn);
633                                                         }
634                                                         /* if the bone has a parent and is connected to the parent, 
635                                                          * don't do anything - will break chain unless we do auto-ik. 
636                                                          */
637                                                 }
638                                         }
639                                 }
640                                 ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
641                                 
642                                 /* auto-keyframing */
643 // XXX                          autokeyframe_pose_cb_func(ob, TFM_TRANSLATION, 0);
644                                 DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
645                         }
646                         else {
647                                 ob->recalc |= OB_RECALC_OB;
648                                 
649                                 vec[0]= -ob->obmat[3][0] + curs[0];
650                                 vec[1]= -ob->obmat[3][1] + curs[1];
651                                 vec[2]= -ob->obmat[3][2] + curs[2];
652                                 
653                                 if(ob->parent) {
654                                         where_is_object(scene, ob);
655                                         
656                                         Mat3Inv(imat, originmat);
657                                         Mat3MulVecfl(imat, vec);
658                                         ob->loc[0]+= vec[0];
659                                         ob->loc[1]+= vec[1];
660                                         ob->loc[2]+= vec[2];
661                                 }
662                                 else {
663                                         ob->loc[0]+= vec[0];
664                                         ob->loc[1]+= vec[1];
665                                         ob->loc[2]+= vec[2];
666                                 }
667                                 /* auto-keyframing */
668 // XXX                          autokeyframe_ob_cb_func(ob, TFM_TRANSLATION);
669                         }
670                 }
671                 CTX_DATA_END;
672         }
673         ED_anim_dag_flush_update(C);
674         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
675         
676         return OPERATOR_FINISHED;
677 }
678
679 void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot)
680 {
681         
682         /* identifiers */
683         ot->name= "Snap Selection to Cursor";
684         ot->description= "Snap selected item(s) to cursor.";
685         ot->idname= "VIEW3D_OT_snap_selected_to_cursor";
686         
687         /* api callbacks */
688         ot->exec= snap_sel_to_curs;
689         ot->poll= ED_operator_view3d_active;
690         
691         /* flags */
692         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
693 }
694
695 /* *************************************************** */
696
697 static int snap_curs_to_grid(bContext *C, wmOperator *op)
698 {
699         Scene *scene= CTX_data_scene(C);
700         View3D *v3d= CTX_wm_view3d(C);
701         float gridf, *curs;
702
703         gridf= v3d->gridview;
704         curs= give_cursor(scene, v3d);
705
706         curs[0]= v3d->gridview*floor(.5+curs[0]/gridf);
707         curs[1]= v3d->gridview*floor(.5+curs[1]/gridf);
708         curs[2]= v3d->gridview*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                 Mat3CpyMat4(bmat, obedit->obmat);
756                 
757                 tv= transvmain;
758                 for(a=0; a<tottrans; a++, tv++) {
759                         VECCOPY(vec, tv->loc);
760                         Mat3MulVecfl(bmat, vec);
761                         VecAddf(vec, vec, obedit->obmat[3]);
762                         VecAddf(centroid, centroid, vec);
763                         DO_MINMAX(vec, min, max);
764                 }
765                 
766                 if(v3d->around==V3D_CENTROID) {
767                         VecMulf(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= OBACT;
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                                                 Mat4MulVecfl(ob->obmat, vec);
789                                                 VecAddf(centroid, centroid, vec);
790                                                 DO_MINMAX(vec, min, max);
791                                                 count++;
792                                         }
793                                 }
794                         }
795                 }
796                 else {
797                         CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
798                                 VECCOPY(vec, base->object->obmat[3]);
799                                 VecAddf(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                                 VecMulf(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         Scene *scene= CTX_data_scene(C);
844         View3D *v3d= CTX_wm_view3d(C);
845         float *curs;
846         
847         curs = give_cursor(scene, v3d);
848
849         if (obedit)  {
850                 if (obedit->type == OB_MESH) {
851                         /* check active */
852                         Mesh *me= obedit->data;
853                         EditSelection ese;
854                         
855                         if (EM_get_actSelection(me->edit_mesh, &ese)) {
856                                 EM_editselection_center(curs, &ese);
857                         }
858                         
859                         Mat4MulVecfl(obedit->obmat, curs);
860                 }
861         }
862         else {
863                 if (BASACT) {
864                         VECCOPY(curs, BASACT->object->obmat[3]);
865                 }
866         }
867         
868         WM_event_add_notifier(C, NC_SCENE|ND_TRANSFORM, scene);
869         return OPERATOR_FINISHED;
870 }
871
872 void VIEW3D_OT_snap_cursor_to_active(wmOperatorType *ot)
873 {
874         
875         /* identifiers */
876         ot->name= "Snap Cursor to Active";
877         ot->description= "Snap cursor to active item.";
878         ot->idname= "VIEW3D_OT_snap_cursor_to_active";
879         
880         /* api callbacks */
881         ot->exec= snap_curs_to_active;
882         ot->poll= ED_operator_view3d_active;
883         
884         /* flags */
885         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
886 }
887
888 /* ************************************** */
889
890 static int snap_selected_to_center(bContext *C, wmOperator *op)
891 {
892         extern float originmat[3][3];   /* XXX object.c */
893         Object *obedit= CTX_data_edit_object(C);
894         Scene *scene= CTX_data_scene(C);
895         View3D *v3d= CTX_wm_view3d(C);
896         TransVert *tv;
897         Object *ob;
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                 Mat3CpyMat4(bmat, obedit->obmat);
915                 Mat3Inv(imat, bmat);
916                 
917                 tv= transvmain;
918                 for(a=0; a<tottrans; a++, tv++) {
919                         VECCOPY(vec, tv->loc);
920                         Mat3MulVecfl(bmat, vec);
921                         VecAddf(vec, vec, obedit->obmat[3]);
922                         VecAddf(centroid, centroid, vec);
923                         DO_MINMAX(vec, min, max);
924                 }
925                 
926                 if(v3d->around==V3D_CENTROID) {
927                         VecMulf(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, Base*, base, selected_editable_bases) {
942                         ob= base->object;
943                         if(ob->mode & OB_MODE_POSE) {
944                                 bPoseChannel *pchan;
945                                 bArmature *arm= ob->data;
946                                 
947                                 for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
948                                         if(pchan->bone->flag & BONE_SELECTED) {
949                                                 if(pchan->bone->layer & arm->layer) {
950                                                         VECCOPY(vec, pchan->pose_mat[3]);
951                                                         VecAddf(centroid, centroid, vec);
952                                                         DO_MINMAX(vec, min, max);
953                                                         count++;
954                                                 }
955                                         }
956                                 }
957                         }
958                         else {
959                                 /* not armature bones (i.e. objects) */
960                                 VECCOPY(vec, base->object->obmat[3]);
961                                 VecAddf(centroid, centroid, vec);
962                                 DO_MINMAX(vec, min, max);
963                                 count++;
964                         }
965                 }
966                 CTX_DATA_END;
967
968                 if(count) {
969                         if(v3d->around==V3D_CENTROID) {
970                                 VecMulf(centroid, 1.0/(float)count);
971                                 VECCOPY(snaploc, centroid);
972                         }
973                         else {
974                                 snaploc[0]= (min[0]+max[0])/2;
975                                 snaploc[1]= (min[1]+max[1])/2;
976                                 snaploc[2]= (min[2]+max[2])/2;
977                         }
978                 }
979         }
980
981         /* Snap the selection to the snaplocation (duh!) */
982         if(obedit) {
983                 tottrans= 0;
984                 
985                 if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
986                         make_trans_verts(obedit, bmat[0], bmat[1], 0);
987                 if(tottrans==0) return OPERATOR_CANCELLED;
988                 
989                 Mat3CpyMat4(bmat, obedit->obmat);
990                 Mat3Inv(imat, bmat);
991                 
992                 tv= transvmain;
993                 for(a=0; a<tottrans; a++, tv++) {
994                         vec[0]= snaploc[0]-obedit->obmat[3][0];
995                         vec[1]= snaploc[1]-obedit->obmat[3][1];
996                         vec[2]= snaploc[2]-obedit->obmat[3][2];
997                         
998                         Mat3MulVecfl(imat, vec);
999                         VECCOPY(tv->loc, vec);
1000                 }
1001                 
1002                 special_transvert_update(scene, obedit);
1003                 
1004                 MEM_freeN(transvmain);
1005                 transvmain= NULL;
1006                 
1007         }
1008         else {
1009
1010                 CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
1011                         ob= base->object;
1012                         if(ob->mode & OB_MODE_POSE) {
1013                                 bPoseChannel *pchan;
1014                                 bArmature *arm= ob->data;
1015                                 
1016                                 for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
1017                                         if(pchan->bone->flag & BONE_SELECTED) {
1018                                                 if(pchan->bone->layer & arm->layer) {
1019                                                         if((pchan->bone->flag & BONE_CONNECTED)==0) { 
1020                                                                 /* get location of cursor in bone-space */
1021                                                                 armature_loc_pose_to_bone(pchan, snaploc, vec);
1022                                                                 
1023                                                                 /* calculate new position */
1024                                                                 VECCOPY(pchan->loc, vec);
1025                                                         }
1026                                                         /* if the bone has a parent and is connected to the parent, 
1027                                                          * don't do anything - will break chain unless we do auto-ik. 
1028                                                          */
1029                                                 }
1030                                         }
1031                                 }
1032                                 
1033                                 /* auto-keyframing */
1034                                 ob->pose->flag |= POSE_DO_UNLOCK;
1035 // XXX                          autokeyframe_pose_cb_func(ob, TFM_TRANSLATION, 0);
1036                                 DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
1037                         }
1038                         else {
1039                                 ob->recalc |= OB_RECALC_OB;
1040                                 
1041                                 vec[0]= -ob->obmat[3][0] + snaploc[0];
1042                                 vec[1]= -ob->obmat[3][1] + snaploc[1];
1043                                 vec[2]= -ob->obmat[3][2] + snaploc[2];
1044                                 
1045                                 if(ob->parent) {
1046                                         where_is_object(scene, ob);
1047                                         
1048                                         Mat3Inv(imat, originmat);
1049                                         Mat3MulVecfl(imat, vec);
1050                                         ob->loc[0]+= vec[0];
1051                                         ob->loc[1]+= vec[1];
1052                                         ob->loc[2]+= vec[2];
1053                                 }
1054                                 else {
1055                                         ob->loc[0]+= vec[0];
1056                                         ob->loc[1]+= vec[1];
1057                                         ob->loc[2]+= vec[2];
1058                                 }
1059                                 /* auto-keyframing */
1060 // XXX                          autokeyframe_ob_cb_func(ob, TFM_TRANSLATION);
1061                         }
1062                 }
1063                 CTX_DATA_END;
1064         }
1065         
1066         ED_anim_dag_flush_update(C);
1067         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
1068         
1069         return OPERATOR_FINISHED;
1070 }
1071
1072 void VIEW3D_OT_snap_selected_to_center(wmOperatorType *ot)
1073 {
1074         
1075         /* identifiers */
1076         ot->name= "Snap Selection to Center";
1077         ot->description= "Snap selected items to selections geometric center.";
1078         ot->idname= "VIEW3D_OT_snap_selected_to_center";
1079         
1080         /* api callbacks */
1081         ot->exec= snap_selected_to_center;
1082         ot->poll= ED_operator_view3d_active;
1083         
1084         /* flags */
1085         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1086 }
1087
1088
1089 int minmax_verts(Object *obedit, float *min, float *max)
1090 {
1091         TransVert *tv;
1092         float centroid[3], vec[3], bmat[3][3];
1093         int a;
1094
1095         tottrans=0;
1096         if ELEM5(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE) 
1097                 make_trans_verts(obedit, bmat[0], bmat[1], 2);
1098         
1099         if(tottrans==0) return 0;
1100
1101         Mat3CpyMat4(bmat, obedit->obmat);
1102         
1103         tv= transvmain;
1104         for(a=0; a<tottrans; a++, tv++) {               
1105                 VECCOPY(vec, tv->loc);
1106                 Mat3MulVecfl(bmat, vec);
1107                 VecAddf(vec, vec, obedit->obmat[3]);
1108                 VecAddf(centroid, centroid, vec);
1109                 DO_MINMAX(vec, min, max);               
1110         }
1111         
1112         MEM_freeN(transvmain);
1113         transvmain= NULL;
1114         
1115         return 1;
1116 }
1117
1118 /* ************************************************* */
1119
1120 static int snap_menu_invoke(bContext *C, wmOperator *unused, wmEvent *event)
1121 {
1122         uiPopupMenu *pup= uiPupMenuBegin(C, "Snap", 0);
1123         uiLayout *layout= uiPupMenuLayout(pup);
1124         
1125         uiItemO(layout, "Selected to Grid", 0, "VIEW3D_OT_snap_selected_to_grid");
1126         uiItemO(layout, "Selected to Cursor", 0, "VIEW3D_OT_snap_selected_to_cursor");
1127         uiItemO(layout, "Selected to Center", 0, "VIEW3D_OT_snap_selected_to_center");
1128         uiItemS(layout);
1129         uiItemO(layout, "Cursor to Selected", 0, "VIEW3D_OT_snap_cursor_to_selected");
1130         uiItemO(layout, "Cursor to Grid", 0, "VIEW3D_OT_snap_cursor_to_grid");
1131         uiItemO(layout, "Cursor to Active", 0, "VIEW3D_OT_snap_cursor_to_active");
1132         
1133         uiPupMenuEnd(C, pup);
1134         
1135         /* this operator is only for a menu, not used further */
1136         return OPERATOR_CANCELLED;
1137 }
1138
1139 /* only used as menu */
1140 void VIEW3D_OT_snap_menu(wmOperatorType *ot)
1141 {
1142         /* identifiers */
1143         ot->name= "Snap Menu";
1144         ot->description= "Display snap menu.";
1145         ot->idname= "VIEW3D_OT_snap_menu";
1146         
1147         /* api callbacks */
1148         ot->invoke= snap_menu_invoke;
1149         
1150         ot->poll= ED_operator_view3d_active;
1151         
1152         /* flags */
1153         ot->flag= 0;
1154 }
1155
1156