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