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