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