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