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