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