fcd8a989dc77777abca8db1fff274384901b0729
[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                         ob->quat[1]= ob->quat[2]= ob->quat[3]= 0.0f;
481                         ob->rotAxis[0]= ob->rotAxis[2]= 0.0f;
482                         ob->rotAngle= 0.0f;
483                         
484                         ob->quat[0]= ob->rotAxis[1]= 1.0f;
485                 }
486
487                 where_is_object(scene, ob);
488                 ignore_parent_tx(bmain, scene, ob);
489
490                 DAG_id_flush_update(&ob->id, OB_RECALC_OB|OB_RECALC_DATA);
491
492                 change = 1;
493         }
494         CTX_DATA_END;
495
496         if(!change)
497                 return OPERATOR_CANCELLED;
498
499         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
500         return OPERATOR_FINISHED;
501 }
502
503 static int visual_transform_apply_exec(bContext *C, wmOperator *op)
504 {
505         Scene *scene= CTX_data_scene(C);
506         int change = 0;
507         
508         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
509                 where_is_object(scene, ob);
510                 
511                 VECCOPY(ob->loc, ob->obmat[3]);
512                 mat4_to_size(ob->size,ob->obmat);
513                 
514                 if (ob->rotmode == ROT_MODE_QUAT)
515                         mat4_to_quat(ob->quat, ob->obmat);
516                 else if (ob->rotmode == ROT_MODE_AXISANGLE)
517                         mat4_to_axis_angle(ob->rotAxis, &ob->rotAngle, ob->obmat);
518                 else
519                         mat4_to_eul(ob->rot,ob->obmat);
520                 
521                 where_is_object(scene, ob);
522                 
523                 change = 1;
524         }
525         CTX_DATA_END;
526
527         if(!change)
528                 return OPERATOR_CANCELLED;
529
530         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
531         return OPERATOR_FINISHED;
532 }
533
534 void OBJECT_OT_visual_transform_apply(wmOperatorType *ot)
535 {
536         /* identifiers */
537         ot->name= "Apply Visual Transform";
538         ot->description = "Apply the object's visual transformation to its data.";
539         ot->idname= "OBJECT_OT_visual_transform_apply";
540         
541         /* api callbacks */
542         ot->exec= visual_transform_apply_exec;
543         ot->poll= ED_operator_object_active;
544         
545         /* flags */
546         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
547 }
548
549 static int location_apply_exec(bContext *C, wmOperator *op)
550 {
551         return apply_objects_internal(C, op->reports, 1, 0, 0);
552 }
553
554 void OBJECT_OT_location_apply(wmOperatorType *ot)
555 {
556         /* identifiers */
557         ot->name= "Apply Location";
558         ot->description = "Apply the object's location to its data.";
559         ot->idname= "OBJECT_OT_location_apply";
560         
561         /* api callbacks */
562         ot->exec= location_apply_exec;
563         ot->poll= ED_operator_object_active;
564         
565         /* flags */
566         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
567 }
568
569 static int scale_apply_exec(bContext *C, wmOperator *op)
570 {
571         return apply_objects_internal(C, op->reports, 0, 1, 0);
572 }
573
574 void OBJECT_OT_scale_apply(wmOperatorType *ot)
575 {
576         /* identifiers */
577         ot->name= "Apply Scale";
578         ot->description = "Apply the object's scale to its data.";
579         ot->idname= "OBJECT_OT_scale_apply";
580         
581         /* api callbacks */
582         ot->exec= scale_apply_exec;
583         ot->poll= ED_operator_object_active;
584         
585         /* flags */
586         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
587 }
588
589 static int rotation_apply_exec(bContext *C, wmOperator *op)
590 {
591         return apply_objects_internal(C, op->reports, 0, 0, 1);
592 }
593
594 void OBJECT_OT_rotation_apply(wmOperatorType *ot)
595 {
596         /* identifiers */
597         ot->name= "Apply Rotation";
598         ot->description = "Apply the object's rotation to its data.";
599         ot->idname= "OBJECT_OT_rotation_apply";
600         
601         /* api callbacks */
602         ot->exec= rotation_apply_exec;
603         ot->poll= ED_operator_object_active;
604         
605         /* flags */
606         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
607 }
608
609 /************************ Texture Space Transform ****************************/
610
611 void texspace_edit(Scene *scene, View3D *v3d)
612 {
613         Base *base;
614         int nr=0;
615         
616         /* first test if from visible and selected objects
617          * texspacedraw is set:
618          */
619         
620         if(scene->obedit) return; // XXX get from context
621         
622         for(base= FIRSTBASE; base; base= base->next) {
623                 if(TESTBASELIB(v3d, base)) {
624                         break;
625                 }
626         }
627
628         if(base==0) {
629                 return;
630         }
631         
632         nr= 0; // XXX pupmenu("Texture Space %t|Grab/Move%x1|Size%x2");
633         if(nr<1) return;
634         
635         for(base= FIRSTBASE; base; base= base->next) {
636                 if(TESTBASELIB(v3d, base)) {
637                         base->object->dtx |= OB_TEXSPACE;
638                 }
639         }
640         
641
642         if(nr==1) {
643 // XXX          initTransform(TFM_TRANSLATION, CTX_TEXTURE);
644 // XXX          Transform();
645         }
646         else if(nr==2) {
647 // XXX          initTransform(TFM_RESIZE, CTX_TEXTURE);
648 // XXX          Transform();
649         }
650         else if(nr==3) {
651 // XXX          initTransform(TFM_ROTATION, CTX_TEXTURE);
652 // XXX          Transform();
653         }
654 }
655
656 /********************* Set Object Center ************************/
657
658 static EnumPropertyItem prop_set_center_types[] = {
659         {0, "CENTER", 0, "ObData to Center", "Move object data around Object center"},
660         {1, "CENTER_NEW", 0, "Center New", "Move Object center to center of object data"},
661         {2, "CENTER_CURSOR", 0, "Center Cursor", "Move Object Center to position of the 3d cursor"},
662         {0, NULL, 0, NULL, NULL}
663 };
664
665 /* 0 == do center, 1 == center new, 2 == center cursor */
666 static int object_center_set_exec(bContext *C, wmOperator *op)
667 {
668         Main *bmain= CTX_data_main(C);
669         Scene *scene= CTX_data_scene(C);
670         ScrArea *sa= CTX_wm_area(C);
671         View3D *v3d= sa->spacedata.first;
672         Object *obedit= CTX_data_edit_object(C);
673         Mesh *me, *tme;
674         Curve *cu;
675 /*      BezTriple *bezt;
676         BPoint *bp; */
677         Nurb *nu, *nu1;
678         EditVert *eve;
679         float cent[3], centn[3], min[3], max[3], omat[3][3];
680         int a, total= 0;
681         int centermode = RNA_enum_get(op->ptr, "type");
682         
683         /* keep track of what is changed */
684         int tot_change=0, tot_lib_error=0, tot_multiuser_arm_error=0;
685         MVert *mvert;
686
687         if(scene->id.lib || v3d==NULL){
688                 BKE_report(op->reports, RPT_ERROR, "Operation cannot be performed on Lib data");
689                  return OPERATOR_CANCELLED;
690         }
691         if (obedit && centermode > 0) {
692                 BKE_report(op->reports, RPT_ERROR, "Operation cannot be performed in EditMode");
693                 return OPERATOR_CANCELLED;
694         }       
695         cent[0]= cent[1]= cent[2]= 0.0; 
696         
697         if(obedit) {
698
699                 INIT_MINMAX(min, max);
700         
701                 if(obedit->type==OB_MESH) {
702                         Mesh *me= obedit->data;
703                         EditMesh *em = BKE_mesh_get_editmesh(me);
704
705                         for(eve= em->verts.first; eve; eve= eve->next) {
706                                 if(v3d->around==V3D_CENTROID) {
707                                         total++;
708                                         VECADD(cent, cent, eve->co);
709                                 }
710                                 else {
711                                         DO_MINMAX(eve->co, min, max);
712                                 }
713                         }
714                         
715                         if(v3d->around==V3D_CENTROID) {
716                                 mul_v3_fl(cent, 1.0f/(float)total);
717                         }
718                         else {
719                                 cent[0]= (min[0]+max[0])/2.0f;
720                                 cent[1]= (min[1]+max[1])/2.0f;
721                                 cent[2]= (min[2]+max[2])/2.0f;
722                         }
723                         
724                         for(eve= em->verts.first; eve; eve= eve->next) {
725                                 sub_v3_v3v3(eve->co, eve->co, cent);                    
726                         }
727                         
728                         recalc_editnormals(em);
729                         tot_change++;
730                         DAG_id_flush_update(&obedit->id, OB_RECALC_DATA);
731                         BKE_mesh_end_editmesh(me, em);
732                 }
733         }
734         
735         /* reset flags */
736         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
737                         ob->flag &= ~OB_DONE;
738         }
739         CTX_DATA_END;
740         
741         for (me= G.main->mesh.first; me; me= me->id.next) {
742                 me->flag &= ~ME_ISDONE;
743         }
744         
745         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
746                 if((ob->flag & OB_DONE)==0) {
747                         ob->flag |= OB_DONE;
748                                 
749                         if(obedit==NULL && (me=get_mesh(ob)) ) {
750                                 if (me->id.lib) {
751                                         tot_lib_error++;
752                                 } else {
753                                         if(centermode==2) {
754                                                 VECCOPY(cent, give_cursor(scene, v3d));
755                                                 invert_m4_m4(ob->imat, ob->obmat);
756                                                 mul_m4_v3(ob->imat, cent);
757                                         } else {
758                                                 INIT_MINMAX(min, max);
759                                                 mvert= me->mvert;
760                                                 for(a=0; a<me->totvert; a++, mvert++) {
761                                                         DO_MINMAX(mvert->co, min, max);
762                                                 }
763                                         
764                                                 cent[0]= (min[0]+max[0])/2.0f;
765                                                 cent[1]= (min[1]+max[1])/2.0f;
766                                                 cent[2]= (min[2]+max[2])/2.0f;
767                                         }
768
769                                         mvert= me->mvert;
770                                         for(a=0; a<me->totvert; a++, mvert++) {
771                                                 sub_v3_v3v3(mvert->co, mvert->co, cent);
772                                         }
773                                         
774                                         if (me->key) {
775                                                 KeyBlock *kb;
776                                                 for (kb=me->key->block.first; kb; kb=kb->next) {
777                                                         float *fp= kb->data;
778                                                         
779                                                         for (a=0; a<kb->totelem; a++, fp+=3) {
780                                                                 sub_v3_v3v3(fp, fp, cent);
781                                                         }
782                                                 }
783                                         }
784                                                 
785                                         me->flag |= ME_ISDONE;
786                                                 
787                                         if(centermode) {
788                                                 copy_m3_m4(omat, ob->obmat);
789                                                 
790                                                 VECCOPY(centn, cent);
791                                                 mul_m3_v3(omat, centn);
792                                                 ob->loc[0]+= centn[0];
793                                                 ob->loc[1]+= centn[1];
794                                                 ob->loc[2]+= centn[2];
795                                                 
796                                                 where_is_object(scene, ob);
797                                                 ignore_parent_tx(bmain, scene, ob);
798                                                 
799                                                 /* other users? */
800                                                 CTX_DATA_BEGIN(C, Object*, ob_other, selected_editable_objects) {
801                                                         if((ob_other->flag & OB_DONE)==0) {
802                                                                 tme= get_mesh(ob_other);
803                                                                 
804                                                                 if(tme==me) {
805                                                                         
806                                                                         ob_other->flag |= OB_DONE;
807                                                                         ob_other->recalc= OB_RECALC_OB|OB_RECALC_DATA;
808
809                                                                         copy_m3_m4(omat, ob_other->obmat);
810                                                                         VECCOPY(centn, cent);
811                                                                         mul_m3_v3(omat, centn);
812                                                                         ob_other->loc[0]+= centn[0];
813                                                                         ob_other->loc[1]+= centn[1];
814                                                                         ob_other->loc[2]+= centn[2];
815                                                                         
816                                                                         where_is_object(scene, ob_other);
817                                                                         ignore_parent_tx(bmain, scene, ob_other);
818                                                                         
819                                                                         if(tme && (tme->flag & ME_ISDONE)==0) {
820                                                                                 mvert= tme->mvert;
821                                                                                 for(a=0; a<tme->totvert; a++, mvert++) {
822                                                                                         sub_v3_v3v3(mvert->co, mvert->co, cent);
823                                                                                 }
824                                                                                 
825                                                                                 if (tme->key) {
826                                                                                         KeyBlock *kb;
827                                                                                         for (kb=tme->key->block.first; kb; kb=kb->next) {
828                                                                                                 float *fp= kb->data;
829                                                                                                 
830                                                                                                 for (a=0; a<kb->totelem; a++, fp+=3) {
831                                                                                                         sub_v3_v3v3(fp, fp, cent);
832                                                                                                 }
833                                                                                         }
834                                                                                 }
835                                                                                 
836                                                                                 tme->flag |= ME_ISDONE;
837                                                                         }
838                                                                 }
839                                                         }
840                                                 }
841                                                 CTX_DATA_END;
842                                         }
843                                         tot_change++;
844                                 }
845                         }
846                         else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
847                                 
848                                 /* weak code here... (ton) */
849                                 if(obedit==ob) {
850                                         ListBase *editnurb= curve_get_editcurve(obedit);
851
852                                         nu1= editnurb->first;
853                                         cu= obedit->data;
854                                 }
855                                 else {
856                                         cu= ob->data;
857                                         nu1= cu->nurb.first;
858                                 }
859                                 
860                                 if (cu->id.lib) {
861                                         tot_lib_error++;
862                                 } else {
863                                         if(centermode==2) {
864                                                 VECCOPY(cent, give_cursor(scene, v3d));
865                                                 invert_m4_m4(ob->imat, ob->obmat);
866                                                 mul_m4_v3(ob->imat, cent);
867
868                                                 /* don't allow Z change if curve is 2D */
869                                                 if( !( cu->flag & CU_3D ) )
870                                                         cent[2] = 0.0;
871                                         } 
872                                         else {
873                                                 INIT_MINMAX(min, max);
874                                                 
875                                                 nu= nu1;
876                                                 while(nu) {
877                                                         minmaxNurb(nu, min, max);
878                                                         nu= nu->next;
879                                                 }
880                                                 
881                                                 cent[0]= (min[0]+max[0])/2.0f;
882                                                 cent[1]= (min[1]+max[1])/2.0f;
883                                                 cent[2]= (min[2]+max[2])/2.0f;
884                                         }
885                                         
886                                         nu= nu1;
887                                         while(nu) {
888                                                 if(nu->type == CU_BEZIER) {
889                                                         a= nu->pntsu;
890                                                         while (a--) {
891                                                                 sub_v3_v3v3(nu->bezt[a].vec[0], nu->bezt[a].vec[0], cent);
892                                                                 sub_v3_v3v3(nu->bezt[a].vec[1], nu->bezt[a].vec[1], cent);
893                                                                 sub_v3_v3v3(nu->bezt[a].vec[2], nu->bezt[a].vec[2], cent);
894                                                         }
895                                                 }
896                                                 else {
897                                                         a= nu->pntsu*nu->pntsv;
898                                                         while (a--)
899                                                                 sub_v3_v3v3(nu->bp[a].vec, nu->bp[a].vec, cent);
900                                                 }
901                                                 nu= nu->next;
902                                         }
903                         
904                                         if(centermode && obedit==NULL) {
905                                                 copy_m3_m4(omat, ob->obmat);
906                                                 
907                                                 mul_m3_v3(omat, cent);
908                                                 ob->loc[0]+= cent[0];
909                                                 ob->loc[1]+= cent[1];
910                                                 ob->loc[2]+= cent[2];
911                                                 
912                                                 where_is_object(scene, ob);
913                                                 ignore_parent_tx(bmain, scene, ob);
914                                         }
915                                         
916                                         tot_change++;
917                                         if(obedit) {
918                                                 if (centermode==0) {
919                                                         DAG_id_flush_update(&obedit->id, OB_RECALC_DATA);
920                                                 }
921                                                 break;
922                                         }
923                                 }
924                         }
925                         else if(ob->type==OB_FONT) {
926                                 /* get from bb */
927                                 
928                                 cu= ob->data;
929                                 
930                                 if(cu->bb==NULL) {
931                                         /* do nothing*/
932                                 } else if (cu->id.lib) {
933                                         tot_lib_error++;
934                                 } else {
935                                         cu->xof= -0.5f*( cu->bb->vec[4][0] - cu->bb->vec[0][0]);
936                                         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 */
937                                         
938                                         /* not really ok, do this better once! */
939                                         cu->xof /= cu->fsize;
940                                         cu->yof /= cu->fsize;
941
942                                         tot_change++;
943                                 }
944                         }
945                         else if(ob->type==OB_ARMATURE) {
946                                 bArmature *arm = ob->data;
947                                 
948                                 if (arm->id.lib) {
949                                         tot_lib_error++;
950                                 } else if(arm->id.us>1) {
951                                         /*BKE_report(op->reports, RPT_ERROR, "Can't apply to a multi user armature");
952                                         return;*/
953                                         tot_multiuser_arm_error++;
954                                 } else {
955                                         /* Function to recenter armatures in editarmature.c 
956                                          * Bone + object locations are handled there.
957                                          */
958                                         docenter_armature(scene, v3d, ob, centermode);
959                                         tot_change++;
960                                         
961                                         where_is_object(scene, ob);
962                                         ignore_parent_tx(bmain, scene, ob);
963                                         
964                                         if(obedit) 
965                                                 break;
966                                 }
967                         }
968                         ob->recalc= OB_RECALC_OB|OB_RECALC_DATA;
969                 }
970         }
971         CTX_DATA_END;
972         
973         if (tot_change) {
974                 ED_anim_dag_flush_update(C);
975         }
976         
977         /* Warn if any errors occured */
978         if (tot_lib_error+tot_multiuser_arm_error) {
979                 BKE_reportf(op->reports, RPT_WARNING, "%i Object(s) Not Centered, %i Changed:",tot_lib_error+tot_multiuser_arm_error, tot_change);              
980                 if (tot_lib_error)
981                         BKE_reportf(op->reports, RPT_WARNING, "|%i linked library objects",tot_lib_error);
982                 if (tot_multiuser_arm_error)
983                         BKE_reportf(op->reports, RPT_WARNING, "|%i multiuser armature object(s)",tot_multiuser_arm_error);
984         }
985         
986         return OPERATOR_FINISHED;
987 }
988
989 void OBJECT_OT_center_set(wmOperatorType *ot)
990 {
991         /* identifiers */
992         ot->name= "Set Center";
993         ot->description = "Set the object's center, by either moving the data, or set to center of data, or use 3d cursor";
994         ot->idname= "OBJECT_OT_center_set";
995         
996         /* api callbacks */
997         ot->invoke= WM_menu_invoke;
998         ot->exec= object_center_set_exec;
999         
1000         ot->poll= ED_operator_view3d_active;
1001         
1002         /* flags */
1003         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1004         
1005         RNA_def_enum(ot->srna, "type", prop_set_center_types, 0, "Type", "");
1006 }
1007