Blender  V2.59
object_transform.c
Go to the documentation of this file.
00001 /*
00002  * $Id: object_transform.c 36595 2011-05-10 14:38:55Z nazgul $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00021  * All rights reserved.
00022  *
00023  * Contributor(s): Blender Foundation, 2002-2008 full recode
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 #include <stdlib.h>
00034 #include <string.h>
00035 
00036 #include "DNA_anim_types.h"
00037 #include "DNA_armature_types.h"
00038 #include "DNA_key_types.h"
00039 #include "DNA_meshdata_types.h"
00040 #include "DNA_object_types.h"
00041 #include "DNA_scene_types.h"
00042 #include "DNA_group_types.h"
00043 
00044 #include "BLI_math.h"
00045 #include "BLI_editVert.h"
00046 #include "BLI_listbase.h"
00047 #include "BLI_utildefines.h"
00048 
00049 #include "BKE_context.h"
00050 #include "BKE_curve.h"
00051 #include "BKE_depsgraph.h"
00052 #include "BKE_main.h"
00053 #include "BKE_mesh.h"
00054 #include "BKE_object.h"
00055 #include "BKE_report.h"
00056 #include "BKE_multires.h"
00057 #include "BKE_armature.h"
00058 
00059 #include "RNA_define.h"
00060 #include "RNA_access.h"
00061 
00062 #include "WM_api.h"
00063 #include "WM_types.h"
00064 
00065 #include "ED_armature.h"
00066 #include "ED_keyframing.h"
00067 #include "ED_mesh.h"
00068 #include "ED_screen.h"
00069 #include "ED_view3d.h"
00070 
00071 #include "object_intern.h"
00072 
00073 /*************************** Clear Transformation ****************************/
00074 
00075 /* clear location of object */
00076 static void object_clear_loc(Object *ob)
00077 {
00078         /* clear location if not locked */
00079         if ((ob->protectflag & OB_LOCK_LOCX)==0)
00080                 ob->loc[0]= ob->dloc[0]= 0.0f;
00081         if ((ob->protectflag & OB_LOCK_LOCY)==0)
00082                 ob->loc[1]= ob->dloc[1]= 0.0f;
00083         if ((ob->protectflag & OB_LOCK_LOCZ)==0)
00084                 ob->loc[2]= ob->dloc[2]= 0.0f;
00085 }
00086 
00087 /* clear rotation of object */
00088 static void object_clear_rot(Object *ob)
00089 {
00090         /* clear rotations that aren't locked */
00091         if (ob->protectflag & (OB_LOCK_ROTX|OB_LOCK_ROTY|OB_LOCK_ROTZ|OB_LOCK_ROTW)) {
00092                 if (ob->protectflag & OB_LOCK_ROT4D) {
00093                         /* perform clamping on a component by component basis */
00094                         if (ob->rotmode == ROT_MODE_AXISANGLE) {
00095                                 if ((ob->protectflag & OB_LOCK_ROTW) == 0)
00096                                         ob->rotAngle= ob->drotAngle= 0.0f;
00097                                 if ((ob->protectflag & OB_LOCK_ROTX) == 0)
00098                                         ob->rotAxis[0]= ob->drotAxis[0]= 0.0f;
00099                                 if ((ob->protectflag & OB_LOCK_ROTY) == 0)
00100                                         ob->rotAxis[1]= ob->drotAxis[1]= 0.0f;
00101                                 if ((ob->protectflag & OB_LOCK_ROTZ) == 0)
00102                                         ob->rotAxis[2]= ob->drotAxis[2]= 0.0f;
00103                                         
00104                                 /* check validity of axis - axis should never be 0,0,0 (if so, then we make it rotate about y) */
00105                                 if (IS_EQF(ob->rotAxis[0], ob->rotAxis[1]) && IS_EQF(ob->rotAxis[1], ob->rotAxis[2]))
00106                                         ob->rotAxis[1] = 1.0f;
00107                                 if (IS_EQF(ob->drotAxis[0], ob->drotAxis[1]) && IS_EQF(ob->drotAxis[1], ob->drotAxis[2]))
00108                                         ob->drotAxis[1]= 1.0f;
00109                         }
00110                         else if (ob->rotmode == ROT_MODE_QUAT) {
00111                                 if ((ob->protectflag & OB_LOCK_ROTW) == 0)
00112                                         ob->quat[0]= ob->dquat[0]= 1.0f;
00113                                 if ((ob->protectflag & OB_LOCK_ROTX) == 0)
00114                                         ob->quat[1]= ob->dquat[1]= 0.0f;
00115                                 if ((ob->protectflag & OB_LOCK_ROTY) == 0)
00116                                         ob->quat[2]= ob->dquat[2]= 0.0f;
00117                                 if ((ob->protectflag & OB_LOCK_ROTZ) == 0)
00118                                         ob->quat[3]= ob->dquat[3]= 0.0f;
00119                                         
00120                                 // TODO: does this quat need normalising now?
00121                         }
00122                         else {
00123                                 /* the flag may have been set for the other modes, so just ignore the extra flag... */
00124                                 if ((ob->protectflag & OB_LOCK_ROTX) == 0)
00125                                         ob->rot[0]= ob->drot[0]= 0.0f;
00126                                 if ((ob->protectflag & OB_LOCK_ROTY) == 0)
00127                                         ob->rot[1]= ob->drot[1]= 0.0f;
00128                                 if ((ob->protectflag & OB_LOCK_ROTZ) == 0)
00129                                         ob->rot[2]= ob->drot[2]= 0.0f;
00130                         }
00131                 }
00132                 else {
00133                         /* perform clamping using euler form (3-components) */
00134                         // FIXME: deltas are not handled for these cases yet...
00135                         float eul[3], oldeul[3], quat1[4] = {0};
00136                         
00137                         if (ob->rotmode == ROT_MODE_QUAT) {
00138                                 QUATCOPY(quat1, ob->quat);
00139                                 quat_to_eul(oldeul, ob->quat);
00140                         }
00141                         else if (ob->rotmode == ROT_MODE_AXISANGLE) {
00142                                 axis_angle_to_eulO(oldeul, EULER_ORDER_DEFAULT, ob->rotAxis, ob->rotAngle);
00143                         }
00144                         else {
00145                                 copy_v3_v3(oldeul, ob->rot);
00146                         }
00147                         
00148                         eul[0]= eul[1]= eul[2]= 0.0f;
00149                         
00150                         if (ob->protectflag & OB_LOCK_ROTX)
00151                                 eul[0]= oldeul[0];
00152                         if (ob->protectflag & OB_LOCK_ROTY)
00153                                 eul[1]= oldeul[1];
00154                         if (ob->protectflag & OB_LOCK_ROTZ)
00155                                 eul[2]= oldeul[2];
00156                         
00157                         if (ob->rotmode == ROT_MODE_QUAT) {
00158                                 eul_to_quat(ob->quat, eul);
00159                                 /* quaternions flip w sign to accumulate rotations correctly */
00160                                 if ((quat1[0]<0.0f && ob->quat[0]>0.0f) || (quat1[0]>0.0f && ob->quat[0]<0.0f)) {
00161                                         mul_qt_fl(ob->quat, -1.0f);
00162                                 }
00163                         }
00164                         else if (ob->rotmode == ROT_MODE_AXISANGLE) {
00165                                 eulO_to_axis_angle(ob->rotAxis, &ob->rotAngle,eul, EULER_ORDER_DEFAULT);
00166                         }
00167                         else {
00168                                 copy_v3_v3(ob->rot, eul);
00169                         }
00170                 }
00171         }                                                // Duplicated in source/blender/editors/armature/editarmature.c
00172         else { 
00173                 if (ob->rotmode == ROT_MODE_QUAT) {
00174                         unit_qt(ob->quat);
00175                         unit_qt(ob->dquat);
00176                 }
00177                 else if (ob->rotmode == ROT_MODE_AXISANGLE) {
00178                         unit_axis_angle(ob->rotAxis, &ob->rotAngle);
00179                         unit_axis_angle(ob->drotAxis, &ob->drotAngle);
00180                 }
00181                 else {
00182                         zero_v3(ob->rot);
00183                         zero_v3(ob->drot);
00184                 }
00185         }
00186 }
00187 
00188 /* clear scale of object */
00189 static void object_clear_scale(Object *ob)
00190 {
00191         /* clear scale factors which are not locked */
00192         if ((ob->protectflag & OB_LOCK_SCALEX)==0) {
00193                 ob->dsize[0]= 0.0f;
00194                 ob->size[0]= 1.0f;
00195         }
00196         if ((ob->protectflag & OB_LOCK_SCALEY)==0) {
00197                 ob->dsize[1]= 0.0f;
00198                 ob->size[1]= 1.0f;
00199         }
00200         if ((ob->protectflag & OB_LOCK_SCALEZ)==0) {
00201                 ob->dsize[2]= 0.0f;
00202                 ob->size[2]= 1.0f;
00203         }
00204 }
00205 
00206 /* --------------- */
00207 
00208 /* generic exec for clear-transform operators */
00209 static int object_clear_transform_generic_exec(bContext *C, wmOperator *op, 
00210                 void (*clear_func)(Object*), const char default_ksName[])
00211 {
00212         Main *bmain = CTX_data_main(C);
00213         Scene *scene= CTX_data_scene(C);
00214         KeyingSet *ks;
00215         
00216         /* sanity checks */
00217         if ELEM(NULL, clear_func, default_ksName) {
00218                 BKE_report(op->reports, RPT_ERROR, "Programming error: missing clear transform func or Keying Set Name");
00219                 return OPERATOR_CANCELLED;
00220         }
00221         
00222         /* get KeyingSet to use */
00223         ks = ANIM_get_keyingset_for_autokeying(scene, default_ksName);
00224         
00225         /* operate on selected objects only if they aren't in weight-paint mode 
00226          * (so that object-transform clearing won't be applied at same time as bone-clearing)
00227          */
00228         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) 
00229         {
00230                 if (!(ob->mode & OB_MODE_WEIGHT_PAINT)) {
00231                         /* run provided clearing function */
00232                         clear_func(ob);
00233                         
00234                         /* auto keyframing */
00235                         if (autokeyframe_cfra_can_key(scene, &ob->id)) {
00236                                 ListBase dsources = {NULL, NULL};
00237                                 
00238                                 /* now insert the keyframe(s) using the Keying Set
00239                                  *      1) add datasource override for the Object
00240                                  *      2) insert keyframes
00241                                  *      3) free the extra info 
00242                                  */
00243                                 ANIM_relative_keyingset_add_source(&dsources, &ob->id, NULL, NULL); 
00244                                 ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
00245                                 BLI_freelistN(&dsources);
00246                         }
00247                         
00248                         /* tag for updates */
00249                         ob->recalc |= OB_RECALC_OB;
00250                 }
00251         }
00252         CTX_DATA_END;
00253         
00254         /* this is needed so children are also updated */
00255         DAG_ids_flush_update(bmain, 0);
00256 
00257         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
00258 
00259         return OPERATOR_FINISHED;
00260 }
00261 
00262 /* --------------- */
00263 
00264 
00265 static int object_location_clear_exec(bContext *C, wmOperator *op)
00266 {
00267         return object_clear_transform_generic_exec(C, op, object_clear_loc, "Location");
00268 }
00269 
00270 void OBJECT_OT_location_clear(wmOperatorType *ot)
00271 {
00272         /* identifiers */
00273         ot->name= "Clear Location";
00274         ot->description = "Clear the object's location";
00275         ot->idname= "OBJECT_OT_location_clear";
00276         
00277         /* api callbacks */
00278         ot->exec= object_location_clear_exec;
00279         ot->poll= ED_operator_scene_editable;
00280         
00281         /* flags */
00282         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00283 }
00284 
00285 static int object_rotation_clear_exec(bContext *C, wmOperator *op)
00286 {
00287         return object_clear_transform_generic_exec(C, op, object_clear_rot, "Rotation");
00288 }
00289 
00290 void OBJECT_OT_rotation_clear(wmOperatorType *ot)
00291 {
00292         /* identifiers */
00293         ot->name= "Clear Rotation";
00294         ot->description = "Clear the object's rotation";
00295         ot->idname= "OBJECT_OT_rotation_clear";
00296         
00297         /* api callbacks */
00298         ot->exec= object_rotation_clear_exec;
00299         ot->poll= ED_operator_scene_editable;
00300         
00301         /* flags */
00302         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00303 }
00304 
00305 static int object_scale_clear_exec(bContext *C, wmOperator *op)
00306 {
00307         return object_clear_transform_generic_exec(C, op, object_clear_scale, "Scaling");
00308 }
00309 
00310 void OBJECT_OT_scale_clear(wmOperatorType *ot)
00311 {
00312         /* identifiers */
00313         ot->name= "Clear Scale";
00314         ot->description = "Clear the object's scale";
00315         ot->idname= "OBJECT_OT_scale_clear";
00316         
00317         /* api callbacks */
00318         ot->exec= object_scale_clear_exec;
00319         ot->poll= ED_operator_scene_editable;
00320         
00321         /* flags */
00322         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00323 }
00324 
00325 /* --------------- */
00326 
00327 static int object_origin_clear_exec(bContext *C, wmOperator *UNUSED(op))
00328 {
00329         Main *bmain= CTX_data_main(C);
00330         float *v1, *v3;
00331         float mat[3][3];
00332 
00333         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) 
00334         {
00335                 if (ob->parent) {
00336                         /* vectors pointed to by v1 and v3 will get modified */
00337                         v1= ob->loc;
00338                         v3= ob->parentinv[3];
00339                         
00340                         copy_m3_m4(mat, ob->parentinv);
00341                         negate_v3_v3(v3, v1);
00342                         mul_m3_v3(mat, v3);
00343                 }
00344                 ob->recalc |= OB_RECALC_OB;
00345         }
00346         CTX_DATA_END;
00347 
00348         DAG_ids_flush_update(bmain, 0);
00349         
00350         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
00351         
00352         return OPERATOR_FINISHED;
00353 }
00354 
00355 void OBJECT_OT_origin_clear(wmOperatorType *ot)
00356 {
00357         /* identifiers */
00358         ot->name= "Clear Origin";
00359         ot->description = "Clear the object's origin";
00360         ot->idname= "OBJECT_OT_origin_clear";
00361         
00362         /* api callbacks */
00363         ot->exec= object_origin_clear_exec;
00364         ot->poll= ED_operator_scene_editable;
00365         
00366         /* flags */
00367         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00368 }
00369 
00370 /*************************** Apply Transformation ****************************/
00371 
00372 /* use this when the loc/size/rot of the parent has changed but the children
00373  * should stay in the same place, e.g. for apply-size-rot or object center */
00374 static void ignore_parent_tx(Main *bmain, Scene *scene, Object *ob ) 
00375 {
00376         Object workob;
00377         Object *ob_child;
00378         
00379         /* a change was made, adjust the children to compensate */
00380         for(ob_child=bmain->object.first; ob_child; ob_child=ob_child->id.next) {
00381                 if(ob_child->parent == ob) {
00382                         object_apply_mat4(ob_child, ob_child->obmat, TRUE, FALSE);
00383                         what_does_parent(scene, ob_child, &workob);
00384                         invert_m4_m4(ob_child->parentinv, workob.obmat);
00385                 }
00386         }
00387 }
00388 
00389 static int apply_objects_internal(bContext *C, ReportList *reports, int apply_loc, int apply_rot, int apply_scale)
00390 {
00391         Main *bmain= CTX_data_main(C);
00392         Scene *scene= CTX_data_scene(C);
00393         float rsmat[3][3], tmat[3][3], obmat[3][3], iobmat[3][3], mat[4][4], scale;
00394         int a, change = 0;
00395         
00396         /* first check if we can execute */
00397         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
00398 
00399                 if(ob->type==OB_MESH) {
00400                         if(ID_REAL_USERS(ob->data) > 1) {
00401                                 BKE_report(reports, RPT_ERROR, "Can't apply to a multi user mesh, doing nothing.");
00402                                 return OPERATOR_CANCELLED;
00403                         }
00404                 }
00405                 else if(ob->type==OB_ARMATURE) {
00406                         if(ID_REAL_USERS(ob->data) > 1) {
00407                                 BKE_report(reports, RPT_ERROR, "Can't apply to a multi user armature, doing nothing.");
00408                                 return OPERATOR_CANCELLED;
00409                         }
00410                 }
00411                 else if(ELEM(ob->type, OB_CURVE, OB_SURF)) {
00412                         Curve *cu;
00413 
00414                         if(ID_REAL_USERS(ob->data) > 1) {
00415                                 BKE_report(reports, RPT_ERROR, "Can't apply to a multi user curve, doing nothing.");
00416                                 return OPERATOR_CANCELLED;
00417                         }
00418 
00419                         cu= ob->data;
00420 
00421                         if(!(cu->flag & CU_3D) && (apply_rot || apply_loc)) {
00422                                 BKE_report(reports, RPT_ERROR, "Neither rotation nor location could be applied to a 2d curve, doing nothing.");
00423                                 return OPERATOR_CANCELLED;
00424                         }
00425                         if(cu->key) {
00426                                 BKE_report(reports, RPT_ERROR, "Can't apply to a curve with vertex keys, doing nothing.");
00427                                 return OPERATOR_CANCELLED;
00428                         }
00429                 }
00430         }
00431         CTX_DATA_END;
00432         
00433         /* now execute */
00434         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
00435 
00436                 /* calculate rotation/scale matrix */
00437                 if(apply_scale && apply_rot)
00438                         object_to_mat3(ob, rsmat);
00439                 else if(apply_scale)
00440                         object_scale_to_mat3(ob, rsmat);
00441                 else if(apply_rot) {
00442                         float tmat[3][3], timat[3][3];
00443 
00444                         /* simple rotation matrix */
00445                         object_rot_to_mat3(ob, rsmat);
00446 
00447                         /* correct for scale, note mul_m3_m3m3 has swapped args! */
00448                         object_scale_to_mat3(ob, tmat);
00449                         invert_m3_m3(timat, tmat);
00450                         mul_m3_m3m3(rsmat, timat, rsmat);
00451                         mul_m3_m3m3(rsmat, rsmat, tmat);
00452                 }
00453                 else
00454                         unit_m3(rsmat);
00455 
00456                 copy_m4_m3(mat, rsmat);
00457 
00458                 /* calculate translation */
00459                 if(apply_loc) {
00460                         copy_v3_v3(mat[3], ob->loc);
00461 
00462                         if(!(apply_scale && apply_rot)) {
00463                                 /* correct for scale and rotation that is still applied */
00464                                 object_to_mat3(ob, obmat);
00465                                 invert_m3_m3(iobmat, obmat);
00466                                 mul_m3_m3m3(tmat, rsmat, iobmat);
00467                                 mul_m3_v3(tmat, mat[3]);
00468                         }
00469                 }
00470 
00471                 /* apply to object data */
00472                 if(ob->type==OB_MESH) {
00473                         Mesh *me= ob->data;
00474                         MVert *mvert;
00475 
00476                         multiresModifier_scale_disp(scene, ob);
00477                         
00478                         /* adjust data */
00479                         mvert= me->mvert;
00480                         for(a=0; a<me->totvert; a++, mvert++)
00481                                 mul_m4_v3(mat, mvert->co);
00482                         
00483                         if(me->key) {
00484                                 KeyBlock *kb;
00485                                 
00486                                 for(kb=me->key->block.first; kb; kb=kb->next) {
00487                                         float *fp= kb->data;
00488                                         
00489                                         for(a=0; a<kb->totelem; a++, fp+=3)
00490                                                 mul_m4_v3(mat, fp);
00491                                 }
00492                         }
00493                         
00494                         /* update normals */
00495                         mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
00496                 }
00497                 else if (ob->type==OB_ARMATURE) {
00498                         ED_armature_apply_transform(ob, mat);
00499                 }
00500                 else if(ELEM(ob->type, OB_CURVE, OB_SURF)) {
00501                         Curve *cu= ob->data;
00502 
00503                         Nurb *nu;
00504                         BPoint *bp;
00505                         BezTriple *bezt;
00506 
00507                         scale = mat3_to_scale(rsmat);
00508 
00509                         for(nu=cu->nurb.first; nu; nu=nu->next) {
00510                                 if(nu->type == CU_BEZIER) {
00511                                         a= nu->pntsu;
00512                                         for(bezt= nu->bezt; a--; bezt++) {
00513                                                 mul_m4_v3(mat, bezt->vec[0]);
00514                                                 mul_m4_v3(mat, bezt->vec[1]);
00515                                                 mul_m4_v3(mat, bezt->vec[2]);
00516                                                 bezt->radius *= scale;
00517                                         }
00518                                         calchandlesNurb(nu);
00519                                 }
00520                                 else {
00521                                         a= nu->pntsu*nu->pntsv;
00522                                         for(bp= nu->bp; a--; bp++)
00523                                                 mul_m4_v3(mat, bp->vec);
00524                                 }
00525                         }
00526                 }
00527                 else
00528                         continue;
00529 
00530                 if(apply_loc)
00531                         zero_v3(ob->loc);
00532                 if(apply_scale)
00533                         ob->size[0]= ob->size[1]= ob->size[2]= 1.0f;
00534                 if(apply_rot) {
00535                         zero_v3(ob->rot);
00536                         unit_qt(ob->quat);
00537                         unit_axis_angle(ob->rotAxis, &ob->rotAngle);
00538                 }
00539 
00540                 where_is_object(scene, ob);
00541                 if(ob->type==OB_ARMATURE) {
00542                         where_is_pose(scene, ob); /* needed for bone parents */
00543                 }
00544 
00545                 ignore_parent_tx(bmain, scene, ob);
00546 
00547                 DAG_id_tag_update(&ob->id, OB_RECALC_OB|OB_RECALC_DATA);
00548 
00549                 change = 1;
00550         }
00551         CTX_DATA_END;
00552 
00553         if(!change)
00554                 return OPERATOR_CANCELLED;
00555 
00556         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
00557         return OPERATOR_FINISHED;
00558 }
00559 
00560 static int visual_transform_apply_exec(bContext *C, wmOperator *UNUSED(op))
00561 {
00562         Scene *scene= CTX_data_scene(C);
00563         int change = 0;
00564         
00565         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
00566                 where_is_object(scene, ob);
00567                 object_apply_mat4(ob, ob->obmat, TRUE, TRUE);
00568                 where_is_object(scene, ob);
00569 
00570                 /* update for any children that may get moved */
00571                 DAG_id_tag_update(&ob->id, OB_RECALC_OB);
00572         
00573                 change = 1;
00574         }
00575         CTX_DATA_END;
00576 
00577         if(!change)
00578                 return OPERATOR_CANCELLED;
00579 
00580         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
00581         return OPERATOR_FINISHED;
00582 }
00583 
00584 void OBJECT_OT_visual_transform_apply(wmOperatorType *ot)
00585 {
00586         /* identifiers */
00587         ot->name= "Apply Visual Transform";
00588         ot->description = "Apply the object's visual transformation to its data";
00589         ot->idname= "OBJECT_OT_visual_transform_apply";
00590         
00591         /* api callbacks */
00592         ot->exec= visual_transform_apply_exec;
00593         ot->poll= ED_operator_scene_editable;
00594         
00595         /* flags */
00596         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00597 }
00598 
00599 static int object_transform_apply_exec(bContext *C, wmOperator *op)
00600 {
00601         const int loc= RNA_boolean_get(op->ptr, "location");
00602         const int rot= RNA_boolean_get(op->ptr, "rotation");
00603         const int sca= RNA_boolean_get(op->ptr, "scale");
00604 
00605         if(loc || rot || sca) {
00606                 return apply_objects_internal(C, op->reports, loc, rot, sca);
00607         }
00608         else {
00609                 return OPERATOR_CANCELLED;
00610         }
00611 }
00612 
00613 void OBJECT_OT_transform_apply(wmOperatorType *ot)
00614 {
00615         /* identifiers */
00616         ot->name= "Apply Object Transform";
00617         ot->description = "Apply the object's transformation to its data";
00618         ot->idname= "OBJECT_OT_transform_apply";
00619 
00620         /* api callbacks */
00621         ot->exec= object_transform_apply_exec;
00622         ot->poll= ED_operator_objectmode;
00623 
00624         /* flags */
00625         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00626 
00627         RNA_def_boolean(ot->srna, "location", 0, "Location", "");
00628         RNA_def_boolean(ot->srna, "rotation", 0, "Rotation", "");
00629         RNA_def_boolean(ot->srna, "scale", 0, "Scale", "");
00630 }
00631 
00632 /********************* Set Object Center ************************/
00633 
00634 enum {
00635         GEOMETRY_TO_ORIGIN=0,
00636         ORIGIN_TO_GEOMETRY,
00637         ORIGIN_TO_CURSOR
00638 };
00639 
00640 static int object_origin_set_exec(bContext *C, wmOperator *op)
00641 {
00642         Main *bmain= CTX_data_main(C);
00643         Scene *scene= CTX_data_scene(C);
00644         Object *obedit= CTX_data_edit_object(C);
00645         Object *tob;
00646         float cursor[3], cent[3], cent_neg[3], centn[3], min[3], max[3];
00647         int centermode = RNA_enum_get(op->ptr, "type");
00648         int around = RNA_enum_get(op->ptr, "center"); /* initialized from v3d->around */
00649 
00650         /* keep track of what is changed */
00651         int tot_change=0, tot_lib_error=0, tot_multiuser_arm_error=0;
00652 
00653         if (obedit && centermode != GEOMETRY_TO_ORIGIN) {
00654                 BKE_report(op->reports, RPT_ERROR, "Operation cannot be performed in EditMode");
00655                 return OPERATOR_CANCELLED;
00656         }
00657         else {
00658                 /* get the view settings if 'around' isnt set and the view is available */
00659                 View3D *v3d= CTX_wm_view3d(C);
00660                 copy_v3_v3(cursor, give_cursor(scene, v3d));
00661                 if(v3d && !RNA_property_is_set(op->ptr, "around"))
00662                         around= v3d->around;
00663         }
00664 
00665         zero_v3(cent);
00666 
00667         if(obedit) {
00668                 INIT_MINMAX(min, max);
00669 
00670                 if(obedit->type==OB_MESH) {
00671                         Mesh *me= obedit->data;
00672                         EditMesh *em = BKE_mesh_get_editmesh(me);
00673                         EditVert *eve;
00674 
00675                         if(around==V3D_CENTROID) {
00676                                 int total= 0;
00677                                 for(eve= em->verts.first; eve; eve= eve->next) {
00678                                         total++;
00679                                         add_v3_v3(cent, eve->co);
00680                                 }
00681                                 if(total) {
00682                                         mul_v3_fl(cent, 1.0f/(float)total);
00683                                 }
00684                         }
00685                         else {
00686                                 for(eve= em->verts.first; eve; eve= eve->next) {
00687                                         DO_MINMAX(eve->co, min, max);
00688                                 }
00689                                 mid_v3_v3v3(cent, min, max);
00690                         }
00691 
00692                         if(!is_zero_v3(cent)) {
00693                                 for(eve= em->verts.first; eve; eve= eve->next) {
00694                                         sub_v3_v3(eve->co, cent);
00695                                 }
00696 
00697                                 recalc_editnormals(em);
00698                                 tot_change++;
00699                                 DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
00700                         }
00701                         BKE_mesh_end_editmesh(me, em);
00702                 }
00703         }
00704 
00705         /* reset flags */
00706         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
00707                         ob->flag &= ~OB_DONE;
00708         }
00709         CTX_DATA_END;
00710 
00711         for (tob= bmain->object.first; tob; tob= tob->id.next) {
00712                 if(tob->data)
00713                         ((ID *)tob->data)->flag &= ~LIB_DOIT;
00714                 if(tob->dup_group)
00715                         ((ID *)tob->dup_group)->flag &= ~LIB_DOIT;
00716         }
00717 
00718         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
00719                 if((ob->flag & OB_DONE)==0) {
00720                         int do_inverse_offset = FALSE;
00721                         ob->flag |= OB_DONE;
00722 
00723                         if(centermode == ORIGIN_TO_CURSOR) {
00724                                 copy_v3_v3(cent, cursor);
00725                                 invert_m4_m4(ob->imat, ob->obmat);
00726                                 mul_m4_v3(ob->imat, cent);
00727                         }
00728                         
00729                         if(ob->data == NULL) {
00730                                 /* special support for dupligroups */
00731                                 if((ob->transflag & OB_DUPLIGROUP) && ob->dup_group && (ob->dup_group->id.flag & LIB_DOIT)==0) {
00732                                         if(ob->dup_group->id.lib) {
00733                                                 tot_lib_error++;
00734                                         }
00735                                         else {
00736                                                 if(centermode == ORIGIN_TO_CURSOR) { /* done */ }
00737                                                 else {
00738                                                         /* only bounds support */
00739                                                         INIT_MINMAX(min, max);
00740                                                         minmax_object_duplis(scene, ob, min, max);
00741                                                         mid_v3_v3v3(cent, min, max);
00742                                                         invert_m4_m4(ob->imat, ob->obmat);
00743                                                         mul_m4_v3(ob->imat, cent);
00744                                                 }
00745                                                 
00746                                                 add_v3_v3(ob->dup_group->dupli_ofs, cent);
00747 
00748                                                 tot_change++;
00749                                                 ob->dup_group->id.flag |= LIB_DOIT;
00750                                                 do_inverse_offset= TRUE;
00751                                         }
00752                                 }
00753                         }
00754                         else if (((ID *)ob->data)->lib) {
00755                                 tot_lib_error++;
00756                         }
00757 
00758                         if(obedit==NULL && ob->type==OB_MESH) {
00759                                 Mesh *me= ob->data;
00760 
00761                                 if(centermode == ORIGIN_TO_CURSOR) { /* done */ }
00762                                 else if(around==V3D_CENTROID) { mesh_center_median(me, cent); }
00763                                 else { mesh_center_bounds(me, cent); }
00764 
00765                                 negate_v3_v3(cent_neg, cent);
00766                                 mesh_translate(me, cent_neg, 1);
00767 
00768                                 tot_change++;
00769                                 me->id.flag |= LIB_DOIT;
00770                                 do_inverse_offset= TRUE;
00771                         }
00772                         else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
00773                                 Curve *cu= ob->data;
00774 
00775                                 if(centermode == ORIGIN_TO_CURSOR) { /* done */ }
00776                                 else if(around==V3D_CENTROID) { curve_center_median(cu, cent); }
00777                                 else { curve_center_bounds(cu, cent);   }
00778 
00779                                 /* don't allow Z change if curve is 2D */
00780                                 if((ob->type == OB_CURVE) && !(cu->flag & CU_3D))
00781                                         cent[2] = 0.0;
00782 
00783                                 negate_v3_v3(cent_neg, cent);
00784                                 curve_translate(cu, cent_neg, 1);
00785 
00786                                 tot_change++;
00787                                 cu->id.flag |= LIB_DOIT;
00788                                 do_inverse_offset= TRUE;
00789 
00790                                 if(obedit) {
00791                                         if (centermode == GEOMETRY_TO_ORIGIN) {
00792                                                 DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
00793                                         }
00794                                         break;
00795                                 }
00796                         }
00797                         else if(ob->type==OB_FONT) {
00798                                 /* get from bb */
00799 
00800                                 Curve *cu= ob->data;
00801 
00802                                 if(cu->bb==NULL && (centermode != ORIGIN_TO_CURSOR)) {
00803                                         /* do nothing*/
00804                                 }
00805                                 else {
00806                                         if(centermode == ORIGIN_TO_CURSOR) {
00807                                                 /* done */
00808                                         }
00809                                         else {
00810                                                 cent[0]= 0.5f * ( cu->bb->vec[4][0] + cu->bb->vec[0][0]);
00811                                                 cent[1]= 0.5f * ( cu->bb->vec[0][1] + cu->bb->vec[2][1]) - 0.5f;        /* extra 0.5 is the height o above line */
00812                                         }
00813 
00814                                         cent[2]= 0.0f;
00815 
00816                                         cu->xof= cu->xof - (cent[0] / cu->fsize);
00817                                         cu->yof= cu->yof - (cent[1] / cu->fsize);
00818 
00819                                         tot_change++;
00820                                         cu->id.flag |= LIB_DOIT;
00821                                         do_inverse_offset= TRUE;
00822                                 }
00823                         }
00824                         else if(ob->type==OB_ARMATURE) {
00825                                 bArmature *arm = ob->data;
00826 
00827                                 if(ID_REAL_USERS(arm) > 1) {
00828                                         /*BKE_report(op->reports, RPT_ERROR, "Can't apply to a multi user armature");
00829                                         return;*/
00830                                         tot_multiuser_arm_error++;
00831                                 }
00832                                 else {
00833                                         /* Function to recenter armatures in editarmature.c
00834                                          * Bone + object locations are handled there.
00835                                          */
00836                                         docenter_armature(scene, ob, cursor, centermode, around);
00837 
00838                                         tot_change++;
00839                                         arm->id.flag |= LIB_DOIT;
00840                                         /* do_inverse_offset= TRUE; */ /* docenter_armature() handles this */
00841 
00842                                         where_is_object(scene, ob);
00843                                         where_is_pose(scene, ob); /* needed for bone parents */
00844 
00845                                         ignore_parent_tx(bmain, scene, ob);
00846 
00847                                         if(obedit)
00848                                                 break;
00849                                 }
00850                         }
00851 
00852                         /* offset other selected objects */
00853                         if(do_inverse_offset && (centermode != GEOMETRY_TO_ORIGIN)) {
00854                                 /* was the object data modified
00855                                  * note: the functions above must set 'cent' */
00856                                 copy_v3_v3(centn, cent);
00857                                 mul_mat3_m4_v3(ob->obmat, centn); /* ommit translation part */
00858                                 add_v3_v3(ob->loc, centn);
00859 
00860                                 where_is_object(scene, ob);
00861                                 if(ob->type==OB_ARMATURE) {
00862                                         where_is_pose(scene, ob); /* needed for bone parents */
00863                                 }
00864 
00865                                 ignore_parent_tx(bmain, scene, ob);
00866                                 
00867                                 /* other users? */
00868                                 CTX_DATA_BEGIN(C, Object*, ob_other, selected_editable_objects) {
00869                                         if(             (ob_other->flag & OB_DONE)==0 &&
00870                                                         (       (ob->data && (ob->data == ob_other->data)) ||
00871                                                                 (ob->dup_group==ob_other->dup_group && (ob->transflag|ob_other->transflag) & OB_DUPLIGROUP) )
00872                                         ) {
00873                                                 ob_other->flag |= OB_DONE;
00874                                                 ob_other->recalc= OB_RECALC_OB|OB_RECALC_DATA;
00875 
00876                                                 copy_v3_v3(centn, cent);
00877                                                 mul_mat3_m4_v3(ob_other->obmat, centn); /* ommit translation part */
00878                                                 add_v3_v3(ob_other->loc, centn);
00879 
00880                                                 where_is_object(scene, ob_other);
00881                                                 if(ob_other->type==OB_ARMATURE) {
00882                                                         where_is_pose(scene, ob_other); /* needed for bone parents */
00883                                                 }
00884                                                 ignore_parent_tx(bmain, scene, ob_other);
00885                                         }
00886                                 }
00887                                 CTX_DATA_END;
00888                         }
00889                 }
00890         }
00891         CTX_DATA_END;
00892 
00893         for (tob= bmain->object.first; tob; tob= tob->id.next) {
00894                 if(tob->data && (((ID *)tob->data)->flag & LIB_DOIT)) {
00895                         tob->recalc= OB_RECALC_OB|OB_RECALC_DATA;
00896                 }
00897         }
00898 
00899         if (tot_change) {
00900                 DAG_ids_flush_update(bmain, 0);
00901                 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
00902         }
00903 
00904         /* Warn if any errors occurred */
00905         if (tot_lib_error+tot_multiuser_arm_error) {
00906                 BKE_reportf(op->reports, RPT_WARNING, "%i Object(s) Not Centered, %i Changed:",tot_lib_error+tot_multiuser_arm_error, tot_change);
00907                 if (tot_lib_error)
00908                         BKE_reportf(op->reports, RPT_WARNING, "|%i linked library objects",tot_lib_error);
00909                 if (tot_multiuser_arm_error)
00910                         BKE_reportf(op->reports, RPT_WARNING, "|%i multiuser armature object(s)",tot_multiuser_arm_error);
00911         }
00912 
00913         return OPERATOR_FINISHED;
00914 }
00915 
00916 void OBJECT_OT_origin_set(wmOperatorType *ot)
00917 {
00918         static EnumPropertyItem prop_set_center_types[] = {
00919                 {GEOMETRY_TO_ORIGIN, "GEOMETRY_ORIGIN", 0, "Geometry to Origin", "Move object geometry to object origin"},
00920                 {ORIGIN_TO_GEOMETRY, "ORIGIN_GEOMETRY", 0, "Origin to Geometry", "Move object origin to center of object geometry"},
00921                 {ORIGIN_TO_CURSOR, "ORIGIN_CURSOR", 0, "Origin to 3D Cursor", "Move object origin to position of the 3d cursor"},
00922                 {0, NULL, 0, NULL, NULL}
00923         };
00924         
00925         static EnumPropertyItem prop_set_bounds_types[] = {
00926                 {V3D_CENTROID, "MEDIAN", 0, "Median Center", ""},
00927                 {V3D_CENTER, "BOUNDS", 0, "Bounds Center", ""},
00928                 {0, NULL, 0, NULL, NULL}
00929         };
00930         
00931         /* identifiers */
00932         ot->name= "Set Origin";
00933         ot->description = "Set the object's origin, by either moving the data, or set to center of data, or use 3d cursor";
00934         ot->idname= "OBJECT_OT_origin_set";
00935         
00936         /* api callbacks */
00937         ot->invoke= WM_menu_invoke;
00938         ot->exec= object_origin_set_exec;
00939         
00940         ot->poll= ED_operator_scene_editable;
00941         
00942         /* flags */
00943         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00944         
00945         ot->prop= RNA_def_enum(ot->srna, "type", prop_set_center_types, 0, "Type", "");
00946         RNA_def_enum(ot->srna, "center", prop_set_bounds_types, V3D_CENTROID, "Center", "");
00947 }
00948