fix [#28850] With "Auto-keyframe" on, the "Selection to Cursor" option doesn't create...
[blender.git] / source / blender / editors / object / object_transform.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * Contributor(s): Blender Foundation, 2002-2008 full recode
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/object/object_transform.c
29  *  \ingroup edobj
30  */
31
32
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "DNA_anim_types.h"
37 #include "DNA_armature_types.h"
38 #include "DNA_key_types.h"
39 #include "DNA_meshdata_types.h"
40 #include "DNA_object_types.h"
41 #include "DNA_scene_types.h"
42 #include "DNA_group_types.h"
43
44 #include "BLI_math.h"
45 #include "BLI_editVert.h"
46 #include "BLI_listbase.h"
47 #include "BLI_utildefines.h"
48
49 #include "BKE_context.h"
50 #include "BKE_curve.h"
51 #include "BKE_depsgraph.h"
52 #include "BKE_main.h"
53 #include "BKE_mesh.h"
54 #include "BKE_object.h"
55 #include "BKE_report.h"
56 #include "BKE_multires.h"
57 #include "BKE_armature.h"
58
59 #include "RNA_define.h"
60 #include "RNA_access.h"
61
62 #include "WM_api.h"
63 #include "WM_types.h"
64
65 #include "ED_armature.h"
66 #include "ED_keyframing.h"
67 #include "ED_mesh.h"
68 #include "ED_screen.h"
69 #include "ED_view3d.h"
70
71 #include "object_intern.h"
72
73 /*************************** Clear Transformation ****************************/
74
75 /* clear location of object */
76 static void object_clear_loc(Object *ob)
77 {
78         /* clear location if not locked */
79         if ((ob->protectflag & OB_LOCK_LOCX)==0)
80                 ob->loc[0]= ob->dloc[0]= 0.0f;
81         if ((ob->protectflag & OB_LOCK_LOCY)==0)
82                 ob->loc[1]= ob->dloc[1]= 0.0f;
83         if ((ob->protectflag & OB_LOCK_LOCZ)==0)
84                 ob->loc[2]= ob->dloc[2]= 0.0f;
85 }
86
87 /* clear rotation of object */
88 static void object_clear_rot(Object *ob)
89 {
90         /* clear rotations that aren't locked */
91         if (ob->protectflag & (OB_LOCK_ROTX|OB_LOCK_ROTY|OB_LOCK_ROTZ|OB_LOCK_ROTW)) {
92                 if (ob->protectflag & OB_LOCK_ROT4D) {
93                         /* perform clamping on a component by component basis */
94                         if (ob->rotmode == ROT_MODE_AXISANGLE) {
95                                 if ((ob->protectflag & OB_LOCK_ROTW) == 0)
96                                         ob->rotAngle= ob->drotAngle= 0.0f;
97                                 if ((ob->protectflag & OB_LOCK_ROTX) == 0)
98                                         ob->rotAxis[0]= ob->drotAxis[0]= 0.0f;
99                                 if ((ob->protectflag & OB_LOCK_ROTY) == 0)
100                                         ob->rotAxis[1]= ob->drotAxis[1]= 0.0f;
101                                 if ((ob->protectflag & OB_LOCK_ROTZ) == 0)
102                                         ob->rotAxis[2]= ob->drotAxis[2]= 0.0f;
103                                         
104                                 /* check validity of axis - axis should never be 0,0,0 (if so, then we make it rotate about y) */
105                                 if (IS_EQF(ob->rotAxis[0], ob->rotAxis[1]) && IS_EQF(ob->rotAxis[1], ob->rotAxis[2]))
106                                         ob->rotAxis[1] = 1.0f;
107                                 if (IS_EQF(ob->drotAxis[0], ob->drotAxis[1]) && IS_EQF(ob->drotAxis[1], ob->drotAxis[2]))
108                                         ob->drotAxis[1]= 1.0f;
109                         }
110                         else if (ob->rotmode == ROT_MODE_QUAT) {
111                                 if ((ob->protectflag & OB_LOCK_ROTW) == 0)
112                                         ob->quat[0]= ob->dquat[0]= 1.0f;
113                                 if ((ob->protectflag & OB_LOCK_ROTX) == 0)
114                                         ob->quat[1]= ob->dquat[1]= 0.0f;
115                                 if ((ob->protectflag & OB_LOCK_ROTY) == 0)
116                                         ob->quat[2]= ob->dquat[2]= 0.0f;
117                                 if ((ob->protectflag & OB_LOCK_ROTZ) == 0)
118                                         ob->quat[3]= ob->dquat[3]= 0.0f;
119                                         
120                                 // TODO: does this quat need normalising now?
121                         }
122                         else {
123                                 /* the flag may have been set for the other modes, so just ignore the extra flag... */
124                                 if ((ob->protectflag & OB_LOCK_ROTX) == 0)
125                                         ob->rot[0]= ob->drot[0]= 0.0f;
126                                 if ((ob->protectflag & OB_LOCK_ROTY) == 0)
127                                         ob->rot[1]= ob->drot[1]= 0.0f;
128                                 if ((ob->protectflag & OB_LOCK_ROTZ) == 0)
129                                         ob->rot[2]= ob->drot[2]= 0.0f;
130                         }
131                 }
132                 else {
133                         /* perform clamping using euler form (3-components) */
134                         // FIXME: deltas are not handled for these cases yet...
135                         float eul[3], oldeul[3], quat1[4] = {0};
136                         
137                         if (ob->rotmode == ROT_MODE_QUAT) {
138                                 QUATCOPY(quat1, ob->quat);
139                                 quat_to_eul(oldeul, ob->quat);
140                         }
141                         else if (ob->rotmode == ROT_MODE_AXISANGLE) {
142                                 axis_angle_to_eulO(oldeul, EULER_ORDER_DEFAULT, ob->rotAxis, ob->rotAngle);
143                         }
144                         else {
145                                 copy_v3_v3(oldeul, ob->rot);
146                         }
147                         
148                         eul[0]= eul[1]= eul[2]= 0.0f;
149                         
150                         if (ob->protectflag & OB_LOCK_ROTX)
151                                 eul[0]= oldeul[0];
152                         if (ob->protectflag & OB_LOCK_ROTY)
153                                 eul[1]= oldeul[1];
154                         if (ob->protectflag & OB_LOCK_ROTZ)
155                                 eul[2]= oldeul[2];
156                         
157                         if (ob->rotmode == ROT_MODE_QUAT) {
158                                 eul_to_quat(ob->quat, eul);
159                                 /* quaternions flip w sign to accumulate rotations correctly */
160                                 if ((quat1[0]<0.0f && ob->quat[0]>0.0f) || (quat1[0]>0.0f && ob->quat[0]<0.0f)) {
161                                         mul_qt_fl(ob->quat, -1.0f);
162                                 }
163                         }
164                         else if (ob->rotmode == ROT_MODE_AXISANGLE) {
165                                 eulO_to_axis_angle(ob->rotAxis, &ob->rotAngle,eul, EULER_ORDER_DEFAULT);
166                         }
167                         else {
168                                 copy_v3_v3(ob->rot, eul);
169                         }
170                 }
171         }                                                // Duplicated in source/blender/editors/armature/editarmature.c
172         else { 
173                 if (ob->rotmode == ROT_MODE_QUAT) {
174                         unit_qt(ob->quat);
175                         unit_qt(ob->dquat);
176                 }
177                 else if (ob->rotmode == ROT_MODE_AXISANGLE) {
178                         unit_axis_angle(ob->rotAxis, &ob->rotAngle);
179                         unit_axis_angle(ob->drotAxis, &ob->drotAngle);
180                 }
181                 else {
182                         zero_v3(ob->rot);
183                         zero_v3(ob->drot);
184                 }
185         }
186 }
187
188 /* clear scale of object */
189 static void object_clear_scale(Object *ob)
190 {
191         /* clear scale factors which are not locked */
192         if ((ob->protectflag & OB_LOCK_SCALEX)==0) {
193                 ob->dsize[0]= 0.0f;
194                 ob->size[0]= 1.0f;
195         }
196         if ((ob->protectflag & OB_LOCK_SCALEY)==0) {
197                 ob->dsize[1]= 0.0f;
198                 ob->size[1]= 1.0f;
199         }
200         if ((ob->protectflag & OB_LOCK_SCALEZ)==0) {
201                 ob->dsize[2]= 0.0f;
202                 ob->size[2]= 1.0f;
203         }
204 }
205
206 /* --------------- */
207
208 /* generic exec for clear-transform operators */
209 static int object_clear_transform_generic_exec(bContext *C, wmOperator *op, 
210                 void (*clear_func)(Object*), const char default_ksName[])
211 {
212         Main *bmain = CTX_data_main(C);
213         Scene *scene= CTX_data_scene(C);
214         KeyingSet *ks;
215         
216         /* sanity checks */
217         if ELEM(NULL, clear_func, default_ksName) {
218                 BKE_report(op->reports, RPT_ERROR, "Programming error: missing clear transform func or Keying Set Name");
219                 return OPERATOR_CANCELLED;
220         }
221         
222         /* get KeyingSet to use */
223         ks = ANIM_get_keyingset_for_autokeying(scene, default_ksName);
224         
225         /* operate on selected objects only if they aren't in weight-paint mode 
226          * (so that object-transform clearing won't be applied at same time as bone-clearing)
227          */
228         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) 
229         {
230                 if (!(ob->mode & OB_MODE_WEIGHT_PAINT)) {
231                         /* run provided clearing function */
232                         clear_func(ob);
233
234                         ED_autokeyframe_object(C, scene, ob, ks);
235
236                         /* tag for updates */
237                         DAG_id_tag_update(&ob->id, OB_RECALC_OB);
238                 }
239         }
240         CTX_DATA_END;
241         
242         /* this is needed so children are also updated */
243         DAG_ids_flush_update(bmain, 0);
244
245         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
246
247         return OPERATOR_FINISHED;
248 }
249
250 /* --------------- */
251
252
253 static int object_location_clear_exec(bContext *C, wmOperator *op)
254 {
255         return object_clear_transform_generic_exec(C, op, object_clear_loc, "Location");
256 }
257
258 void OBJECT_OT_location_clear(wmOperatorType *ot)
259 {
260         /* identifiers */
261         ot->name= "Clear Location";
262         ot->description = "Clear the object's location";
263         ot->idname= "OBJECT_OT_location_clear";
264         
265         /* api callbacks */
266         ot->exec= object_location_clear_exec;
267         ot->poll= ED_operator_scene_editable;
268         
269         /* flags */
270         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
271 }
272
273 static int object_rotation_clear_exec(bContext *C, wmOperator *op)
274 {
275         return object_clear_transform_generic_exec(C, op, object_clear_rot, "Rotation");
276 }
277
278 void OBJECT_OT_rotation_clear(wmOperatorType *ot)
279 {
280         /* identifiers */
281         ot->name= "Clear Rotation";
282         ot->description = "Clear the object's rotation";
283         ot->idname= "OBJECT_OT_rotation_clear";
284         
285         /* api callbacks */
286         ot->exec= object_rotation_clear_exec;
287         ot->poll= ED_operator_scene_editable;
288         
289         /* flags */
290         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
291 }
292
293 static int object_scale_clear_exec(bContext *C, wmOperator *op)
294 {
295         return object_clear_transform_generic_exec(C, op, object_clear_scale, "Scaling");
296 }
297
298 void OBJECT_OT_scale_clear(wmOperatorType *ot)
299 {
300         /* identifiers */
301         ot->name= "Clear Scale";
302         ot->description = "Clear the object's scale";
303         ot->idname= "OBJECT_OT_scale_clear";
304         
305         /* api callbacks */
306         ot->exec= object_scale_clear_exec;
307         ot->poll= ED_operator_scene_editable;
308         
309         /* flags */
310         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
311 }
312
313 /* --------------- */
314
315 static int object_origin_clear_exec(bContext *C, wmOperator *UNUSED(op))
316 {
317         Main *bmain= CTX_data_main(C);
318         float *v1, *v3;
319         float mat[3][3];
320
321         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) 
322         {
323                 if (ob->parent) {
324                         /* vectors pointed to by v1 and v3 will get modified */
325                         v1= ob->loc;
326                         v3= ob->parentinv[3];
327                         
328                         copy_m3_m4(mat, ob->parentinv);
329                         negate_v3_v3(v3, v1);
330                         mul_m3_v3(mat, v3);
331                 }
332
333                 DAG_id_tag_update(&ob->id, OB_RECALC_OB);
334         }
335         CTX_DATA_END;
336
337         DAG_ids_flush_update(bmain, 0);
338         
339         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
340         
341         return OPERATOR_FINISHED;
342 }
343
344 void OBJECT_OT_origin_clear(wmOperatorType *ot)
345 {
346         /* identifiers */
347         ot->name= "Clear Origin";
348         ot->description = "Clear the object's origin";
349         ot->idname= "OBJECT_OT_origin_clear";
350         
351         /* api callbacks */
352         ot->exec= object_origin_clear_exec;
353         ot->poll= ED_operator_scene_editable;
354         
355         /* flags */
356         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
357 }
358
359 /*************************** Apply Transformation ****************************/
360
361 /* use this when the loc/size/rot of the parent has changed but the children
362  * should stay in the same place, e.g. for apply-size-rot or object center */
363 static void ignore_parent_tx(Main *bmain, Scene *scene, Object *ob ) 
364 {
365         Object workob;
366         Object *ob_child;
367         
368         /* a change was made, adjust the children to compensate */
369         for(ob_child=bmain->object.first; ob_child; ob_child=ob_child->id.next) {
370                 if(ob_child->parent == ob) {
371                         object_apply_mat4(ob_child, ob_child->obmat, TRUE, FALSE);
372                         what_does_parent(scene, ob_child, &workob);
373                         invert_m4_m4(ob_child->parentinv, workob.obmat);
374                 }
375         }
376 }
377
378 static int apply_objects_internal(bContext *C, ReportList *reports, int apply_loc, int apply_rot, int apply_scale)
379 {
380         Main *bmain= CTX_data_main(C);
381         Scene *scene= CTX_data_scene(C);
382         float rsmat[3][3], tmat[3][3], obmat[3][3], iobmat[3][3], mat[4][4], scale;
383         int a, change = 0;
384         
385         /* first check if we can execute */
386         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
387
388                 if(ob->type==OB_MESH) {
389                         if(ID_REAL_USERS(ob->data) > 1) {
390                                 BKE_report(reports, RPT_ERROR, "Can't apply to a multi user mesh, doing nothing");
391                                 return OPERATOR_CANCELLED;
392                         }
393                 }
394                 else if(ob->type==OB_ARMATURE) {
395                         if(ID_REAL_USERS(ob->data) > 1) {
396                                 BKE_report(reports, RPT_ERROR, "Can't apply to a multi user armature, doing nothing");
397                                 return OPERATOR_CANCELLED;
398                         }
399                 }
400                 else if(ELEM(ob->type, OB_CURVE, OB_SURF)) {
401                         Curve *cu;
402
403                         if(ID_REAL_USERS(ob->data) > 1) {
404                                 BKE_report(reports, RPT_ERROR, "Can't apply to a multi user curve, doing nothing");
405                                 return OPERATOR_CANCELLED;
406                         }
407
408                         cu= ob->data;
409
410                         if(!(cu->flag & CU_3D) && (apply_rot || apply_loc)) {
411                                 BKE_report(reports, RPT_ERROR, "Neither rotation nor location could be applied to a 2d curve, doing nothing");
412                                 return OPERATOR_CANCELLED;
413                         }
414                         if(cu->key) {
415                                 BKE_report(reports, RPT_ERROR, "Can't apply to a curve with vertex keys, doing nothing");
416                                 return OPERATOR_CANCELLED;
417                         }
418                 }
419         }
420         CTX_DATA_END;
421         
422         /* now execute */
423         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
424
425                 /* calculate rotation/scale matrix */
426                 if(apply_scale && apply_rot)
427                         object_to_mat3(ob, rsmat);
428                 else if(apply_scale)
429                         object_scale_to_mat3(ob, rsmat);
430                 else if(apply_rot) {
431                         float tmat[3][3], timat[3][3];
432
433                         /* simple rotation matrix */
434                         object_rot_to_mat3(ob, rsmat);
435
436                         /* correct for scale, note mul_m3_m3m3 has swapped args! */
437                         object_scale_to_mat3(ob, tmat);
438                         invert_m3_m3(timat, tmat);
439                         mul_m3_m3m3(rsmat, timat, rsmat);
440                         mul_m3_m3m3(rsmat, rsmat, tmat);
441                 }
442                 else
443                         unit_m3(rsmat);
444
445                 copy_m4_m3(mat, rsmat);
446
447                 /* calculate translation */
448                 if(apply_loc) {
449                         copy_v3_v3(mat[3], ob->loc);
450
451                         if(!(apply_scale && apply_rot)) {
452                                 /* correct for scale and rotation that is still applied */
453                                 object_to_mat3(ob, obmat);
454                                 invert_m3_m3(iobmat, obmat);
455                                 mul_m3_m3m3(tmat, rsmat, iobmat);
456                                 mul_m3_v3(tmat, mat[3]);
457                         }
458                 }
459
460                 /* apply to object data */
461                 if(ob->type==OB_MESH) {
462                         Mesh *me= ob->data;
463                         MVert *mvert;
464
465                         multiresModifier_scale_disp(scene, ob);
466                         
467                         /* adjust data */
468                         mvert= me->mvert;
469                         for(a=0; a<me->totvert; a++, mvert++)
470                                 mul_m4_v3(mat, mvert->co);
471                         
472                         if(me->key) {
473                                 KeyBlock *kb;
474                                 
475                                 for(kb=me->key->block.first; kb; kb=kb->next) {
476                                         float *fp= kb->data;
477                                         
478                                         for(a=0; a<kb->totelem; a++, fp+=3)
479                                                 mul_m4_v3(mat, fp);
480                                 }
481                         }
482                         
483                         /* update normals */
484                         mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
485                 }
486                 else if (ob->type==OB_ARMATURE) {
487                         ED_armature_apply_transform(ob, mat);
488                 }
489                 else if(ELEM(ob->type, OB_CURVE, OB_SURF)) {
490                         Curve *cu= ob->data;
491
492                         Nurb *nu;
493                         BPoint *bp;
494                         BezTriple *bezt;
495
496                         scale = mat3_to_scale(rsmat);
497
498                         for(nu=cu->nurb.first; nu; nu=nu->next) {
499                                 if(nu->type == CU_BEZIER) {
500                                         a= nu->pntsu;
501                                         for(bezt= nu->bezt; a--; bezt++) {
502                                                 mul_m4_v3(mat, bezt->vec[0]);
503                                                 mul_m4_v3(mat, bezt->vec[1]);
504                                                 mul_m4_v3(mat, bezt->vec[2]);
505                                                 bezt->radius *= scale;
506                                         }
507                                         calchandlesNurb(nu);
508                                 }
509                                 else {
510                                         a= nu->pntsu*nu->pntsv;
511                                         for(bp= nu->bp; a--; bp++)
512                                                 mul_m4_v3(mat, bp->vec);
513                                 }
514                         }
515                 }
516                 else
517                         continue;
518
519                 if(apply_loc)
520                         zero_v3(ob->loc);
521                 if(apply_scale)
522                         ob->size[0]= ob->size[1]= ob->size[2]= 1.0f;
523                 if(apply_rot) {
524                         zero_v3(ob->rot);
525                         unit_qt(ob->quat);
526                         unit_axis_angle(ob->rotAxis, &ob->rotAngle);
527                 }
528
529                 where_is_object(scene, ob);
530                 if(ob->type==OB_ARMATURE) {
531                         where_is_pose(scene, ob); /* needed for bone parents */
532                 }
533
534                 ignore_parent_tx(bmain, scene, ob);
535
536                 DAG_id_tag_update(&ob->id, OB_RECALC_OB|OB_RECALC_DATA);
537
538                 change = 1;
539         }
540         CTX_DATA_END;
541
542         if(!change)
543                 return OPERATOR_CANCELLED;
544
545         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
546         return OPERATOR_FINISHED;
547 }
548
549 static int visual_transform_apply_exec(bContext *C, wmOperator *UNUSED(op))
550 {
551         Scene *scene= CTX_data_scene(C);
552         int change = 0;
553         
554         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
555                 where_is_object(scene, ob);
556                 object_apply_mat4(ob, ob->obmat, TRUE, TRUE);
557                 where_is_object(scene, ob);
558
559                 /* update for any children that may get moved */
560                 DAG_id_tag_update(&ob->id, OB_RECALC_OB);
561         
562                 change = 1;
563         }
564         CTX_DATA_END;
565
566         if(!change)
567                 return OPERATOR_CANCELLED;
568
569         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
570         return OPERATOR_FINISHED;
571 }
572
573 void OBJECT_OT_visual_transform_apply(wmOperatorType *ot)
574 {
575         /* identifiers */
576         ot->name= "Apply Visual Transform";
577         ot->description = "Apply the object's visual transformation to its data";
578         ot->idname= "OBJECT_OT_visual_transform_apply";
579         
580         /* api callbacks */
581         ot->exec= visual_transform_apply_exec;
582         ot->poll= ED_operator_scene_editable;
583         
584         /* flags */
585         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
586 }
587
588 static int object_transform_apply_exec(bContext *C, wmOperator *op)
589 {
590         const int loc= RNA_boolean_get(op->ptr, "location");
591         const int rot= RNA_boolean_get(op->ptr, "rotation");
592         const int sca= RNA_boolean_get(op->ptr, "scale");
593
594         if(loc || rot || sca) {
595                 return apply_objects_internal(C, op->reports, loc, rot, sca);
596         }
597         else {
598                 return OPERATOR_CANCELLED;
599         }
600 }
601
602 void OBJECT_OT_transform_apply(wmOperatorType *ot)
603 {
604         /* identifiers */
605         ot->name= "Apply Object Transform";
606         ot->description = "Apply the object's transformation to its data";
607         ot->idname= "OBJECT_OT_transform_apply";
608
609         /* api callbacks */
610         ot->exec= object_transform_apply_exec;
611         ot->poll= ED_operator_objectmode;
612
613         /* flags */
614         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
615
616         RNA_def_boolean(ot->srna, "location", 0, "Location", "");
617         RNA_def_boolean(ot->srna, "rotation", 0, "Rotation", "");
618         RNA_def_boolean(ot->srna, "scale", 0, "Scale", "");
619 }
620
621 /********************* Set Object Center ************************/
622
623 enum {
624         GEOMETRY_TO_ORIGIN=0,
625         ORIGIN_TO_GEOMETRY,
626         ORIGIN_TO_CURSOR
627 };
628
629 static int object_origin_set_exec(bContext *C, wmOperator *op)
630 {
631         Main *bmain= CTX_data_main(C);
632         Scene *scene= CTX_data_scene(C);
633         Object *obedit= CTX_data_edit_object(C);
634         Object *tob;
635         float cursor[3], cent[3], cent_neg[3], centn[3], min[3], max[3];
636         int centermode = RNA_enum_get(op->ptr, "type");
637         int around = RNA_enum_get(op->ptr, "center"); /* initialized from v3d->around */
638
639         /* keep track of what is changed */
640         int tot_change=0, tot_lib_error=0, tot_multiuser_arm_error=0;
641
642         if (obedit && centermode != GEOMETRY_TO_ORIGIN) {
643                 BKE_report(op->reports, RPT_ERROR, "Operation cannot be performed in EditMode");
644                 return OPERATOR_CANCELLED;
645         }
646         else {
647                 /* get the view settings if 'around' isnt set and the view is available */
648                 View3D *v3d= CTX_wm_view3d(C);
649                 copy_v3_v3(cursor, give_cursor(scene, v3d));
650                 if(v3d && !RNA_property_is_set(op->ptr, "around"))
651                         around= v3d->around;
652         }
653
654         zero_v3(cent);
655
656         if(obedit) {
657                 INIT_MINMAX(min, max);
658
659                 if(obedit->type==OB_MESH) {
660                         Mesh *me= obedit->data;
661                         EditMesh *em = BKE_mesh_get_editmesh(me);
662                         EditVert *eve;
663
664                         if(around==V3D_CENTROID) {
665                                 int total= 0;
666                                 for(eve= em->verts.first; eve; eve= eve->next) {
667                                         total++;
668                                         add_v3_v3(cent, eve->co);
669                                 }
670                                 if(total) {
671                                         mul_v3_fl(cent, 1.0f/(float)total);
672                                 }
673                         }
674                         else {
675                                 for(eve= em->verts.first; eve; eve= eve->next) {
676                                         DO_MINMAX(eve->co, min, max);
677                                 }
678                                 mid_v3_v3v3(cent, min, max);
679                         }
680
681                         if(!is_zero_v3(cent)) {
682                                 for(eve= em->verts.first; eve; eve= eve->next) {
683                                         sub_v3_v3(eve->co, cent);
684                                 }
685
686                                 recalc_editnormals(em);
687                                 tot_change++;
688                                 DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
689                         }
690                         BKE_mesh_end_editmesh(me, em);
691                 }
692         }
693
694         /* reset flags */
695         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
696                         ob->flag &= ~OB_DONE;
697         }
698         CTX_DATA_END;
699
700         for (tob= bmain->object.first; tob; tob= tob->id.next) {
701                 if(tob->data)
702                         ((ID *)tob->data)->flag &= ~LIB_DOIT;
703                 if(tob->dup_group)
704                         ((ID *)tob->dup_group)->flag &= ~LIB_DOIT;
705         }
706
707         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
708                 if((ob->flag & OB_DONE)==0) {
709                         int do_inverse_offset = FALSE;
710                         ob->flag |= OB_DONE;
711
712                         if(centermode == ORIGIN_TO_CURSOR) {
713                                 copy_v3_v3(cent, cursor);
714                                 invert_m4_m4(ob->imat, ob->obmat);
715                                 mul_m4_v3(ob->imat, cent);
716                         }
717                         
718                         if(ob->data == NULL) {
719                                 /* special support for dupligroups */
720                                 if((ob->transflag & OB_DUPLIGROUP) && ob->dup_group && (ob->dup_group->id.flag & LIB_DOIT)==0) {
721                                         if(ob->dup_group->id.lib) {
722                                                 tot_lib_error++;
723                                         }
724                                         else {
725                                                 if(centermode == ORIGIN_TO_CURSOR) { /* done */ }
726                                                 else {
727                                                         /* only bounds support */
728                                                         INIT_MINMAX(min, max);
729                                                         minmax_object_duplis(scene, ob, min, max);
730                                                         mid_v3_v3v3(cent, min, max);
731                                                         invert_m4_m4(ob->imat, ob->obmat);
732                                                         mul_m4_v3(ob->imat, cent);
733                                                 }
734                                                 
735                                                 add_v3_v3(ob->dup_group->dupli_ofs, cent);
736
737                                                 tot_change++;
738                                                 ob->dup_group->id.flag |= LIB_DOIT;
739                                                 do_inverse_offset= TRUE;
740                                         }
741                                 }
742                         }
743                         else if (((ID *)ob->data)->lib) {
744                                 tot_lib_error++;
745                         }
746
747                         if(obedit==NULL && ob->type==OB_MESH) {
748                                 Mesh *me= ob->data;
749
750                                 if(centermode == ORIGIN_TO_CURSOR) { /* done */ }
751                                 else if(around==V3D_CENTROID) { mesh_center_median(me, cent); }
752                                 else { mesh_center_bounds(me, cent); }
753
754                                 negate_v3_v3(cent_neg, cent);
755                                 mesh_translate(me, cent_neg, 1);
756
757                                 tot_change++;
758                                 me->id.flag |= LIB_DOIT;
759                                 do_inverse_offset= TRUE;
760                         }
761                         else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
762                                 Curve *cu= ob->data;
763
764                                 if(centermode == ORIGIN_TO_CURSOR) { /* done */ }
765                                 else if(around==V3D_CENTROID) { curve_center_median(cu, cent); }
766                                 else { curve_center_bounds(cu, cent);   }
767
768                                 /* don't allow Z change if curve is 2D */
769                                 if((ob->type == OB_CURVE) && !(cu->flag & CU_3D))
770                                         cent[2] = 0.0;
771
772                                 negate_v3_v3(cent_neg, cent);
773                                 curve_translate(cu, cent_neg, 1);
774
775                                 tot_change++;
776                                 cu->id.flag |= LIB_DOIT;
777                                 do_inverse_offset= TRUE;
778
779                                 if(obedit) {
780                                         if (centermode == GEOMETRY_TO_ORIGIN) {
781                                                 DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
782                                         }
783                                         break;
784                                 }
785                         }
786                         else if(ob->type==OB_FONT) {
787                                 /* get from bb */
788
789                                 Curve *cu= ob->data;
790
791                                 if(cu->bb==NULL && (centermode != ORIGIN_TO_CURSOR)) {
792                                         /* do nothing*/
793                                 }
794                                 else {
795                                         if(centermode == ORIGIN_TO_CURSOR) {
796                                                 /* done */
797                                         }
798                                         else {
799                                                 cent[0]= 0.5f * ( cu->bb->vec[4][0] + cu->bb->vec[0][0]);
800                                                 cent[1]= 0.5f * ( cu->bb->vec[0][1] + cu->bb->vec[2][1]) - 0.5f;        /* extra 0.5 is the height o above line */
801                                         }
802
803                                         cent[2]= 0.0f;
804
805                                         cu->xof= cu->xof - (cent[0] / cu->fsize);
806                                         cu->yof= cu->yof - (cent[1] / cu->fsize);
807
808                                         tot_change++;
809                                         cu->id.flag |= LIB_DOIT;
810                                         do_inverse_offset= TRUE;
811                                 }
812                         }
813                         else if(ob->type==OB_ARMATURE) {
814                                 bArmature *arm = ob->data;
815
816                                 if(ID_REAL_USERS(arm) > 1) {
817                                         /*BKE_report(op->reports, RPT_ERROR, "Can't apply to a multi user armature");
818                                         return;*/
819                                         tot_multiuser_arm_error++;
820                                 }
821                                 else {
822                                         /* Function to recenter armatures in editarmature.c
823                                          * Bone + object locations are handled there.
824                                          */
825                                         docenter_armature(scene, ob, cursor, centermode, around);
826
827                                         tot_change++;
828                                         arm->id.flag |= LIB_DOIT;
829                                         /* do_inverse_offset= TRUE; */ /* docenter_armature() handles this */
830
831                                         where_is_object(scene, ob);
832                                         where_is_pose(scene, ob); /* needed for bone parents */
833
834                                         ignore_parent_tx(bmain, scene, ob);
835
836                                         if(obedit)
837                                                 break;
838                                 }
839                         }
840
841                         /* offset other selected objects */
842                         if(do_inverse_offset && (centermode != GEOMETRY_TO_ORIGIN)) {
843                                 /* was the object data modified
844                                  * note: the functions above must set 'cent' */
845                                 copy_v3_v3(centn, cent);
846                                 mul_mat3_m4_v3(ob->obmat, centn); /* ommit translation part */
847                                 add_v3_v3(ob->loc, centn);
848
849                                 where_is_object(scene, ob);
850                                 if(ob->type==OB_ARMATURE) {
851                                         where_is_pose(scene, ob); /* needed for bone parents */
852                                 }
853
854                                 ignore_parent_tx(bmain, scene, ob);
855                                 
856                                 /* other users? */
857                                 CTX_DATA_BEGIN(C, Object*, ob_other, selected_editable_objects) {
858                                         if(             (ob_other->flag & OB_DONE)==0 &&
859                                                         (       (ob->data && (ob->data == ob_other->data)) ||
860                                                                 (ob->dup_group==ob_other->dup_group && (ob->transflag|ob_other->transflag) & OB_DUPLIGROUP) )
861                                         ) {
862                                                 ob_other->flag |= OB_DONE;
863                                                 DAG_id_tag_update(&ob_other->id, OB_RECALC_OB|OB_RECALC_DATA);
864
865                                                 copy_v3_v3(centn, cent);
866                                                 mul_mat3_m4_v3(ob_other->obmat, centn); /* ommit translation part */
867                                                 add_v3_v3(ob_other->loc, centn);
868
869                                                 where_is_object(scene, ob_other);
870                                                 if(ob_other->type==OB_ARMATURE) {
871                                                         where_is_pose(scene, ob_other); /* needed for bone parents */
872                                                 }
873                                                 ignore_parent_tx(bmain, scene, ob_other);
874                                         }
875                                 }
876                                 CTX_DATA_END;
877                         }
878                 }
879         }
880         CTX_DATA_END;
881
882         for (tob= bmain->object.first; tob; tob= tob->id.next)
883                 if(tob->data && (((ID *)tob->data)->flag & LIB_DOIT))
884                         DAG_id_tag_update(&tob->id, OB_RECALC_OB|OB_RECALC_DATA);
885
886         if (tot_change) {
887                 DAG_ids_flush_update(bmain, 0);
888                 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
889         }
890
891         /* Warn if any errors occurred */
892         if (tot_lib_error+tot_multiuser_arm_error) {
893                 BKE_reportf(op->reports, RPT_WARNING, "%i Object(s) Not Centered, %i Changed:",tot_lib_error+tot_multiuser_arm_error, tot_change);
894                 if (tot_lib_error)
895                         BKE_reportf(op->reports, RPT_WARNING, "|%i linked library objects",tot_lib_error);
896                 if (tot_multiuser_arm_error)
897                         BKE_reportf(op->reports, RPT_WARNING, "|%i multiuser armature object(s)",tot_multiuser_arm_error);
898         }
899
900         return OPERATOR_FINISHED;
901 }
902
903 void OBJECT_OT_origin_set(wmOperatorType *ot)
904 {
905         static EnumPropertyItem prop_set_center_types[] = {
906                 {GEOMETRY_TO_ORIGIN, "GEOMETRY_ORIGIN", 0, "Geometry to Origin", "Move object geometry to object origin"},
907                 {ORIGIN_TO_GEOMETRY, "ORIGIN_GEOMETRY", 0, "Origin to Geometry", "Move object origin to center of object geometry"},
908                 {ORIGIN_TO_CURSOR, "ORIGIN_CURSOR", 0, "Origin to 3D Cursor", "Move object origin to position of the 3d cursor"},
909                 {0, NULL, 0, NULL, NULL}
910         };
911         
912         static EnumPropertyItem prop_set_bounds_types[] = {
913                 {V3D_CENTROID, "MEDIAN", 0, "Median Center", ""},
914                 {V3D_CENTER, "BOUNDS", 0, "Bounds Center", ""},
915                 {0, NULL, 0, NULL, NULL}
916         };
917         
918         /* identifiers */
919         ot->name= "Set Origin";
920         ot->description = "Set the object's origin, by either moving the data, or set to center of data, or use 3d cursor";
921         ot->idname= "OBJECT_OT_origin_set";
922         
923         /* api callbacks */
924         ot->invoke= WM_menu_invoke;
925         ot->exec= object_origin_set_exec;
926         
927         ot->poll= ED_operator_scene_editable;
928         
929         /* flags */
930         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
931         
932         ot->prop= RNA_def_enum(ot->srna, "type", prop_set_center_types, 0, "Type", "");
933         RNA_def_enum(ot->srna, "center", prop_set_bounds_types, V3D_CENTROID, "Center", "");
934 }
935