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