fba8d13c6a5408b0850b896eeec0c69c7e2b3cc5
[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_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_object_flush_update(scene, obedit, 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 & 7)==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 & 7)==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->flag & OB_POSEMODE) {
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_object_flush_update(scene, ob, 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->idname= "VIEW3D_OT_snap_selected_to_grid";
559         
560         /* api callbacks */
561         ot->exec= snap_sel_to_grid;
562         ot->poll= ED_operator_view3d_active;
563         
564         /* flags */
565         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
566 }
567
568 /* *************************************************** */
569
570 static int snap_sel_to_curs(bContext *C, wmOperator *op)
571 {
572         extern float originmat[3][3];   /* XXX object.c */
573         Object *obedit= CTX_data_edit_object(C);
574         Scene *scene= CTX_data_scene(C);
575         View3D *v3d= CTX_wm_view3d(C);
576         TransVert *tv;
577         Object *ob;
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                 Mat3CpyMat4(bmat, obedit->obmat);
591                 Mat3Inv(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                         Mat3MulVecfl(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, Base*, base, selected_editable_bases) {
611                         ob= base->object;
612                         if(ob->flag & OB_POSEMODE) {
613                                 bPoseChannel *pchan;
614                                 bArmature *arm= ob->data;
615                                 float cursp[3];
616                                 
617                                 Mat4Invert(ob->imat, ob->obmat);
618                                 VECCOPY(cursp, curs);
619                                 Mat4MulVecfl(ob->imat, cursp);
620                                 
621                                 for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
622                                         if(pchan->bone->flag & BONE_SELECTED) {
623                                                 if(pchan->bone->layer & arm->layer) {
624                                                         if((pchan->bone->flag & BONE_CONNECTED)==0) { 
625                                                                 float curspn[3];
626                                                                 
627                                                                 /* get location of cursor in bone-space */
628                                                                 armature_loc_pose_to_bone(pchan, cursp, curspn);
629                                                                 
630                                                                 /* calculate new position */
631                                                                 VECCOPY(pchan->loc, curspn);
632                                                         }
633                                                         /* if the bone has a parent and is connected to the parent, 
634                                                          * don't do anything - will break chain unless we do auto-ik. 
635                                                          */
636                                                 }
637                                         }
638                                 }
639                                 ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
640                                 
641                                 /* auto-keyframing */
642 // XXX                          autokeyframe_pose_cb_func(ob, TFM_TRANSLATION, 0);
643                                 DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
644                         }
645                         else {
646                                 ob->recalc |= OB_RECALC_OB;
647                                 
648                                 vec[0]= -ob->obmat[3][0] + curs[0];
649                                 vec[1]= -ob->obmat[3][1] + curs[1];
650                                 vec[2]= -ob->obmat[3][2] + curs[2];
651                                 
652                                 if(ob->parent) {
653                                         where_is_object(scene, ob);
654                                         
655                                         Mat3Inv(imat, originmat);
656                                         Mat3MulVecfl(imat, vec);
657                                         ob->loc[0]+= vec[0];
658                                         ob->loc[1]+= vec[1];
659                                         ob->loc[2]+= vec[2];
660                                 }
661                                 else {
662                                         ob->loc[0]+= vec[0];
663                                         ob->loc[1]+= vec[1];
664                                         ob->loc[2]+= vec[2];
665                                 }
666                                 /* auto-keyframing */
667 // XXX                          autokeyframe_ob_cb_func(ob, TFM_TRANSLATION);
668                         }
669                 }
670                 CTX_DATA_END;
671         }
672         ED_anim_dag_flush_update(C);
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->idname= "VIEW3D_OT_snap_selected_to_cursor";
684         
685         /* api callbacks */
686         ot->exec= snap_sel_to_curs;
687         ot->poll= ED_operator_view3d_active;
688         
689         /* flags */
690         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
691 }
692
693 /* *************************************************** */
694
695 static int snap_curs_to_grid(bContext *C, wmOperator *op)
696 {
697         Scene *scene= CTX_data_scene(C);
698         View3D *v3d= CTX_wm_view3d(C);
699         float gridf, *curs;
700
701         gridf= v3d->gridview;
702         curs= give_cursor(scene, v3d);
703
704         curs[0]= v3d->gridview*floor(.5+curs[0]/gridf);
705         curs[1]= v3d->gridview*floor(.5+curs[1]/gridf);
706         curs[2]= v3d->gridview*floor(.5+curs[2]/gridf);
707         
708         WM_event_add_notifier(C, NC_SCENE|ND_TRANSFORM, scene); // hrm
709         
710         return OPERATOR_FINISHED;
711 }
712
713 void VIEW3D_OT_snap_cursor_to_grid(wmOperatorType *ot)
714 {
715         
716         /* identifiers */
717         ot->name= "Snap Cursor to Grid";
718         ot->idname= "VIEW3D_OT_snap_cursor_to_grid";
719         
720         /* api callbacks */
721         ot->exec= snap_curs_to_grid;
722         ot->poll= ED_operator_view3d_active;
723         
724         /* flags */
725         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
726 }
727
728 /* **************************************************** */
729
730 static int snap_curs_to_sel(bContext *C, wmOperator *op)
731 {
732         Object *obedit= CTX_data_edit_object(C);
733         Scene *scene= CTX_data_scene(C);
734         View3D *v3d= CTX_wm_view3d(C);
735         TransVert *tv;
736         float *curs, bmat[3][3], vec[3], min[3], max[3], centroid[3];
737         int count, a;
738
739         curs= give_cursor(scene, v3d);
740
741         count= 0;
742         INIT_MINMAX(min, max);
743         centroid[0]= centroid[1]= centroid[2]= 0.0;
744
745         if(obedit) {
746                 tottrans=0;
747                 
748                 if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
749                         make_trans_verts(obedit, bmat[0], bmat[1], 2);
750                 if(tottrans==0) return OPERATOR_CANCELLED;
751                 
752                 Mat3CpyMat4(bmat, obedit->obmat);
753                 
754                 tv= transvmain;
755                 for(a=0; a<tottrans; a++, tv++) {
756                         VECCOPY(vec, tv->loc);
757                         Mat3MulVecfl(bmat, vec);
758                         VecAddf(vec, vec, obedit->obmat[3]);
759                         VecAddf(centroid, centroid, vec);
760                         DO_MINMAX(vec, min, max);
761                 }
762                 
763                 if(v3d->around==V3D_CENTROID) {
764                         VecMulf(centroid, 1.0/(float)tottrans);
765                         VECCOPY(curs, centroid);
766                 }
767                 else {
768                         curs[0]= (min[0]+max[0])/2;
769                         curs[1]= (min[1]+max[1])/2;
770                         curs[2]= (min[2]+max[2])/2;
771                 }
772                 MEM_freeN(transvmain);
773                 transvmain= NULL;
774         }
775         else {
776                 Object *ob= OBACT;
777                 
778                 if(ob && (ob->flag & OB_POSEMODE)) {
779                         bArmature *arm= ob->data;
780                         bPoseChannel *pchan;
781                         for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
782                                 if(arm->layer & pchan->bone->layer) {
783                                         if(pchan->bone->flag & BONE_SELECTED) {
784                                                 VECCOPY(vec, pchan->pose_head);
785                                                 Mat4MulVecfl(ob->obmat, vec);
786                                                 VecAddf(centroid, centroid, vec);
787                                                 DO_MINMAX(vec, min, max);
788                                                 count++;
789                                         }
790                                 }
791                         }
792                 }
793                 else {
794                         CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
795                                 VECCOPY(vec, base->object->obmat[3]);
796                                 VecAddf(centroid, centroid, vec);
797                                 DO_MINMAX(vec, min, max);
798                                 count++;
799                         }
800                         CTX_DATA_END;
801                 }
802                 if(count) {
803                         if(v3d->around==V3D_CENTROID) {
804                                 VecMulf(centroid, 1.0/(float)count);
805                                 VECCOPY(curs, centroid);
806                         }
807                         else {
808                                 curs[0]= (min[0]+max[0])/2;
809                                 curs[1]= (min[1]+max[1])/2;
810                                 curs[2]= (min[2]+max[2])/2;
811                         }
812                 }
813         }
814         WM_event_add_notifier(C, NC_SCENE|ND_TRANSFORM, scene); // hrm
815         
816         return OPERATOR_FINISHED;
817 }
818
819 void VIEW3D_OT_snap_cursor_to_selected(wmOperatorType *ot)
820 {
821         
822         /* identifiers */
823         ot->name= "Snap Cursor to Selected";
824         ot->idname= "VIEW3D_OT_snap_cursor_to_selected";
825         
826         /* api callbacks */
827         ot->exec= snap_curs_to_sel;
828         ot->poll= ED_operator_view3d_active;
829         
830         /* flags */
831         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
832 }
833
834 /* ********************************************** */
835
836 static int snap_curs_to_active(bContext *C, wmOperator *op)
837 {
838         Object *obedit= CTX_data_edit_object(C);
839         Scene *scene= CTX_data_scene(C);
840         View3D *v3d= CTX_wm_view3d(C);
841         float *curs;
842         
843         curs = give_cursor(scene, v3d);
844
845         if (obedit)  {
846                 if (obedit->type == OB_MESH) {
847                         /* check active */
848                         Mesh *me= obedit->data;
849                         EditSelection ese;
850                         
851                         if (EM_get_actSelection(me->edit_mesh, &ese)) {
852                                 EM_editselection_center(curs, &ese);
853                         }
854                         
855                         Mat4MulVecfl(obedit->obmat, curs);
856                 }
857         }
858         else {
859                 if (BASACT) {
860                         VECCOPY(curs, BASACT->object->obmat[3]);
861                 }
862         }
863         
864         WM_event_add_notifier(C, NC_SCENE|ND_TRANSFORM, scene);
865         return OPERATOR_FINISHED;
866 }
867
868 void VIEW3D_OT_snap_cursor_to_active(wmOperatorType *ot)
869 {
870         
871         /* identifiers */
872         ot->name= "Snap Cursor to Active";
873         ot->idname= "VIEW3D_OT_snap_cursor_to_active";
874         
875         /* api callbacks */
876         ot->exec= snap_curs_to_active;
877         ot->poll= ED_operator_view3d_active;
878         
879         /* flags */
880         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
881 }
882
883 /* ************************************** */
884
885 static int snap_selected_to_center(bContext *C, wmOperator *op)
886 {
887         extern float originmat[3][3];   /* XXX object.c */
888         Object *obedit= CTX_data_edit_object(C);
889         Scene *scene= CTX_data_scene(C);
890         View3D *v3d= CTX_wm_view3d(C);
891         TransVert *tv;
892         Object *ob;
893         float snaploc[3], imat[3][3], bmat[3][3], vec[3], min[3], max[3], centroid[3];
894         int count, a;
895
896         /*calculate the snaplocation (centerpoint) */
897         count= 0;
898         INIT_MINMAX(min, max);
899         centroid[0]= centroid[1]= centroid[2]= 0.0f;
900         snaploc[0]= snaploc[1]= snaploc[2]= 0.0f;
901
902         if(obedit) {
903                 tottrans= 0;
904                 
905                 if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
906                         make_trans_verts(obedit, bmat[0], bmat[1], 0);
907                 if(tottrans==0) return OPERATOR_CANCELLED;
908                 
909                 Mat3CpyMat4(bmat, obedit->obmat);
910                 Mat3Inv(imat, bmat);
911                 
912                 tv= transvmain;
913                 for(a=0; a<tottrans; a++, tv++) {
914                         VECCOPY(vec, tv->loc);
915                         Mat3MulVecfl(bmat, vec);
916                         VecAddf(vec, vec, obedit->obmat[3]);
917                         VecAddf(centroid, centroid, vec);
918                         DO_MINMAX(vec, min, max);
919                 }
920                 
921                 if(v3d->around==V3D_CENTROID) {
922                         VecMulf(centroid, 1.0/(float)tottrans);
923                         VECCOPY(snaploc, centroid);
924                 }
925                 else {
926                         snaploc[0]= (min[0]+max[0])/2;
927                         snaploc[1]= (min[1]+max[1])/2;
928                         snaploc[2]= (min[2]+max[2])/2;
929                 }
930                 
931                 MEM_freeN(transvmain);
932                 transvmain= NULL;
933         }
934         else {
935                 
936                 CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
937                         ob= base->object;
938                         if(ob->flag & OB_POSEMODE) {
939                                 bPoseChannel *pchan;
940                                 bArmature *arm= ob->data;
941                                 
942                                 for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
943                                         if(pchan->bone->flag & BONE_SELECTED) {
944                                                 if(pchan->bone->layer & arm->layer) {
945                                                         VECCOPY(vec, pchan->pose_mat[3]);
946                                                         VecAddf(centroid, centroid, vec);
947                                                         DO_MINMAX(vec, min, max);
948                                                         count++;
949                                                 }
950                                         }
951                                 }
952                         }
953                         else {
954                                 /* not armature bones (i.e. objects) */
955                                 VECCOPY(vec, base->object->obmat[3]);
956                                 VecAddf(centroid, centroid, vec);
957                                 DO_MINMAX(vec, min, max);
958                                 count++;
959                         }
960                 }
961                 CTX_DATA_END;
962
963                 if(count) {
964                         if(v3d->around==V3D_CENTROID) {
965                                 VecMulf(centroid, 1.0/(float)count);
966                                 VECCOPY(snaploc, centroid);
967                         }
968                         else {
969                                 snaploc[0]= (min[0]+max[0])/2;
970                                 snaploc[1]= (min[1]+max[1])/2;
971                                 snaploc[2]= (min[2]+max[2])/2;
972                         }
973                 }
974         }
975
976         /* Snap the selection to the snaplocation (duh!) */
977         if(obedit) {
978                 tottrans= 0;
979                 
980                 if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
981                         make_trans_verts(obedit, bmat[0], bmat[1], 0);
982                 if(tottrans==0) return OPERATOR_CANCELLED;
983                 
984                 Mat3CpyMat4(bmat, obedit->obmat);
985                 Mat3Inv(imat, bmat);
986                 
987                 tv= transvmain;
988                 for(a=0; a<tottrans; a++, tv++) {
989                         vec[0]= snaploc[0]-obedit->obmat[3][0];
990                         vec[1]= snaploc[1]-obedit->obmat[3][1];
991                         vec[2]= snaploc[2]-obedit->obmat[3][2];
992                         
993                         Mat3MulVecfl(imat, vec);
994                         VECCOPY(tv->loc, vec);
995                 }
996                 
997                 special_transvert_update(scene, obedit);
998                 
999                 MEM_freeN(transvmain);
1000                 transvmain= NULL;
1001                 
1002         }
1003         else {
1004
1005                 CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
1006                         ob= base->object;
1007                         if(ob->flag & OB_POSEMODE) {
1008                                 bPoseChannel *pchan;
1009                                 bArmature *arm= ob->data;
1010                                 
1011                                 for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
1012                                         if(pchan->bone->flag & BONE_SELECTED) {
1013                                                 if(pchan->bone->layer & arm->layer) {
1014                                                         if((pchan->bone->flag & BONE_CONNECTED)==0) { 
1015                                                                 /* get location of cursor in bone-space */
1016                                                                 armature_loc_pose_to_bone(pchan, snaploc, vec);
1017                                                                 
1018                                                                 /* calculate new position */
1019                                                                 VECCOPY(pchan->loc, vec);
1020                                                         }
1021                                                         /* if the bone has a parent and is connected to the parent, 
1022                                                          * don't do anything - will break chain unless we do auto-ik. 
1023                                                          */
1024                                                 }
1025                                         }
1026                                 }
1027                                 
1028                                 /* auto-keyframing */
1029                                 ob->pose->flag |= POSE_DO_UNLOCK;
1030 // XXX                          autokeyframe_pose_cb_func(ob, TFM_TRANSLATION, 0);
1031                                 DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
1032                         }
1033                         else {
1034                                 ob->recalc |= OB_RECALC_OB;
1035                                 
1036                                 vec[0]= -ob->obmat[3][0] + snaploc[0];
1037                                 vec[1]= -ob->obmat[3][1] + snaploc[1];
1038                                 vec[2]= -ob->obmat[3][2] + snaploc[2];
1039                                 
1040                                 if(ob->parent) {
1041                                         where_is_object(scene, ob);
1042                                         
1043                                         Mat3Inv(imat, originmat);
1044                                         Mat3MulVecfl(imat, vec);
1045                                         ob->loc[0]+= vec[0];
1046                                         ob->loc[1]+= vec[1];
1047                                         ob->loc[2]+= vec[2];
1048                                 }
1049                                 else {
1050                                         ob->loc[0]+= vec[0];
1051                                         ob->loc[1]+= vec[1];
1052                                         ob->loc[2]+= vec[2];
1053                                 }
1054                                 /* auto-keyframing */
1055 // XXX                          autokeyframe_ob_cb_func(ob, TFM_TRANSLATION);
1056                         }
1057                 }
1058                 CTX_DATA_END;
1059         }
1060         
1061         ED_anim_dag_flush_update(C);
1062         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
1063         
1064         return OPERATOR_FINISHED;
1065 }
1066
1067 void VIEW3D_OT_snap_selected_to_center(wmOperatorType *ot)
1068 {
1069         
1070         /* identifiers */
1071         ot->name= "Snap Selection to Center";
1072         ot->idname= "VIEW3D_OT_snap_selected_to_center";
1073         
1074         /* api callbacks */
1075         ot->exec= snap_selected_to_center;
1076         ot->poll= ED_operator_view3d_active;
1077         
1078         /* flags */
1079         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1080 }
1081
1082
1083 int minmax_verts(Object *obedit, float *min, float *max)
1084 {
1085         TransVert *tv;
1086         float centroid[3], vec[3], bmat[3][3];
1087         int a;
1088
1089         tottrans=0;
1090         if ELEM5(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE) 
1091                 make_trans_verts(obedit, bmat[0], bmat[1], 2);
1092         
1093         if(tottrans==0) return 0;
1094
1095         Mat3CpyMat4(bmat, obedit->obmat);
1096         
1097         tv= transvmain;
1098         for(a=0; a<tottrans; a++, tv++) {               
1099                 VECCOPY(vec, tv->loc);
1100                 Mat3MulVecfl(bmat, vec);
1101                 VecAddf(vec, vec, obedit->obmat[3]);
1102                 VecAddf(centroid, centroid, vec);
1103                 DO_MINMAX(vec, min, max);               
1104         }
1105         
1106         MEM_freeN(transvmain);
1107         transvmain= NULL;
1108         
1109         return 1;
1110 }
1111
1112 /* ************************************************* */
1113
1114 static int snap_menu_invoke(bContext *C, wmOperator *unused, wmEvent *event)
1115 {
1116         uiPopupMenu *pup= uiPupMenuBegin(C, "Snap", 0);
1117         uiLayout *layout= uiPupMenuLayout(pup);
1118         
1119         uiItemO(layout, NULL, 0, "VIEW3D_OT_snap_selected_to_grid");
1120         uiItemO(layout, NULL, 0, "VIEW3D_OT_snap_selected_to_cursor");
1121         uiItemO(layout, NULL, 0, "VIEW3D_OT_snap_selected_to_center");
1122         uiItemS(layout);
1123         uiItemO(layout, NULL, 0, "VIEW3D_OT_snap_cursor_to_selected");
1124         uiItemO(layout, NULL, 0, "VIEW3D_OT_snap_cursor_to_grid");
1125         uiItemO(layout, NULL, 0, "VIEW3D_OT_snap_cursor_to_active");
1126         
1127         uiPupMenuEnd(C, pup);
1128         
1129         /* this operator is only for a menu, not used further */
1130         return OPERATOR_CANCELLED;
1131 }
1132
1133 /* only used as menu */
1134 void VIEW3D_OT_snap_menu(wmOperatorType *ot)
1135 {
1136         /* identifiers */
1137         ot->name= "Snap Menu";
1138         ot->idname= "VIEW3D_OT_snap_menu";
1139         
1140         /* api callbacks */
1141         ot->invoke= snap_menu_invoke;
1142         
1143         ot->poll= ED_operator_view3d_active;
1144         
1145         /* flags */
1146         ot->flag= 0;
1147 }
1148
1149