diff options
Diffstat (limited to 'source/blender/editors/armature/poselib.c')
-rw-r--r-- | source/blender/editors/armature/poselib.c | 571 |
1 files changed, 342 insertions, 229 deletions
diff --git a/source/blender/editors/armature/poselib.c b/source/blender/editors/armature/poselib.c index 6fe584c7f98..13a8cef3d07 100644 --- a/source/blender/editors/armature/poselib.c +++ b/source/blender/editors/armature/poselib.c @@ -1,4 +1,4 @@ -/** +/* * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** @@ -38,6 +38,7 @@ #include "BLI_blenlib.h" #include "BLI_dynstr.h" #include "BLI_dlrbTree.h" +#include "BLI_utildefines.h" #include "DNA_anim_types.h" #include "DNA_armature_types.h" @@ -48,6 +49,8 @@ #include "BKE_action.h" #include "BKE_armature.h" #include "BKE_depsgraph.h" +#include "BKE_idprop.h" +#include "BKE_library.h" #include "BKE_context.h" #include "BKE_report.h" @@ -73,7 +76,7 @@ /* ******* XXX ********** */ -static void action_set_activemarker() {} +static void action_set_activemarker(void *UNUSED(a), void *UNUSED(b), void *UNUSED(c)) {} /* ************************************************************* */ /* == POSE-LIBRARY TOOL FOR BLENDER == @@ -94,41 +97,11 @@ static void action_set_activemarker() {} */ /* ************************************************************* */ -/* gets list of poses in poselib as a string usable for pupmenu() */ -char *poselib_build_poses_menu (bAction *act, char title[]) -{ - DynStr *pupds= BLI_dynstr_new(); - TimeMarker *marker; - char *str; - char buf[64]; - int i; - - /* add title first */ - sprintf(buf, "%s%%t|", title); - BLI_dynstr_append(pupds, buf); - - /* loop through markers, adding them */ - for (marker=act->markers.first, i=1; marker; marker=marker->next, i++) { - BLI_dynstr_append(pupds, marker->name); - - sprintf(buf, "%%x%d", i); - BLI_dynstr_append(pupds, buf); - - if (marker->next) - BLI_dynstr_append(pupds, "|"); - } - - /* convert to normal MEM_malloc'd string */ - str= BLI_dynstr_get_cstring(pupds); - BLI_dynstr_free(pupds); - - return str; -} /* gets the first available frame in poselib to store a pose on * - frames start from 1, and a pose should occur on every frame... 0 is error! */ -int poselib_get_free_index (bAction *act) +static int poselib_get_free_index (bAction *act) { TimeMarker *marker; int low=0, high=0; @@ -159,7 +132,7 @@ int poselib_get_free_index (bAction *act) } /* returns the active pose for a poselib */ -TimeMarker *poselib_get_active_pose (bAction *act) +static TimeMarker *poselib_get_active_pose (bAction *act) { if ((act) && (act->active_marker)) return BLI_findlink(&act->markers, act->active_marker-1); @@ -167,10 +140,35 @@ TimeMarker *poselib_get_active_pose (bAction *act) return NULL; } -/* ************************************************************* */ +/* Get object that Pose Lib should be found on */ + /* XXX C can be zero */ +static Object *get_poselib_object (bContext *C) +{ + ScrArea *sa; + + /* sanity check */ + if (C == NULL) + return NULL; + + sa = CTX_wm_area(C); + + if (sa && (sa->spacetype == SPACE_BUTS)) + return CTX_data_pointer_get_type(C, "object", &RNA_Object).data; + else + return ED_object_pose_armature(CTX_data_active_object(C)); +} + +/* Poll callback for operators that require existing PoseLib data (with poses) to work */ +static int has_poselib_pose_data_poll (bContext *C) +{ + Object *ob = get_poselib_object(C); + return (ob && ob->poselib); +} + +/* ----------------------------------- */ /* Initialise a new poselib (whether it is needed or not) */ -bAction *poselib_init_new (Object *ob) +static bAction *poselib_init_new (Object *ob) { /* sanity checks - only for armatures */ if (ELEM(NULL, ob, ob->pose)) @@ -178,14 +176,14 @@ bAction *poselib_init_new (Object *ob) /* init object's poselib action (unlink old one if there) */ if (ob->poselib) - ob->poselib->id.us--; + id_us_min(&ob->poselib->id); ob->poselib= add_empty_action("PoseLib"); return ob->poselib; } /* Initialise a new poselib (checks if that needs to happen) */ -bAction *poselib_validate (Object *ob) +static bAction *poselib_validate (Object *ob) { if (ELEM(NULL, ob, ob->pose)) return NULL; @@ -195,29 +193,102 @@ bAction *poselib_validate (Object *ob) return ob->poselib; } +/* ************************************************************* */ +/* Pose Lib UI Operators */ + +static int poselib_new_exec (bContext *C, wmOperator *UNUSED(op)) +{ + Object *ob = get_poselib_object(C); + + /* sanity checks */ + if (ob == NULL) + return OPERATOR_CANCELLED; + + /* new method here deals with the rest... */ + poselib_init_new(ob); + + /* notifier here might evolve? */ + WM_event_add_notifier(C, NC_OBJECT|ND_POSE, NULL); + + return OPERATOR_FINISHED; +} + +void POSELIB_OT_new (wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "New Pose Library"; + ot->idname = "POSELIB_OT_new"; + ot->description = "Add New Pose Library to active Object"; + + /* callbacks */ + ot->exec = poselib_new_exec; + ot->poll= ED_operator_posemode; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/* ------------------------------------------------ */ + +static int poselib_unlink_exec (bContext *C, wmOperator *UNUSED(op)) +{ + Object *ob = get_poselib_object(C); + + /* sanity checks */ + if (ELEM(NULL, ob, ob->poselib)) + return OPERATOR_CANCELLED; + + /* there should be a poselib (we just checked above!), so just lower its user count and remove */ + id_us_min(&ob->poselib->id); + ob->poselib = NULL; + + /* notifier here might evolve? */ + WM_event_add_notifier(C, NC_OBJECT|ND_POSE, NULL); + + return OPERATOR_FINISHED; +} + +void POSELIB_OT_unlink (wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Unlink Pose Library"; + ot->idname = "POSELIB_OT_unlink"; + ot->description = "Remove Pose Library from active Object"; + + /* callbacks */ + ot->exec = poselib_unlink_exec; + ot->poll= has_poselib_pose_data_poll; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/* ************************************************************* */ +/* Pose Editing Operators */ /* This tool automagically generates/validates poselib data so that it corresponds to the data * in the action. This is for use in making existing actions usable as poselibs. */ -// TODO: operatorfy me! -void poselib_validate_act (bAction *act) +static int poselib_sanitise_exec (bContext *C, wmOperator *op) { - DLRBT_Tree keys = {NULL, NULL}; + Object *ob = get_poselib_object(C); + bAction *act = (ob)? ob->poselib : NULL; + DLRBT_Tree keys; ActKeyColumn *ak; TimeMarker *marker, *markern; - /* validate action and poselib */ + /* validate action */ if (act == NULL) { - //error("No Action to validate"); - return; + BKE_report(op->reports, RPT_WARNING, "No Action to validate"); + return OPERATOR_CANCELLED; } /* determine which frames have keys */ BLI_dlrbTree_init(&keys); - action_to_keylist(NULL, act, &keys, NULL); + action_to_keylist(NULL, act, &keys, NULL); BLI_dlrbTree_linkedlist_sync(&keys); - /* for each key, make sure there is a correspnding pose */ + /* for each key, make sure there is a corresponding pose */ for (ak= keys.first; ak; ak= ak->next) { /* check if any pose matches this */ // TODO: don't go looking through the list like this every time... @@ -230,13 +301,10 @@ void poselib_validate_act (bAction *act) /* add new if none found */ if (marker == NULL) { - char name[64]; - /* add pose to poselib */ marker= MEM_callocN(sizeof(TimeMarker), "ActionMarker"); - strcpy(name, "Pose"); - BLI_strncpy(marker->name, name, sizeof(marker->name)); + BLI_strncpy(marker->name, "Pose", sizeof(marker->name)); marker->frame= (int)ak->cfra; marker->flag= -1; @@ -256,22 +324,32 @@ void poselib_validate_act (bAction *act) } /* free temp memory */ - BLI_freelistN((ListBase *)&keys); + BLI_dlrbTree_free(&keys); - //BIF_undo_push("PoseLib Validate Action"); + return OPERATOR_FINISHED; } -/* ************************************************************* */ - -/* Pointers to the builtin KeyingSets that we want to use */ -static KeyingSet *poselib_ks_locrotscale = NULL; /* the only keyingset we'll need */ +void POSELIB_OT_action_sanitise (wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Sanitise Pose Library Action"; + ot->idname = "POSELIB_OT_action_sanitise"; + ot->description = "Make action suitable for use as a Pose Library"; + + /* callbacks */ + ot->exec = poselib_sanitise_exec; + ot->poll = has_poselib_pose_data_poll; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} -/* ----- */ +/* ------------------------------------------ */ -static void poselib_add_menu_invoke__replacemenu (bContext *C, uiLayout *layout, void *arg) +static void poselib_add_menu_invoke__replacemenu (bContext *C, uiLayout *layout, void *UNUSED(arg)) { - Object *ob= CTX_data_active_object(C); - bAction *act= ob->poselib; + Object *ob= get_poselib_object(C); + bAction *act= (ob) ? ob->poselib : NULL; TimeMarker *marker; /* set the operator execution context correctly */ @@ -287,34 +365,33 @@ static void poselib_add_menu_invoke__replacemenu (bContext *C, uiLayout *layout, RNA_int_set(&props_ptr, "frame", marker->frame); RNA_string_set(&props_ptr, "name", marker->name); -} + } } -static int poselib_add_menu_invoke (bContext *C, wmOperator *op, wmEvent *evt) +static int poselib_add_menu_invoke (bContext *C, wmOperator *op, wmEvent *UNUSED(evt)) { Scene *scene= CTX_data_scene(C); - Object *ob= CTX_data_active_object(C); - bArmature *arm= (ob) ? ob->data : NULL; + Object *ob= get_poselib_object(C); bPose *pose= (ob) ? ob->pose : NULL; uiPopupMenu *pup; uiLayout *layout; /* sanity check */ - if (ELEM3(NULL, ob, arm, pose)) + if (ELEM(NULL, ob, pose)) return OPERATOR_CANCELLED; /* start building */ - pup= uiPupMenuBegin(C, op->type->name, 0); + pup= uiPupMenuBegin(C, op->type->name, ICON_NULL); layout= uiPupMenuLayout(pup); uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT); /* add new (adds to the first unoccupied frame) */ - uiItemIntO(layout, "Add New", 0, "POSELIB_OT_pose_add", "frame", poselib_get_free_index(ob->poselib)); + uiItemIntO(layout, "Add New", ICON_NULL, "POSELIB_OT_pose_add", "frame", poselib_get_free_index(ob->poselib)); /* check if we have any choices to add a new pose in any other way */ if ((ob->poselib) && (ob->poselib->markers.first)) { /* add new (on current frame) */ - uiItemIntO(layout, "Add New (Current Frame)", 0, "POSELIB_OT_pose_add", "frame", CFRA); + uiItemIntO(layout, "Add New (Current Frame)", ICON_NULL, "POSELIB_OT_pose_add", "frame", CFRA); /* replace existing - submenu */ uiItemMenuF(layout, "Replace Existing...", 0, poselib_add_menu_invoke__replacemenu, NULL); @@ -329,16 +406,16 @@ static int poselib_add_menu_invoke (bContext *C, wmOperator *op, wmEvent *evt) static int poselib_add_exec (bContext *C, wmOperator *op) { - Object *ob= CTX_data_active_object(C); + Object *ob= get_poselib_object(C); bAction *act = poselib_validate(ob); - bArmature *arm= (ob) ? ob->data : NULL; bPose *pose= (ob) ? ob->pose : NULL; TimeMarker *marker; + KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Whole Character"); /* this includes custom props :)*/ int frame= RNA_int_get(op->ptr, "frame"); char name[64]; /* sanity check (invoke should have checked this anyway) */ - if (ELEM3(NULL, ob, arm, pose)) + if (ELEM(NULL, ob, pose)) return OPERATOR_CANCELLED; /* get name to give to pose */ @@ -366,12 +443,10 @@ static int poselib_add_exec (bContext *C, wmOperator *op) /* validate name */ BLI_uniquename(&act->markers, marker, "Pose", '.', offsetof(TimeMarker, name), sizeof(marker->name)); - /* KeyingSet to use depends on rotation mode (but that's handled by the templates code) */ - if (poselib_ks_locrotscale == NULL) - poselib_ks_locrotscale= ANIM_builtin_keyingset_get_named(NULL, "LocRotScale"); - - /* make the keyingset use context info to determine where to add keyframes */ - ANIM_apply_keyingset(C, NULL, act, poselib_ks_locrotscale, MODIFYKEY_MODE_INSERT, (float)frame); + /* use Keying Set to determine what to store for the pose */ + // FIXME: in the past, the Keying Set respected selections (LocRotScale), but the current one doesn't (Whole Character) + // so perhaps we need either a new Keying Set, or just to add overrides here... + ANIM_apply_keyingset(C, NULL, act, ks, MODIFYKEY_MODE_INSERT, (float)frame); /* store new 'active' pose number */ act->active_marker= BLI_countlist(&act->markers); @@ -402,20 +477,19 @@ void POSELIB_OT_pose_add (wmOperatorType *ot) /* ----- */ -static EnumPropertyItem *poselib_stored_pose_itemf(bContext *C, PointerRNA *ptr, int *free) +/* can be called with C == NULL */ +static EnumPropertyItem *poselib_stored_pose_itemf(bContext *C, PointerRNA *UNUSED(ptr), int *free) { - Object *ob= CTX_data_active_object(C); - bAction *act= (ob) ? ob->poselib : NULL; + Object *ob = get_poselib_object(C); + bAction *act = (ob) ? ob->poselib : NULL; TimeMarker *marker; - EnumPropertyItem *item= NULL, item_tmp; + EnumPropertyItem *item= NULL, item_tmp= {0}; int totitem= 0; int i= 0; - if (C==NULL) { + if (C == NULL) { return DummyRNA_DEFAULT_items; } - - memset(&item_tmp, 0, sizeof(item_tmp)); /* check that the action exists */ if (act) { @@ -436,7 +510,7 @@ static EnumPropertyItem *poselib_stored_pose_itemf(bContext *C, PointerRNA *ptr, static int poselib_remove_exec (bContext *C, wmOperator *op) { - Object *ob= CTX_data_active_object(C); + Object *ob= get_poselib_object(C); bAction *act= (ob) ? ob->poselib : NULL; TimeMarker *marker; FCurve *fcu; @@ -450,7 +524,7 @@ static int poselib_remove_exec (bContext *C, wmOperator *op) /* get index (and pointer) of pose to remove */ marker= BLI_findlink(&act->markers, RNA_int_get(op->ptr, "pose")); if (marker == NULL) { - BKE_report(op->reports, RPT_ERROR, "Invalid index for Pose"); + BKE_reportf(op->reports, RPT_ERROR, "Invalid Pose specified %d", RNA_int_get(op->ptr, "pose")); return OPERATOR_CANCELLED; } @@ -492,20 +566,20 @@ void POSELIB_OT_pose_remove (wmOperatorType *ot) /* api callbacks */ ot->invoke= WM_menu_invoke; ot->exec= poselib_remove_exec; - ot->poll= ED_operator_posemode; + ot->poll= has_poselib_pose_data_poll; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; /* properties */ prop= RNA_def_enum(ot->srna, "pose", DummyRNA_DEFAULT_items, 0, "Pose", "The pose to remove"); - RNA_def_enum_funcs(prop, poselib_stored_pose_itemf); + RNA_def_enum_funcs(prop, poselib_stored_pose_itemf); ot->prop= prop; } static int poselib_rename_invoke (bContext *C, wmOperator *op, wmEvent *evt) { - Object *ob= CTX_data_active_object(C); + Object *ob= get_poselib_object(C); bAction *act= (ob) ? ob->poselib : NULL; TimeMarker *marker; @@ -533,7 +607,7 @@ static int poselib_rename_invoke (bContext *C, wmOperator *op, wmEvent *evt) static int poselib_rename_exec (bContext *C, wmOperator *op) { - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); bAction *act= (ob) ? ob->poselib : NULL; TimeMarker *marker; char newname[64]; @@ -572,23 +646,25 @@ void POSELIB_OT_pose_rename (wmOperatorType *ot) /* identifiers */ ot->name= "PoseLib Rename Pose"; ot->idname= "POSELIB_OT_pose_rename"; - ot->description= "Rename nth pose from the active Pose Library"; + ot->description= "Rename specified pose from the active Pose Library"; /* api callbacks */ ot->invoke= poselib_rename_invoke; ot->exec= poselib_rename_exec; - ot->poll= ED_operator_posemode; + ot->poll= has_poselib_pose_data_poll; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; /* properties */ + /* NOTE: name not pose is the operator's "main" property, so that it will get activated in the popup for easy renaming */ + ot->prop= RNA_def_string(ot->srna, "name", "RenamedPose", 64, "New Pose Name", "New name for pose"); prop= RNA_def_enum(ot->srna, "pose", prop_poses_dummy_types, 0, "Pose", "The pose to rename"); RNA_def_enum_funcs(prop, poselib_stored_pose_itemf); - RNA_def_string(ot->srna, "name", "RenamedPose", 64, "New Pose Name", "New name for pose"); } /* ************************************************************* */ +/* Pose-Lib Browsing/Previewing Operator */ /* Simple struct for storing settings/data for use during PoseLib preview */ typedef struct tPoseLib_PreviewData { @@ -647,8 +723,10 @@ enum { typedef struct tPoseLib_Backup { struct tPoseLib_Backup *next, *prev; - bPoseChannel *pchan; - bPoseChannel olddata; + bPoseChannel *pchan; /* pose channel backups are for */ + + bPoseChannel olddata; /* copy of pose channel's old data (at start) */ + IDProperty *oldprops; /* copy (needs freeing) of pose channel's properties (at start) */ } tPoseLib_Backup; /* Makes a copy of the current pose for restoration purposes - doesn't do constraints currently */ @@ -672,6 +750,9 @@ static void poselib_backup_posecopy (tPoseLib_PreviewData *pld) plb->pchan= pchan; memcpy(&plb->olddata, plb->pchan, sizeof(bPoseChannel)); + if (pchan->prop) + plb->oldprops= IDP_CopyProperty(pchan->prop); + BLI_addtail(&pld->backups, plb); /* mark as being affected */ @@ -682,13 +763,39 @@ static void poselib_backup_posecopy (tPoseLib_PreviewData *pld) } } -/* Restores original pose - doesn't do constraints currently */ +/* Restores original pose */ static void poselib_backup_restore (tPoseLib_PreviewData *pld) { tPoseLib_Backup *plb; for (plb= pld->backups.first; plb; plb= plb->next) { + /* copy most of data straight back */ memcpy(plb->pchan, &plb->olddata, sizeof(bPoseChannel)); + + /* just overwrite values of properties from the stored copies (there should be some) */ + if (plb->oldprops) + IDP_SyncGroupValues(plb->pchan->prop, plb->oldprops); + + // TODO: constraints settings aren't restored yet, even though these could change (though not that likely) + } +} + +/* Free list of backups, including any side data it may use */ +static void poselib_backup_free_data (tPoseLib_PreviewData *pld) +{ + tPoseLib_Backup *plb, *plbn; + + for (plb= pld->backups.first; plb; plb= plbn) { + plbn= plb->next; + + /* free custom data */ + if (plb->oldprops) { + IDP_FreeProperty(plb->oldprops); + MEM_freeN(plb->oldprops); + } + + /* free backup element now */ + BLI_freelinkN(&pld->backups, plb); } } @@ -708,7 +815,7 @@ static void poselib_apply_pose (tPoseLib_PreviewData *pld) bAction *act= pld->act; bActionGroup *agrp; - KeyframeEditData ked; + KeyframeEditData ked= {{0}}; KeyframeEditFunc group_ok_cb; int frame= 1; @@ -721,7 +828,6 @@ static void poselib_apply_pose (tPoseLib_PreviewData *pld) /* init settings for testing groups for keyframes */ group_ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE); - memset(&ked, 0, sizeof(KeyframeEditData)); ked.f1= ((float)frame) - 0.5f; ked.f2= ((float)frame) + 0.5f; @@ -743,7 +849,7 @@ static void poselib_apply_pose (tPoseLib_PreviewData *pld) } else if (pchan->bone) { /* only ok if bone is visible and selected */ - if ( (pchan->bone->flag & BONE_SELECTED || pchan->bone == arm->act_bone) && + if ( (pchan->bone->flag & BONE_SELECTED) && (pchan->bone->flag & BONE_HIDDEN_P)==0 && (pchan->bone->layer & arm->layer) ) ok = 1; @@ -764,6 +870,10 @@ static void poselib_keytag_pose (bContext *C, Scene *scene, tPoseLib_PreviewData bAction *act= pld->act; bActionGroup *agrp; + KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, "Whole Character"); + ListBase dsources = {NULL, NULL}; + short autokey = autokeyframe_cfra_can_key(scene, &pld->ob->id); + /* start tagging/keying */ for (agrp= act->groups.first; agrp; agrp= agrp->next) { /* only for selected action channels */ @@ -771,30 +881,9 @@ static void poselib_keytag_pose (bContext *C, Scene *scene, tPoseLib_PreviewData pchan= get_pose_channel(pose, agrp->name); if (pchan) { - if (autokeyframe_cfra_can_key(scene, &pld->ob->id)) { - ListBase dsources = {NULL, NULL}; - KeyingSet *ks = NULL; - - /* get KeyingSet to use - * - use the active KeyingSet if defined (and user wants to use it for all autokeying), - * or otherwise key transforms only - */ - if (poselib_ks_locrotscale == NULL) - poselib_ks_locrotscale= ANIM_builtin_keyingset_get_named(NULL, "LocRotScale"); - - if (IS_AUTOKEY_FLAG(ONLYKEYINGSET) && (scene->active_keyingset)) - ks = ANIM_scene_get_active_keyingset(scene); - else - ks = ANIM_builtin_keyingset_get_named(NULL, "LocRotScale"); - - /* now insert the keyframe(s) using the Keying Set - * 1) add datasource override for the PoseChannel - * 2) insert keyframes - * 3) free the extra info - */ + if (autokey) { + /* add datasource override for the PoseChannel, to be used later */ ANIM_relative_keyingset_add_source(&dsources, &pld->ob->id, &RNA_PoseBone, pchan); - ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); - BLI_freelistN(&dsources); /* clear any unkeyed tags */ if (pchan->bone) @@ -809,6 +898,13 @@ static void poselib_keytag_pose (bContext *C, Scene *scene, tPoseLib_PreviewData } } + /* perform actual auto-keying now */ + if (autokey) { + /* insert keyframes for all relevant bones in one go */ + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); + BLI_freelistN(&dsources); + } + /* send notifiers for this */ WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); } @@ -839,7 +935,7 @@ static void poselib_preview_apply (bContext *C, wmOperator *op) */ // FIXME: shouldn't this use the builtin stuff? if ((pld->arm->flag & ARM_DELAYDEFORM)==0) - DAG_id_flush_update(&pld->ob->id, OB_RECALC_DATA); /* sets recalc flags */ + DAG_id_tag_update(&pld->ob->id, OB_RECALC_DATA); /* sets recalc flags */ else where_is_pose(pld->scene, pld->ob); } @@ -894,91 +990,90 @@ static void poselib_preview_apply (bContext *C, wmOperator *op) */ static void poselib_preview_get_next (tPoseLib_PreviewData *pld, int step) { - /* check if we no longer have search-string, but don't have any marker */ - if (pld->marker == NULL) { - if ((step) && (pld->searchstr[0] == 0)) - pld->marker= pld->act->markers.first; - } - - /* the following operations assume that there is a starting point and direction */ - if ((pld->marker) && (step)) { - /* search-string dictates a special approach */ - if (pld->searchstr[0]) { - TimeMarker *marker; - LinkData *ld, *ldn, *ldc; + /* stop if not going anywhere, as we assume that there is a direction to move in */ + if (step == 0) + return; + + /* search-string dictates a special approach */ + if (pld->searchstr[0]) { + TimeMarker *marker; + LinkData *ld, *ldn, *ldc; + + /* free and rebuild if needed (i.e. if search-str changed) */ + if (strcmp(pld->searchstr, pld->searchold)) { + /* free list of temporary search matches */ + BLI_freelistN(&pld->searchp); - /* free and rebuild if needed (i.e. if search-str changed) */ - if (strcmp(pld->searchstr, pld->searchold)) { - /* free list of temporary search matches */ - BLI_freelistN(&pld->searchp); - - /* generate a new list of search matches */ - for (marker= pld->act->markers.first; marker; marker= marker->next) { - /* does the name partially match? - * - don't worry about case, to make it easier for users to quickly input a name (or - * part of one), which is the whole point of this feature - */ - if (BLI_strcasestr(marker->name, pld->searchstr)) { - /* make link-data to store reference to it */ - ld= MEM_callocN(sizeof(LinkData), "PoseMatch"); - ld->data= marker; - BLI_addtail(&pld->searchp, ld); - } + /* generate a new list of search matches */ + for (marker= pld->act->markers.first; marker; marker= marker->next) { + /* does the name partially match? + * - don't worry about case, to make it easier for users to quickly input a name (or + * part of one), which is the whole point of this feature + */ + if (BLI_strcasestr(marker->name, pld->searchstr)) { + /* make link-data to store reference to it */ + ld= MEM_callocN(sizeof(LinkData), "PoseMatch"); + ld->data= marker; + BLI_addtail(&pld->searchp, ld); } - - /* set current marker to NULL (so that we start from first) */ - pld->marker= NULL; } - /* check if any matches */ - if (pld->searchp.first == NULL) { - pld->marker= NULL; - return; - } - - /* find first match */ - for (ldc= pld->searchp.first; ldc; ldc= ldc->next) { - if (ldc->data == pld->marker) - break; - } - if (ldc == NULL) - ldc= pld->searchp.first; - - /* Loop through the matches in a cyclic fashion, incrementing/decrementing step as appropriate - * until step == 0. At this point, marker should be the correct marker. - */ - if (step > 0) { - for (ld=ldc; ld && step; ld=ldn, step--) - ldn= (ld->next) ? ld->next : pld->searchp.first; - } - else { - for (ld=ldc; ld && step; ld=ldn, step++) - ldn= (ld->prev) ? ld->prev : pld->searchp.last; - } + /* set current marker to NULL (so that we start from first) */ + pld->marker= NULL; + } + + /* check if any matches */ + if (pld->searchp.first == NULL) { + pld->marker= NULL; + return; + } + + /* find first match */ + for (ldc= pld->searchp.first; ldc; ldc= ldc->next) { + if (ldc->data == pld->marker) + break; + } + if (ldc == NULL) + ldc= pld->searchp.first; - /* set marker */ - if (ld) - pld->marker= ld->data; + /* Loop through the matches in a cyclic fashion, incrementing/decrementing step as appropriate + * until step == 0. At this point, marker should be the correct marker. + */ + if (step > 0) { + for (ld=ldc; ld && step; ld=ldn, step--) + ldn= (ld->next) ? ld->next : pld->searchp.first; } else { - TimeMarker *marker, *next; - - /* Loop through the markers in a cyclic fashion, incrementing/decrementing step as appropriate - * until step == 0. At this point, marker should be the correct marker. - */ - if (step > 0) { - for (marker=pld->marker; marker && step; marker=next, step--) - next= (marker->next) ? marker->next : pld->act->markers.first; - } - else { - for (marker=pld->marker; marker && step; marker=next, step++) - next= (marker->prev) ? marker->prev : pld->act->markers.last; - } - - /* it should be fairly impossible for marker to be NULL */ - if (marker) - pld->marker= marker; + for (ld=ldc; ld && step; ld=ldn, step++) + ldn= (ld->prev) ? ld->prev : pld->searchp.last; + } + + /* set marker */ + if (ld) + pld->marker= ld->data; + } + else { + TimeMarker *marker, *next; + + /* if no marker, because we just ended searching, then set that to the start of the list */ + if (pld->marker == NULL) + pld->marker= pld->act->markers.first; + + /* Loop through the markers in a cyclic fashion, incrementing/decrementing step as appropriate + * until step == 0. At this point, marker should be the correct marker. + */ + if (step > 0) { + for (marker=pld->marker; marker && step; marker=next, step--) + next= (marker->next) ? marker->next : pld->act->markers.first; + } + else { + for (marker=pld->marker; marker && step; marker=next, step++) + next= (marker->prev) ? marker->prev : pld->act->markers.last; } + + /* it should be fairly impossible for marker to be NULL */ + if (marker) + pld->marker= marker; } } @@ -1044,11 +1139,17 @@ static void poselib_preview_handle_search (tPoseLib_PreviewData *pld, unsigned s } /* handle events for poselib_preview_poses */ -static int poselib_preview_handle_event (bContext *C, wmOperator *op, wmEvent *event) +static int poselib_preview_handle_event (bContext *UNUSED(C), wmOperator *op, wmEvent *event) { tPoseLib_PreviewData *pld= op->customdata; int ret = OPERATOR_RUNNING_MODAL; + /* only accept 'press' event, and ignore 'release', so that we don't get double actions */ + if (ELEM(event->val, KM_PRESS, KM_NOTHING) == 0) { + //printf("PoseLib: skipping event with type '%s' and val %d\n", WM_key_event_string(event->type), event->val); + return ret; + } + /* backup stuff that needs to occur before every operation * - make a copy of searchstr, so that we know if cache needs to be rebuilt */ @@ -1077,18 +1178,16 @@ static int poselib_preview_handle_event (bContext *C, wmOperator *op, wmEvent *e */ case PAD0: case PAD1: case PAD2: case PAD3: case PAD4: case PAD5: case PAD6: case PAD7: case PAD8: case PAD9: - case PADPLUSKEY: case PADMINUS: case MIDDLEMOUSE: + case PADPLUSKEY: case PADMINUS: + case MIDDLEMOUSE: case MOUSEMOVE: //pld->redraw= PL_PREVIEW_REDRAWHEADER; - ret |= OPERATOR_PASS_THROUGH; + ret = OPERATOR_PASS_THROUGH; break; /* quicky compare to original */ case TABKEY: - /* only respond to one event */ - if (event->val == 0) { - pld->flag &= ~PL_PREVIEW_SHOWORIGINAL; - pld->redraw= PL_PREVIEW_REDRAWALL; - } + pld->flag &= ~PL_PREVIEW_SHOWORIGINAL; + pld->redraw= PL_PREVIEW_REDRAWALL; break; } @@ -1115,11 +1214,8 @@ static int poselib_preview_handle_event (bContext *C, wmOperator *op, wmEvent *e /* toggle between original pose and poselib pose*/ case TABKEY: - /* only respond to one event */ - if (event->val == 0) { - pld->flag |= PL_PREVIEW_SHOWORIGINAL; - pld->redraw= PL_PREVIEW_REDRAWALL; - } + pld->flag |= PL_PREVIEW_SHOWORIGINAL; + pld->redraw= PL_PREVIEW_REDRAWALL; break; /* change to previous pose (cyclic) */ @@ -1212,9 +1308,9 @@ static int poselib_preview_handle_event (bContext *C, wmOperator *op, wmEvent *e /* we add pass through here, so that the operators responsible for these can still run, * even though we still maintain control (as RUNNING_MODAL flag is still set too) */ - case MIDDLEMOUSE: + case MIDDLEMOUSE: case MOUSEMOVE: //pld->redraw= PL_PREVIEW_REDRAWHEADER; - ret |= OPERATOR_PASS_THROUGH; + ret = OPERATOR_PASS_THROUGH; break; /* view manipulation, or searching */ @@ -1228,7 +1324,7 @@ static int poselib_preview_handle_event (bContext *C, wmOperator *op, wmEvent *e else { /* view manipulation (see above) */ //pld->redraw= PL_PREVIEW_REDRAWHEADER; - ret |= OPERATOR_PASS_THROUGH; + ret = OPERATOR_PASS_THROUGH; } break; @@ -1247,7 +1343,7 @@ static int poselib_preview_handle_event (bContext *C, wmOperator *op, wmEvent *e static void poselib_preview_init_data (bContext *C, wmOperator *op) { tPoseLib_PreviewData *pld; - Object *ob= CTX_data_active_object(C); + Object *ob= get_poselib_object(C); int pose_index = RNA_int_get(op->ptr, "pose_index"); /* set up preview state info */ @@ -1343,7 +1439,7 @@ static void poselib_preview_cleanup (bContext *C, wmOperator *op) * - note: code copied from transform_generics.c -> recalcData() */ if ((arm->flag & ARM_DELAYDEFORM)==0) - DAG_id_flush_update(&ob->id, OB_RECALC_DATA); /* sets recalc flags */ + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); /* sets recalc flags */ else where_is_pose(scene, ob); @@ -1357,21 +1453,18 @@ static void poselib_preview_cleanup (bContext *C, wmOperator *op) action_set_activemarker(act, marker, 0); /* Update event for pose and deformation children */ - DAG_id_flush_update(&ob->id, OB_RECALC_DATA); + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); /* updates */ if (IS_AUTOKEY_MODE(scene, NORMAL)) { //remake_action_ipos(ob->action); } - else { - /* need to trick depgraph, action is not allowed to execute on pose */ + else where_is_pose(scene, ob); - ob->recalc= 0; - } } - /* free memory used for backups */ - BLI_freelistN(&pld->backups); + /* free memory used for backups and searching */ + poselib_backup_free_data(pld); BLI_freelistN(&pld->searchp); /* free temp data for operator */ @@ -1383,11 +1476,12 @@ static void poselib_preview_cleanup (bContext *C, wmOperator *op) static int poselib_preview_exit (bContext *C, wmOperator *op) { tPoseLib_PreviewData *pld= op->customdata; + int exit_state = pld->state; /* finish up */ poselib_preview_cleanup(C, op); - if (ELEM(pld->state, PL_PREVIEW_CANCEL, PL_PREVIEW_ERROR)) + if (ELEM(exit_state, PL_PREVIEW_CANCEL, PL_PREVIEW_ERROR)) return OPERATOR_CANCELLED; else return OPERATOR_FINISHED; @@ -1421,7 +1515,7 @@ static int poselib_preview_modal (bContext *C, wmOperator *op, wmEvent *event) } /* Modal Operator init */ -static int poselib_preview_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int poselib_preview_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) { tPoseLib_PreviewData *pld; @@ -1481,12 +1575,12 @@ void POSELIB_OT_browse_interactive (wmOperatorType *ot) ot->idname= "POSELIB_OT_browse_interactive"; ot->description= "Interactively browse poses in 3D-View"; - /* api callbacks */ + /* callbacks */ ot->invoke= poselib_preview_invoke; ot->modal= poselib_preview_modal; ot->cancel= poselib_preview_cancel; ot->exec= poselib_preview_exec; - ot->poll= ED_operator_posemode; + ot->poll= has_poselib_pose_data_poll; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; @@ -1499,3 +1593,22 @@ void POSELIB_OT_browse_interactive (wmOperatorType *ot) /* not used yet */ /* 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); */ } + +void POSELIB_OT_apply_pose (wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Apply Pose Library Pose"; + ot->idname = "POSELIB_OT_apply_pose"; + ot->description = "Apply specified Pose Library pose to the rig"; + + /* callbacks */ + ot->exec= poselib_preview_exec; + ot->poll= has_poselib_pose_data_poll; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + // TODO: make the pose_index into a proper enum instead of a cryptic int... + 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); +} |