Merging r42648 through r42722 from trunk into soc-2011-tomato
[blender.git] / source / blender / editors / space_view3d / view3d_snap.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/space_view3d/view3d_snap.c
29  *  \ingroup spview3d
30  */
31
32
33 #include <math.h>
34 #include <string.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "DNA_armature_types.h"
39 #include "DNA_curve_types.h"
40 #include "DNA_lattice_types.h"
41 #include "DNA_meta_types.h"
42 #include "DNA_scene_types.h"
43 #include "DNA_object_types.h"
44
45 #include "BLI_blenlib.h"
46 #include "BLI_math.h"
47 #include "BLI_editVert.h"
48 #include "BLI_linklist.h"
49 #include "BLI_utildefines.h"
50
51 #include "BKE_armature.h"
52 #include "BKE_context.h"
53 #include "BKE_curve.h"
54 #include "BKE_depsgraph.h"
55 #include "BKE_lattice.h"
56 #include "BKE_main.h"
57 #include "BKE_object.h"
58 #include "BKE_scene.h"
59 #include "BKE_tracking.h"
60
61 #include "WM_api.h"
62 #include "WM_types.h"
63
64
65
66 #include "ED_armature.h"
67 #include "ED_mesh.h"
68 #include "ED_keyframing.h"
69 #include "ED_screen.h"
70 #include "ED_curve.h" /* for curve_editnurbs */
71
72 #include "view3d_intern.h"
73
74 extern float originmat[3][3];   /* XXX object.c */
75
76 /* ************************************************** */
77 /* ********************* old transform stuff ******** */
78 /* *********** will get replaced with new transform * */
79 /* ************************************************** */
80
81 typedef struct TransVert {
82         float *loc;
83         float oldloc[3], fac;
84         float *val, oldval;
85         int flag;
86         float *nor;
87 } TransVert;
88
89 static TransVert *transvmain=NULL;
90 static int tottrans= 0;
91
92 /* copied from editobject.c, now uses (almost) proper depgraph */
93 static void special_transvert_update(Object *obedit)
94 {
95         if(obedit) {
96                 DAG_id_tag_update(obedit->data, 0);
97                 
98                 if(obedit->type==OB_MESH) {
99                         Mesh *me= obedit->data;
100                         recalc_editnormals(me->edit_mesh);      // does face centers too
101                 }
102                 else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
103                         Curve *cu= obedit->data;
104                         ListBase *nurbs= curve_editnurbs(cu);
105                         Nurb *nu= nurbs->first;
106
107                         while(nu) {
108                                 /* keep handles' vectors unchanged */
109                                 if(nu->bezt) {
110                                         int a= nu->pntsu;
111                                         TransVert *tv= transvmain;
112                                         BezTriple *bezt= nu->bezt;
113
114                                         while(a--) {
115                                                 if(bezt->f1 & SELECT) tv++;
116
117                                                 if(bezt->f2 & SELECT) {
118                                                         float v[3];
119
120                                                         if(bezt->f1 & SELECT) {
121                                                                 sub_v3_v3v3(v, (tv-1)->oldloc, tv->oldloc);
122                                                                 add_v3_v3v3(bezt->vec[0], bezt->vec[1], v);
123                                                         }
124
125                                                         if(bezt->f3 & SELECT) {
126                                                                 sub_v3_v3v3(v, (tv+1)->oldloc, tv->oldloc);
127                                                                 add_v3_v3v3(bezt->vec[2], bezt->vec[1], v);
128                                                         }
129
130                                                         tv++;
131                                                 }
132
133                                                 if(bezt->f3 & SELECT) tv++;
134
135                                                 bezt++;
136                                         }
137                                 }
138
139                                 test2DNurb(nu);
140                                 testhandlesNurb(nu); /* test for bezier too */
141                                 nu= nu->next;
142                         }
143                 }
144                 else if(obedit->type==OB_ARMATURE){
145                         bArmature *arm= obedit->data;
146                         EditBone *ebo;
147                         TransVert *tv= transvmain;
148                         int a=0;
149                         
150                         /* Ensure all bone tails are correctly adjusted */
151                         for (ebo= arm->edbo->first; ebo; ebo=ebo->next) {
152                                 /* adjust tip if both ends selected */
153                                 if ((ebo->flag & BONE_ROOTSEL) && (ebo->flag & BONE_TIPSEL)) {
154                                         if (tv) {
155                                                 float diffvec[3];
156                                                 
157                                                 sub_v3_v3v3(diffvec, tv->loc, tv->oldloc);
158                                                 add_v3_v3(ebo->tail, diffvec);
159                                                 
160                                                 a++;
161                                                 if (a<tottrans) tv++;
162                                         }
163                                 }
164                         }
165                         
166                         /* Ensure all bones are correctly adjusted */
167                         for (ebo= arm->edbo->first; ebo; ebo=ebo->next) {
168                                 if ((ebo->flag & BONE_CONNECTED) && ebo->parent){
169                                         /* If this bone has a parent tip that has been moved */
170                                         if (ebo->parent->flag & BONE_TIPSEL){
171                                                 copy_v3_v3(ebo->head, ebo->parent->tail);
172                                         }
173                                         /* If this bone has a parent tip that has NOT been moved */
174                                         else{
175                                                 copy_v3_v3(ebo->parent->tail, ebo->head);
176                                         }
177                                 }
178                         }
179                         if(arm->flag & ARM_MIRROR_EDIT)
180                                 transform_armature_mirror_update(obedit);
181                 }
182                 else if(obedit->type==OB_LATTICE) {
183                         Lattice *lt= obedit->data;
184                         
185                         if(lt->editlatt->latt->flag & LT_OUTSIDE)
186                                 outside_lattice(lt->editlatt->latt);
187                 }
188         }
189 }
190
191 /* copied from editobject.c, needs to be replaced with new transform code still */
192 /* mode flags: */
193 #define TM_ALL_JOINTS           1 /* all joints (for bones only) */
194 #define TM_SKIP_HANDLES         2 /* skip handles when control point is selected (for curves only) */
195 static void make_trans_verts(Object *obedit, float *min, float *max, int mode)
196 {
197         Nurb *nu;
198         BezTriple *bezt;
199         BPoint *bp;
200         TransVert *tv=NULL;
201         MetaElem *ml;
202         EditVert *eve;
203         EditBone        *ebo;
204         float total, center[3], centroid[3];
205         int a;
206
207         tottrans= 0; // global!
208         
209         INIT_MINMAX(min, max);
210         centroid[0]=centroid[1]=centroid[2]= 0.0;
211         
212         if(obedit->type==OB_MESH) {
213                 Mesh *me= obedit->data;
214                 EditMesh *em= me->edit_mesh;
215                 
216                 // transform now requires awareness for select mode, so we tag the f1 flags in verts
217                 tottrans= 0;
218                 if(em->selectmode & SCE_SELECT_VERTEX) {
219                         for(eve= em->verts.first; eve; eve= eve->next) {
220                                 if(eve->h==0 && (eve->f & SELECT)) {
221                                         eve->f1= SELECT;
222                                         tottrans++;
223                                 }
224                                 else eve->f1= 0;
225                         }
226                 }
227                 else if(em->selectmode & SCE_SELECT_EDGE) {
228                         EditEdge *eed;
229                         for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
230                         for(eed= em->edges.first; eed; eed= eed->next) {
231                                 if(eed->h==0 && (eed->f & SELECT)) eed->v1->f1= eed->v2->f1= SELECT;
232                         }
233                         for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++;
234                 }
235                 else {
236                         EditFace *efa;
237                         for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
238                         for(efa= em->faces.first; efa; efa= efa->next) {
239                                 if(efa->h==0 && (efa->f & SELECT)) {
240                                         efa->v1->f1= efa->v2->f1= efa->v3->f1= SELECT;
241                                         if(efa->v4) efa->v4->f1= SELECT;
242                                 }
243                         }
244                         for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++;
245                 }
246                 
247                 /* and now make transverts */
248                 if(tottrans) {
249                         tv=transvmain= MEM_callocN(tottrans*sizeof(TransVert), "maketransverts");
250
251                         for(eve= em->verts.first; eve; eve= eve->next) {
252                                 if(eve->f1) {
253                                         copy_v3_v3(tv->oldloc, eve->co);
254                                         tv->loc= eve->co;
255                                         if(eve->no[0] != 0.0f || eve->no[1] != 0.0f ||eve->no[2] != 0.0f)
256                                                 tv->nor= eve->no; // note this is a hackish signal (ton)
257                                         tv->flag= eve->f1 & SELECT;
258                                         tv++;
259                                 }
260                         }
261                 }
262         }
263         else if (obedit->type==OB_ARMATURE){
264                 bArmature *arm= obedit->data;
265                 int totmalloc= BLI_countlist(arm->edbo);
266
267                 totmalloc *= 2;  /* probably overkill but bones can have 2 trans verts each */
268
269                 tv=transvmain= MEM_callocN(totmalloc*sizeof(TransVert), "maketransverts armature");
270                 
271                 for (ebo= arm->edbo->first; ebo; ebo=ebo->next){
272                         if(ebo->layer & arm->layer) {
273                                 short tipsel= (ebo->flag & BONE_TIPSEL);
274                                 short rootsel= (ebo->flag & BONE_ROOTSEL);
275                                 short rootok= (!(ebo->parent && (ebo->flag & BONE_CONNECTED) && ebo->parent->flag & BONE_TIPSEL));
276                                 
277                                 if ((tipsel && rootsel) || (rootsel)) {
278                                         /* Don't add the tip (unless mode & TM_ALL_JOINTS, for getting all joints),
279                                          * otherwise we get zero-length bones as tips will snap to the same
280                                          * location as heads.
281                                          */
282                                         if (rootok) {
283                                                 copy_v3_v3(tv->oldloc, ebo->head);
284                                                 tv->loc= ebo->head;
285                                                 tv->nor= NULL;
286                                                 tv->flag= 1;
287                                                 tv++;
288                                                 tottrans++;
289                                         }       
290                                         
291                                         if ((mode & TM_ALL_JOINTS) && (tipsel)) {
292                                                 copy_v3_v3(tv->oldloc, ebo->tail);
293                                                 tv->loc= ebo->tail;
294                                                 tv->nor= NULL;
295                                                 tv->flag= 1;
296                                                 tv++;
297                                                 tottrans++;
298                                         }
299                                 }
300                                 else if (tipsel) {
301                                         copy_v3_v3(tv->oldloc, ebo->tail);
302                                         tv->loc= ebo->tail;
303                                         tv->nor= NULL;
304                                         tv->flag= 1;
305                                         tv++;
306                                         tottrans++;
307                                 }
308                         }
309                 }
310         }
311         else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
312                 Curve *cu= obedit->data;
313                 int totmalloc= 0;
314                 ListBase *nurbs= curve_editnurbs(cu);
315
316                 for(nu= nurbs->first; nu; nu= nu->next) {
317                         if(nu->type == CU_BEZIER)
318                                 totmalloc += 3*nu->pntsu;
319                         else
320                                 totmalloc += nu->pntsu*nu->pntsv;
321                 }
322                 tv=transvmain= MEM_callocN(totmalloc*sizeof(TransVert), "maketransverts curve");
323
324                 nu= nurbs->first;
325                 while(nu) {
326                         if(nu->type == CU_BEZIER) {
327                                 a= nu->pntsu;
328                                 bezt= nu->bezt;
329                                 while(a--) {
330                                         if(bezt->hide==0) {
331                                                 int skip_handle= 0;
332                                                 if(bezt->f2 & SELECT)
333                                                         skip_handle= mode & TM_SKIP_HANDLES;
334
335                                                 if((bezt->f1 & SELECT) && !skip_handle) {
336                                                         copy_v3_v3(tv->oldloc, bezt->vec[0]);
337                                                         tv->loc= bezt->vec[0];
338                                                         tv->flag= bezt->f1 & SELECT;
339                                                         tv++;
340                                                         tottrans++;
341                                                 }
342                                                 if(bezt->f2 & SELECT) {
343                                                         copy_v3_v3(tv->oldloc, bezt->vec[1]);
344                                                         tv->loc= bezt->vec[1];
345                                                         tv->val= &(bezt->alfa);
346                                                         tv->oldval= bezt->alfa;
347                                                         tv->flag= bezt->f2 & SELECT;
348                                                         tv++;
349                                                         tottrans++;
350                                                 }
351                                                 if((bezt->f3 & SELECT) && !skip_handle) {
352                                                         copy_v3_v3(tv->oldloc, bezt->vec[2]);
353                                                         tv->loc= bezt->vec[2];
354                                                         tv->flag= bezt->f3 & SELECT;
355                                                         tv++;
356                                                         tottrans++;
357                                                 }
358                                         }
359                                         bezt++;
360                                 }
361                         }
362                         else {
363                                 a= nu->pntsu*nu->pntsv;
364                                 bp= nu->bp;
365                                 while(a--) {
366                                         if(bp->hide==0) {
367                                                 if(bp->f1 & SELECT) {
368                                                         copy_v3_v3(tv->oldloc, bp->vec);
369                                                         tv->loc= bp->vec;
370                                                         tv->val= &(bp->alfa);
371                                                         tv->oldval= bp->alfa;
372                                                         tv->flag= bp->f1 & SELECT;
373                                                         tv++;
374                                                         tottrans++;
375                                                 }
376                                         }
377                                         bp++;
378                                 }
379                         }
380                         nu= nu->next;
381                 }
382         }
383         else if(obedit->type==OB_MBALL) {
384                 MetaBall *mb= obedit->data;
385                 int totmalloc= BLI_countlist(mb->editelems);
386                 
387                 tv=transvmain= MEM_callocN(totmalloc*sizeof(TransVert), "maketransverts mball");
388                 
389                 ml= mb->editelems->first;
390                 while(ml) {
391                         if(ml->flag & SELECT) {
392                                 tv->loc= &ml->x;
393                                 copy_v3_v3(tv->oldloc, tv->loc);
394                                 tv->val= &(ml->rad);
395                                 tv->oldval= ml->rad;
396                                 tv->flag= 1;
397                                 tv++;
398                                 tottrans++;
399                         }
400                         ml= ml->next;
401                 }
402         }
403         else if(obedit->type==OB_LATTICE) {
404                 Lattice *lt= obedit->data;
405                 
406                 bp= lt->editlatt->latt->def;
407                 
408                 a= lt->editlatt->latt->pntsu*lt->editlatt->latt->pntsv*lt->editlatt->latt->pntsw;
409                 
410                 tv=transvmain= MEM_callocN(a*sizeof(TransVert), "maketransverts latt");
411                 
412                 while(a--) {
413                         if(bp->f1 & SELECT) {
414                                 if(bp->hide==0) {
415                                         copy_v3_v3(tv->oldloc, bp->vec);
416                                         tv->loc= bp->vec;
417                                         tv->flag= bp->f1 & SELECT;
418                                         tv++;
419                                         tottrans++;
420                                 }
421                         }
422                         bp++;
423                 }
424         }
425         
426         if(!tottrans && transvmain) {
427                 /* prevent memory leak. happens for curves/latticies due to */
428                 /* difficult condition of adding points to trans data */
429                 MEM_freeN(transvmain);
430                 transvmain= NULL;
431         }
432
433         /* cent etc */
434         tv= transvmain;
435         total= 0.0;
436         for(a=0; a<tottrans; a++, tv++) {
437                 if(tv->flag & SELECT) {
438                         add_v3_v3(centroid, tv->oldloc);
439                         total += 1.0f;
440                         DO_MINMAX(tv->oldloc, min, max);
441                 }
442         }
443         if(total != 0.0f) {
444                 mul_v3_fl(centroid, 1.0f/total);
445         }
446
447         mid_v3_v3v3(center, min, max);
448 }
449
450 /* *********************** operators ******************** */
451
452 static int snap_sel_to_grid(bContext *C, wmOperator *UNUSED(op))
453 {
454         Main *bmain= CTX_data_main(C);
455         Object *obedit= CTX_data_edit_object(C);
456         Scene *scene= CTX_data_scene(C);
457         RegionView3D *rv3d= CTX_wm_region_data(C);
458         TransVert *tv;
459         float gridf, imat[3][3], bmat[3][3], vec[3];
460         int a;
461
462         gridf= rv3d->gridview;
463
464         if(obedit) {
465                 tottrans= 0;
466                 
467                 if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL)
468                         make_trans_verts(obedit, bmat[0], bmat[1], 0);
469                 if(tottrans==0) return OPERATOR_CANCELLED;
470                 
471                 copy_m3_m4(bmat, obedit->obmat);
472                 invert_m3_m3(imat, bmat);
473                 
474                 tv= transvmain;
475                 for(a=0; a<tottrans; a++, tv++) {
476                         copy_v3_v3(vec, tv->loc);
477                         mul_m3_v3(bmat, vec);
478                         add_v3_v3(vec, obedit->obmat[3]);
479                         vec[0]= gridf*floorf(0.5f+ vec[0]/gridf);
480                         vec[1]= gridf*floorf(0.5f+ vec[1]/gridf);
481                         vec[2]= gridf*floorf(0.5f+ vec[2]/gridf);
482                         sub_v3_v3(vec, obedit->obmat[3]);
483                         
484                         mul_m3_v3(imat, vec);
485                         copy_v3_v3(tv->loc, vec);
486                 }
487                 
488                 special_transvert_update(obedit);
489                 
490                 MEM_freeN(transvmain);
491                 transvmain= NULL;
492         }
493         else {
494                 struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
495
496                 CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
497                         if(ob->mode & OB_MODE_POSE) {
498                                 bPoseChannel *pchan;
499                                 bArmature *arm= ob->data;
500                                 
501                                 invert_m4_m4(ob->imat, ob->obmat);
502                                 
503                                 for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
504                                         if(pchan->bone->flag & BONE_SELECTED) {
505                                                 if(pchan->bone->layer & arm->layer) {
506                                                         if((pchan->bone->flag & BONE_CONNECTED)==0) {
507                                                                 float nLoc[3];
508                                                                 float inv_restmat[4][4];
509                                                                 
510                                                                 /* get nearest grid point to snap to */
511                                                                 copy_v3_v3(nLoc, pchan->pose_mat[3]);
512                                                                 /* We must operate in world space! */
513                                                                 mul_m4_v3(ob->obmat, nLoc);
514                                                                 vec[0]= gridf * (float)(floor(0.5f+ nLoc[0]/gridf));
515                                                                 vec[1]= gridf * (float)(floor(0.5f+ nLoc[1]/gridf));
516                                                                 vec[2]= gridf * (float)(floor(0.5f+ nLoc[2]/gridf));
517                                                                 /* Back in object space... */
518                                                                 mul_m4_v3(ob->imat, vec);
519                                                                 
520                                                                 /* get location of grid point in *rest* bone-space */
521                                                                 invert_m4_m4(inv_restmat, pchan->bone->arm_mat);
522                                                                 mul_m4_v3(inv_restmat, vec);
523                                                                 
524                                                                 /* adjust location */
525                                                                 if ((pchan->protectflag & OB_LOCK_LOCX)==0)
526                                                                         pchan->loc[0]= vec[0];
527                                                                 if ((pchan->protectflag & OB_LOCK_LOCY)==0)
528                                                                         pchan->loc[1]= vec[1];
529                                                                 if ((pchan->protectflag & OB_LOCK_LOCZ)==0)
530                                                                         pchan->loc[2]= vec[2];
531
532                                                                 /* auto-keyframing */
533                                                                 ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
534                                                         }
535                                                         /* if the bone has a parent and is connected to the parent,
536                                                          * don't do anything - will break chain unless we do auto-ik.
537                                                          */
538                                                 }
539                                         }
540                                 }
541                                 ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
542                                 
543                                 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
544                         }
545                         else {
546                                 ob->recalc |= OB_RECALC_OB;
547                                 
548                                 vec[0]= -ob->obmat[3][0]+gridf*floorf(0.5f+ ob->obmat[3][0]/gridf);
549                                 vec[1]= -ob->obmat[3][1]+gridf*floorf(0.5f+ ob->obmat[3][1]/gridf);
550                                 vec[2]= -ob->obmat[3][2]+gridf*floorf(0.5f+ ob->obmat[3][2]/gridf);
551                                 
552                                 if(ob->parent) {
553                                         where_is_object(scene, ob);
554                                         
555                                         invert_m3_m3(imat, originmat);
556                                         mul_m3_v3(imat, vec);
557                                 }
558                                 if ((ob->protectflag & OB_LOCK_LOCX)==0)
559                                         ob->loc[0]+= vec[0];
560                                 if ((ob->protectflag & OB_LOCK_LOCY)==0)
561                                         ob->loc[1]+= vec[1];
562                                 if ((ob->protectflag & OB_LOCK_LOCZ)==0)
563                                         ob->loc[2]+= vec[2];
564                                 
565                                 /* auto-keyframing */
566                                 ED_autokeyframe_object(C, scene, ob, ks);
567                         }
568                 }
569                 CTX_DATA_END;
570         }
571
572         DAG_ids_flush_update(bmain, 0);
573         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
574         
575         return OPERATOR_FINISHED;
576 }
577
578 void VIEW3D_OT_snap_selected_to_grid(wmOperatorType *ot)
579 {
580         /* identifiers */
581         ot->name= "Snap Selection to Grid";
582         ot->description= "Snap selected item(s) to nearest grid node";
583         ot->idname= "VIEW3D_OT_snap_selected_to_grid";
584         
585         /* api callbacks */
586         ot->exec= snap_sel_to_grid;
587         ot->poll= ED_operator_region_view3d_active;
588         
589         /* flags */
590         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
591 }
592
593 /* *************************************************** */
594
595 static int snap_sel_to_curs(bContext *C, wmOperator *UNUSED(op))
596 {
597         Main *bmain= CTX_data_main(C);
598         Object *obedit= CTX_data_edit_object(C);
599         Scene *scene= CTX_data_scene(C);
600         View3D *v3d= CTX_wm_view3d(C);
601         TransVert *tv;
602         float *curs, imat[3][3], bmat[3][3], vec[3];
603         int a;
604
605         curs= give_cursor(scene, v3d);
606
607         if(obedit) {
608                 tottrans= 0;
609                 
610                 if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL)
611                         make_trans_verts(obedit, bmat[0], bmat[1], 0);
612                 if(tottrans==0) return OPERATOR_CANCELLED;
613                 
614                 copy_m3_m4(bmat, obedit->obmat);
615                 invert_m3_m3(imat, bmat);
616                 
617                 tv= transvmain;
618                 for(a=0; a<tottrans; a++, tv++) {
619                         sub_v3_v3v3(vec, curs, obedit->obmat[3]);
620                         mul_m3_v3(imat, vec);
621                         copy_v3_v3(tv->loc, vec);
622                 }
623                 
624                 special_transvert_update(obedit);
625                 
626                 MEM_freeN(transvmain);
627                 transvmain= NULL;
628         }
629         else {
630                 struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
631
632                 CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
633                         if(ob->mode & OB_MODE_POSE) {
634                                 bPoseChannel *pchan;
635                                 bArmature *arm= ob->data;
636                                 
637                                 invert_m4_m4(ob->imat, ob->obmat);
638                                 copy_v3_v3(vec, curs);
639                                 mul_m4_v3(ob->imat, vec);
640                                 
641                                 for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
642                                         if(pchan->bone->flag & BONE_SELECTED) {
643                                                 if(pchan->bone->layer & arm->layer) {
644                                                         if((pchan->bone->flag & BONE_CONNECTED)==0) {
645                                                                 float inv_restmat[4][4];
646                                                                 
647                                                                 /* get location of cursor in *rest* bone-space */
648                                                                 invert_m4_m4(inv_restmat, pchan->bone->arm_mat);
649                                                                 mul_m4_v3(inv_restmat, vec);
650                                                                 
651                                                                 /* copy new position */
652                                                                 if ((pchan->protectflag & OB_LOCK_LOCX)==0)
653                                                                         pchan->loc[0]= vec[0];
654                                                                 if ((pchan->protectflag & OB_LOCK_LOCY)==0)
655                                                                         pchan->loc[1]= vec[1];
656                                                                 if ((pchan->protectflag & OB_LOCK_LOCZ)==0)
657                                                                         pchan->loc[2]= vec[2];
658
659                                                                 /* auto-keyframing */
660                                                                 ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
661                                                         }
662                                                         /* if the bone has a parent and is connected to the parent,
663                                                          * don't do anything - will break chain unless we do auto-ik.
664                                                          */
665                                                 }
666                                         }
667                                 }
668                                 ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
669                                 
670                                 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
671                         }
672                         else {
673                                 ob->recalc |= OB_RECALC_OB;
674                                 
675                                 vec[0]= -ob->obmat[3][0] + curs[0];
676                                 vec[1]= -ob->obmat[3][1] + curs[1];
677                                 vec[2]= -ob->obmat[3][2] + curs[2];
678                                 
679                                 if(ob->parent) {
680                                         where_is_object(scene, ob);
681                                         
682                                         invert_m3_m3(imat, originmat);
683                                         mul_m3_v3(imat, vec);
684                                 }
685                                 if ((ob->protectflag & OB_LOCK_LOCX)==0)
686                                         ob->loc[0]+= vec[0];
687                                 if ((ob->protectflag & OB_LOCK_LOCY)==0)
688                                         ob->loc[1]+= vec[1];
689                                 if ((ob->protectflag & OB_LOCK_LOCZ)==0)
690                                         ob->loc[2]+= vec[2];
691
692                                 /* auto-keyframing */
693                                 ED_autokeyframe_object(C, scene, ob, ks);
694                         }
695                 }
696                 CTX_DATA_END;
697         }
698
699         DAG_ids_flush_update(bmain, 0);
700         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
701         
702         return OPERATOR_FINISHED;
703 }
704
705 void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot)
706 {
707         /* identifiers */
708         ot->name= "Snap Selection to Cursor";
709         ot->description= "Snap selected item(s) to cursor";
710         ot->idname= "VIEW3D_OT_snap_selected_to_cursor";
711         
712         /* api callbacks */
713         ot->exec= snap_sel_to_curs;
714         ot->poll= ED_operator_view3d_active;
715         
716         /* flags */
717         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
718 }
719
720 /* *************************************************** */
721
722 static int snap_curs_to_grid(bContext *C, wmOperator *UNUSED(op))
723 {
724         Scene *scene= CTX_data_scene(C);
725         RegionView3D *rv3d= CTX_wm_region_data(C);
726         View3D *v3d= CTX_wm_view3d(C);
727         float gridf, *curs;
728
729         gridf= rv3d->gridview;
730         curs= give_cursor(scene, v3d);
731
732         curs[0]= gridf*floorf(0.5f+curs[0]/gridf);
733         curs[1]= gridf*floorf(0.5f+curs[1]/gridf);
734         curs[2]= gridf*floorf(0.5f+curs[2]/gridf);
735         
736         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);        // hrm
737         
738         return OPERATOR_FINISHED;
739 }
740
741 void VIEW3D_OT_snap_cursor_to_grid(wmOperatorType *ot)
742 {
743         /* identifiers */
744         ot->name= "Snap Cursor to Grid";
745         ot->description= "Snap cursor to nearest grid node";
746         ot->idname= "VIEW3D_OT_snap_cursor_to_grid";
747         
748         /* api callbacks */
749         ot->exec= snap_curs_to_grid;
750         ot->poll= ED_operator_region_view3d_active;
751         
752         /* flags */
753         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
754 }
755
756 /* **************************************************** */
757
758 static void bundle_midpoint(Scene *scene, Object *ob, float vec[3])
759 {
760         MovieClip *clip= object_get_movieclip(scene, ob, 0);
761         MovieTracking *tracking= &clip->tracking;
762         MovieTrackingObject *object= tracking->objects.first;
763         int ok= 0;
764         float min[3], max[3], mat[4][4], pos[3], cammat[4][4];
765
766         if(!clip)
767                 return;
768
769         unit_m4(cammat);
770
771         if(!scene->camera)
772                 scene->camera= scene_find_camera(scene);
773
774         if(scene->camera)
775                 copy_m4_m4(cammat, scene->camera->obmat);
776
777         BKE_get_tracking_mat(scene, ob, mat);
778
779         INIT_MINMAX(min, max);
780
781         while(object) {
782                 ListBase *tracksbase= BKE_tracking_object_tracks(tracking, object);
783                 MovieTrackingTrack *track= tracksbase->first;
784                 float obmat[4][4];
785
786                 if(object->flag & TRACKING_OBJECT_CAMERA) {
787                         copy_m4_m4(obmat, mat);
788                 }
789                 else {
790                         float imat[4][4];
791
792                         BKE_tracking_get_interpolated_camera(tracking, object, scene->r.cfra, imat);
793                         invert_m4(imat);
794
795                         mult_m4_m4m4(obmat, cammat, imat);
796                 }
797
798                 while(track) {
799                         if((track->flag&TRACK_HAS_BUNDLE) && TRACK_SELECTED(track)) {
800                                 ok= 1;
801                                 mul_v3_m4v3(pos, obmat, track->bundle_pos);
802                                 DO_MINMAX(pos, min, max);
803                         }
804
805                         track= track->next;
806                 }
807
808                 object= object->next;
809         }
810
811         if(ok) {
812                 mid_v3_v3v3(vec, min, max);
813         }
814 }
815
816 static int snap_curs_to_sel(bContext *C, wmOperator *UNUSED(op))
817 {
818         Object *obedit= CTX_data_edit_object(C);
819         Scene *scene= CTX_data_scene(C);
820         View3D *v3d= CTX_wm_view3d(C);
821         TransVert *tv;
822         float *curs, bmat[3][3], vec[3], min[3], max[3], centroid[3];
823         int count, a;
824
825         curs= give_cursor(scene, v3d);
826
827         count= 0;
828         INIT_MINMAX(min, max);
829         centroid[0]= centroid[1]= centroid[2]= 0.0;
830
831         if(obedit) {
832                 tottrans=0;
833                 
834                 if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL)
835                         make_trans_verts(obedit, bmat[0], bmat[1], TM_ALL_JOINTS|TM_SKIP_HANDLES);
836                 if(tottrans==0) return OPERATOR_CANCELLED;
837                 
838                 copy_m3_m4(bmat, obedit->obmat);
839                 
840                 tv= transvmain;
841                 for(a=0; a<tottrans; a++, tv++) {
842                         copy_v3_v3(vec, tv->loc);
843                         mul_m3_v3(bmat, vec);
844                         add_v3_v3(vec, obedit->obmat[3]);
845                         add_v3_v3(centroid, vec);
846                         DO_MINMAX(vec, min, max);
847                 }
848                 
849                 if(v3d->around==V3D_CENTROID) {
850                         mul_v3_fl(centroid, 1.0f/(float)tottrans);
851                         copy_v3_v3(curs, centroid);
852                 }
853                 else {
854                         mid_v3_v3v3(curs, min, max);
855                 }
856                 MEM_freeN(transvmain);
857                 transvmain= NULL;
858         }
859         else {
860                 Object *obact= CTX_data_active_object(C);
861                 
862                 if(obact && (obact->mode & OB_MODE_POSE)) {
863                         bArmature *arm= obact->data;
864                         bPoseChannel *pchan;
865                         for (pchan = obact->pose->chanbase.first; pchan; pchan=pchan->next) {
866                                 if(arm->layer & pchan->bone->layer) {
867                                         if(pchan->bone->flag & BONE_SELECTED) {
868                                                 copy_v3_v3(vec, pchan->pose_head);
869                                                 mul_m4_v3(obact->obmat, vec);
870                                                 add_v3_v3(centroid, vec);
871                                                 DO_MINMAX(vec, min, max);
872                                                 count++;
873                                         }
874                                 }
875                         }
876                 }
877                 else {
878                         CTX_DATA_BEGIN(C, Object*, ob, selected_objects) {
879                                 copy_v3_v3(vec, ob->obmat[3]);
880
881                                 /* special case for camera -- snap to bundles */
882                                 if(ob->type==OB_CAMERA) {
883                                         /* snap to bundles should happen only when bundles are visible */
884                                         if(v3d->flag2&V3D_SHOW_RECONSTRUCTION) {
885                                                 bundle_midpoint(scene, ob, vec);
886                                         }
887                                 }
888
889                                 add_v3_v3(centroid, vec);
890                                 DO_MINMAX(vec, min, max);
891                                 count++;
892                         }
893                         CTX_DATA_END;
894                 }
895                 if(count) {
896                         if(v3d->around==V3D_CENTROID) {
897                                 mul_v3_fl(centroid, 1.0f/(float)count);
898                                 copy_v3_v3(curs, centroid);
899                         }
900                         else {
901                                 mid_v3_v3v3(curs, min, max);
902                         }
903                 }
904         }
905         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
906         
907         return OPERATOR_FINISHED;
908 }
909
910 void VIEW3D_OT_snap_cursor_to_selected(wmOperatorType *ot)
911 {
912         /* identifiers */
913         ot->name= "Snap Cursor to Selected";
914         ot->description= "Snap cursor to center of selected item(s)";
915         ot->idname= "VIEW3D_OT_snap_cursor_to_selected";
916         
917         /* api callbacks */
918         ot->exec= snap_curs_to_sel;
919         ot->poll= ED_operator_view3d_active;
920         
921         /* flags */
922         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
923 }
924
925 /* ********************************************** */
926
927 static int snap_curs_to_active(bContext *C, wmOperator *UNUSED(op))
928 {
929         Object *obedit= CTX_data_edit_object(C);
930         Object *obact= CTX_data_active_object(C);
931         Scene *scene= CTX_data_scene(C);
932         View3D *v3d= CTX_wm_view3d(C);
933         float *curs;
934         
935         curs = give_cursor(scene, v3d);
936
937         if (obedit)  {
938                 if (obedit->type == OB_MESH) {
939                         /* check active */
940                         Mesh *me= obedit->data;
941                         EditSelection ese;
942                         
943                         if (EM_get_actSelection(me->edit_mesh, &ese)) {
944                                 EM_editselection_center(curs, &ese);
945                         }
946                         
947                         mul_m4_v3(obedit->obmat, curs);
948                 }
949         }
950         else {
951                 if (obact) {
952                         copy_v3_v3(curs, obact->obmat[3]);
953                 }
954         }
955         
956         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
957         return OPERATOR_FINISHED;
958 }
959
960 void VIEW3D_OT_snap_cursor_to_active(wmOperatorType *ot)
961 {
962         /* identifiers */
963         ot->name= "Snap Cursor to Active";
964         ot->description= "Snap cursor to active item";
965         ot->idname= "VIEW3D_OT_snap_cursor_to_active";
966         
967         /* api callbacks */
968         ot->exec= snap_curs_to_active;
969         ot->poll= ED_operator_view3d_active;
970         
971         /* flags */
972         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
973 }
974
975 /* **************************************************** */
976 /*New Code - Snap Cursor to Center -*/
977 static int snap_curs_to_center(bContext *C, wmOperator *UNUSED(op))
978 {
979         Scene *scene= CTX_data_scene(C);
980         View3D *v3d= CTX_wm_view3d(C);
981         float *curs;
982         curs= give_cursor(scene, v3d);
983
984         curs[0]= 0.0;
985         curs[1]= 0.0;
986         curs[2]= 0.0;
987         
988         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
989         
990         return OPERATOR_FINISHED;
991 }
992
993 void VIEW3D_OT_snap_cursor_to_center(wmOperatorType *ot)
994 {
995         /* identifiers */
996         ot->name= "Snap Cursor to Center";
997         ot->description= "Snap cursor to the Center";
998         ot->idname= "VIEW3D_OT_snap_cursor_to_center";
999         
1000         /* api callbacks */
1001         ot->exec= snap_curs_to_center;
1002         ot->poll= ED_operator_view3d_active;
1003         
1004         /* flags */
1005         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1006 }
1007
1008 /* **************************************************** */
1009
1010
1011 int minmax_verts(Object *obedit, float *min, float *max)
1012 {
1013         TransVert *tv;
1014         float centroid[3], vec[3], bmat[3][3];
1015         int a;
1016
1017         tottrans=0;
1018         if ELEM5(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE)
1019                 make_trans_verts(obedit, bmat[0], bmat[1], TM_ALL_JOINTS);
1020         
1021         if(tottrans==0) return 0;
1022
1023         copy_m3_m4(bmat, obedit->obmat);
1024         
1025         tv= transvmain;
1026         for(a=0; a<tottrans; a++, tv++) {
1027                 copy_v3_v3(vec, tv->loc);
1028                 mul_m3_v3(bmat, vec);
1029                 add_v3_v3(vec, obedit->obmat[3]);
1030                 add_v3_v3(centroid, vec);
1031                 DO_MINMAX(vec, min, max);
1032         }
1033         
1034         MEM_freeN(transvmain);
1035         transvmain= NULL;
1036         
1037         return 1;
1038 }
1039