Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00019 * All rights reserved. 00020 * 00021 * Contributor(s): Ton Roosendaal, Blender Foundation '05, full recode. 00022 * Joshua Leung 00023 * 00024 * ***** END GPL LICENSE BLOCK ***** 00025 * support for animation modes - Reevan McKay 00026 */ 00027 00033 #include <stdlib.h> 00034 #include <stddef.h> 00035 #include <string.h> 00036 00037 #include "MEM_guardedalloc.h" 00038 00039 #include "BLI_math.h" 00040 #include "BLI_blenlib.h" 00041 #include "BLI_dynstr.h" 00042 #include "BLI_utildefines.h" 00043 00044 #include "DNA_anim_types.h" 00045 #include "DNA_armature_types.h" 00046 #include "DNA_constraint_types.h" 00047 #include "DNA_scene_types.h" 00048 #include "DNA_object_types.h" 00049 00050 #include "BKE_animsys.h" 00051 #include "BKE_anim.h" 00052 #include "BKE_idprop.h" 00053 #include "BKE_action.h" 00054 #include "BKE_armature.h" 00055 #include "BKE_context.h" 00056 #include "BKE_constraint.h" 00057 #include "BKE_deform.h" 00058 #include "BKE_depsgraph.h" 00059 #include "BKE_fcurve.h" 00060 #include "BKE_modifier.h" 00061 #include "BKE_object.h" 00062 #include "BKE_report.h" 00063 00064 00065 #include "RNA_access.h" 00066 #include "RNA_define.h" 00067 #include "RNA_enum_types.h" 00068 00069 #include "WM_api.h" 00070 #include "WM_types.h" 00071 00072 #include "ED_armature.h" 00073 #include "ED_keyframing.h" 00074 #include "ED_mesh.h" 00075 #include "ED_screen.h" 00076 #include "ED_object.h" 00077 00078 #include "UI_interface.h" 00079 #include "UI_resources.h" 00080 00081 #include "armature_intern.h" 00082 00083 /* This function is used to process the necessary updates for */ 00084 void ED_armature_enter_posemode(bContext *C, Base *base) 00085 { 00086 ReportList *reports= CTX_wm_reports(C); 00087 Object *ob= base->object; 00088 00089 if (ob->id.lib) { 00090 BKE_report(reports, RPT_WARNING, "Can't pose libdata"); 00091 return; 00092 } 00093 00094 switch (ob->type) { 00095 case OB_ARMATURE: 00096 ob->restore_mode = ob->mode; 00097 ob->mode |= OB_MODE_POSE; 00098 00099 WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_POSE, NULL); 00100 00101 break; 00102 default: 00103 return; 00104 } 00105 00106 // XXX: disabled as this would otherwise cause a nasty loop... 00107 //ED_object_toggle_modes(C, ob->mode); 00108 } 00109 00110 void ED_armature_exit_posemode(bContext *C, Base *base) 00111 { 00112 if(base) { 00113 Object *ob= base->object; 00114 00115 ob->restore_mode = ob->mode; 00116 ob->mode &= ~OB_MODE_POSE; 00117 00118 WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, NULL); 00119 } 00120 } 00121 00122 /* if a selected or active bone is protected, throw error (oonly if warn==1) and return 1 */ 00123 /* only_selected==1 : the active bone is allowed to be protected */ 00124 #if 0 /* UNUSED 2.5 */ 00125 static short pose_has_protected_selected(Object *ob, short warn) 00126 { 00127 /* check protection */ 00128 if (ob->proxy) { 00129 bPoseChannel *pchan; 00130 bArmature *arm= ob->data; 00131 00132 for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { 00133 if (pchan->bone && (pchan->bone->layer & arm->layer)) { 00134 if (pchan->bone->layer & arm->layer_protected) { 00135 if (pchan->bone->flag & BONE_SELECTED) 00136 break; 00137 } 00138 } 00139 } 00140 if (pchan) { 00141 if (warn) error("Cannot change Proxy protected bones"); 00142 return 1; 00143 } 00144 } 00145 return 0; 00146 } 00147 #endif 00148 00149 /* only for real IK, not for auto-IK */ 00150 static int pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan, int level) 00151 { 00152 bConstraint *con; 00153 Bone *bone; 00154 00155 /* No need to check if constraint is active (has influence), 00156 * since all constraints with CONSTRAINT_IK_AUTO are active */ 00157 for(con= pchan->constraints.first; con; con= con->next) { 00158 if(con->type==CONSTRAINT_TYPE_KINEMATIC) { 00159 bKinematicConstraint *data= con->data; 00160 if(data->rootbone == 0 || data->rootbone > level) { 00161 if((data->flag & CONSTRAINT_IK_AUTO)==0) 00162 return 1; 00163 } 00164 } 00165 } 00166 for(bone= pchan->bone->childbase.first; bone; bone= bone->next) { 00167 pchan= get_pose_channel(ob->pose, bone->name); 00168 if(pchan && pose_channel_in_IK_chain(ob, pchan, level + 1)) 00169 return 1; 00170 } 00171 return 0; 00172 } 00173 00174 int ED_pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan) 00175 { 00176 return pose_channel_in_IK_chain(ob, pchan, 0); 00177 } 00178 00179 /* ********************************************** */ 00180 /* Motion Paths */ 00181 00182 /* For the object with pose/action: update paths for those that have got them 00183 * This should selectively update paths that exist... 00184 * 00185 * To be called from various tools that do incremental updates 00186 */ 00187 void ED_pose_recalculate_paths(Scene *scene, Object *ob) 00188 { 00189 ListBase targets = {NULL, NULL}; 00190 00191 /* set flag to force recalc, then grab the relevant bones to target */ 00192 ob->pose->avs.recalc |= ANIMVIZ_RECALC_PATHS; 00193 animviz_get_object_motionpaths(ob, &targets); 00194 00195 /* recalculate paths, then free */ 00196 animviz_calc_motionpaths(scene, &targets); 00197 BLI_freelistN(&targets); 00198 } 00199 00200 /* For the object with pose/action: create path curves for selected bones 00201 * This recalculates the WHOLE path within the pchan->pathsf and pchan->pathef range 00202 */ 00203 static int pose_calculate_paths_exec (bContext *C, wmOperator *op) 00204 { 00205 ScrArea *sa= CTX_wm_area(C); 00206 Scene *scene= CTX_data_scene(C); 00207 Object *ob; 00208 00209 /* since this call may also be used from the buttons window, we need to check for where to get the object */ 00210 if (sa->spacetype == SPACE_BUTS) 00211 ob= ED_object_context(C); 00212 else 00213 ob= object_pose_armature_get(CTX_data_active_object(C)); 00214 00215 if (ELEM(NULL, ob, ob->pose)) 00216 return OPERATOR_CANCELLED; 00217 00218 /* set up path data for bones being calculated */ 00219 CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) 00220 { 00221 /* verify makes sure that the selected bone has a bone with the appropriate settings */ 00222 animviz_verify_motionpaths(op->reports, scene, ob, pchan); 00223 } 00224 CTX_DATA_END; 00225 00226 /* calculate the bones that now have motionpaths... */ 00227 // TODO: only make for the selected bones? 00228 ED_pose_recalculate_paths(scene, ob); 00229 00230 /* notifiers for updates */ 00231 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob); 00232 00233 return OPERATOR_FINISHED; 00234 } 00235 00236 void POSE_OT_paths_calculate (wmOperatorType *ot) 00237 { 00238 /* identifiers */ 00239 ot->name= "Calculate Bone Paths"; 00240 ot->idname= "POSE_OT_paths_calculate"; 00241 ot->description= "Calculate paths for the selected bones"; 00242 00243 /* api callbacks */ 00244 ot->exec= pose_calculate_paths_exec; 00245 ot->poll= ED_operator_posemode; 00246 00247 /* flags */ 00248 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00249 } 00250 00251 /* --------- */ 00252 00253 /* for the object with pose/action: clear path curves for selected bones only */ 00254 static void ED_pose_clear_paths(Object *ob) 00255 { 00256 bPoseChannel *pchan; 00257 short skipped = 0; 00258 00259 if ELEM(NULL, ob, ob->pose) 00260 return; 00261 00262 /* free the motionpath blocks, but also take note of whether we skipped some... */ 00263 for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { 00264 if (pchan->mpath) { 00265 if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) { 00266 animviz_free_motionpath(pchan->mpath); 00267 pchan->mpath= NULL; 00268 } 00269 else 00270 skipped = 1; 00271 } 00272 } 00273 00274 /* if we didn't skip any, we shouldn't have any paths left */ 00275 if (skipped == 0) 00276 ob->pose->avs.path_bakeflag &= ~MOTIONPATH_BAKE_HAS_PATHS; 00277 } 00278 00279 /* operator callback for this */ 00280 static int pose_clear_paths_exec (bContext *C, wmOperator *UNUSED(op)) 00281 { 00282 ScrArea *sa= CTX_wm_area(C); 00283 Object *ob; 00284 00285 /* since this call may also be used from the buttons window, we need to check for where to get the object */ 00286 if (sa->spacetype == SPACE_BUTS) 00287 ob= ED_object_context(C); 00288 else 00289 ob= object_pose_armature_get(CTX_data_active_object(C)); 00290 00291 /* only continue if there's an object */ 00292 if ELEM(NULL, ob, ob->pose) 00293 return OPERATOR_CANCELLED; 00294 00295 /* use the backend function for this */ 00296 ED_pose_clear_paths(ob); 00297 00298 /* notifiers for updates */ 00299 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob); 00300 00301 return OPERATOR_FINISHED; 00302 } 00303 00304 void POSE_OT_paths_clear (wmOperatorType *ot) 00305 { 00306 /* identifiers */ 00307 ot->name= "Clear Bone Paths"; 00308 ot->idname= "POSE_OT_paths_clear"; 00309 ot->description= "Clear path caches for selected bones"; 00310 00311 /* api callbacks */ 00312 ot->exec= pose_clear_paths_exec; 00313 ot->poll= ED_operator_posemode; 00314 00315 /* flags */ 00316 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; 00317 } 00318 00319 /* ******************* Select Constraint Target Operator ************* */ 00320 00321 static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op)) 00322 { 00323 Object *ob= object_pose_armature_get(CTX_data_active_object(C)); 00324 bConstraint *con; 00325 int found= 0; 00326 00327 CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) 00328 { 00329 if (pchan->bone->flag & BONE_SELECTED) { 00330 for (con= pchan->constraints.first; con; con= con->next) { 00331 bConstraintTypeInfo *cti= constraint_get_typeinfo(con); 00332 ListBase targets = {NULL, NULL}; 00333 bConstraintTarget *ct; 00334 00335 if (cti && cti->get_constraint_targets) { 00336 cti->get_constraint_targets(con, &targets); 00337 00338 for (ct= targets.first; ct; ct= ct->next) { 00339 if ((ct->tar == ob) && (ct->subtarget[0])) { 00340 bPoseChannel *pchanc= get_pose_channel(ob->pose, ct->subtarget); 00341 if((pchanc) && !(pchanc->bone->flag & BONE_UNSELECTABLE)) { 00342 pchanc->bone->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL; 00343 found= 1; 00344 } 00345 } 00346 } 00347 00348 if (cti->flush_constraint_targets) 00349 cti->flush_constraint_targets(con, &targets, 1); 00350 } 00351 } 00352 } 00353 } 00354 CTX_DATA_END; 00355 00356 if (!found) 00357 return OPERATOR_CANCELLED; 00358 00359 WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, ob); 00360 00361 return OPERATOR_FINISHED; 00362 } 00363 00364 void POSE_OT_select_constraint_target(wmOperatorType *ot) 00365 { 00366 /* identifiers */ 00367 ot->name= "Select Constraint Target"; 00368 ot->idname= "POSE_OT_select_constraint_target"; 00369 ot->description= "Select bones used as targets for the currently selected bones"; 00370 00371 /* api callbacks */ 00372 ot->exec= pose_select_constraint_target_exec; 00373 ot->poll= ED_operator_posemode; 00374 00375 /* flags */ 00376 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00377 } 00378 00379 /* ******************* select hierarchy operator ************* */ 00380 00381 static int pose_select_hierarchy_exec(bContext *C, wmOperator *op) 00382 { 00383 Object *ob= object_pose_armature_get(CTX_data_active_object(C)); 00384 bArmature *arm= ob->data; 00385 Bone *curbone, *pabone, *chbone; 00386 int direction = RNA_enum_get(op->ptr, "direction"); 00387 int add_to_sel = RNA_boolean_get(op->ptr, "extend"); 00388 int found= 0; 00389 00390 CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) 00391 { 00392 curbone= pchan->bone; 00393 00394 if ((curbone->flag & BONE_UNSELECTABLE)==0) { 00395 if (curbone == arm->act_bone) { 00396 if (direction == BONE_SELECT_PARENT) { 00397 if (pchan->parent == NULL) continue; 00398 else pabone= pchan->parent->bone; 00399 00400 if (PBONE_VISIBLE(arm, pabone)) { 00401 if (!add_to_sel) curbone->flag &= ~BONE_SELECTED; 00402 pabone->flag |= BONE_SELECTED; 00403 arm->act_bone= pabone; 00404 00405 found= 1; 00406 break; 00407 } 00408 } 00409 else { /* direction == BONE_SELECT_CHILD */ 00410 if (pchan->child == NULL) continue; 00411 else chbone = pchan->child->bone; 00412 00413 if (PBONE_VISIBLE(arm, chbone)) { 00414 if (!add_to_sel) curbone->flag &= ~BONE_SELECTED; 00415 chbone->flag |= BONE_SELECTED; 00416 arm->act_bone= chbone; 00417 00418 found= 1; 00419 break; 00420 } 00421 } 00422 } 00423 } 00424 } 00425 CTX_DATA_END; 00426 00427 if (found == 0) 00428 return OPERATOR_CANCELLED; 00429 00430 WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, ob); 00431 00432 return OPERATOR_FINISHED; 00433 } 00434 00435 void POSE_OT_select_hierarchy(wmOperatorType *ot) 00436 { 00437 static EnumPropertyItem direction_items[]= { 00438 {BONE_SELECT_PARENT, "PARENT", 0, "Select Parent", ""}, 00439 {BONE_SELECT_CHILD, "CHILD", 0, "Select Child", ""}, 00440 {0, NULL, 0, NULL, NULL} 00441 }; 00442 00443 /* identifiers */ 00444 ot->name= "Select Hierarchy"; 00445 ot->idname= "POSE_OT_select_hierarchy"; 00446 ot->description= "Select immediate parent/children of selected bones"; 00447 00448 /* api callbacks */ 00449 ot->exec= pose_select_hierarchy_exec; 00450 ot->poll= ED_operator_posemode; 00451 00452 /* flags */ 00453 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00454 00455 /* props */ 00456 ot->prop= RNA_def_enum(ot->srna, "direction", direction_items, BONE_SELECT_PARENT, "Direction", ""); 00457 RNA_def_boolean(ot->srna, "extend", 0, "Add to Selection", ""); 00458 00459 } 00460 00461 /* ******************* select grouped operator ************* */ 00462 00463 static short pose_select_same_group (bContext *C, Object *ob, short extend) 00464 { 00465 bArmature *arm= (ob)? ob->data : NULL; 00466 bPose *pose= (ob)? ob->pose : NULL; 00467 char *group_flags; 00468 int numGroups = 0; 00469 short changed=0, tagged=0; 00470 00471 /* sanity checks */ 00472 if (ELEM3(NULL, ob, pose, arm)) 00473 return 0; 00474 00475 /* count the number of groups */ 00476 numGroups= BLI_countlist(&pose->agroups); 00477 if (numGroups == 0) 00478 return 0; 00479 00480 /* alloc a small array to keep track of the groups to use 00481 * - each cell stores on/off state for whether group should be used 00482 * - size is numGroups + 1, since index=0 is used for no-group 00483 */ 00484 group_flags= MEM_callocN(numGroups+1, "pose_select_same_group"); 00485 00486 CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) 00487 { 00488 /* keep track of group as group to use later? */ 00489 if (pchan->bone->flag & BONE_SELECTED) { 00490 group_flags[pchan->agrp_index] = 1; 00491 tagged= 1; 00492 } 00493 00494 /* deselect all bones before selecting new ones? */ 00495 if ((extend == 0) && (pchan->bone->flag & BONE_UNSELECTABLE)==0) 00496 pchan->bone->flag &= ~BONE_SELECTED; 00497 } 00498 CTX_DATA_END; 00499 00500 /* small optimisation: only loop through bones a second time if there are any groups tagged */ 00501 if (tagged) { 00502 /* only if group matches (and is not selected or current bone) */ 00503 CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) 00504 { 00505 if ((pchan->bone->flag & BONE_UNSELECTABLE)==0) { 00506 /* check if the group used by this bone is counted */ 00507 if (group_flags[pchan->agrp_index]) { 00508 pchan->bone->flag |= BONE_SELECTED; 00509 changed= 1; 00510 } 00511 } 00512 } 00513 CTX_DATA_END; 00514 } 00515 00516 /* free temp info */ 00517 MEM_freeN(group_flags); 00518 00519 return changed; 00520 } 00521 00522 static short pose_select_same_layer (bContext *C, Object *ob, short extend) 00523 { 00524 bPose *pose= (ob)? ob->pose : NULL; 00525 bArmature *arm= (ob)? ob->data : NULL; 00526 short changed= 0; 00527 int layers= 0; 00528 00529 if (ELEM3(NULL, ob, pose, arm)) 00530 return 0; 00531 00532 /* figure out what bones are selected */ 00533 CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) 00534 { 00535 /* keep track of layers to use later? */ 00536 if (pchan->bone->flag & BONE_SELECTED) 00537 layers |= pchan->bone->layer; 00538 00539 /* deselect all bones before selecting new ones? */ 00540 if ((extend == 0) && (pchan->bone->flag & BONE_UNSELECTABLE)==0) 00541 pchan->bone->flag &= ~BONE_SELECTED; 00542 } 00543 CTX_DATA_END; 00544 if (layers == 0) 00545 return 0; 00546 00547 /* select bones that are on same layers as layers flag */ 00548 CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) 00549 { 00550 /* if bone is on a suitable layer, and the bone can have its selection changed, select it */ 00551 if ((layers & pchan->bone->layer) && (pchan->bone->flag & BONE_UNSELECTABLE)==0) { 00552 pchan->bone->flag |= BONE_SELECTED; 00553 changed= 1; 00554 } 00555 } 00556 CTX_DATA_END; 00557 00558 return changed; 00559 } 00560 00561 static int pose_select_same_keyingset(bContext *C, Object *ob, short extend) 00562 { 00563 KeyingSet *ks = ANIM_scene_get_active_keyingset(CTX_data_scene(C)); 00564 KS_Path *ksp; 00565 00566 bArmature *arm = (ob)? ob->data : NULL; 00567 bPose *pose= (ob)? ob->pose : NULL; 00568 short changed= 0; 00569 00570 /* sanity checks: validate Keying Set and object */ 00571 if ((ks == NULL) || (ANIM_validate_keyingset(C, NULL, ks) != 0)) 00572 return 0; 00573 00574 if (ELEM3(NULL, ob, pose, arm)) 00575 return 0; 00576 00577 /* if not extending selection, deselect all selected first */ 00578 if (extend == 0) { 00579 CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) 00580 { 00581 if ((pchan->bone->flag & BONE_UNSELECTABLE)==0) 00582 pchan->bone->flag &= ~BONE_SELECTED; 00583 } 00584 CTX_DATA_END; 00585 } 00586 00587 /* iterate over elements in the Keying Set, setting selection depending on whether 00588 * that bone is visible or not... 00589 */ 00590 for (ksp = ks->paths.first; ksp; ksp = ksp->next) { 00591 /* only items related to this object will be relevant */ 00592 if ((ksp->id == &ob->id) && (ksp->rna_path != NULL)) { 00593 if (strstr(ksp->rna_path, "bones")) { 00594 char *boneName = BLI_getQuotedStr(ksp->rna_path, "bones["); 00595 00596 if (boneName) { 00597 bPoseChannel *pchan = get_pose_channel(pose, boneName); 00598 00599 if (pchan) { 00600 /* select if bone is visible and can be affected */ 00601 if ((PBONE_VISIBLE(arm, pchan->bone)) && 00602 (pchan->bone->flag & BONE_UNSELECTABLE)==0) 00603 { 00604 pchan->bone->flag |= BONE_SELECTED; 00605 changed = 1; 00606 } 00607 } 00608 00609 /* free temp memory */ 00610 MEM_freeN(boneName); 00611 } 00612 } 00613 } 00614 } 00615 00616 return changed; 00617 } 00618 00619 static int pose_select_grouped_exec (bContext *C, wmOperator *op) 00620 { 00621 Object *ob= object_pose_armature_get(CTX_data_active_object(C)); 00622 short extend= RNA_boolean_get(op->ptr, "extend"); 00623 short changed = 0; 00624 00625 /* sanity check */ 00626 if (ELEM(NULL, ob, ob->pose)) 00627 return OPERATOR_CANCELLED; 00628 00629 /* selection types 00630 * NOTE: for the order of these, see the enum in POSE_OT_select_grouped() 00631 */ 00632 switch (RNA_enum_get(op->ptr, "type")) { 00633 case 1: /* group */ 00634 changed= pose_select_same_group(C, ob, extend); 00635 break; 00636 case 2: /* Keying Set */ 00637 changed= pose_select_same_keyingset(C, ob, extend); 00638 break; 00639 default: /* layer */ 00640 changed= pose_select_same_layer(C, ob, extend); 00641 break; 00642 } 00643 00644 /* notifiers for updates */ 00645 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob); 00646 00647 /* report done status */ 00648 if (changed) 00649 return OPERATOR_FINISHED; 00650 else 00651 return OPERATOR_CANCELLED; 00652 } 00653 00654 void POSE_OT_select_grouped (wmOperatorType *ot) 00655 { 00656 static EnumPropertyItem prop_select_grouped_types[] = { 00657 {0, "LAYER", 0, "Layer", "Shared layers"}, 00658 {1, "GROUP", 0, "Group", "Shared group"}, 00659 {2, "KEYINGSET", 0, "Keying Set", "All bones affected by active Keying Set"}, 00660 {0, NULL, 0, NULL, NULL} 00661 }; 00662 00663 /* identifiers */ 00664 ot->name= "Select Grouped"; 00665 ot->description = "Select all visible bones grouped by similar properties"; 00666 ot->idname= "POSE_OT_select_grouped"; 00667 00668 /* api callbacks */ 00669 ot->invoke= WM_menu_invoke; 00670 ot->exec= pose_select_grouped_exec; 00671 ot->poll= ED_operator_posemode; 00672 00673 /* flags */ 00674 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00675 00676 /* properties */ 00677 RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first"); 00678 ot->prop= RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", ""); 00679 } 00680 00681 00682 /* ********************************************** */ 00683 00684 /* context active object, or weightpainted object with armature in posemode */ 00685 static int pose_bone_flip_active_exec (bContext *C, wmOperator *UNUSED(op)) 00686 { 00687 Object *ob_act= CTX_data_active_object(C); 00688 Object *ob= object_pose_armature_get(ob_act); 00689 00690 if(ob && (ob->mode & OB_MODE_POSE)) { 00691 bArmature *arm= ob->data; 00692 00693 if(arm->act_bone) { 00694 bPoseChannel *pchanf; 00695 char name[MAXBONENAME]; 00696 flip_side_name(name, arm->act_bone->name, TRUE); 00697 00698 pchanf= get_pose_channel(ob->pose, name); 00699 if(pchanf && pchanf->bone != arm->act_bone) { 00700 arm->act_bone->flag &= ~BONE_SELECTED; 00701 pchanf->bone->flag |= BONE_SELECTED; 00702 00703 arm->act_bone= pchanf->bone; 00704 00705 /* in weightpaint we select the associated vertex group too */ 00706 if(ob_act->mode & OB_MODE_WEIGHT_PAINT) { 00707 ED_vgroup_select_by_name(ob_act, name); 00708 DAG_id_tag_update(&ob_act->id, OB_RECALC_DATA); 00709 } 00710 00711 WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, ob); 00712 00713 return OPERATOR_FINISHED; 00714 } 00715 } 00716 } 00717 00718 return OPERATOR_CANCELLED; 00719 } 00720 00721 void POSE_OT_select_flip_active(wmOperatorType *ot) 00722 { 00723 /* identifiers */ 00724 ot->name= "Flip Selected Active Bone"; 00725 ot->idname= "POSE_OT_select_flip_active"; 00726 ot->description= "Activate the bone with a flipped name"; 00727 00728 /* api callbacks */ 00729 ot->exec= pose_bone_flip_active_exec; 00730 ot->poll= ED_operator_posemode; 00731 00732 /* flags */ 00733 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; 00734 } 00735 00736 00737 /* ********************************************** */ 00738 #if 0 /* UNUSED 2.5 */ 00739 static void pose_copy_menu(Scene *scene) 00740 { 00741 Object *obedit= scene->obedit; // XXX context 00742 Object *ob= OBACT; 00743 bArmature *arm; 00744 bPoseChannel *pchan, *pchanact; 00745 short nr=0; 00746 int i=0; 00747 00748 /* paranoia checks */ 00749 if (ELEM(NULL, ob, ob->pose)) return; 00750 if ((ob==obedit) || (ob->mode & OB_MODE_POSE)==0) return; 00751 00752 pchan= get_active_posechannel(ob); 00753 00754 if (pchan==NULL) return; 00755 pchanact= pchan; 00756 arm= ob->data; 00757 00758 /* if proxy-protected bones selected, some things (such as locks + displays) shouldn't be changable, 00759 * but for constraints (just add local constraints) 00760 */ 00761 if (pose_has_protected_selected(ob, 0)) { 00762 i= BLI_countlist(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */ 00763 if (i < 25) 00764 nr= pupmenu("Copy Pose Attributes %t|Local Location%x1|Local Rotation%x2|Local Size%x3|%l|Visual Location %x9|Visual Rotation%x10|Visual Size%x11|%l|Constraints (All)%x4|Constraints...%x5"); 00765 else 00766 nr= pupmenu("Copy Pose Attributes %t|Local Location%x1|Local Rotation%x2|Local Size%x3|%l|Visual Location %x9|Visual Rotation%x10|Visual Size%x11|%l|Constraints (All)%x4"); 00767 } 00768 else { 00769 i= BLI_countlist(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */ 00770 if (i < 25) 00771 nr= pupmenu("Copy Pose Attributes %t|Local Location%x1|Local Rotation%x2|Local Size%x3|%l|Visual Location %x9|Visual Rotation%x10|Visual Size%x11|%l|Constraints (All)%x4|Constraints...%x5|%l|Transform Locks%x6|IK Limits%x7|Bone Shape%x8"); 00772 else 00773 nr= pupmenu("Copy Pose Attributes %t|Local Location%x1|Local Rotation%x2|Local Size%x3|%l|Visual Location %x9|Visual Rotation%x10|Visual Size%x11|%l|Constraints (All)%x4|%l|Transform Locks%x6|IK Limits%x7|Bone Shape%x8"); 00774 } 00775 00776 if (nr <= 0) 00777 return; 00778 00779 if (nr != 5) { 00780 for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { 00781 if ( (arm->layer & pchan->bone->layer) && 00782 (pchan->bone->flag & BONE_SELECTED) && 00783 (pchan != pchanact) ) 00784 { 00785 switch (nr) { 00786 case 1: /* Local Location */ 00787 copy_v3_v3(pchan->loc, pchanact->loc); 00788 break; 00789 case 2: /* Local Rotation */ 00790 copy_qt_qt(pchan->quat, pchanact->quat); 00791 copy_v3_v3(pchan->eul, pchanact->eul); 00792 break; 00793 case 3: /* Local Size */ 00794 copy_v3_v3(pchan->size, pchanact->size); 00795 break; 00796 case 4: /* All Constraints */ 00797 { 00798 ListBase tmp_constraints = {NULL, NULL}; 00799 00800 /* copy constraints to tmpbase and apply 'local' tags before 00801 * appending to list of constraints for this channel 00802 */ 00803 copy_constraints(&tmp_constraints, &pchanact->constraints, TRUE); 00804 if ((ob->proxy) && (pchan->bone->layer & arm->layer_protected)) { 00805 bConstraint *con; 00806 00807 /* add proxy-local tags */ 00808 for (con= tmp_constraints.first; con; con= con->next) 00809 con->flag |= CONSTRAINT_PROXY_LOCAL; 00810 } 00811 BLI_movelisttolist(&pchan->constraints, &tmp_constraints); 00812 00813 /* update flags (need to add here, not just copy) */ 00814 pchan->constflag |= pchanact->constflag; 00815 00816 if (ob->pose) 00817 ob->pose->flag |= POSE_RECALC; 00818 } 00819 break; 00820 case 6: /* Transform Locks */ 00821 pchan->protectflag = pchanact->protectflag; 00822 break; 00823 case 7: /* IK (DOF) settings */ 00824 { 00825 pchan->ikflag = pchanact->ikflag; 00826 copy_v3_v3(pchan->limitmin, pchanact->limitmin); 00827 copy_v3_v3(pchan->limitmax, pchanact->limitmax); 00828 copy_v3_v3(pchan->stiffness, pchanact->stiffness); 00829 pchan->ikstretch= pchanact->ikstretch; 00830 pchan->ikrotweight= pchanact->ikrotweight; 00831 pchan->iklinweight= pchanact->iklinweight; 00832 } 00833 break; 00834 case 8: /* Custom Bone Shape */ 00835 pchan->custom = pchanact->custom; 00836 break; 00837 case 9: /* Visual Location */ 00838 armature_loc_pose_to_bone(pchan, pchanact->pose_mat[3], pchan->loc); 00839 break; 00840 case 10: /* Visual Rotation */ 00841 { 00842 float delta_mat[4][4]; 00843 00844 armature_mat_pose_to_bone(pchan, pchanact->pose_mat, delta_mat); 00845 00846 if (pchan->rotmode == ROT_MODE_AXISANGLE) { 00847 float tmp_quat[4]; 00848 00849 /* need to convert to quat first (in temp var)... */ 00850 mat4_to_quat( tmp_quat,delta_mat); 00851 quat_to_axis_angle( pchan->rotAxis, &pchan->rotAngle,tmp_quat); 00852 } 00853 else if (pchan->rotmode == ROT_MODE_QUAT) 00854 mat4_to_quat( pchan->quat,delta_mat); 00855 else 00856 mat4_to_eulO( pchan->eul, pchan->rotmode,delta_mat); 00857 } 00858 break; 00859 case 11: /* Visual Size */ 00860 { 00861 float delta_mat[4][4], size[4]; 00862 00863 armature_mat_pose_to_bone(pchan, pchanact->pose_mat, delta_mat); 00864 mat4_to_size( size,delta_mat); 00865 copy_v3_v3(pchan->size, size); 00866 } 00867 } 00868 } 00869 } 00870 } 00871 else { /* constraints, optional (note: max we can have is 24 constraints) */ 00872 bConstraint *con, *con_back; 00873 int const_toggle[24]= {0}; /* XXX, initialize as 0 to quiet errors */ 00874 ListBase const_copy = {NULL, NULL}; 00875 00876 BLI_duplicatelist(&const_copy, &(pchanact->constraints)); 00877 00878 /* build the puplist of constraints */ 00879 for (con = pchanact->constraints.first, i=0; con; con=con->next, i++){ 00880 const_toggle[i]= 1; 00881 // add_numbut(i, TOG|INT, con->name, 0, 0, &(const_toggle[i]), ""); 00882 } 00883 00884 // if (!do_clever_numbuts("Select Constraints", i, REDRAW)) { 00885 // BLI_freelistN(&const_copy); 00886 // return; 00887 // } 00888 00889 /* now build a new listbase from the options selected */ 00890 for (i=0, con=const_copy.first; con; i++) { 00891 /* if not selected, free/remove it from the list */ 00892 if (!const_toggle[i]) { 00893 con_back= con->next; 00894 BLI_freelinkN(&const_copy, con); 00895 con= con_back; 00896 } 00897 else 00898 con= con->next; 00899 } 00900 00901 /* Copy the temo listbase to the selected posebones */ 00902 for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { 00903 if ( (arm->layer & pchan->bone->layer) && 00904 (pchan->bone->flag & BONE_SELECTED) && 00905 (pchan!=pchanact) ) 00906 { 00907 ListBase tmp_constraints = {NULL, NULL}; 00908 00909 /* copy constraints to tmpbase and apply 'local' tags before 00910 * appending to list of constraints for this channel 00911 */ 00912 copy_constraints(&tmp_constraints, &const_copy, TRUE); 00913 if ((ob->proxy) && (pchan->bone->layer & arm->layer_protected)) { 00914 /* add proxy-local tags */ 00915 for (con= tmp_constraints.first; con; con= con->next) 00916 con->flag |= CONSTRAINT_PROXY_LOCAL; 00917 } 00918 BLI_movelisttolist(&pchan->constraints, &tmp_constraints); 00919 00920 /* update flags (need to add here, not just copy) */ 00921 pchan->constflag |= pchanact->constflag; 00922 } 00923 } 00924 BLI_freelistN(&const_copy); 00925 update_pose_constraint_flags(ob->pose); /* we could work out the flags but its simpler to do this */ 00926 00927 if (ob->pose) 00928 ob->pose->flag |= POSE_RECALC; 00929 } 00930 00931 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); // and all its relations 00932 00933 BIF_undo_push("Copy Pose Attributes"); 00934 00935 } 00936 #endif 00937 00938 /* ******************** copy/paste pose ********************** */ 00939 00940 /* Global copy/paste buffer for pose - cleared on start/end session + before every copy operation */ 00941 static bPose *g_posebuf = NULL; 00942 00943 void free_posebuf(void) 00944 { 00945 if (g_posebuf) { 00946 bPoseChannel *pchan; 00947 00948 for (pchan= g_posebuf->chanbase.first; pchan; pchan= pchan->next) { 00949 if(pchan->prop) { 00950 IDP_FreeProperty(pchan->prop); 00951 MEM_freeN(pchan->prop); 00952 } 00953 } 00954 00955 /* was copied without constraints */ 00956 BLI_freelistN(&g_posebuf->chanbase); 00957 MEM_freeN(g_posebuf); 00958 } 00959 00960 g_posebuf=NULL; 00961 } 00962 00963 /* This function is used to indicate that a bone is selected 00964 * and needs to be included in copy buffer (used to be for inserting keys) 00965 */ 00966 static void set_pose_keys (Object *ob) 00967 { 00968 bArmature *arm= ob->data; 00969 bPoseChannel *chan; 00970 00971 if (ob->pose){ 00972 for (chan=ob->pose->chanbase.first; chan; chan=chan->next){ 00973 Bone *bone= chan->bone; 00974 if ((bone) && (bone->flag & BONE_SELECTED) && (arm->layer & bone->layer)) 00975 chan->flag |= POSE_KEY; 00976 else 00977 chan->flag &= ~POSE_KEY; 00978 } 00979 } 00980 } 00981 00982 /* perform paste pose, for a single bone 00983 * < ob: object where bone to paste to lives 00984 * < chan: bone that pose to paste comes from 00985 * < selOnly: only paste on selected bones 00986 * < flip: flip on x-axis 00987 * 00988 * > returns: whether the bone that we pasted to if we succeeded 00989 */ 00990 static bPoseChannel *pose_bone_do_paste (Object *ob, bPoseChannel *chan, short selOnly, short flip) 00991 { 00992 bPoseChannel *pchan; 00993 char name[MAXBONENAME]; 00994 short paste_ok; 00995 00996 /* get the name - if flipping, we must flip this first */ 00997 if (flip) 00998 flip_side_name(name, chan->name, 0); /* 0 = don't strip off number extensions */ 00999 else 01000 BLI_strncpy(name, chan->name, sizeof(name)); 01001 01002 /* only copy when: 01003 * 1) channel exists - poses are not meant to add random channels to anymore 01004 * 2) if selection-masking is on, channel is selected - only selected bones get pasted on, allowing making both sides symmetrical 01005 */ 01006 pchan= get_pose_channel(ob->pose, name); 01007 01008 if (selOnly) 01009 paste_ok= ((pchan) && (pchan->bone->flag & BONE_SELECTED)); 01010 else 01011 paste_ok= ((pchan != NULL)); 01012 01013 /* continue? */ 01014 if (paste_ok) { 01015 /* only loc rot size 01016 * - only copies transform info for the pose 01017 */ 01018 copy_v3_v3(pchan->loc, chan->loc); 01019 copy_v3_v3(pchan->size, chan->size); 01020 pchan->flag= chan->flag; 01021 01022 /* check if rotation modes are compatible (i.e. do they need any conversions) */ 01023 if (pchan->rotmode == chan->rotmode) { 01024 /* copy the type of rotation in use */ 01025 if (pchan->rotmode > 0) { 01026 copy_v3_v3(pchan->eul, chan->eul); 01027 } 01028 else if (pchan->rotmode == ROT_MODE_AXISANGLE) { 01029 copy_v3_v3(pchan->rotAxis, chan->rotAxis); 01030 pchan->rotAngle = chan->rotAngle; 01031 } 01032 else { 01033 copy_qt_qt(pchan->quat, chan->quat); 01034 } 01035 } 01036 else if (pchan->rotmode > 0) { 01037 /* quat/axis-angle to euler */ 01038 if (chan->rotmode == ROT_MODE_AXISANGLE) 01039 axis_angle_to_eulO( pchan->eul, pchan->rotmode,chan->rotAxis, chan->rotAngle); 01040 else 01041 quat_to_eulO( pchan->eul, pchan->rotmode,chan->quat); 01042 } 01043 else if (pchan->rotmode == ROT_MODE_AXISANGLE) { 01044 /* quat/euler to axis angle */ 01045 if (chan->rotmode > 0) 01046 eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->eul, chan->rotmode); 01047 else 01048 quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->quat); 01049 } 01050 else { 01051 /* euler/axis-angle to quat */ 01052 if (chan->rotmode > 0) 01053 eulO_to_quat(pchan->quat, chan->eul, chan->rotmode); 01054 else 01055 axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle); 01056 } 01057 01058 /* paste flipped pose? */ 01059 if (flip) { 01060 pchan->loc[0]*= -1; 01061 01062 /* has to be done as eulers... */ 01063 if (pchan->rotmode > 0) { 01064 pchan->eul[1] *= -1; 01065 pchan->eul[2] *= -1; 01066 } 01067 else if (pchan->rotmode == ROT_MODE_AXISANGLE) { 01068 float eul[3]; 01069 01070 axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle); 01071 eul[1]*= -1; 01072 eul[2]*= -1; 01073 eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT); 01074 } 01075 else { 01076 float eul[3]; 01077 01078 normalize_qt(pchan->quat); 01079 quat_to_eul(eul, pchan->quat); 01080 eul[1]*= -1; 01081 eul[2]*= -1; 01082 eul_to_quat(pchan->quat, eul); 01083 } 01084 } 01085 01086 /* ID properties */ 01087 if (chan->prop) { 01088 if (pchan->prop) { 01089 /* if we have existing properties on a bone, just copy over the values of 01090 * matching properties (i.e. ones which will have some impact) on to the 01091 * target instead of just blinding replacing all [ 01092 */ 01093 IDP_SyncGroupValues(pchan->prop, chan->prop); 01094 } 01095 else { 01096 /* no existing properties, so assume that we want copies too? */ 01097 pchan->prop= IDP_CopyProperty(chan->prop); 01098 } 01099 } 01100 } 01101 01102 /* return whether paste went ahead */ 01103 return pchan; 01104 } 01105 01106 /* ---- */ 01107 01108 static int pose_copy_exec (bContext *C, wmOperator *op) 01109 { 01110 Object *ob= object_pose_armature_get(CTX_data_active_object(C)); 01111 01112 /* sanity checking */ 01113 if ELEM(NULL, ob, ob->pose) { 01114 BKE_report(op->reports, RPT_ERROR, "No Pose to Copy"); 01115 return OPERATOR_CANCELLED; 01116 } 01117 01118 /* free existing pose buffer */ 01119 free_posebuf(); 01120 01121 /* sets chan->flag to POSE_KEY if bone selected, then copy those bones to the buffer */ 01122 set_pose_keys(ob); 01123 copy_pose(&g_posebuf, ob->pose, 0); 01124 01125 01126 return OPERATOR_FINISHED; 01127 } 01128 01129 void POSE_OT_copy (wmOperatorType *ot) 01130 { 01131 /* identifiers */ 01132 ot->name= "Copy Pose"; 01133 ot->idname= "POSE_OT_copy"; 01134 ot->description= "Copies the current pose of the selected bones to copy/paste buffer"; 01135 01136 /* api callbacks */ 01137 ot->exec= pose_copy_exec; 01138 ot->poll= ED_operator_posemode; 01139 01140 /* flag */ 01141 ot->flag= OPTYPE_REGISTER; 01142 } 01143 01144 /* ---- */ 01145 01146 static int pose_paste_exec (bContext *C, wmOperator *op) 01147 { 01148 Object *ob= object_pose_armature_get(CTX_data_active_object(C)); 01149 Scene *scene= CTX_data_scene(C); 01150 bPoseChannel *chan; 01151 int flip= RNA_boolean_get(op->ptr, "flipped"); 01152 int selOnly= RNA_boolean_get(op->ptr, "selected_mask"); 01153 01154 /* get KeyingSet to use */ 01155 KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOC_ROT_SCALE_ID); 01156 01157 /* sanity checks */ 01158 if ELEM(NULL, ob, ob->pose) 01159 return OPERATOR_CANCELLED; 01160 01161 if (g_posebuf == NULL) { 01162 BKE_report(op->reports, RPT_ERROR, "Copy buffer is empty"); 01163 return OPERATOR_CANCELLED; 01164 } 01165 01166 /* if selOnly option is enabled, if user hasn't selected any bones, 01167 * just go back to default behaviour to be more in line with other pose tools 01168 */ 01169 if (selOnly) { 01170 if (CTX_DATA_COUNT(C, selected_pose_bones) == 0) 01171 selOnly = 0; 01172 } 01173 01174 /* Safely merge all of the channels in the buffer pose into any existing pose */ 01175 for (chan= g_posebuf->chanbase.first; chan; chan=chan->next) { 01176 if (chan->flag & POSE_KEY) { 01177 /* try to perform paste on this bone */ 01178 bPoseChannel *pchan = pose_bone_do_paste(ob, chan, selOnly, flip); 01179 01180 if (pchan) { 01181 /* keyframing tagging for successful paste */ 01182 ED_autokeyframe_pchan(C, scene, ob, pchan, ks); 01183 } 01184 } 01185 } 01186 01187 /* Update event for pose and deformation children */ 01188 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 01189 01190 /* notifiers for updates */ 01191 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob); 01192 01193 return OPERATOR_FINISHED; 01194 } 01195 01196 void POSE_OT_paste (wmOperatorType *ot) 01197 { 01198 /* identifiers */ 01199 ot->name= "Paste Pose"; 01200 ot->idname= "POSE_OT_paste"; 01201 ot->description= "Paste the stored pose on to the current pose"; 01202 01203 /* api callbacks */ 01204 ot->exec= pose_paste_exec; 01205 ot->poll= ED_operator_posemode; 01206 01207 /* flag */ 01208 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01209 01210 /* properties */ 01211 RNA_def_boolean(ot->srna, "flipped", FALSE, "Flipped on X-Axis", "Paste the stored pose flipped on to current pose"); 01212 RNA_def_boolean(ot->srna, "selected_mask", FALSE, "On Selected Only", "Only paste the stored pose on to selected bones in the current pose"); 01213 } 01214 01215 /* ********************************************** */ 01216 /* Bone Groups */ 01217 01218 static int pose_group_add_exec (bContext *C, wmOperator *UNUSED(op)) 01219 { 01220 ScrArea *sa= CTX_wm_area(C); 01221 Object *ob; 01222 01223 /* since this call may also be used from the buttons window, we need to check for where to get the object */ 01224 if (sa->spacetype == SPACE_BUTS) 01225 ob= ED_object_context(C); 01226 else 01227 ob= object_pose_armature_get(CTX_data_active_object(C)); 01228 01229 /* only continue if there's an object */ 01230 if (ob == NULL) 01231 return OPERATOR_CANCELLED; 01232 01233 /* for now, just call the API function for this */ 01234 pose_add_group(ob); 01235 01236 /* notifiers for updates */ 01237 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob); 01238 01239 return OPERATOR_FINISHED; 01240 } 01241 01242 void POSE_OT_group_add (wmOperatorType *ot) 01243 { 01244 /* identifiers */ 01245 ot->name= "Add Bone Group"; 01246 ot->idname= "POSE_OT_group_add"; 01247 ot->description= "Add a new bone group"; 01248 01249 /* api callbacks */ 01250 ot->exec= pose_group_add_exec; 01251 ot->poll= ED_operator_posemode; 01252 01253 /* flags */ 01254 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; 01255 } 01256 01257 01258 static int pose_group_remove_exec (bContext *C, wmOperator *UNUSED(op)) 01259 { 01260 ScrArea *sa= CTX_wm_area(C); 01261 Object *ob; 01262 01263 /* since this call may also be used from the buttons window, we need to check for where to get the object */ 01264 if (sa->spacetype == SPACE_BUTS) 01265 ob= ED_object_context(C); 01266 else 01267 ob= object_pose_armature_get(CTX_data_active_object(C)); 01268 01269 /* only continue if there's an object */ 01270 if (ob == NULL) 01271 return OPERATOR_CANCELLED; 01272 01273 /* for now, just call the API function for this */ 01274 pose_remove_group(ob); 01275 01276 /* notifiers for updates */ 01277 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob); 01278 01279 return OPERATOR_FINISHED; 01280 } 01281 01282 void POSE_OT_group_remove (wmOperatorType *ot) 01283 { 01284 /* identifiers */ 01285 ot->name= "Remove Bone Group"; 01286 ot->idname= "POSE_OT_group_remove"; 01287 ot->description= "Removes the active bone group"; 01288 01289 /* api callbacks */ 01290 ot->exec= pose_group_remove_exec; 01291 ot->poll= ED_operator_posemode; 01292 01293 /* flags */ 01294 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; 01295 } 01296 01297 /* ------------ */ 01298 01299 /* invoke callback which presents a list of bone-groups for the user to choose from */ 01300 static int pose_groups_menu_invoke (bContext *C, wmOperator *op, wmEvent *UNUSED(evt)) 01301 { 01302 ScrArea *sa= CTX_wm_area(C); 01303 Object *ob; 01304 bPose *pose; 01305 01306 uiPopupMenu *pup; 01307 uiLayout *layout; 01308 bActionGroup *grp; 01309 int i; 01310 01311 /* since this call may also be used from the buttons window, we need to check for where to get the object */ 01312 if (sa->spacetype == SPACE_BUTS) 01313 ob= ED_object_context(C); 01314 else 01315 ob= object_pose_armature_get(CTX_data_active_object(C)); 01316 01317 /* only continue if there's an object, and a pose there too */ 01318 if (ELEM(NULL, ob, ob->pose)) 01319 return OPERATOR_CANCELLED; 01320 pose= ob->pose; 01321 01322 /* if there's no active group (or active is invalid), create a new menu to find it */ 01323 if (pose->active_group <= 0) { 01324 /* create a new menu, and start populating it with group names */ 01325 pup= uiPupMenuBegin(C, op->type->name, ICON_NONE); 01326 layout= uiPupMenuLayout(pup); 01327 01328 /* special entry - allow to create new group, then use that 01329 * (not to be used for removing though) 01330 */ 01331 if (strstr(op->idname, "assign")) { 01332 uiItemIntO(layout, "New Group", ICON_NONE, op->idname, "type", 0); 01333 uiItemS(layout); 01334 } 01335 01336 /* add entries for each group */ 01337 for (grp= pose->agroups.first, i=1; grp; grp=grp->next, i++) 01338 uiItemIntO(layout, grp->name, ICON_NONE, op->idname, "type", i); 01339 01340 /* finish building the menu, and process it (should result in calling self again) */ 01341 uiPupMenuEnd(C, pup); 01342 01343 return OPERATOR_CANCELLED; 01344 } 01345 else { 01346 /* just use the active group index, and call the exec callback for the calling operator */ 01347 RNA_int_set(op->ptr, "type", pose->active_group); 01348 return op->type->exec(C, op); 01349 } 01350 } 01351 01352 /* Assign selected pchans to the bone group that the user selects */ 01353 static int pose_group_assign_exec (bContext *C, wmOperator *op) 01354 { 01355 ScrArea *sa= CTX_wm_area(C); 01356 Object *ob; 01357 bPose *pose; 01358 short done= 0; 01359 01360 /* since this call may also be used from the buttons window, we need to check for where to get the object */ 01361 if (sa->spacetype == SPACE_BUTS) 01362 ob= ED_object_context(C); 01363 else 01364 ob= object_pose_armature_get(CTX_data_active_object(C)); 01365 01366 /* only continue if there's an object, and a pose there too */ 01367 if (ELEM(NULL, ob, ob->pose)) 01368 return OPERATOR_CANCELLED; 01369 01370 pose= ob->pose; 01371 01372 /* set the active group number to the one from operator props 01373 * - if 0 after this, make a new group... 01374 */ 01375 pose->active_group= RNA_int_get(op->ptr, "type"); 01376 if (pose->active_group == 0) 01377 pose_add_group(ob); 01378 01379 /* add selected bones to group then */ 01380 CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) 01381 { 01382 pchan->agrp_index= pose->active_group; 01383 done= 1; 01384 } 01385 CTX_DATA_END; 01386 01387 /* notifiers for updates */ 01388 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob); 01389 01390 /* report done status */ 01391 if (done) 01392 return OPERATOR_FINISHED; 01393 else 01394 return OPERATOR_CANCELLED; 01395 } 01396 01397 void POSE_OT_group_assign (wmOperatorType *ot) 01398 { 01399 /* identifiers */ 01400 ot->name= "Add Selected to Bone Group"; 01401 ot->idname= "POSE_OT_group_assign"; 01402 ot->description= "Add selected bones to the chosen bone group"; 01403 01404 /* api callbacks */ 01405 ot->invoke= pose_groups_menu_invoke; 01406 ot->exec= pose_group_assign_exec; 01407 ot->poll= ED_operator_posemode; 01408 01409 /* flags */ 01410 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; 01411 01412 /* properties */ 01413 RNA_def_int(ot->srna, "type", 0, 0, 10, "Bone Group Index", "", 0, INT_MAX); 01414 } 01415 01416 01417 static int pose_group_unassign_exec (bContext *C, wmOperator *UNUSED(op)) 01418 { 01419 ScrArea *sa= CTX_wm_area(C); 01420 Object *ob; 01421 short done= 0; 01422 01423 /* since this call may also be used from the buttons window, we need to check for where to get the object */ 01424 if (sa->spacetype == SPACE_BUTS) 01425 ob= ED_object_context(C); 01426 else 01427 ob= object_pose_armature_get(CTX_data_active_object(C)); 01428 01429 /* only continue if there's an object, and a pose there too */ 01430 if (ELEM(NULL, ob, ob->pose)) 01431 return OPERATOR_CANCELLED; 01432 01433 /* find selected bones to remove from all bone groups */ 01434 CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) 01435 { 01436 if (pchan->agrp_index) { 01437 pchan->agrp_index= 0; 01438 done= 1; 01439 } 01440 } 01441 CTX_DATA_END; 01442 01443 /* notifiers for updates */ 01444 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob); 01445 01446 /* report done status */ 01447 if (done) 01448 return OPERATOR_FINISHED; 01449 else 01450 return OPERATOR_CANCELLED; 01451 } 01452 01453 void POSE_OT_group_unassign (wmOperatorType *ot) 01454 { 01455 /* identifiers */ 01456 ot->name= "Remove Selected from Bone Groups"; 01457 ot->idname= "POSE_OT_group_unassign"; 01458 ot->description= "Remove selected bones from all bone groups"; 01459 01460 /* api callbacks */ 01461 ot->exec= pose_group_unassign_exec; 01462 ot->poll= ED_operator_posemode; 01463 01464 /* flags */ 01465 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; 01466 } 01467 01468 static int group_move_exec(bContext *C, wmOperator *op) 01469 { 01470 Object *ob = ED_object_context(C); 01471 bPose *pose= (ob) ? ob->pose : NULL; 01472 bPoseChannel *pchan; 01473 bActionGroup *grp; 01474 int dir= RNA_enum_get(op->ptr, "direction"); 01475 int grpIndexA, grpIndexB; 01476 01477 if (ELEM(NULL, ob, pose)) 01478 return OPERATOR_CANCELLED; 01479 if (pose->active_group <= 0) 01480 return OPERATOR_CANCELLED; 01481 01482 /* get group to move */ 01483 grp= BLI_findlink(&pose->agroups, pose->active_group-1); 01484 if (grp == NULL) 01485 return OPERATOR_CANCELLED; 01486 01487 /* move bone group */ 01488 grpIndexA = pose->active_group; 01489 if (dir == 1) { /* up */ 01490 void *prev = grp->prev; 01491 01492 if (prev == NULL) 01493 return OPERATOR_FINISHED; 01494 01495 BLI_remlink(&pose->agroups, grp); 01496 BLI_insertlinkbefore(&pose->agroups, prev, grp); 01497 01498 grpIndexB = grpIndexA - 1; 01499 pose->active_group--; 01500 } 01501 else { /* down */ 01502 void *next = grp->next; 01503 01504 if (next == NULL) 01505 return OPERATOR_FINISHED; 01506 01507 BLI_remlink(&pose->agroups, grp); 01508 BLI_insertlinkafter(&pose->agroups, next, grp); 01509 01510 grpIndexB = grpIndexA + 1; 01511 pose->active_group++; 01512 } 01513 01514 /* fix changed bone group indices in bones (swap grpIndexA with grpIndexB) */ 01515 for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { 01516 if (pchan->agrp_index == grpIndexB) 01517 pchan->agrp_index= grpIndexA; 01518 else if (pchan->agrp_index == grpIndexA) 01519 pchan->agrp_index= grpIndexB; 01520 } 01521 01522 /* notifiers for updates */ 01523 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob); 01524 01525 return OPERATOR_FINISHED; 01526 } 01527 01528 void POSE_OT_group_move(wmOperatorType *ot) 01529 { 01530 static EnumPropertyItem group_slot_move[] = { 01531 {1, "UP", 0, "Up", ""}, 01532 {-1, "DOWN", 0, "Down", ""}, 01533 {0, NULL, 0, NULL, NULL} 01534 }; 01535 01536 /* identifiers */ 01537 ot->name= "Move Bone Group"; 01538 ot->idname= "POSE_OT_group_move"; 01539 ot->description= "Change position of active Bone Group in list of Bone Groups"; 01540 01541 /* api callbacks */ 01542 ot->exec= group_move_exec; 01543 ot->poll= ED_operator_posemode; 01544 01545 /* flags */ 01546 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01547 01548 RNA_def_enum(ot->srna, "direction", group_slot_move, 0, "Direction", "Direction to move, UP or DOWN"); 01549 } 01550 01551 /* bone group sort element */ 01552 typedef struct tSortActionGroup { 01553 bActionGroup *agrp; 01554 int index; 01555 } tSortActionGroup; 01556 01557 /* compare bone groups by name */ 01558 static int compare_agroup(const void *sgrp_a_ptr, const void *sgrp_b_ptr) 01559 { 01560 tSortActionGroup *sgrp_a= (tSortActionGroup *)sgrp_a_ptr; 01561 tSortActionGroup *sgrp_b= (tSortActionGroup *)sgrp_b_ptr; 01562 01563 return strcmp(sgrp_a->agrp->name, sgrp_b->agrp->name); 01564 } 01565 01566 static int group_sort_exec(bContext *C, wmOperator *UNUSED(op)) 01567 { 01568 Object *ob = ED_object_context(C); 01569 bPose *pose= (ob) ? ob->pose : NULL; 01570 bPoseChannel *pchan; 01571 tSortActionGroup *agrp_array; 01572 bActionGroup *agrp; 01573 int agrp_count; 01574 int i; 01575 01576 if (ELEM(NULL, ob, pose)) 01577 return OPERATOR_CANCELLED; 01578 if (pose->active_group <= 0) 01579 return OPERATOR_CANCELLED; 01580 01581 /* create temporary array with bone groups and indices */ 01582 agrp_count = BLI_countlist(&pose->agroups); 01583 agrp_array = MEM_mallocN(sizeof(tSortActionGroup) * agrp_count, "sort bone groups"); 01584 for (agrp= pose->agroups.first, i= 0; agrp; agrp= agrp->next, i++) { 01585 BLI_assert(i < agrp_count); 01586 agrp_array[i].agrp = agrp; 01587 agrp_array[i].index = i+1; 01588 } 01589 01590 /* sort bone groups by name */ 01591 qsort(agrp_array, agrp_count, sizeof(tSortActionGroup), compare_agroup); 01592 01593 /* create sorted bone group list from sorted array */ 01594 pose->agroups.first= pose->agroups.last= NULL; 01595 for (i= 0; i < agrp_count; i++) { 01596 BLI_addtail(&pose->agroups, agrp_array[i].agrp); 01597 } 01598 01599 /* fix changed bone group indizes in bones */ 01600 for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { 01601 for (i= 0; i < agrp_count; i++) { 01602 if (pchan->agrp_index == agrp_array[i].index) { 01603 pchan->agrp_index= i+1; 01604 break; 01605 } 01606 } 01607 } 01608 01609 /* free temp resources */ 01610 MEM_freeN(agrp_array); 01611 01612 /* notifiers for updates */ 01613 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob); 01614 01615 return OPERATOR_FINISHED; 01616 } 01617 01618 void POSE_OT_group_sort(wmOperatorType *ot) 01619 { 01620 /* identifiers */ 01621 ot->name= "Sort Bone Groups"; 01622 ot->idname= "POSE_OT_group_sort"; 01623 ot->description= "Sort Bone Groups by their names in ascending order"; 01624 01625 /* api callbacks */ 01626 ot->exec= group_sort_exec; 01627 ot->poll= ED_operator_posemode; 01628 01629 /* flags */ 01630 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01631 } 01632 01633 static void pose_group_select(bContext *C, Object *ob, int select) 01634 { 01635 bPose *pose= ob->pose; 01636 01637 CTX_DATA_BEGIN(C, bPoseChannel*, pchan, visible_pose_bones) 01638 { 01639 if ((pchan->bone->flag & BONE_UNSELECTABLE)==0) { 01640 if (select) { 01641 if (pchan->agrp_index == pose->active_group) 01642 pchan->bone->flag |= BONE_SELECTED; 01643 } 01644 else { 01645 if (pchan->agrp_index == pose->active_group) 01646 pchan->bone->flag &= ~BONE_SELECTED; 01647 } 01648 } 01649 } 01650 CTX_DATA_END; 01651 } 01652 01653 static int pose_group_select_exec (bContext *C, wmOperator *UNUSED(op)) 01654 { 01655 ScrArea *sa= CTX_wm_area(C); 01656 Object *ob; 01657 01658 /* since this call may also be used from the buttons window, we need to check for where to get the object */ 01659 if (sa->spacetype == SPACE_BUTS) 01660 ob= ED_object_context(C); 01661 else 01662 ob= object_pose_armature_get(CTX_data_active_object(C)); 01663 01664 /* only continue if there's an object, and a pose there too */ 01665 if (ELEM(NULL, ob, ob->pose)) 01666 return OPERATOR_CANCELLED; 01667 01668 pose_group_select(C, ob, 1); 01669 01670 /* notifiers for updates */ 01671 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob); 01672 01673 return OPERATOR_FINISHED; 01674 } 01675 01676 void POSE_OT_group_select (wmOperatorType *ot) 01677 { 01678 /* identifiers */ 01679 ot->name= "Select Bones of Bone Group"; 01680 ot->idname= "POSE_OT_group_select"; 01681 ot->description= "Select bones in active Bone Group"; 01682 01683 /* api callbacks */ 01684 ot->exec= pose_group_select_exec; 01685 ot->poll= ED_operator_posemode; 01686 01687 /* flags */ 01688 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; 01689 } 01690 01691 static int pose_group_deselect_exec (bContext *C, wmOperator *UNUSED(op)) 01692 { 01693 ScrArea *sa= CTX_wm_area(C); 01694 Object *ob; 01695 01696 /* since this call may also be used from the buttons window, we need to check for where to get the object */ 01697 if (sa->spacetype == SPACE_BUTS) 01698 ob= ED_object_context(C); 01699 else 01700 ob= object_pose_armature_get(CTX_data_active_object(C)); 01701 01702 /* only continue if there's an object, and a pose there too */ 01703 if (ELEM(NULL, ob, ob->pose)) 01704 return OPERATOR_CANCELLED; 01705 01706 pose_group_select(C, ob, 0); 01707 01708 /* notifiers for updates */ 01709 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob); 01710 01711 return OPERATOR_FINISHED; 01712 } 01713 01714 void POSE_OT_group_deselect (wmOperatorType *ot) 01715 { 01716 /* identifiers */ 01717 ot->name= "Deselect Bone Group"; 01718 ot->idname= "POSE_OT_group_deselect"; 01719 ot->description= "Deselect bones of active Bone Group"; 01720 01721 /* api callbacks */ 01722 ot->exec= pose_group_deselect_exec; 01723 ot->poll= ED_operator_posemode; 01724 01725 /* flags */ 01726 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; 01727 } 01728 01729 /* ********************************************** */ 01730 01731 static int pose_flip_names_exec (bContext *C, wmOperator *UNUSED(op)) 01732 { 01733 Object *ob= object_pose_armature_get(CTX_data_active_object(C)); 01734 bArmature *arm; 01735 01736 /* paranoia checks */ 01737 if (ELEM(NULL, ob, ob->pose)) 01738 return OPERATOR_CANCELLED; 01739 arm= ob->data; 01740 01741 /* loop through selected bones, auto-naming them */ 01742 CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) 01743 { 01744 char newname[MAXBONENAME]; 01745 flip_side_name(newname, pchan->name, TRUE); 01746 ED_armature_bone_rename(arm, pchan->name, newname); 01747 } 01748 CTX_DATA_END; 01749 01750 /* since we renamed stuff... */ 01751 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 01752 01753 /* note, notifier might evolve */ 01754 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob); 01755 01756 return OPERATOR_FINISHED; 01757 } 01758 01759 void POSE_OT_flip_names (wmOperatorType *ot) 01760 { 01761 /* identifiers */ 01762 ot->name= "Flip Names"; 01763 ot->idname= "POSE_OT_flip_names"; 01764 ot->description= "Flips (and corrects) the axis suffixes of the the names of selected bones"; 01765 01766 /* api callbacks */ 01767 ot->exec= pose_flip_names_exec; 01768 ot->poll= ED_operator_posemode; 01769 01770 /* flags */ 01771 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01772 } 01773 01774 /* ------------------ */ 01775 01776 static int pose_autoside_names_exec (bContext *C, wmOperator *op) 01777 { 01778 Object *ob= object_pose_armature_get(CTX_data_active_object(C)); 01779 bArmature *arm; 01780 char newname[MAXBONENAME]; 01781 short axis= RNA_enum_get(op->ptr, "axis"); 01782 01783 /* paranoia checks */ 01784 if (ELEM(NULL, ob, ob->pose)) 01785 return OPERATOR_CANCELLED; 01786 arm= ob->data; 01787 01788 /* loop through selected bones, auto-naming them */ 01789 CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) 01790 { 01791 BLI_strncpy(newname, pchan->name, sizeof(newname)); 01792 if(bone_autoside_name(newname, 1, axis, pchan->bone->head[axis], pchan->bone->tail[axis])) 01793 ED_armature_bone_rename(arm, pchan->name, newname); 01794 } 01795 CTX_DATA_END; 01796 01797 /* since we renamed stuff... */ 01798 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 01799 01800 /* note, notifier might evolve */ 01801 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob); 01802 01803 return OPERATOR_FINISHED; 01804 } 01805 01806 void POSE_OT_autoside_names (wmOperatorType *ot) 01807 { 01808 static EnumPropertyItem axis_items[]= { 01809 {0, "XAXIS", 0, "X-Axis", "Left/Right"}, 01810 {1, "YAXIS", 0, "Y-Axis", "Front/Back"}, 01811 {2, "ZAXIS", 0, "Z-Axis", "Top/Bottom"}, 01812 {0, NULL, 0, NULL, NULL}}; 01813 01814 /* identifiers */ 01815 ot->name= "AutoName by Axis"; 01816 ot->idname= "POSE_OT_autoside_names"; 01817 ot->description= "Automatically renames the selected bones according to which side of the target axis they fall on"; 01818 01819 /* api callbacks */ 01820 ot->invoke= WM_menu_invoke; 01821 ot->exec= pose_autoside_names_exec; 01822 ot->poll= ED_operator_posemode; 01823 01824 /* flags */ 01825 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01826 01827 /* settings */ 01828 ot->prop= RNA_def_enum(ot->srna, "axis", axis_items, 0, "Axis", "Axis tag names with"); 01829 } 01830 01831 /* ********************************************** */ 01832 01833 static int pose_bone_rotmode_exec (bContext *C, wmOperator *op) 01834 { 01835 Object *ob = CTX_data_active_object(C); 01836 int mode = RNA_enum_get(op->ptr, "type"); 01837 01838 /* set rotation mode of selected bones */ 01839 CTX_DATA_BEGIN(C, bPoseChannel *, pchan, selected_pose_bones) 01840 { 01841 pchan->rotmode = mode; 01842 } 01843 CTX_DATA_END; 01844 01845 /* notifiers and updates */ 01846 DAG_id_tag_update((ID *)ob, OB_RECALC_DATA); 01847 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob); 01848 01849 return OPERATOR_FINISHED; 01850 } 01851 01852 void POSE_OT_rotation_mode_set (wmOperatorType *ot) 01853 { 01854 /* identifiers */ 01855 ot->name= "Set Rotation Mode"; 01856 ot->idname= "POSE_OT_rotation_mode_set"; 01857 ot->description= "Set the rotation representation used by selected bones"; 01858 01859 /* callbacks */ 01860 ot->invoke= WM_menu_invoke; 01861 ot->exec= pose_bone_rotmode_exec; 01862 ot->poll= ED_operator_posemode; 01863 01864 /* flags */ 01865 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01866 01867 /* properties */ 01868 ot->prop= RNA_def_enum(ot->srna, "type", posebone_rotmode_items, 0, "Rotation Mode", ""); 01869 } 01870 01871 /* ********************************************** */ 01872 01873 /* Show all armature layers */ 01874 static int pose_armature_layers_showall_poll (bContext *C) 01875 { 01876 /* this single operator can be used in posemode OR editmode for armatures */ 01877 return ED_operator_posemode(C) || ED_operator_editarmature(C); 01878 } 01879 01880 static int pose_armature_layers_showall_exec (bContext *C, wmOperator *op) 01881 { 01882 Object *ob= object_pose_armature_get(CTX_data_active_object(C)); 01883 bArmature *arm = (ob)? ob->data : NULL; 01884 PointerRNA ptr; 01885 int maxLayers = (RNA_boolean_get(op->ptr, "all"))? 32 : 16; 01886 int layers[32] = {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */ 01887 int i; 01888 01889 /* sanity checking */ 01890 if (arm == NULL) 01891 return OPERATOR_CANCELLED; 01892 01893 /* use RNA to set the layers 01894 * although it would be faster to just set directly using bitflags, we still 01895 * need to setup a RNA pointer so that we get the "update" callbacks for free... 01896 */ 01897 RNA_id_pointer_create(&arm->id, &ptr); 01898 01899 for (i = 0; i < maxLayers; i++) 01900 layers[i] = 1; 01901 01902 RNA_boolean_set_array(&ptr, "layers", layers); 01903 01904 /* note, notifier might evolve */ 01905 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob); 01906 01907 /* done */ 01908 return OPERATOR_FINISHED; 01909 } 01910 01911 void ARMATURE_OT_layers_show_all (wmOperatorType *ot) 01912 { 01913 /* identifiers */ 01914 ot->name= "Show All Layers"; 01915 ot->idname= "ARMATURE_OT_layers_show_all"; 01916 ot->description= "Make all armature layers visible"; 01917 01918 /* callbacks */ 01919 ot->exec= pose_armature_layers_showall_exec; 01920 ot->poll= pose_armature_layers_showall_poll; 01921 01922 /* flags */ 01923 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01924 01925 /* properties */ 01926 ot->prop = RNA_def_boolean(ot->srna, "all", 1, "All Layers", "Enable all layers or just the first 16 (top row)"); 01927 } 01928 01929 /* ------------------- */ 01930 01931 /* Present a popup to get the layers that should be used */ 01932 static int pose_armature_layers_invoke (bContext *C, wmOperator *op, wmEvent *evt) 01933 { 01934 Object *ob= object_pose_armature_get(CTX_data_active_object(C)); 01935 bArmature *arm= (ob)? ob->data : NULL; 01936 PointerRNA ptr; 01937 int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */ 01938 01939 /* sanity checking */ 01940 if (arm == NULL) 01941 return OPERATOR_CANCELLED; 01942 01943 /* get RNA pointer to armature data to use that to retrieve the layers as ints to init the operator */ 01944 RNA_id_pointer_create((ID *)arm, &ptr); 01945 RNA_boolean_get_array(&ptr, "layers", layers); 01946 RNA_boolean_set_array(op->ptr, "layers", layers); 01947 01948 /* part to sync with other similar operators... */ 01949 return WM_operator_props_popup(C, op, evt); 01950 } 01951 01952 /* Set the visible layers for the active armature (edit and pose modes) */ 01953 static int pose_armature_layers_exec (bContext *C, wmOperator *op) 01954 { 01955 Object *ob= object_pose_armature_get(CTX_data_active_object(C)); 01956 PointerRNA ptr; 01957 int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */ 01958 01959 if (ELEM(NULL, ob, ob->data)) { 01960 return OPERATOR_CANCELLED; 01961 } 01962 01963 /* get the values set in the operator properties */ 01964 RNA_boolean_get_array(op->ptr, "layers", layers); 01965 01966 /* get pointer for armature, and write data there... */ 01967 RNA_id_pointer_create((ID *)ob->data, &ptr); 01968 RNA_boolean_set_array(&ptr, "layers", layers); 01969 01970 /* note, notifier might evolve */ 01971 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob); 01972 01973 return OPERATOR_FINISHED; 01974 } 01975 01976 01977 void POSE_OT_armature_layers (wmOperatorType *ot) 01978 { 01979 /* identifiers */ 01980 ot->name= "Change Armature Layers"; 01981 ot->idname= "POSE_OT_armature_layers"; 01982 ot->description= "Change the visible armature layers"; 01983 01984 /* callbacks */ 01985 ot->invoke= pose_armature_layers_invoke; 01986 ot->exec= pose_armature_layers_exec; 01987 ot->poll= ED_operator_posemode; 01988 01989 /* flags */ 01990 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01991 01992 /* properties */ 01993 RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers to make visible"); 01994 } 01995 01996 void ARMATURE_OT_armature_layers (wmOperatorType *ot) 01997 { 01998 /* identifiers */ 01999 ot->name= "Change Armature Layers"; 02000 ot->idname= "ARMATURE_OT_armature_layers"; 02001 ot->description= "Change the visible armature layers"; 02002 02003 /* callbacks */ 02004 ot->invoke= pose_armature_layers_invoke; 02005 ot->exec= pose_armature_layers_exec; 02006 ot->poll= ED_operator_editarmature; 02007 02008 /* flags */ 02009 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02010 02011 /* properties */ 02012 RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers to make visible"); 02013 } 02014 02015 /* ------------------- */ 02016 02017 /* Present a popup to get the layers that should be used */ 02018 static int pose_bone_layers_invoke (bContext *C, wmOperator *op, wmEvent *evt) 02019 { 02020 int layers[32]= {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */ 02021 02022 /* get layers that are active already */ 02023 CTX_DATA_BEGIN(C, bPoseChannel *, pchan, selected_pose_bones) 02024 { 02025 short bit; 02026 02027 /* loop over the bits for this pchan's layers, adding layers where they're needed */ 02028 for (bit= 0; bit < 32; bit++) { 02029 if (pchan->bone->layer & (1<<bit)) 02030 layers[bit]= 1; 02031 } 02032 } 02033 CTX_DATA_END; 02034 02035 /* copy layers to operator */ 02036 RNA_boolean_set_array(op->ptr, "layers", layers); 02037 02038 /* part to sync with other similar operators... */ 02039 return WM_operator_props_popup(C, op, evt); 02040 } 02041 02042 /* Set the visible layers for the active armature (edit and pose modes) */ 02043 static int pose_bone_layers_exec (bContext *C, wmOperator *op) 02044 { 02045 Object *ob= object_pose_armature_get(CTX_data_active_object(C)); 02046 PointerRNA ptr; 02047 int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */ 02048 02049 if(ob==NULL || ob->data==NULL) { 02050 return OPERATOR_CANCELLED; 02051 } 02052 02053 /* get the values set in the operator properties */ 02054 RNA_boolean_get_array(op->ptr, "layers", layers); 02055 02056 /* set layers of pchans based on the values set in the operator props */ 02057 CTX_DATA_BEGIN(C, bPoseChannel *, pchan, selected_pose_bones) 02058 { 02059 /* get pointer for pchan, and write flags this way */ 02060 RNA_pointer_create((ID *)ob->data, &RNA_Bone, pchan->bone, &ptr); 02061 RNA_boolean_set_array(&ptr, "layers", layers); 02062 } 02063 CTX_DATA_END; 02064 02065 /* note, notifier might evolve */ 02066 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob); 02067 02068 return OPERATOR_FINISHED; 02069 } 02070 02071 void POSE_OT_bone_layers (wmOperatorType *ot) 02072 { 02073 /* identifiers */ 02074 ot->name= "Change Bone Layers"; 02075 ot->idname= "POSE_OT_bone_layers"; 02076 ot->description= "Change the layers that the selected bones belong to"; 02077 02078 /* callbacks */ 02079 ot->invoke= pose_bone_layers_invoke; 02080 ot->exec= pose_bone_layers_exec; 02081 ot->poll= ED_operator_posemode; 02082 02083 /* flags */ 02084 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02085 02086 /* properties */ 02087 RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers that bone belongs to"); 02088 } 02089 02090 /* ------------------- */ 02091 02092 /* Present a popup to get the layers that should be used */ 02093 static int armature_bone_layers_invoke (bContext *C, wmOperator *op, wmEvent *evt) 02094 { 02095 int layers[32]= {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */ 02096 02097 /* get layers that are active already */ 02098 CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones) 02099 { 02100 short bit; 02101 02102 /* loop over the bits for this pchan's layers, adding layers where they're needed */ 02103 for (bit= 0; bit < 32; bit++) { 02104 if (ebone->layer & (1<<bit)) 02105 layers[bit]= 1; 02106 } 02107 } 02108 CTX_DATA_END; 02109 02110 /* copy layers to operator */ 02111 RNA_boolean_set_array(op->ptr, "layers", layers); 02112 02113 /* part to sync with other similar operators... */ 02114 return WM_operator_props_popup(C, op, evt); 02115 } 02116 02117 /* Set the visible layers for the active armature (edit and pose modes) */ 02118 static int armature_bone_layers_exec (bContext *C, wmOperator *op) 02119 { 02120 Object *ob= CTX_data_edit_object(C); 02121 bArmature *arm= (ob)? ob->data : NULL; 02122 PointerRNA ptr; 02123 int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */ 02124 02125 /* get the values set in the operator properties */ 02126 RNA_boolean_get_array(op->ptr, "layers", layers); 02127 02128 /* set layers of pchans based on the values set in the operator props */ 02129 CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones) 02130 { 02131 /* get pointer for pchan, and write flags this way */ 02132 RNA_pointer_create((ID *)arm, &RNA_EditBone, ebone, &ptr); 02133 RNA_boolean_set_array(&ptr, "layers", layers); 02134 } 02135 CTX_DATA_END; 02136 02137 /* note, notifier might evolve */ 02138 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob); 02139 02140 return OPERATOR_FINISHED; 02141 } 02142 02143 void ARMATURE_OT_bone_layers (wmOperatorType *ot) 02144 { 02145 /* identifiers */ 02146 ot->name= "Change Bone Layers"; 02147 ot->idname= "ARMATURE_OT_bone_layers"; 02148 ot->description= "Change the layers that the selected bones belong to"; 02149 02150 /* callbacks */ 02151 ot->invoke= armature_bone_layers_invoke; 02152 ot->exec= armature_bone_layers_exec; 02153 ot->poll= ED_operator_editarmature; 02154 02155 /* flags */ 02156 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02157 02158 /* properties */ 02159 RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers that bone belongs to"); 02160 } 02161 02162 /* ********************************************** */ 02163 /* Flip Quats */ 02164 02165 static int pose_flip_quats_exec (bContext *C, wmOperator *UNUSED(op)) 02166 { 02167 Scene *scene= CTX_data_scene(C); 02168 Object *ob= object_pose_armature_get(CTX_data_active_object(C)); 02169 KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID); 02170 02171 /* loop through all selected pchans, flipping and keying (as needed) */ 02172 CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) 02173 { 02174 /* only if bone is using quaternion rotation */ 02175 if (pchan->rotmode == ROT_MODE_QUAT) { 02176 /* quaternions have 720 degree range */ 02177 negate_v4(pchan->quat); 02178 02179 ED_autokeyframe_pchan(C, scene, ob, pchan, ks); 02180 } 02181 } 02182 CTX_DATA_END; 02183 02184 /* notifiers and updates */ 02185 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 02186 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob); 02187 02188 return OPERATOR_FINISHED; 02189 } 02190 02191 void POSE_OT_quaternions_flip (wmOperatorType *ot) 02192 { 02193 /* identifiers */ 02194 ot->name = "Flip Quats"; 02195 ot->idname= "POSE_OT_quaternions_flip"; 02196 ot->description= "Flip quaternion values to achieve desired rotations, while maintaining the same orientations"; 02197 02198 /* callbacks */ 02199 ot->exec= pose_flip_quats_exec; 02200 ot->poll= ED_operator_posemode; 02201 02202 /* flags */ 02203 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02204 } 02205 02206 /* ********************************************** */ 02207 /* Clear User Transforms */ 02208 02209 static int pose_clear_user_transforms_exec (bContext *C, wmOperator *UNUSED(op)) 02210 { 02211 Scene *scene = CTX_data_scene(C); 02212 Object *ob = CTX_data_active_object(C); 02213 float cframe = (float)CFRA; 02214 02215 if ((ob->adt) && (ob->adt->action)) { 02216 /* XXX: this is just like this to avoid contaminating anything else; 02217 * just pose values should change, so this should be fine 02218 */ 02219 bPose *dummyPose = NULL; 02220 Object workob = {{0}}; 02221 bPoseChannel *pchan; 02222 02223 /* execute animation step for current frame using a dummy copy of the pose */ 02224 copy_pose(&dummyPose, ob->pose, 0); 02225 02226 BLI_strncpy(workob.id.name, "OB<ClearTfmWorkOb>", sizeof(workob.id.name)); 02227 workob.type = OB_ARMATURE; 02228 workob.data = ob->data; 02229 workob.adt = ob->adt; 02230 workob.pose = dummyPose; 02231 02232 BKE_animsys_evaluate_animdata(scene, &workob.id, workob.adt, cframe, ADT_RECALC_ANIM); 02233 02234 /* copy back values, but on selected bones only */ 02235 for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) { 02236 pose_bone_do_paste(ob, pchan, 1, 0); 02237 } 02238 02239 /* free temp data - free manually as was copied without constraints */ 02240 if (dummyPose) { 02241 for (pchan= dummyPose->chanbase.first; pchan; pchan= pchan->next) { 02242 if (pchan->prop) { 02243 IDP_FreeProperty(pchan->prop); 02244 MEM_freeN(pchan->prop); 02245 } 02246 } 02247 02248 /* was copied without constraints */ 02249 BLI_freelistN(&dummyPose->chanbase); 02250 MEM_freeN(dummyPose); 02251 } 02252 } 02253 else { 02254 /* no animation, so just reset whole pose to rest pose 02255 * (cannot just restore for selected though) 02256 */ 02257 rest_pose(ob->pose); 02258 } 02259 02260 /* notifiers and updates */ 02261 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 02262 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob); 02263 02264 return OPERATOR_FINISHED; 02265 } 02266 02267 void POSE_OT_user_transforms_clear (wmOperatorType *ot) 02268 { 02269 /* identifiers */ 02270 ot->name = "Clear User Transforms"; 02271 ot->idname= "POSE_OT_user_transforms_clear"; 02272 ot->description= "Reset pose on selected bones to keyframed state"; 02273 02274 /* callbacks */ 02275 ot->exec= pose_clear_user_transforms_exec; 02276 ot->poll= ED_operator_posemode; 02277 02278 /* flags */ 02279 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02280 } 02281