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