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