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) 2007, Blender Foundation 00019 * This is a new part of Blender 00020 * 00021 * Contributor(s): Joshua Leung 00022 * 00023 * ***** END GPL LICENSE BLOCK ***** 00024 */ 00025 00031 #include <stdlib.h> 00032 #include <stdio.h> 00033 #include <stddef.h> 00034 #include <string.h> 00035 #include <math.h> 00036 #include <float.h> 00037 00038 #include "MEM_guardedalloc.h" 00039 00040 #include "BLI_math.h" 00041 #include "BLI_blenlib.h" 00042 #include "BLI_dynstr.h" 00043 #include "BLI_dlrbTree.h" 00044 #include "BLI_utildefines.h" 00045 00046 #include "BLF_translation.h" 00047 00048 #include "DNA_anim_types.h" 00049 #include "DNA_armature_types.h" 00050 #include "DNA_object_types.h" 00051 #include "DNA_scene_types.h" 00052 00053 #include "BKE_animsys.h" 00054 #include "BKE_action.h" 00055 #include "BKE_armature.h" 00056 #include "BKE_depsgraph.h" 00057 #include "BKE_idprop.h" 00058 #include "BKE_library.h" 00059 #include "BKE_object.h" 00060 00061 #include "BKE_context.h" 00062 #include "BKE_report.h" 00063 00064 #include "RNA_access.h" 00065 #include "RNA_define.h" 00066 #include "RNA_enum_types.h" 00067 00068 #include "WM_api.h" 00069 #include "WM_types.h" 00070 00071 #include "UI_interface.h" 00072 #include "UI_resources.h" 00073 00074 #include "ED_anim_api.h" 00075 #include "ED_armature.h" 00076 #include "ED_keyframes_draw.h" 00077 #include "ED_keyframing.h" 00078 #include "ED_keyframes_edit.h" 00079 #include "ED_screen.h" 00080 #include "ED_object.h" 00081 00082 #include "armature_intern.h" 00083 00084 /* ******* XXX ********** */ 00085 00086 static void action_set_activemarker(void *UNUSED(a), void *UNUSED(b), void *UNUSED(c)) {} 00087 00088 /* ************************************************************* */ 00089 /* == POSE-LIBRARY TOOL FOR BLENDER == 00090 * 00091 * Overview: 00092 * This tool allows animators to store a set of frequently used poses to dump into 00093 * the active action to help in "budget" productions to quickly block out new actions. 00094 * It acts as a kind of "glorified clipboard for poses", allowing for naming of poses. 00095 * 00096 * Features: 00097 * - PoseLibs are simply normal Actions 00098 * - Each "pose" is simply a set of keyframes that occur on a particular frame 00099 * -> a set of TimeMarkers that belong to each Action, help 'label' where a 'pose' can be 00100 * found in the Action 00101 * - The Scrollwheel or PageUp/Down buttons when used in a special mode or after pressing/holding 00102 * [a modifier] key, cycles through the poses available for the active pose's poselib, allowing the 00103 * animator to preview what action best suits that pose 00104 */ 00105 /* ************************************************************* */ 00106 00107 00108 /* gets the first available frame in poselib to store a pose on 00109 * - frames start from 1, and a pose should occur on every frame... 0 is error! 00110 */ 00111 static int poselib_get_free_index (bAction *act) 00112 { 00113 TimeMarker *marker; 00114 int low=0, high=0; 00115 short changed = 0; 00116 00117 /* sanity checks */ 00118 if (ELEM(NULL, act, act->markers.first)) return 1; 00119 00120 /* As poses are not stored in chronological order, we must iterate over this list 00121 * a few times until we don't make any new discoveries (mostly about the lower bound). 00122 * Prevents problems with deleting then trying to add new poses [#27412] 00123 */ 00124 do { 00125 changed = 0; 00126 00127 for (marker= act->markers.first; marker; marker= marker->next) { 00128 /* only increase low if value is 1 greater than low, to find "gaps" where 00129 * poses were removed from the poselib 00130 */ 00131 if (marker->frame == (low + 1)) { 00132 low++; 00133 changed = 1; 00134 } 00135 00136 /* value replaces high if it is the highest value encountered yet */ 00137 if (marker->frame > high) { 00138 high= marker->frame; 00139 changed = 1; 00140 } 00141 } 00142 } while (changed != 0); 00143 00144 /* - if low is not equal to high, then low+1 is a gap 00145 * - if low is equal to high, then high+1 is the next index (add at end) 00146 */ 00147 if (low < high) 00148 return (low + 1); 00149 else 00150 return (high + 1); 00151 } 00152 00153 /* returns the active pose for a poselib */ 00154 static TimeMarker *poselib_get_active_pose (bAction *act) 00155 { 00156 if ((act) && (act->active_marker)) 00157 return BLI_findlink(&act->markers, act->active_marker-1); 00158 else 00159 return NULL; 00160 } 00161 00162 /* Get object that Pose Lib should be found on */ 00163 /* XXX C can be zero */ 00164 static Object *get_poselib_object (bContext *C) 00165 { 00166 ScrArea *sa; 00167 00168 /* sanity check */ 00169 if (C == NULL) 00170 return NULL; 00171 00172 sa = CTX_wm_area(C); 00173 00174 if (sa && (sa->spacetype == SPACE_BUTS)) 00175 return ED_object_context(C); 00176 else 00177 return object_pose_armature_get(CTX_data_active_object(C)); 00178 } 00179 00180 /* Poll callback for operators that require existing PoseLib data (with poses) to work */ 00181 static int has_poselib_pose_data_poll (bContext *C) 00182 { 00183 Object *ob = get_poselib_object(C); 00184 return (ob && ob->poselib); 00185 } 00186 00187 /* ----------------------------------- */ 00188 00189 /* Initialise a new poselib (whether it is needed or not) */ 00190 static bAction *poselib_init_new (Object *ob) 00191 { 00192 /* sanity checks - only for armatures */ 00193 if (ELEM(NULL, ob, ob->pose)) 00194 return NULL; 00195 00196 /* init object's poselib action (unlink old one if there) */ 00197 if (ob->poselib) 00198 id_us_min(&ob->poselib->id); 00199 ob->poselib= add_empty_action("PoseLib"); 00200 00201 return ob->poselib; 00202 } 00203 00204 /* Initialise a new poselib (checks if that needs to happen) */ 00205 static bAction *poselib_validate (Object *ob) 00206 { 00207 if (ELEM(NULL, ob, ob->pose)) 00208 return NULL; 00209 else if (ob->poselib == NULL) 00210 return poselib_init_new(ob); 00211 else 00212 return ob->poselib; 00213 } 00214 00215 /* ************************************************************* */ 00216 /* Pose Lib UI Operators */ 00217 00218 static int poselib_new_exec (bContext *C, wmOperator *UNUSED(op)) 00219 { 00220 Object *ob = get_poselib_object(C); 00221 00222 /* sanity checks */ 00223 if (ob == NULL) 00224 return OPERATOR_CANCELLED; 00225 00226 /* new method here deals with the rest... */ 00227 poselib_init_new(ob); 00228 00229 /* notifier here might evolve? */ 00230 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, NULL); 00231 00232 return OPERATOR_FINISHED; 00233 } 00234 00235 void POSELIB_OT_new (wmOperatorType *ot) 00236 { 00237 /* identifiers */ 00238 ot->name = "New Pose Library"; 00239 ot->idname = "POSELIB_OT_new"; 00240 ot->description = "Add New Pose Library to active Object"; 00241 00242 /* callbacks */ 00243 ot->exec = poselib_new_exec; 00244 ot->poll= ED_operator_posemode; 00245 00246 /* flags */ 00247 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00248 } 00249 00250 /* ------------------------------------------------ */ 00251 00252 static int poselib_unlink_exec (bContext *C, wmOperator *UNUSED(op)) 00253 { 00254 Object *ob = get_poselib_object(C); 00255 00256 /* sanity checks */ 00257 if (ELEM(NULL, ob, ob->poselib)) 00258 return OPERATOR_CANCELLED; 00259 00260 /* there should be a poselib (we just checked above!), so just lower its user count and remove */ 00261 id_us_min(&ob->poselib->id); 00262 ob->poselib = NULL; 00263 00264 /* notifier here might evolve? */ 00265 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, NULL); 00266 00267 return OPERATOR_FINISHED; 00268 } 00269 00270 void POSELIB_OT_unlink (wmOperatorType *ot) 00271 { 00272 /* identifiers */ 00273 ot->name = "Unlink Pose Library"; 00274 ot->idname = "POSELIB_OT_unlink"; 00275 ot->description = "Remove Pose Library from active Object"; 00276 00277 /* callbacks */ 00278 ot->exec = poselib_unlink_exec; 00279 ot->poll= has_poselib_pose_data_poll; 00280 00281 /* flags */ 00282 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00283 } 00284 00285 /* ************************************************************* */ 00286 /* Pose Editing Operators */ 00287 00288 /* This tool automagically generates/validates poselib data so that it corresponds to the data 00289 * in the action. This is for use in making existing actions usable as poselibs. 00290 */ 00291 static int poselib_sanitise_exec (bContext *C, wmOperator *op) 00292 { 00293 Object *ob = get_poselib_object(C); 00294 bAction *act = (ob)? ob->poselib : NULL; 00295 DLRBT_Tree keys; 00296 ActKeyColumn *ak; 00297 TimeMarker *marker, *markern; 00298 00299 /* validate action */ 00300 if (act == NULL) { 00301 BKE_report(op->reports, RPT_WARNING, "No Action to validate"); 00302 return OPERATOR_CANCELLED; 00303 } 00304 00305 /* determine which frames have keys */ 00306 BLI_dlrbTree_init(&keys); 00307 action_to_keylist(NULL, act, &keys, NULL); 00308 BLI_dlrbTree_linkedlist_sync(&keys); 00309 00310 /* for each key, make sure there is a corresponding pose */ 00311 for (ak= keys.first; ak; ak= ak->next) { 00312 /* check if any pose matches this */ 00313 // TODO: don't go looking through the list like this every time... 00314 for (marker= act->markers.first; marker; marker= marker->next) { 00315 if (IS_EQ(marker->frame, (double)ak->cfra)) { 00316 marker->flag = -1; 00317 break; 00318 } 00319 } 00320 00321 /* add new if none found */ 00322 if (marker == NULL) { 00323 /* add pose to poselib */ 00324 marker= MEM_callocN(sizeof(TimeMarker), "ActionMarker"); 00325 00326 BLI_strncpy(marker->name, "Pose", sizeof(marker->name)); 00327 00328 marker->frame= (int)ak->cfra; 00329 marker->flag= -1; 00330 00331 BLI_addtail(&act->markers, marker); 00332 } 00333 } 00334 00335 /* remove all untagged poses (unused), and remove all tags */ 00336 for (marker= act->markers.first; marker; marker= markern) { 00337 markern= marker->next; 00338 00339 if (marker->flag != -1) 00340 BLI_freelinkN(&act->markers, marker); 00341 else 00342 marker->flag = 0; 00343 } 00344 00345 /* free temp memory */ 00346 BLI_dlrbTree_free(&keys); 00347 00348 /* send notifiers for this - using keyframe editing notifiers, since action 00349 * may be being shown in anim editors as active action 00350 */ 00351 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); 00352 00353 return OPERATOR_FINISHED; 00354 } 00355 00356 void POSELIB_OT_action_sanitise (wmOperatorType *ot) 00357 { 00358 /* identifiers */ 00359 ot->name = "Sanitise Pose Library Action"; 00360 ot->idname = "POSELIB_OT_action_sanitise"; 00361 ot->description = "Make action suitable for use as a Pose Library"; 00362 00363 /* callbacks */ 00364 ot->exec = poselib_sanitise_exec; 00365 ot->poll = has_poselib_pose_data_poll; 00366 00367 /* flags */ 00368 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00369 } 00370 00371 /* ------------------------------------------ */ 00372 00373 static void poselib_add_menu_invoke__replacemenu (bContext *C, uiLayout *layout, void *UNUSED(arg)) 00374 { 00375 Object *ob= get_poselib_object(C); 00376 bAction *act= ob->poselib; /* never NULL */ 00377 TimeMarker *marker; 00378 00379 /* set the operator execution context correctly */ 00380 uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT); 00381 00382 /* add each marker to this menu */ 00383 for (marker= act->markers.first; marker; marker= marker->next) { 00384 PointerRNA props_ptr; 00385 00386 props_ptr = uiItemFullO(layout, "POSELIB_OT_pose_add", 00387 marker->name, ICON_ARMATURE_DATA, NULL, 00388 WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); 00389 00390 RNA_int_set(&props_ptr, "frame", marker->frame); 00391 RNA_string_set(&props_ptr, "name", marker->name); 00392 } 00393 } 00394 00395 static int poselib_add_menu_invoke (bContext *C, wmOperator *op, wmEvent *UNUSED(evt)) 00396 { 00397 Scene *scene= CTX_data_scene(C); 00398 Object *ob= get_poselib_object(C); 00399 bPose *pose= (ob) ? ob->pose : NULL; 00400 uiPopupMenu *pup; 00401 uiLayout *layout; 00402 00403 /* sanity check */ 00404 if (ELEM(NULL, ob, pose)) 00405 return OPERATOR_CANCELLED; 00406 00407 /* start building */ 00408 pup= uiPupMenuBegin(C, op->type->name, ICON_NONE); 00409 layout= uiPupMenuLayout(pup); 00410 uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT); 00411 00412 /* add new (adds to the first unoccupied frame) */ 00413 uiItemIntO(layout, IFACE_("Add New"), ICON_NONE, "POSELIB_OT_pose_add", "frame", poselib_get_free_index(ob->poselib)); 00414 00415 /* check if we have any choices to add a new pose in any other way */ 00416 if ((ob->poselib) && (ob->poselib->markers.first)) { 00417 /* add new (on current frame) */ 00418 uiItemIntO(layout, IFACE_("Add New (Current Frame)"), ICON_NONE, "POSELIB_OT_pose_add", "frame", CFRA); 00419 00420 /* replace existing - submenu */ 00421 uiItemMenuF(layout, IFACE_("Replace Existing..."), 0, poselib_add_menu_invoke__replacemenu, NULL); 00422 } 00423 00424 uiPupMenuEnd(C, pup); 00425 00426 /* this operator is only for a menu, not used further */ 00427 return OPERATOR_CANCELLED; 00428 } 00429 00430 00431 static int poselib_add_exec (bContext *C, wmOperator *op) 00432 { 00433 Object *ob= get_poselib_object(C); 00434 bAction *act = poselib_validate(ob); 00435 bPose *pose= (ob) ? ob->pose : NULL; 00436 TimeMarker *marker; 00437 KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_WHOLE_CHARACTER_ID); /* this includes custom props :)*/ 00438 int frame= RNA_int_get(op->ptr, "frame"); 00439 char name[64]; 00440 00441 /* sanity check (invoke should have checked this anyway) */ 00442 if (ELEM(NULL, ob, pose)) 00443 return OPERATOR_CANCELLED; 00444 00445 /* get name to give to pose */ 00446 RNA_string_get(op->ptr, "name", name); 00447 00448 /* add pose to poselib - replaces any existing pose there 00449 * - for the 'replace' option, this should end up finding the appropriate marker, 00450 * so no new one will be added 00451 */ 00452 for (marker= act->markers.first; marker; marker= marker->next) { 00453 if (marker->frame == frame) { 00454 BLI_strncpy(marker->name, name, sizeof(marker->name)); 00455 break; 00456 } 00457 } 00458 if (marker == NULL) { 00459 marker= MEM_callocN(sizeof(TimeMarker), "ActionMarker"); 00460 00461 BLI_strncpy(marker->name, name, sizeof(marker->name)); 00462 marker->frame= frame; 00463 00464 BLI_addtail(&act->markers, marker); 00465 } 00466 00467 /* validate name */ 00468 BLI_uniquename(&act->markers, marker, "Pose", '.', offsetof(TimeMarker, name), sizeof(marker->name)); 00469 00470 /* use Keying Set to determine what to store for the pose */ 00471 // FIXME: in the past, the Keying Set respected selections (LocRotScale), but the current one doesn't (Whole Character) 00472 // so perhaps we need either a new Keying Set, or just to add overrides here... 00473 ANIM_apply_keyingset(C, NULL, act, ks, MODIFYKEY_MODE_INSERT, (float)frame); 00474 00475 /* store new 'active' pose number */ 00476 act->active_marker= BLI_countlist(&act->markers); 00477 00478 /* done */ 00479 return OPERATOR_FINISHED; 00480 } 00481 00482 void POSELIB_OT_pose_add (wmOperatorType *ot) 00483 { 00484 /* identifiers */ 00485 ot->name= "PoseLib Add Pose"; 00486 ot->idname= "POSELIB_OT_pose_add"; 00487 ot->description= "Add the current Pose to the active Pose Library"; 00488 00489 /* api callbacks */ 00490 ot->invoke= poselib_add_menu_invoke; 00491 ot->exec= poselib_add_exec; 00492 ot->poll= ED_operator_posemode; 00493 00494 /* flags */ 00495 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00496 00497 /* properties */ 00498 RNA_def_int(ot->srna, "frame", 1, 0, INT_MAX, "Frame", "Frame to store pose on", 0, INT_MAX); 00499 RNA_def_string(ot->srna, "name", "Pose", 64, "Pose Name", "Name of newly added Pose"); 00500 } 00501 00502 /* ----- */ 00503 00504 /* can be called with C == NULL */ 00505 static EnumPropertyItem *poselib_stored_pose_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free) 00506 { 00507 Object *ob = get_poselib_object(C); 00508 bAction *act = (ob) ? ob->poselib : NULL; 00509 TimeMarker *marker; 00510 EnumPropertyItem *item= NULL, item_tmp= {0}; 00511 int totitem= 0; 00512 int i= 0; 00513 00514 if (C == NULL) { 00515 return DummyRNA_DEFAULT_items; 00516 } 00517 00518 /* check that the action exists */ 00519 if (act) { 00520 /* add each marker to the list */ 00521 for (marker=act->markers.first, i=0; marker; marker= marker->next, i++) { 00522 item_tmp.identifier= item_tmp.name= marker->name; 00523 item_tmp.icon= ICON_ARMATURE_DATA; 00524 item_tmp.value= i; 00525 RNA_enum_item_add(&item, &totitem, &item_tmp); 00526 } 00527 } 00528 00529 RNA_enum_item_end(&item, &totitem); 00530 *free= 1; 00531 00532 return item; 00533 } 00534 00535 static int poselib_remove_exec (bContext *C, wmOperator *op) 00536 { 00537 Object *ob= get_poselib_object(C); 00538 bAction *act= (ob) ? ob->poselib : NULL; 00539 TimeMarker *marker; 00540 FCurve *fcu; 00541 00542 /* check if valid poselib */ 00543 if (act == NULL) { 00544 BKE_report(op->reports, RPT_ERROR, "Object doesn't have PoseLib data"); 00545 return OPERATOR_CANCELLED; 00546 } 00547 00548 /* get index (and pointer) of pose to remove */ 00549 marker= BLI_findlink(&act->markers, RNA_enum_get(op->ptr, "pose")); 00550 if (marker == NULL) { 00551 BKE_reportf(op->reports, RPT_ERROR, "Invalid Pose specified %d", RNA_int_get(op->ptr, "pose")); 00552 return OPERATOR_CANCELLED; 00553 } 00554 00555 /* remove relevant keyframes */ 00556 for (fcu= act->curves.first; fcu; fcu= fcu->next) { 00557 BezTriple *bezt; 00558 unsigned int i; 00559 00560 if (fcu->bezt) { 00561 for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) { 00562 /* check if remove */ 00563 if (IS_EQ(bezt->vec[1][0], marker->frame)) { 00564 delete_fcurve_key(fcu, i, 1); 00565 break; 00566 } 00567 } 00568 } 00569 } 00570 00571 /* remove poselib from list */ 00572 BLI_freelinkN(&act->markers, marker); 00573 00574 /* fix active pose number */ 00575 act->active_marker= 0; 00576 00577 /* send notifiers for this - using keyframe editing notifiers, since action 00578 * may be being shown in anim editors as active action 00579 */ 00580 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); 00581 00582 /* done */ 00583 return OPERATOR_FINISHED; 00584 } 00585 00586 void POSELIB_OT_pose_remove (wmOperatorType *ot) 00587 { 00588 PropertyRNA *prop; 00589 00590 /* identifiers */ 00591 ot->name= "PoseLib Remove Pose"; 00592 ot->idname= "POSELIB_OT_pose_remove"; 00593 ot->description= "Remove nth pose from the active Pose Library"; 00594 00595 /* api callbacks */ 00596 ot->invoke= WM_menu_invoke; 00597 ot->exec= poselib_remove_exec; 00598 ot->poll= has_poselib_pose_data_poll; 00599 00600 /* flags */ 00601 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00602 00603 /* properties */ 00604 prop= RNA_def_enum(ot->srna, "pose", DummyRNA_DEFAULT_items, 0, "Pose", "The pose to remove"); 00605 RNA_def_enum_funcs(prop, poselib_stored_pose_itemf); 00606 ot->prop= prop; 00607 } 00608 00609 static int poselib_rename_invoke (bContext *C, wmOperator *op, wmEvent *evt) 00610 { 00611 Object *ob= get_poselib_object(C); 00612 bAction *act= (ob) ? ob->poselib : NULL; 00613 TimeMarker *marker; 00614 00615 /* check if valid poselib */ 00616 if (act == NULL) { 00617 BKE_report(op->reports, RPT_ERROR, "Object doesn't have PoseLib data"); 00618 return OPERATOR_CANCELLED; 00619 } 00620 00621 /* get index (and pointer) of pose to remove */ 00622 marker= BLI_findlink(&act->markers, act->active_marker-1); 00623 if (marker == NULL) { 00624 BKE_report(op->reports, RPT_ERROR, "Invalid index for Pose"); 00625 return OPERATOR_CANCELLED; 00626 } 00627 else { 00628 /* use the existing name of the marker as the name, and use the active marker as the one to rename */ 00629 RNA_enum_set(op->ptr, "pose", act->active_marker-1); 00630 RNA_string_set(op->ptr, "name", marker->name); 00631 } 00632 00633 /* part to sync with other similar operators... */ 00634 return WM_operator_props_popup(C, op, evt); 00635 } 00636 00637 static int poselib_rename_exec (bContext *C, wmOperator *op) 00638 { 00639 Object *ob= object_pose_armature_get(CTX_data_active_object(C)); 00640 bAction *act= (ob) ? ob->poselib : NULL; 00641 TimeMarker *marker; 00642 char newname[64]; 00643 00644 /* check if valid poselib */ 00645 if (act == NULL) { 00646 BKE_report(op->reports, RPT_ERROR, "Object doesn't have PoseLib data"); 00647 return OPERATOR_CANCELLED; 00648 } 00649 00650 /* get index (and pointer) of pose to remove */ 00651 marker= BLI_findlink(&act->markers, RNA_int_get(op->ptr, "pose")); 00652 if (marker == NULL) { 00653 BKE_report(op->reports, RPT_ERROR, "Invalid index for Pose"); 00654 return OPERATOR_CANCELLED; 00655 } 00656 00657 /* get new name */ 00658 RNA_string_get(op->ptr, "name", newname); 00659 00660 /* copy name and validate it */ 00661 BLI_strncpy(marker->name, newname, sizeof(marker->name)); 00662 BLI_uniquename(&act->markers, marker, "Pose", '.', offsetof(TimeMarker, name), sizeof(marker->name)); 00663 00664 /* send notifiers for this - using keyframe editing notifiers, since action 00665 * may be being shown in anim editors as active action 00666 */ 00667 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); 00668 00669 /* done */ 00670 return OPERATOR_FINISHED; 00671 } 00672 00673 void POSELIB_OT_pose_rename (wmOperatorType *ot) 00674 { 00675 PropertyRNA *prop; 00676 static EnumPropertyItem prop_poses_dummy_types[] = { 00677 {0, NULL, 0, NULL, NULL} 00678 }; 00679 00680 /* identifiers */ 00681 ot->name= "PoseLib Rename Pose"; 00682 ot->idname= "POSELIB_OT_pose_rename"; 00683 ot->description= "Rename specified pose from the active Pose Library"; 00684 00685 /* api callbacks */ 00686 ot->invoke= poselib_rename_invoke; 00687 ot->exec= poselib_rename_exec; 00688 ot->poll= has_poselib_pose_data_poll; 00689 00690 /* flags */ 00691 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00692 00693 /* properties */ 00694 /* NOTE: name not pose is the operator's "main" property, so that it will get activated in the popup for easy renaming */ 00695 ot->prop= RNA_def_string(ot->srna, "name", "RenamedPose", 64, "New Pose Name", "New name for pose"); 00696 prop= RNA_def_enum(ot->srna, "pose", prop_poses_dummy_types, 0, "Pose", "The pose to rename"); 00697 RNA_def_enum_funcs(prop, poselib_stored_pose_itemf); 00698 } 00699 00700 /* ************************************************************* */ 00701 /* Pose-Lib Browsing/Previewing Operator */ 00702 00703 /* Simple struct for storing settings/data for use during PoseLib preview */ 00704 typedef struct tPoseLib_PreviewData { 00705 ListBase backups; /* tPoseLib_Backup structs for restoring poses */ 00706 ListBase searchp; /* LinkData structs storing list of poses which match the current search-string */ 00707 00708 Scene *scene; /* active scene */ 00709 ScrArea *sa; /* active area */ 00710 00711 PointerRNA rna_ptr; /* RNA-Pointer to Object 'ob' */ 00712 Object *ob; /* object to work on */ 00713 bArmature *arm; /* object's armature data */ 00714 bPose *pose; /* object's pose */ 00715 bAction *act; /* poselib to use */ 00716 TimeMarker *marker; /* 'active' pose */ 00717 00718 int selcount; /* number of selected elements to work on */ 00719 int totcount; /* total number of elements to work on */ 00720 00721 short state; /* state of main loop */ 00722 short redraw; /* redraw/update settings during main loop */ 00723 short flag; /* flags for various settings */ 00724 00725 short search_cursor; /* position of cursor in searchstr (cursor occurs before the item at the nominated index) */ 00726 char searchstr[64]; /* (Part of) Name to search for to filter poses that get shown */ 00727 char searchold[64]; /* Previously set searchstr (from last loop run), so that we can detected when to rebuild searchp */ 00728 00729 char headerstr[200]; /* Info-text to print in header */ 00730 } tPoseLib_PreviewData; 00731 00732 /* defines for tPoseLib_PreviewData->state values */ 00733 enum { 00734 PL_PREVIEW_ERROR = -1, 00735 PL_PREVIEW_RUNNING, 00736 PL_PREVIEW_CONFIRM, 00737 PL_PREVIEW_CANCEL, 00738 PL_PREVIEW_RUNONCE 00739 }; 00740 00741 /* defines for tPoseLib_PreviewData->redraw values */ 00742 enum { 00743 PL_PREVIEW_NOREDRAW = 0, 00744 PL_PREVIEW_REDRAWALL, 00745 PL_PREVIEW_REDRAWHEADER, 00746 }; 00747 00748 /* defines for tPoseLib_PreviewData->flag values */ 00749 enum { 00750 PL_PREVIEW_FIRSTTIME = (1<<0), 00751 PL_PREVIEW_SHOWORIGINAL = (1<<1) 00752 }; 00753 00754 /* ---------------------------- */ 00755 00756 /* simple struct for storing backup info */ 00757 typedef struct tPoseLib_Backup { 00758 struct tPoseLib_Backup *next, *prev; 00759 00760 bPoseChannel *pchan; /* pose channel backups are for */ 00761 00762 bPoseChannel olddata; /* copy of pose channel's old data (at start) */ 00763 IDProperty *oldprops; /* copy (needs freeing) of pose channel's properties (at start) */ 00764 } tPoseLib_Backup; 00765 00766 /* Makes a copy of the current pose for restoration purposes - doesn't do constraints currently */ 00767 static void poselib_backup_posecopy (tPoseLib_PreviewData *pld) 00768 { 00769 bActionGroup *agrp; 00770 bPoseChannel *pchan; 00771 00772 /* for each posechannel that has an actionchannel in */ 00773 for (agrp= pld->act->groups.first; agrp; agrp= agrp->next) { 00774 /* try to find posechannel */ 00775 pchan= get_pose_channel(pld->pose, agrp->name); 00776 00777 /* backup data if available */ 00778 if (pchan) { 00779 tPoseLib_Backup *plb; 00780 00781 /* store backup */ 00782 plb= MEM_callocN(sizeof(tPoseLib_Backup), "tPoseLib_Backup"); 00783 00784 plb->pchan= pchan; 00785 memcpy(&plb->olddata, plb->pchan, sizeof(bPoseChannel)); 00786 00787 if (pchan->prop) 00788 plb->oldprops= IDP_CopyProperty(pchan->prop); 00789 00790 BLI_addtail(&pld->backups, plb); 00791 00792 /* mark as being affected */ 00793 if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) 00794 pld->selcount++; 00795 pld->totcount++; 00796 } 00797 } 00798 } 00799 00800 /* Restores original pose */ 00801 static void poselib_backup_restore (tPoseLib_PreviewData *pld) 00802 { 00803 tPoseLib_Backup *plb; 00804 00805 for (plb= pld->backups.first; plb; plb= plb->next) { 00806 /* copy most of data straight back */ 00807 memcpy(plb->pchan, &plb->olddata, sizeof(bPoseChannel)); 00808 00809 /* just overwrite values of properties from the stored copies (there should be some) */ 00810 if (plb->oldprops) 00811 IDP_SyncGroupValues(plb->pchan->prop, plb->oldprops); 00812 00813 // TODO: constraints settings aren't restored yet, even though these could change (though not that likely) 00814 } 00815 } 00816 00817 /* Free list of backups, including any side data it may use */ 00818 static void poselib_backup_free_data (tPoseLib_PreviewData *pld) 00819 { 00820 tPoseLib_Backup *plb, *plbn; 00821 00822 for (plb= pld->backups.first; plb; plb= plbn) { 00823 plbn= plb->next; 00824 00825 /* free custom data */ 00826 if (plb->oldprops) { 00827 IDP_FreeProperty(plb->oldprops); 00828 MEM_freeN(plb->oldprops); 00829 } 00830 00831 /* free backup element now */ 00832 BLI_freelinkN(&pld->backups, plb); 00833 } 00834 } 00835 00836 /* ---------------------------- */ 00837 00838 /* Applies the appropriate stored pose from the pose-library to the current pose 00839 * - assumes that a valid object, with a poselib has been supplied 00840 * - gets the string to print in the header 00841 * - this code is based on the code for extract_pose_from_action in blenkernel/action.c 00842 */ 00843 static void poselib_apply_pose (tPoseLib_PreviewData *pld) 00844 { 00845 PointerRNA *ptr= &pld->rna_ptr; 00846 bArmature *arm= pld->arm; 00847 bPose *pose= pld->pose; 00848 bPoseChannel *pchan; 00849 bAction *act= pld->act; 00850 bActionGroup *agrp; 00851 00852 KeyframeEditData ked= {{NULL}}; 00853 KeyframeEditFunc group_ok_cb; 00854 int frame= 1; 00855 00856 /* get the frame */ 00857 if (pld->marker) 00858 frame= pld->marker->frame; 00859 else 00860 return; 00861 00862 00863 /* init settings for testing groups for keyframes */ 00864 group_ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE); 00865 ked.f1= ((float)frame) - 0.5f; 00866 ked.f2= ((float)frame) + 0.5f; 00867 00868 00869 /* start applying - only those channels which have a key at this point in time! */ 00870 for (agrp= act->groups.first; agrp; agrp= agrp->next) { 00871 /* check if group has any keyframes */ 00872 if (ANIM_animchanneldata_keyframes_loop(&ked, NULL, agrp, ALE_GROUP, NULL, group_ok_cb, NULL)) { 00873 /* has keyframe on this frame, so try to get a PoseChannel with this name */ 00874 pchan= get_pose_channel(pose, agrp->name); 00875 00876 if (pchan) { 00877 short ok= 0; 00878 00879 /* check if this bone should get any animation applied */ 00880 if (pld->selcount == 0) { 00881 /* if no bones are selected, then any bone is ok */ 00882 ok= 1; 00883 } 00884 else if (pchan->bone) { 00885 /* only ok if bone is visible and selected */ 00886 if ( (pchan->bone->flag & BONE_SELECTED) && 00887 (pchan->bone->flag & BONE_HIDDEN_P)==0 && 00888 (pchan->bone->layer & arm->layer) ) 00889 ok = 1; 00890 } 00891 00892 if (ok) 00893 animsys_evaluate_action_group(ptr, act, agrp, NULL, (float)frame); 00894 } 00895 } 00896 } 00897 } 00898 00899 /* Auto-keys/tags bones affected by the pose used from the poselib */ 00900 static void poselib_keytag_pose (bContext *C, Scene *scene, tPoseLib_PreviewData *pld) 00901 { 00902 bPose *pose= pld->pose; 00903 bPoseChannel *pchan; 00904 bAction *act= pld->act; 00905 bActionGroup *agrp; 00906 00907 KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID); 00908 ListBase dsources = {NULL, NULL}; 00909 short autokey = autokeyframe_cfra_can_key(scene, &pld->ob->id); 00910 00911 /* start tagging/keying */ 00912 for (agrp= act->groups.first; agrp; agrp= agrp->next) { 00913 /* only for selected bones unless there aren't any selected, in which case all are included */ 00914 pchan= get_pose_channel(pose, agrp->name); 00915 00916 if (pchan) { 00917 if ( (pld->selcount == 0) || ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) ) { 00918 if (autokey) { 00919 /* add datasource override for the PoseChannel, to be used later */ 00920 ANIM_relative_keyingset_add_source(&dsources, &pld->ob->id, &RNA_PoseBone, pchan); 00921 00922 /* clear any unkeyed tags */ 00923 if (pchan->bone) 00924 pchan->bone->flag &= ~BONE_UNKEYED; 00925 } 00926 else { 00927 /* add unkeyed tags */ 00928 if (pchan->bone) 00929 pchan->bone->flag |= BONE_UNKEYED; 00930 } 00931 } 00932 } 00933 } 00934 00935 /* perform actual auto-keying now */ 00936 if (autokey) { 00937 /* insert keyframes for all relevant bones in one go */ 00938 ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); 00939 BLI_freelistN(&dsources); 00940 } 00941 00942 /* send notifiers for this */ 00943 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); 00944 } 00945 00946 /* Apply the relevant changes to the pose */ 00947 static void poselib_preview_apply (bContext *C, wmOperator *op) 00948 { 00949 tPoseLib_PreviewData *pld= (tPoseLib_PreviewData *)op->customdata; 00950 00951 /* only recalc pose (and its dependencies) if pose has changed */ 00952 if (pld->redraw == PL_PREVIEW_REDRAWALL) { 00953 /* don't clear pose if firsttime */ 00954 if ((pld->flag & PL_PREVIEW_FIRSTTIME)==0) 00955 poselib_backup_restore(pld); 00956 else 00957 pld->flag &= ~PL_PREVIEW_FIRSTTIME; 00958 00959 /* pose should be the right one to draw (unless we're temporarily not showing it) */ 00960 if ((pld->flag & PL_PREVIEW_SHOWORIGINAL)==0) { 00961 RNA_int_set(op->ptr, "pose_index", BLI_findindex(&pld->act->markers, pld->marker)); 00962 poselib_apply_pose(pld); 00963 } 00964 else 00965 RNA_int_set(op->ptr, "pose_index", -2); /* -2 means don't apply any pose */ 00966 00967 /* old optimize trick... this enforces to bypass the depgraph 00968 * - note: code copied from transform_generics.c -> recalcData() 00969 */ 00970 // FIXME: shouldn't this use the builtin stuff? 00971 if ((pld->arm->flag & ARM_DELAYDEFORM)==0) 00972 DAG_id_tag_update(&pld->ob->id, OB_RECALC_DATA); /* sets recalc flags */ 00973 else 00974 where_is_pose(pld->scene, pld->ob); 00975 } 00976 00977 /* do header print - if interactively previewing */ 00978 if (pld->state == PL_PREVIEW_RUNNING) { 00979 if (pld->flag & PL_PREVIEW_SHOWORIGINAL) { 00980 BLI_strncpy(pld->headerstr, 00981 "PoseLib Previewing Pose: [Showing Original Pose] | Use Tab to start previewing poses again", 00982 sizeof(pld->headerstr)); 00983 ED_area_headerprint(pld->sa, pld->headerstr); 00984 } 00985 else if (pld->searchstr[0]) { 00986 char tempstr[65]; 00987 char markern[64]; 00988 short index; 00989 00990 /* get search-string */ 00991 index= pld->search_cursor; 00992 00993 if (index >= 0 && index <= sizeof(tempstr) - 1) { 00994 memcpy(&tempstr[0], &pld->searchstr[0], index); 00995 tempstr[index]= '|'; 00996 memcpy(&tempstr[index+1], &pld->searchstr[index], (sizeof(tempstr) - 1) - index); 00997 } 00998 else { 00999 BLI_strncpy(tempstr, pld->searchstr, sizeof(tempstr)); 01000 } 01001 01002 /* get marker name */ 01003 BLI_strncpy(markern, pld->marker ? pld->marker->name : "No Matches", sizeof(markern)); 01004 01005 BLI_snprintf(pld->headerstr, sizeof(pld->headerstr), 01006 "PoseLib Previewing Pose: Filter - [%s] | " 01007 "Current Pose - \"%s\" | " 01008 "Use ScrollWheel or PageUp/Down to change", 01009 tempstr, markern); 01010 ED_area_headerprint(pld->sa, pld->headerstr); 01011 } 01012 else { 01013 BLI_snprintf(pld->headerstr, sizeof(pld->headerstr), 01014 "PoseLib Previewing Pose: \"%s\" | " 01015 "Use ScrollWheel or PageUp/Down to change", 01016 pld->marker->name); 01017 ED_area_headerprint(pld->sa, pld->headerstr); 01018 } 01019 } 01020 01021 /* request drawing of view + clear redraw flag */ 01022 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, pld->ob); 01023 pld->redraw= PL_PREVIEW_NOREDRAW; 01024 } 01025 01026 /* ---------------------------- */ 01027 01028 /* This helper function is called during poselib_preview_poses to find the 01029 * pose to preview next (after a change event) 01030 */ 01031 static void poselib_preview_get_next (tPoseLib_PreviewData *pld, int step) 01032 { 01033 /* stop if not going anywhere, as we assume that there is a direction to move in */ 01034 if (step == 0) 01035 return; 01036 01037 /* search-string dictates a special approach */ 01038 if (pld->searchstr[0]) { 01039 TimeMarker *marker; 01040 LinkData *ld, *ldn, *ldc; 01041 01042 /* free and rebuild if needed (i.e. if search-str changed) */ 01043 if (strcmp(pld->searchstr, pld->searchold)) { 01044 /* free list of temporary search matches */ 01045 BLI_freelistN(&pld->searchp); 01046 01047 /* generate a new list of search matches */ 01048 for (marker= pld->act->markers.first; marker; marker= marker->next) { 01049 /* does the name partially match? 01050 * - don't worry about case, to make it easier for users to quickly input a name (or 01051 * part of one), which is the whole point of this feature 01052 */ 01053 if (BLI_strcasestr(marker->name, pld->searchstr)) { 01054 /* make link-data to store reference to it */ 01055 ld= MEM_callocN(sizeof(LinkData), "PoseMatch"); 01056 ld->data= marker; 01057 BLI_addtail(&pld->searchp, ld); 01058 } 01059 } 01060 01061 /* set current marker to NULL (so that we start from first) */ 01062 pld->marker= NULL; 01063 } 01064 01065 /* check if any matches */ 01066 if (pld->searchp.first == NULL) { 01067 pld->marker= NULL; 01068 return; 01069 } 01070 01071 /* find first match */ 01072 for (ldc= pld->searchp.first; ldc; ldc= ldc->next) { 01073 if (ldc->data == pld->marker) 01074 break; 01075 } 01076 if (ldc == NULL) 01077 ldc= pld->searchp.first; 01078 01079 /* Loop through the matches in a cyclic fashion, incrementing/decrementing step as appropriate 01080 * until step == 0. At this point, marker should be the correct marker. 01081 */ 01082 if (step > 0) { 01083 for (ld=ldc; ld && step; ld=ldn, step--) 01084 ldn= (ld->next) ? ld->next : pld->searchp.first; 01085 } 01086 else { 01087 for (ld=ldc; ld && step; ld=ldn, step++) 01088 ldn= (ld->prev) ? ld->prev : pld->searchp.last; 01089 } 01090 01091 /* set marker */ 01092 if (ld) 01093 pld->marker= ld->data; 01094 } 01095 else { 01096 TimeMarker *marker, *next; 01097 01098 /* if no marker, because we just ended searching, then set that to the start of the list */ 01099 if (pld->marker == NULL) 01100 pld->marker= pld->act->markers.first; 01101 01102 /* Loop through the markers in a cyclic fashion, incrementing/decrementing step as appropriate 01103 * until step == 0. At this point, marker should be the correct marker. 01104 */ 01105 if (step > 0) { 01106 for (marker=pld->marker; marker && step; marker=next, step--) 01107 next= (marker->next) ? marker->next : pld->act->markers.first; 01108 } 01109 else { 01110 for (marker=pld->marker; marker && step; marker=next, step++) 01111 next= (marker->prev) ? marker->prev : pld->act->markers.last; 01112 } 01113 01114 /* it should be fairly impossible for marker to be NULL */ 01115 if (marker) 01116 pld->marker= marker; 01117 } 01118 } 01119 01120 /* specially handle events for searching */ 01121 static void poselib_preview_handle_search (tPoseLib_PreviewData *pld, unsigned short event, char ascii) 01122 { 01123 /* try doing some form of string manipulation first */ 01124 switch (event) { 01125 case BACKSPACEKEY: 01126 if (pld->searchstr[0] && pld->search_cursor) { 01127 short len= strlen(pld->searchstr); 01128 short index= pld->search_cursor; 01129 short i; 01130 01131 for (i = index; i <= len; i++) 01132 pld->searchstr[i-1] = pld->searchstr[i]; 01133 01134 pld->search_cursor--; 01135 01136 poselib_preview_get_next(pld, 1); 01137 pld->redraw = PL_PREVIEW_REDRAWALL; 01138 return; 01139 } 01140 break; 01141 01142 case DELKEY: 01143 if (pld->searchstr[0] && pld->searchstr[1]) { 01144 short len= strlen(pld->searchstr); 01145 short index= pld->search_cursor; 01146 int i; 01147 01148 if (index < len) { 01149 for (i = index; i < len; i++) 01150 pld->searchstr[i] = pld->searchstr[i+1]; 01151 01152 poselib_preview_get_next(pld, 1); 01153 pld->redraw = PL_PREVIEW_REDRAWALL; 01154 return; 01155 } 01156 } 01157 break; 01158 } 01159 01160 if (ascii) { 01161 /* character to add to the string */ 01162 short index= pld->search_cursor; 01163 short len= (pld->searchstr[0]) ? strlen(pld->searchstr) : 0; 01164 short i; 01165 01166 if (len) { 01167 for (i = len; i > index; i--) 01168 pld->searchstr[i]= pld->searchstr[i-1]; 01169 } 01170 else 01171 pld->searchstr[1]= 0; 01172 01173 pld->searchstr[index]= ascii; 01174 pld->search_cursor++; 01175 01176 poselib_preview_get_next(pld, 1); 01177 pld->redraw = PL_PREVIEW_REDRAWALL; 01178 } 01179 } 01180 01181 /* handle events for poselib_preview_poses */ 01182 static int poselib_preview_handle_event (bContext *UNUSED(C), wmOperator *op, wmEvent *event) 01183 { 01184 tPoseLib_PreviewData *pld= op->customdata; 01185 int ret = OPERATOR_RUNNING_MODAL; 01186 01187 /* only accept 'press' event, and ignore 'release', so that we don't get double actions */ 01188 if (ELEM(event->val, KM_PRESS, KM_NOTHING) == 0) { 01189 //printf("PoseLib: skipping event with type '%s' and val %d\n", WM_key_event_string(event->type), event->val); 01190 return ret; 01191 } 01192 01193 /* backup stuff that needs to occur before every operation 01194 * - make a copy of searchstr, so that we know if cache needs to be rebuilt 01195 */ 01196 BLI_strncpy(pld->searchold, pld->searchstr, sizeof(pld->searchold)); 01197 01198 /* if we're currently showing the original pose, only certain events are handled */ 01199 if (pld->flag & PL_PREVIEW_SHOWORIGINAL) { 01200 switch (event->type) { 01201 /* exit - cancel */ 01202 case ESCKEY: 01203 case RIGHTMOUSE: 01204 pld->state= PL_PREVIEW_CANCEL; 01205 break; 01206 01207 /* exit - confirm */ 01208 case LEFTMOUSE: 01209 case RETKEY: 01210 case PADENTER: 01211 case SPACEKEY: 01212 pld->state= PL_PREVIEW_CONFIRM; 01213 break; 01214 01215 /* view manipulation */ 01216 /* we add pass through here, so that the operators responsible for these can still run, 01217 * even though we still maintain control (as RUNNING_MODAL flag is still set too) 01218 */ 01219 case PAD0: case PAD1: case PAD2: case PAD3: case PAD4: 01220 case PAD5: case PAD6: case PAD7: case PAD8: case PAD9: 01221 case PADPLUSKEY: case PADMINUS: 01222 case MIDDLEMOUSE: case MOUSEMOVE: 01223 //pld->redraw= PL_PREVIEW_REDRAWHEADER; 01224 ret = OPERATOR_PASS_THROUGH; 01225 break; 01226 01227 /* quicky compare to original */ 01228 case TABKEY: 01229 pld->flag &= ~PL_PREVIEW_SHOWORIGINAL; 01230 pld->redraw= PL_PREVIEW_REDRAWALL; 01231 break; 01232 } 01233 01234 /* EXITS HERE... */ 01235 return ret; 01236 } 01237 01238 /* NORMAL EVENT HANDLING... */ 01239 /* searching takes priority over normal activity */ 01240 switch (event->type) { 01241 /* exit - cancel */ 01242 case ESCKEY: 01243 case RIGHTMOUSE: 01244 pld->state= PL_PREVIEW_CANCEL; 01245 break; 01246 01247 /* exit - confirm */ 01248 case LEFTMOUSE: 01249 case RETKEY: 01250 case PADENTER: 01251 case SPACEKEY: 01252 pld->state= PL_PREVIEW_CONFIRM; 01253 break; 01254 01255 /* toggle between original pose and poselib pose*/ 01256 case TABKEY: 01257 pld->flag |= PL_PREVIEW_SHOWORIGINAL; 01258 pld->redraw= PL_PREVIEW_REDRAWALL; 01259 break; 01260 01261 /* change to previous pose (cyclic) */ 01262 case PAGEUPKEY: 01263 case WHEELUPMOUSE: 01264 poselib_preview_get_next(pld, -1); 01265 pld->redraw= PL_PREVIEW_REDRAWALL; 01266 break; 01267 01268 /* change to next pose (cyclic) */ 01269 case PAGEDOWNKEY: 01270 case WHEELDOWNMOUSE: 01271 poselib_preview_get_next(pld, 1); 01272 pld->redraw= PL_PREVIEW_REDRAWALL; 01273 break; 01274 01275 /* jump 5 poses (cyclic, back) */ 01276 case DOWNARROWKEY: 01277 poselib_preview_get_next(pld, -5); 01278 pld->redraw= PL_PREVIEW_REDRAWALL; 01279 break; 01280 01281 /* jump 5 poses (cyclic, forward) */ 01282 case UPARROWKEY: 01283 poselib_preview_get_next(pld, 5); 01284 pld->redraw= PL_PREVIEW_REDRAWALL; 01285 break; 01286 01287 /* change to next pose or searching cursor control */ 01288 case RIGHTARROWKEY: 01289 if (pld->searchstr[0]) { 01290 /* move text-cursor to the right */ 01291 if (pld->search_cursor < strlen(pld->searchstr)) 01292 pld->search_cursor++; 01293 pld->redraw= PL_PREVIEW_REDRAWHEADER; 01294 } 01295 else { 01296 /* change to next pose (cyclic) */ 01297 poselib_preview_get_next(pld, 1); 01298 pld->redraw= PL_PREVIEW_REDRAWALL; 01299 } 01300 break; 01301 01302 /* change to next pose or searching cursor control */ 01303 case LEFTARROWKEY: 01304 if (pld->searchstr[0]) { 01305 /* move text-cursor to the left */ 01306 if (pld->search_cursor) 01307 pld->search_cursor--; 01308 pld->redraw= PL_PREVIEW_REDRAWHEADER; 01309 } 01310 else { 01311 /* change to previous pose (cyclic) */ 01312 poselib_preview_get_next(pld, -1); 01313 pld->redraw= PL_PREVIEW_REDRAWALL; 01314 } 01315 break; 01316 01317 /* change to first pose or start of searching string */ 01318 case HOMEKEY: 01319 if (pld->searchstr[0]) { 01320 pld->search_cursor= 0; 01321 pld->redraw= PL_PREVIEW_REDRAWHEADER; 01322 } 01323 else { 01324 /* change to first pose */ 01325 pld->marker= pld->act->markers.first; 01326 pld->act->active_marker= 1; 01327 01328 pld->redraw= PL_PREVIEW_REDRAWALL; 01329 } 01330 break; 01331 01332 /* change to last pose or start of searching string */ 01333 case ENDKEY: 01334 if (pld->searchstr[0]) { 01335 pld->search_cursor= strlen(pld->searchstr); 01336 pld->redraw= PL_PREVIEW_REDRAWHEADER; 01337 } 01338 else { 01339 /* change to last pose */ 01340 pld->marker= pld->act->markers.last; 01341 pld->act->active_marker= BLI_countlist(&pld->act->markers); 01342 01343 pld->redraw= PL_PREVIEW_REDRAWALL; 01344 } 01345 break; 01346 01347 /* view manipulation */ 01348 /* we add pass through here, so that the operators responsible for these can still run, 01349 * even though we still maintain control (as RUNNING_MODAL flag is still set too) 01350 */ 01351 case MIDDLEMOUSE: case MOUSEMOVE: 01352 //pld->redraw= PL_PREVIEW_REDRAWHEADER; 01353 ret = OPERATOR_PASS_THROUGH; 01354 break; 01355 01356 /* view manipulation, or searching */ 01357 case PAD0: case PAD1: case PAD2: case PAD3: case PAD4: 01358 case PAD5: case PAD6: case PAD7: case PAD8: case PAD9: 01359 case PADPLUSKEY: case PADMINUS: 01360 if (pld->searchstr[0]) { 01361 /* searching... */ 01362 poselib_preview_handle_search(pld, event->type, event->ascii); 01363 } 01364 else { 01365 /* view manipulation (see above) */ 01366 //pld->redraw= PL_PREVIEW_REDRAWHEADER; 01367 ret = OPERATOR_PASS_THROUGH; 01368 } 01369 break; 01370 01371 /* otherwise, assume that searching might be able to handle it */ 01372 default: 01373 poselib_preview_handle_search(pld, event->type, event->ascii); 01374 break; 01375 } 01376 01377 return ret; 01378 } 01379 01380 /* ---------------------------- */ 01381 01382 /* Init PoseLib Previewing data */ 01383 static void poselib_preview_init_data (bContext *C, wmOperator *op) 01384 { 01385 tPoseLib_PreviewData *pld; 01386 Object *ob= get_poselib_object(C); 01387 int pose_index = RNA_int_get(op->ptr, "pose_index"); 01388 01389 /* set up preview state info */ 01390 op->customdata= pld= MEM_callocN(sizeof(tPoseLib_PreviewData), "PoseLib Preview Data"); 01391 01392 /* get basic data */ 01393 pld->ob= ob; 01394 pld->arm= (ob) ? (ob->data) : NULL; 01395 pld->pose= (ob) ? (ob->pose) : NULL; 01396 pld->act= (ob) ? (ob->poselib) : NULL; 01397 01398 pld->scene= CTX_data_scene(C); 01399 pld->sa= CTX_wm_area(C); 01400 01401 /* get starting pose based on RNA-props for this operator */ 01402 if (pose_index == -1) 01403 pld->marker= poselib_get_active_pose(pld->act); 01404 else if (pose_index == -2) 01405 pld->flag |= PL_PREVIEW_SHOWORIGINAL; 01406 else 01407 pld->marker= (pld->act) ? BLI_findlink(&pld->act->markers, pose_index) : NULL; 01408 01409 /* check if valid poselib */ 01410 if (ELEM3(NULL, pld->ob, pld->pose, pld->arm)) { 01411 BKE_report(op->reports, RPT_ERROR, "PoseLib is only for Armatures in PoseMode"); 01412 pld->state= PL_PREVIEW_ERROR; 01413 return; 01414 } 01415 if (pld->act == NULL) { 01416 BKE_report(op->reports, RPT_ERROR, "Object doesn't have a valid PoseLib"); 01417 pld->state= PL_PREVIEW_ERROR; 01418 return; 01419 } 01420 if (pld->marker == NULL) { 01421 if (pld->act->markers.first) { 01422 /* just use first one then... */ 01423 pld->marker= pld->act->markers.first; 01424 if (pose_index > -2) 01425 BKE_report(op->reports, RPT_WARNING, "PoseLib had no active pose"); 01426 } 01427 else { 01428 BKE_report(op->reports, RPT_ERROR, "PoseLib has no poses to preview/apply"); 01429 pld->state= PL_PREVIEW_ERROR; 01430 return; 01431 } 01432 } 01433 01434 /* get ID pointer for applying poses */ 01435 RNA_id_pointer_create(&ob->id, &pld->rna_ptr); 01436 01437 /* make backups for restoring pose */ 01438 poselib_backup_posecopy(pld); 01439 01440 /* set flags for running */ 01441 pld->state= PL_PREVIEW_RUNNING; 01442 pld->redraw= PL_PREVIEW_REDRAWALL; 01443 pld->flag |= PL_PREVIEW_FIRSTTIME; 01444 01445 /* set depsgraph flags */ 01446 /* make sure the lock is set OK, unlock can be accidentally saved? */ 01447 pld->pose->flag |= POSE_LOCKED; 01448 pld->pose->flag &= ~POSE_DO_UNLOCK; 01449 01450 /* clear strings + search */ 01451 pld->headerstr[0]= pld->searchstr[0]= pld->searchold[0]= '\0'; 01452 pld->search_cursor= 0; 01453 } 01454 01455 /* After previewing poses */ 01456 static void poselib_preview_cleanup (bContext *C, wmOperator *op) 01457 { 01458 tPoseLib_PreviewData *pld= (tPoseLib_PreviewData *)op->customdata; 01459 Scene *scene= pld->scene; 01460 Object *ob= pld->ob; 01461 bPose *pose= pld->pose; 01462 bArmature *arm= pld->arm; 01463 bAction *act= pld->act; 01464 TimeMarker *marker= pld->marker; 01465 01466 /* redraw the header so that it doesn't show any of our stuff anymore */ 01467 ED_area_headerprint(pld->sa, NULL); 01468 01469 /* this signal does one recalc on pose, then unlocks, so ESC or edit will work */ 01470 pose->flag |= POSE_DO_UNLOCK; 01471 01472 /* clear pose if cancelled */ 01473 if (pld->state == PL_PREVIEW_CANCEL) { 01474 poselib_backup_restore(pld); 01475 01476 /* old optimize trick... this enforces to bypass the depgraph 01477 * - note: code copied from transform_generics.c -> recalcData() 01478 */ 01479 if ((arm->flag & ARM_DELAYDEFORM)==0) 01480 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); /* sets recalc flags */ 01481 else 01482 where_is_pose(scene, ob); 01483 01484 } 01485 else if (pld->state == PL_PREVIEW_CONFIRM) { 01486 /* tag poses as appropriate */ 01487 poselib_keytag_pose(C, scene, pld); 01488 01489 /* change active pose setting */ 01490 act->active_marker= BLI_findindex(&act->markers, marker) + 1; 01491 action_set_activemarker(act, marker, NULL); 01492 01493 /* Update event for pose and deformation children */ 01494 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 01495 01496 /* updates */ 01497 if (IS_AUTOKEY_MODE(scene, NORMAL)) { 01498 //remake_action_ipos(ob->action); 01499 } 01500 else 01501 where_is_pose(scene, ob); 01502 } 01503 01504 /* free memory used for backups and searching */ 01505 poselib_backup_free_data(pld); 01506 BLI_freelistN(&pld->searchp); 01507 01508 /* free temp data for operator */ 01509 MEM_freeN(pld); 01510 op->customdata= NULL; 01511 } 01512 01513 /* End previewing operation */ 01514 static int poselib_preview_exit (bContext *C, wmOperator *op) 01515 { 01516 tPoseLib_PreviewData *pld= op->customdata; 01517 int exit_state = pld->state; 01518 01519 /* finish up */ 01520 poselib_preview_cleanup(C, op); 01521 01522 if (ELEM(exit_state, PL_PREVIEW_CANCEL, PL_PREVIEW_ERROR)) 01523 return OPERATOR_CANCELLED; 01524 else 01525 return OPERATOR_FINISHED; 01526 } 01527 01528 /* Cancel previewing operation (called when exiting Blender) */ 01529 static int poselib_preview_cancel (bContext *C, wmOperator *op) 01530 { 01531 poselib_preview_exit(C, op); 01532 return OPERATOR_CANCELLED; 01533 } 01534 01535 /* main modal status check */ 01536 static int poselib_preview_modal (bContext *C, wmOperator *op, wmEvent *event) 01537 { 01538 tPoseLib_PreviewData *pld= op->customdata; 01539 int ret; 01540 01541 /* 1) check state to see if we're still running */ 01542 if (pld->state != PL_PREVIEW_RUNNING) 01543 return poselib_preview_exit(C, op); 01544 01545 /* 2) handle events */ 01546 ret= poselib_preview_handle_event(C, op, event); 01547 01548 /* 3) apply changes and redraw, otherwise, confirming goes wrong */ 01549 if (pld->redraw) 01550 poselib_preview_apply(C, op); 01551 01552 return ret; 01553 } 01554 01555 /* Modal Operator init */ 01556 static int poselib_preview_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 01557 { 01558 tPoseLib_PreviewData *pld; 01559 01560 /* check if everything is ok, and init settings for modal operator */ 01561 poselib_preview_init_data(C, op); 01562 pld= (tPoseLib_PreviewData *)op->customdata; 01563 01564 if (pld->state == PL_PREVIEW_ERROR) { 01565 /* an error occurred, so free temp mem used */ 01566 poselib_preview_cleanup(C, op); 01567 return OPERATOR_CANCELLED; 01568 } 01569 01570 /* do initial apply to have something to look at */ 01571 poselib_preview_apply(C, op); 01572 01573 /* add temp handler if we're running as a modal operator */ 01574 WM_event_add_modal_handler(C, op); 01575 01576 return OPERATOR_RUNNING_MODAL; 01577 } 01578 01579 /* Repeat operator */ 01580 static int poselib_preview_exec (bContext *C, wmOperator *op) 01581 { 01582 tPoseLib_PreviewData *pld; 01583 01584 /* check if everything is ok, and init settings for modal operator */ 01585 poselib_preview_init_data(C, op); 01586 pld= (tPoseLib_PreviewData *)op->customdata; 01587 01588 if (pld->state == PL_PREVIEW_ERROR) { 01589 /* an error occurred, so free temp mem used */ 01590 poselib_preview_cleanup(C, op); 01591 return OPERATOR_CANCELLED; 01592 } 01593 01594 /* the exec() callback is effectively a 'run-once' scenario, so set the state to that 01595 * so that everything draws correctly 01596 */ 01597 pld->state = PL_PREVIEW_RUNONCE; 01598 01599 /* apply the active pose */ 01600 poselib_preview_apply(C, op); 01601 01602 /* now, set the status to exit */ 01603 pld->state = PL_PREVIEW_CONFIRM; 01604 01605 /* cleanup */ 01606 return poselib_preview_exit(C, op); 01607 } 01608 01609 void POSELIB_OT_browse_interactive (wmOperatorType *ot) 01610 { 01611 /* identifiers */ 01612 ot->name= "PoseLib Browse Poses"; 01613 ot->idname= "POSELIB_OT_browse_interactive"; 01614 ot->description= "Interactively browse poses in 3D-View"; 01615 01616 /* callbacks */ 01617 ot->invoke= poselib_preview_invoke; 01618 ot->modal= poselib_preview_modal; 01619 ot->cancel= poselib_preview_cancel; 01620 ot->exec= poselib_preview_exec; 01621 ot->poll= has_poselib_pose_data_poll; 01622 01623 /* flags */ 01624 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; 01625 01626 /* properties */ 01627 // TODO: make the pose_index into a proper enum instead of a cryptic int... 01628 ot->prop= RNA_def_int(ot->srna, "pose_index", -1, -2, INT_MAX, "Pose", "Index of the pose to apply (-2 for no change to pose, -1 for poselib active pose)", 0, INT_MAX); 01629 01630 // XXX: percentage vs factor? 01631 /* not used yet */ 01632 /* RNA_def_float_factor(ot->srna, "blend_factor", 1.0f, 0.0f, 1.0f, "Blend Factor", "Amount that the pose is applied on top of the existing poses", 0.0f, 1.0f); */ 01633 } 01634 01635 void POSELIB_OT_apply_pose (wmOperatorType *ot) 01636 { 01637 /* identifiers */ 01638 ot->name = "Apply Pose Library Pose"; 01639 ot->idname = "POSELIB_OT_apply_pose"; 01640 ot->description = "Apply specified Pose Library pose to the rig"; 01641 01642 /* callbacks */ 01643 ot->exec= poselib_preview_exec; 01644 ot->poll= has_poselib_pose_data_poll; 01645 01646 /* flags */ 01647 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01648 01649 /* properties */ 01650 // TODO: make the pose_index into a proper enum instead of a cryptic int... 01651 ot->prop= RNA_def_int(ot->srna, "pose_index", -1, -2, INT_MAX, "Pose", "Index of the pose to apply (-2 for no change to pose, -1 for poselib active pose)", 0, INT_MAX); 01652 }