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