2
* ***** BEGIN GPL LICENSE BLOCK *****
4
* This program is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU General Public License
6
* as published by the Free Software Foundation; either version 2
7
* of the License, or (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software Foundation,
16
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
* The Original Code is Copyright (C) 2007, Blender Foundation
19
* This is a new part of Blender
21
* Contributor(s): Joshua Leung
23
* ***** END GPL LICENSE BLOCK *****
26
/** \file blender/editors/armature/poselib.c
38
#include "MEM_guardedalloc.h"
41
#include "BLI_blenlib.h"
42
#include "BLI_dynstr.h"
43
#include "BLI_dlrbTree.h"
44
#include "BLI_utildefines.h"
46
#include "BLF_translation.h"
48
#include "DNA_anim_types.h"
49
#include "DNA_armature_types.h"
50
#include "DNA_object_types.h"
51
#include "DNA_scene_types.h"
53
#include "BKE_animsys.h"
54
#include "BKE_action.h"
55
#include "BKE_armature.h"
56
#include "BKE_depsgraph.h"
57
#include "BKE_global.h"
58
#include "BKE_idprop.h"
59
#include "BKE_library.h"
60
#include "BKE_object.h"
62
#include "BKE_context.h"
63
#include "BKE_report.h"
65
#include "RNA_access.h"
66
#include "RNA_define.h"
67
#include "RNA_enum_types.h"
72
#include "UI_interface.h"
73
#include "UI_resources.h"
75
#include "ED_anim_api.h"
76
#include "ED_armature.h"
77
#include "ED_keyframes_draw.h"
78
#include "ED_keyframing.h"
79
#include "ED_keyframes_edit.h"
80
#include "ED_screen.h"
81
#include "ED_object.h"
83
#include "armature_intern.h"
85
/* ******* XXX ********** */
87
static void action_set_activemarker(void *UNUSED(a), void *UNUSED(b), void *UNUSED(c)) {}
89
/* ************************************************************* */
90
/* == POSE-LIBRARY TOOL FOR BLENDER ==
93
* This tool allows animators to store a set of frequently used poses to dump into
94
* the active action to help in "budget" productions to quickly block out new actions.
95
* It acts as a kind of "glorified clipboard for poses", allowing for naming of poses.
98
* - PoseLibs are simply normal Actions
99
* - Each "pose" is simply a set of keyframes that occur on a particular frame
100
* -> a set of TimeMarkers that belong to each Action, help 'label' where a 'pose' can be
101
* found in the Action
102
* - The Scrollwheel or PageUp/Down buttons when used in a special mode or after pressing/holding
103
* [a modifier] key, cycles through the poses available for the active pose's poselib, allowing the
104
* animator to preview what action best suits that pose
106
/* ************************************************************* */
109
/* gets the first available frame in poselib to store a pose on
110
* - frames start from 1, and a pose should occur on every frame... 0 is error!
112
static int poselib_get_free_index(bAction *act)
115
int low = 0, high = 0;
119
if (ELEM(NULL, act, act->markers.first)) return 1;
121
/* As poses are not stored in chronological order, we must iterate over this list
122
* a few times until we don't make any new discoveries (mostly about the lower bound).
123
* Prevents problems with deleting then trying to add new poses [#27412]
128
for (marker = act->markers.first; marker; marker = marker->next) {
129
/* only increase low if value is 1 greater than low, to find "gaps" where
130
* poses were removed from the poselib
132
if (marker->frame == (low + 1)) {
137
/* value replaces high if it is the highest value encountered yet */
138
if (marker->frame > high) {
139
high = marker->frame;
143
} while (changed != 0);
145
/* - if low is not equal to high, then low+1 is a gap
146
* - if low is equal to high, then high+1 is the next index (add at end)
154
/* returns the active pose for a poselib */
155
static TimeMarker *poselib_get_active_pose(bAction *act)
157
if ((act) && (act->active_marker))
158
return BLI_findlink(&act->markers, act->active_marker - 1);
163
/* Get object that Pose Lib should be found on */
164
/* XXX C can be zero */
165
static Object *get_poselib_object(bContext *C)
175
if (sa && (sa->spacetype == SPACE_BUTS))
176
return ED_object_context(C);
178
return BKE_object_pose_armature_get(CTX_data_active_object(C));
181
/* Poll callback for operators that require existing PoseLib data (with poses) to work */
182
static int has_poselib_pose_data_poll(bContext *C)
184
Object *ob = get_poselib_object(C);
185
return (ob && ob->poselib);
188
/* ----------------------------------- */
190
/* Initialize a new poselib (whether it is needed or not) */
191
static bAction *poselib_init_new(Object *ob)
193
/* sanity checks - only for armatures */
194
if (ELEM(NULL, ob, ob->pose))
197
/* init object's poselib action (unlink old one if there) */
199
id_us_min(&ob->poselib->id);
200
ob->poselib = add_empty_action(G.main, "PoseLib");
205
/* Initialize a new poselib (checks if that needs to happen) */
206
static bAction *poselib_validate(Object *ob)
208
if (ELEM(NULL, ob, ob->pose))
210
else if (ob->poselib == NULL)
211
return poselib_init_new(ob);
216
/* ************************************************************* */
217
/* Pose Lib UI Operators */
219
static int poselib_new_exec(bContext *C, wmOperator *UNUSED(op))
221
Object *ob = get_poselib_object(C);
225
return OPERATOR_CANCELLED;
227
/* new method here deals with the rest... */
228
poselib_init_new(ob);
230
/* notifier here might evolve? */
231
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
233
return OPERATOR_FINISHED;
236
void POSELIB_OT_new(wmOperatorType *ot)
239
ot->name = "New Pose Library";
240
ot->idname = "POSELIB_OT_new";
241
ot->description = "Add New Pose Library to active Object";
244
ot->exec = poselib_new_exec;
245
ot->poll = ED_operator_posemode;
248
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
251
/* ------------------------------------------------ */
253
static int poselib_unlink_exec(bContext *C, wmOperator *UNUSED(op))
255
Object *ob = get_poselib_object(C);
258
if (ELEM(NULL, ob, ob->poselib))
259
return OPERATOR_CANCELLED;
261
/* there should be a poselib (we just checked above!), so just lower its user count and remove */
262
id_us_min(&ob->poselib->id);
265
/* notifier here might evolve? */
266
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
268
return OPERATOR_FINISHED;
271
void POSELIB_OT_unlink(wmOperatorType *ot)
274
ot->name = "Unlink Pose Library";
275
ot->idname = "POSELIB_OT_unlink";
276
ot->description = "Remove Pose Library from active Object";
279
ot->exec = poselib_unlink_exec;
280
ot->poll = has_poselib_pose_data_poll;
283
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
286
/* ************************************************************* */
287
/* Pose Editing Operators */
289
/* This tool automagically generates/validates poselib data so that it corresponds to the data
290
* in the action. This is for use in making existing actions usable as poselibs.
292
static int poselib_sanitize_exec(bContext *C, wmOperator *op)
294
Object *ob = get_poselib_object(C);
295
bAction *act = (ob) ? ob->poselib : NULL;
298
TimeMarker *marker, *markern;
300
/* validate action */
302
BKE_report(op->reports, RPT_WARNING, "No action to validate");
303
return OPERATOR_CANCELLED;
306
/* determine which frames have keys */
307
BLI_dlrbTree_init(&keys);
308
action_to_keylist(NULL, act, &keys, NULL);
309
BLI_dlrbTree_linkedlist_sync(&keys);
311
/* for each key, make sure there is a corresponding pose */
312
for (ak = keys.first; ak; ak = ak->next) {
313
/* check if any pose matches this */
314
/* TODO: don't go looking through the list like this every time... */
315
for (marker = act->markers.first; marker; marker = marker->next) {
316
if (IS_EQ(marker->frame, (double)ak->cfra)) {
322
/* add new if none found */
323
if (marker == NULL) {
324
/* add pose to poselib */
325
marker = MEM_callocN(sizeof(TimeMarker), "ActionMarker");
327
BLI_strncpy(marker->name, "Pose", sizeof(marker->name));
329
marker->frame = (int)ak->cfra;
332
BLI_addtail(&act->markers, marker);
336
/* remove all untagged poses (unused), and remove all tags */
337
for (marker = act->markers.first; marker; marker = markern) {
338
markern = marker->next;
340
if (marker->flag != -1)
341
BLI_freelinkN(&act->markers, marker);
346
/* free temp memory */
347
BLI_dlrbTree_free(&keys);
349
/* send notifiers for this - using keyframe editing notifiers, since action
350
* may be being shown in anim editors as active action
352
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
354
return OPERATOR_FINISHED;
357
void POSELIB_OT_action_sanitize(wmOperatorType *ot)
360
ot->name = "Sanitize Pose Library Action";
361
ot->idname = "POSELIB_OT_action_sanitize";
362
ot->description = "Make action suitable for use as a Pose Library";
365
ot->exec = poselib_sanitize_exec;
366
ot->poll = has_poselib_pose_data_poll;
369
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
372
/* ------------------------------------------ */
374
static void poselib_add_menu_invoke__replacemenu(bContext *C, uiLayout *layout, void *UNUSED(arg))
376
Object *ob = get_poselib_object(C);
377
bAction *act = ob->poselib; /* never NULL */
380
wmOperatorType *ot = WM_operatortype_find("POSELIB_OT_pose_add", 1);
382
BLI_assert(ot != NULL);
384
/* set the operator execution context correctly */
385
uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
387
/* add each marker to this menu */
388
for (marker = act->markers.first; marker; marker = marker->next) {
389
PointerRNA props_ptr;
391
props_ptr = uiItemFullO_ptr(layout, ot,
392
marker->name, ICON_ARMATURE_DATA, NULL,
393
WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
395
RNA_int_set(&props_ptr, "frame", marker->frame);
396
RNA_string_set(&props_ptr, "name", marker->name);
400
static int poselib_add_menu_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(evt))
402
Scene *scene = CTX_data_scene(C);
403
Object *ob = get_poselib_object(C);
404
bPose *pose = (ob) ? ob->pose : NULL;
409
if (ELEM(NULL, ob, pose))
410
return OPERATOR_CANCELLED;
413
pup = uiPupMenuBegin(C, op->type->name, ICON_NONE);
414
layout = uiPupMenuLayout(pup);
415
uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
417
/* add new (adds to the first unoccupied frame) */
418
uiItemIntO(layout, IFACE_("Add New"), ICON_NONE, "POSELIB_OT_pose_add", "frame", poselib_get_free_index(ob->poselib));
420
/* check if we have any choices to add a new pose in any other way */
421
if ((ob->poselib) && (ob->poselib->markers.first)) {
422
/* add new (on current frame) */
423
uiItemIntO(layout, IFACE_("Add New (Current Frame)"), ICON_NONE, "POSELIB_OT_pose_add", "frame", CFRA);
425
/* replace existing - submenu */
426
uiItemMenuF(layout, IFACE_("Replace Existing..."), 0, poselib_add_menu_invoke__replacemenu, NULL);
429
uiPupMenuEnd(C, pup);
431
/* this operator is only for a menu, not used further */
432
return OPERATOR_CANCELLED;
436
static int poselib_add_exec(bContext *C, wmOperator *op)
438
Object *ob = get_poselib_object(C);
439
bAction *act = poselib_validate(ob);
440
bPose *pose = (ob) ? ob->pose : NULL;
442
KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_WHOLE_CHARACTER_ID); /* this includes custom props :)*/
443
int frame = RNA_int_get(op->ptr, "frame");
446
/* sanity check (invoke should have checked this anyway) */
447
if (ELEM(NULL, ob, pose))
448
return OPERATOR_CANCELLED;
450
/* get name to give to pose */
451
RNA_string_get(op->ptr, "name", name);
453
/* add pose to poselib - replaces any existing pose there
454
* - for the 'replace' option, this should end up finding the appropriate marker,
455
* so no new one will be added
457
for (marker = act->markers.first; marker; marker = marker->next) {
458
if (marker->frame == frame) {
459
BLI_strncpy(marker->name, name, sizeof(marker->name));
463
if (marker == NULL) {
464
marker = MEM_callocN(sizeof(TimeMarker), "ActionMarker");
466
BLI_strncpy(marker->name, name, sizeof(marker->name));
467
marker->frame = frame;
469
BLI_addtail(&act->markers, marker);
473
BLI_uniquename(&act->markers, marker, "Pose", '.', offsetof(TimeMarker, name), sizeof(marker->name));
475
/* use Keying Set to determine what to store for the pose */
476
/* FIXME: in the past, the Keying Set respected selections (LocRotScale), but the current one doesn't
477
* (WholeCharacter) so perhaps we need either a new Keying Set, or just to add overrides here... */
478
ANIM_apply_keyingset(C, NULL, act, ks, MODIFYKEY_MODE_INSERT, (float)frame);
480
/* store new 'active' pose number */
481
act->active_marker = BLI_countlist(&act->markers);
484
return OPERATOR_FINISHED;
487
void POSELIB_OT_pose_add(wmOperatorType *ot)
490
ot->name = "PoseLib Add Pose";
491
ot->idname = "POSELIB_OT_pose_add";
492
ot->description = "Add the current Pose to the active Pose Library";
495
ot->invoke = poselib_add_menu_invoke;
496
ot->exec = poselib_add_exec;
497
ot->poll = ED_operator_posemode;
500
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
503
RNA_def_int(ot->srna, "frame", 1, 0, INT_MAX, "Frame", "Frame to store pose on", 0, INT_MAX);
504
RNA_def_string(ot->srna, "name", "Pose", 64, "Pose Name", "Name of newly added Pose");
509
/* can be called with C == NULL */
510
static EnumPropertyItem *poselib_stored_pose_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
512
Object *ob = get_poselib_object(C);
513
bAction *act = (ob) ? ob->poselib : NULL;
515
EnumPropertyItem *item = NULL, item_tmp = {0};
520
return DummyRNA_NULL_items;
523
/* check that the action exists */
525
/* add each marker to the list */
526
for (marker = act->markers.first, i = 0; marker; marker = marker->next, i++) {
527
item_tmp.identifier = item_tmp.name = marker->name;
528
item_tmp.icon = ICON_ARMATURE_DATA;
530
RNA_enum_item_add(&item, &totitem, &item_tmp);
534
RNA_enum_item_end(&item, &totitem);
540
static int poselib_remove_exec(bContext *C, wmOperator *op)
542
Object *ob = get_poselib_object(C);
543
bAction *act = (ob) ? ob->poselib : NULL;
549
/* check if valid poselib */
551
BKE_report(op->reports, RPT_ERROR, "Object does not have pose lib data");
552
return OPERATOR_CANCELLED;
555
prop = RNA_struct_find_property(op->ptr, "pose");
556
if (RNA_property_is_set(op->ptr, prop)) {
557
marker_index = RNA_property_enum_get(op->ptr, prop);
560
marker_index = act->active_marker - 1;
563
/* get index (and pointer) of pose to remove */
564
marker = BLI_findlink(&act->markers, marker_index);
565
if (marker == NULL) {
566
BKE_reportf(op->reports, RPT_ERROR, "Invalid pose specified %d", marker_index);
567
return OPERATOR_CANCELLED;
570
/* remove relevant keyframes */
571
for (fcu = act->curves.first; fcu; fcu = fcu->next) {
576
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
577
/* check if remove */
578
if (IS_EQ(bezt->vec[1][0], marker->frame)) {
579
delete_fcurve_key(fcu, i, 1);
586
/* remove poselib from list */
587
BLI_freelinkN(&act->markers, marker);
589
/* fix active pose number */
590
act->active_marker = 0;
592
/* send notifiers for this - using keyframe editing notifiers, since action
593
* may be being shown in anim editors as active action
595
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
598
return OPERATOR_FINISHED;
601
void POSELIB_OT_pose_remove(wmOperatorType *ot)
606
ot->name = "PoseLib Remove Pose";
607
ot->idname = "POSELIB_OT_pose_remove";
608
ot->description = "Remove nth pose from the active Pose Library";
611
ot->invoke = WM_menu_invoke;
612
ot->exec = poselib_remove_exec;
613
ot->poll = has_poselib_pose_data_poll;
616
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
619
prop = RNA_def_enum(ot->srna, "pose", DummyRNA_NULL_items, 0, "Pose", "The pose to remove");
620
RNA_def_enum_funcs(prop, poselib_stored_pose_itemf);
624
static int poselib_rename_invoke(bContext *C, wmOperator *op, wmEvent *evt)
626
Object *ob = get_poselib_object(C);
627
bAction *act = (ob) ? ob->poselib : NULL;
630
/* check if valid poselib */
632
BKE_report(op->reports, RPT_ERROR, "Object does not have pose lib data");
633
return OPERATOR_CANCELLED;
636
/* get index (and pointer) of pose to remove */
637
marker = BLI_findlink(&act->markers, act->active_marker - 1);
638
if (marker == NULL) {
639
BKE_report(op->reports, RPT_ERROR, "Invalid index for pose");
640
return OPERATOR_CANCELLED;
643
/* use the existing name of the marker as the name, and use the active marker as the one to rename */
644
RNA_enum_set(op->ptr, "pose", act->active_marker - 1);
645
RNA_string_set(op->ptr, "name", marker->name);
648
/* part to sync with other similar operators... */
649
return WM_operator_props_popup(C, op, evt);
652
static int poselib_rename_exec(bContext *C, wmOperator *op)
654
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
655
bAction *act = (ob) ? ob->poselib : NULL;
659
/* check if valid poselib */
661
BKE_report(op->reports, RPT_ERROR, "Object does not have pose lib data");
662
return OPERATOR_CANCELLED;
665
/* get index (and pointer) of pose to remove */
666
marker = BLI_findlink(&act->markers, RNA_enum_get(op->ptr, "pose"));
667
if (marker == NULL) {
668
BKE_report(op->reports, RPT_ERROR, "Invalid index for pose");
669
return OPERATOR_CANCELLED;
673
RNA_string_get(op->ptr, "name", newname);
675
/* copy name and validate it */
676
BLI_strncpy(marker->name, newname, sizeof(marker->name));
677
BLI_uniquename(&act->markers, marker, "Pose", '.', offsetof(TimeMarker, name), sizeof(marker->name));
679
/* send notifiers for this - using keyframe editing notifiers, since action
680
* may be being shown in anim editors as active action
682
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
685
return OPERATOR_FINISHED;
688
void POSELIB_OT_pose_rename(wmOperatorType *ot)
693
ot->name = "PoseLib Rename Pose";
694
ot->idname = "POSELIB_OT_pose_rename";
695
ot->description = "Rename specified pose from the active Pose Library";
698
ot->invoke = poselib_rename_invoke;
699
ot->exec = poselib_rename_exec;
700
ot->poll = has_poselib_pose_data_poll;
703
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
706
/* NOTE: name not pose is the operator's "main" property, so that it will get activated in the popup for easy renaming */
707
ot->prop = RNA_def_string(ot->srna, "name", "RenamedPose", 64, "New Pose Name", "New name for pose");
708
prop = RNA_def_enum(ot->srna, "pose", DummyRNA_NULL_items, 0, "Pose", "The pose to rename");
709
RNA_def_enum_funcs(prop, poselib_stored_pose_itemf);
712
/* ************************************************************* */
713
/* Pose-Lib Browsing/Previewing Operator */
715
/* Simple struct for storing settings/data for use during PoseLib preview */
716
typedef struct tPoseLib_PreviewData {
717
ListBase backups; /* tPoseLib_Backup structs for restoring poses */
718
ListBase searchp; /* LinkData structs storing list of poses which match the current search-string */
720
Scene *scene; /* active scene */
721
ScrArea *sa; /* active area */
723
PointerRNA rna_ptr; /* RNA-Pointer to Object 'ob' */
724
Object *ob; /* object to work on */
725
bArmature *arm; /* object's armature data */
726
bPose *pose; /* object's pose */
727
bAction *act; /* poselib to use */
728
TimeMarker *marker; /* 'active' pose */
730
int selcount; /* number of selected elements to work on */
731
int totcount; /* total number of elements to work on */
733
short state; /* state of main loop */
734
short redraw; /* redraw/update settings during main loop */
735
short flag; /* flags for various settings */
737
short search_cursor; /* position of cursor in searchstr (cursor occurs before the item at the nominated index) */
738
char searchstr[64]; /* (Part of) Name to search for to filter poses that get shown */
739
char searchold[64]; /* Previously set searchstr (from last loop run), so that we can detected when to rebuild searchp */
741
char headerstr[200]; /* Info-text to print in header */
742
} tPoseLib_PreviewData;
744
/* defines for tPoseLib_PreviewData->state values */
746
PL_PREVIEW_ERROR = -1,
753
/* defines for tPoseLib_PreviewData->redraw values */
755
PL_PREVIEW_NOREDRAW = 0,
756
PL_PREVIEW_REDRAWALL,
757
PL_PREVIEW_REDRAWHEADER,
760
/* defines for tPoseLib_PreviewData->flag values */
762
PL_PREVIEW_FIRSTTIME = (1 << 0),
763
PL_PREVIEW_SHOWORIGINAL = (1 << 1)
766
/* ---------------------------- */
768
/* simple struct for storing backup info */
769
typedef struct tPoseLib_Backup {
770
struct tPoseLib_Backup *next, *prev;
772
bPoseChannel *pchan; /* pose channel backups are for */
774
bPoseChannel olddata; /* copy of pose channel's old data (at start) */
775
IDProperty *oldprops; /* copy (needs freeing) of pose channel's properties (at start) */
778
/* Makes a copy of the current pose for restoration purposes - doesn't do constraints currently */
779
static void poselib_backup_posecopy(tPoseLib_PreviewData *pld)
784
/* for each posechannel that has an actionchannel in */
785
for (agrp = pld->act->groups.first; agrp; agrp = agrp->next) {
786
/* try to find posechannel */
787
pchan = BKE_pose_channel_find_name(pld->pose, agrp->name);
789
/* backup data if available */
791
tPoseLib_Backup *plb;
794
plb = MEM_callocN(sizeof(tPoseLib_Backup), "tPoseLib_Backup");
797
memcpy(&plb->olddata, plb->pchan, sizeof(bPoseChannel));
800
plb->oldprops = IDP_CopyProperty(pchan->prop);
802
BLI_addtail(&pld->backups, plb);
804
/* mark as being affected */
805
if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED))
812
/* Restores original pose */
813
static void poselib_backup_restore(tPoseLib_PreviewData *pld)
815
tPoseLib_Backup *plb;
817
for (plb = pld->backups.first; plb; plb = plb->next) {
818
/* copy most of data straight back */
819
memcpy(plb->pchan, &plb->olddata, sizeof(bPoseChannel));
821
/* just overwrite values of properties from the stored copies (there should be some) */
823
IDP_SyncGroupValues(plb->pchan->prop, plb->oldprops);
825
/* TODO: constraints settings aren't restored yet, even though these could change (though not that likely) */
829
/* Free list of backups, including any side data it may use */
830
static void poselib_backup_free_data(tPoseLib_PreviewData *pld)
832
tPoseLib_Backup *plb, *plbn;
834
for (plb = pld->backups.first; plb; plb = plbn) {
837
/* free custom data */
839
IDP_FreeProperty(plb->oldprops);
840
MEM_freeN(plb->oldprops);
843
/* free backup element now */
844
BLI_freelinkN(&pld->backups, plb);
848
/* ---------------------------- */
850
/* Applies the appropriate stored pose from the pose-library to the current pose
851
* - assumes that a valid object, with a poselib has been supplied
852
* - gets the string to print in the header
853
* - this code is based on the code for extract_pose_from_action in blenkernel/action.c
855
static void poselib_apply_pose(tPoseLib_PreviewData *pld)
857
PointerRNA *ptr = &pld->rna_ptr;
858
bArmature *arm = pld->arm;
859
bPose *pose = pld->pose;
861
bAction *act = pld->act;
864
KeyframeEditData ked = {{NULL}};
865
KeyframeEditFunc group_ok_cb;
870
frame = pld->marker->frame;
875
/* init settings for testing groups for keyframes */
876
group_ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE);
877
ked.f1 = ((float)frame) - 0.5f;
878
ked.f2 = ((float)frame) + 0.5f;
881
/* start applying - only those channels which have a key at this point in time! */
882
for (agrp = act->groups.first; agrp; agrp = agrp->next) {
883
/* check if group has any keyframes */
884
if (ANIM_animchanneldata_keyframes_loop(&ked, NULL, agrp, ALE_GROUP, NULL, group_ok_cb, NULL)) {
885
/* has keyframe on this frame, so try to get a PoseChannel with this name */
886
pchan = BKE_pose_channel_find_name(pose, agrp->name);
891
/* check if this bone should get any animation applied */
892
if (pld->selcount == 0) {
893
/* if no bones are selected, then any bone is ok */
896
else if (pchan->bone) {
897
/* only ok if bone is visible and selected */
898
if ((pchan->bone->flag & BONE_SELECTED) &&
899
(pchan->bone->flag & BONE_HIDDEN_P) == 0 &&
900
(pchan->bone->layer & arm->layer))
907
animsys_evaluate_action_group(ptr, act, agrp, NULL, (float)frame);
913
/* Auto-keys/tags bones affected by the pose used from the poselib */
914
static void poselib_keytag_pose(bContext *C, Scene *scene, tPoseLib_PreviewData *pld)
916
bPose *pose = pld->pose;
918
bAction *act = pld->act;
921
KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID);
922
ListBase dsources = {NULL, NULL};
923
short autokey = autokeyframe_cfra_can_key(scene, &pld->ob->id);
925
/* start tagging/keying */
926
for (agrp = act->groups.first; agrp; agrp = agrp->next) {
927
/* only for selected bones unless there aren't any selected, in which case all are included */
928
pchan = BKE_pose_channel_find_name(pose, agrp->name);
931
if ( (pld->selcount == 0) || ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) ) {
933
/* add datasource override for the PoseChannel, to be used later */
934
ANIM_relative_keyingset_add_source(&dsources, &pld->ob->id, &RNA_PoseBone, pchan);
936
/* clear any unkeyed tags */
938
pchan->bone->flag &= ~BONE_UNKEYED;
941
/* add unkeyed tags */
943
pchan->bone->flag |= BONE_UNKEYED;
949
/* perform actual auto-keying now */
951
/* insert keyframes for all relevant bones in one go */
952
ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
953
BLI_freelistN(&dsources);
956
/* send notifiers for this */
957
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
960
/* Apply the relevant changes to the pose */
961
static void poselib_preview_apply(bContext *C, wmOperator *op)
963
tPoseLib_PreviewData *pld = (tPoseLib_PreviewData *)op->customdata;
965
/* only recalc pose (and its dependencies) if pose has changed */
966
if (pld->redraw == PL_PREVIEW_REDRAWALL) {
967
/* don't clear pose if firsttime */
968
if ((pld->flag & PL_PREVIEW_FIRSTTIME) == 0)
969
poselib_backup_restore(pld);
971
pld->flag &= ~PL_PREVIEW_FIRSTTIME;
973
/* pose should be the right one to draw (unless we're temporarily not showing it) */
974
if ((pld->flag & PL_PREVIEW_SHOWORIGINAL) == 0) {
975
RNA_int_set(op->ptr, "pose_index", BLI_findindex(&pld->act->markers, pld->marker));
976
poselib_apply_pose(pld);
979
RNA_int_set(op->ptr, "pose_index", -2); /* -2 means don't apply any pose */
981
/* old optimize trick... this enforces to bypass the depgraph
982
* - note: code copied from transform_generics.c -> recalcData()
984
// FIXME: shouldn't this use the builtin stuff?
985
if ((pld->arm->flag & ARM_DELAYDEFORM) == 0)
986
DAG_id_tag_update(&pld->ob->id, OB_RECALC_DATA); /* sets recalc flags */
988
BKE_pose_where_is(pld->scene, pld->ob);
991
/* do header print - if interactively previewing */
992
if (pld->state == PL_PREVIEW_RUNNING) {
993
if (pld->flag & PL_PREVIEW_SHOWORIGINAL) {
994
BLI_strncpy(pld->headerstr,
995
"PoseLib Previewing Pose: [Showing Original Pose] | Use Tab to start previewing poses again",
996
sizeof(pld->headerstr));
997
ED_area_headerprint(pld->sa, pld->headerstr);
999
else if (pld->searchstr[0]) {
1004
/* get search-string */
1005
index = pld->search_cursor;
1007
if (index >= 0 && index < sizeof(tempstr) - 1) {
1008
memcpy(&tempstr[0], &pld->searchstr[0], index);
1009
tempstr[index] = '|';
1010
memcpy(&tempstr[index + 1], &pld->searchstr[index], (sizeof(tempstr) - 1) - index);
1013
BLI_strncpy(tempstr, pld->searchstr, sizeof(tempstr));
1016
/* get marker name */
1017
BLI_strncpy(markern, pld->marker ? pld->marker->name : "No Matches", sizeof(markern));
1019
BLI_snprintf(pld->headerstr, sizeof(pld->headerstr),
1020
"PoseLib Previewing Pose: Filter - [%s] | "
1021
"Current Pose - \"%s\" | "
1022
"Use ScrollWheel or PageUp/Down to change",
1024
ED_area_headerprint(pld->sa, pld->headerstr);
1027
BLI_snprintf(pld->headerstr, sizeof(pld->headerstr),
1028
"PoseLib Previewing Pose: \"%s\" | "
1029
"Use ScrollWheel or PageUp/Down to change",
1031
ED_area_headerprint(pld->sa, pld->headerstr);
1035
/* request drawing of view + clear redraw flag */
1036
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, pld->ob);
1037
pld->redraw = PL_PREVIEW_NOREDRAW;
1040
/* ---------------------------- */
1042
/* This helper function is called during poselib_preview_poses to find the
1043
* pose to preview next (after a change event)
1045
static void poselib_preview_get_next(tPoseLib_PreviewData *pld, int step)
1047
/* stop if not going anywhere, as we assume that there is a direction to move in */
1051
/* search-string dictates a special approach */
1052
if (pld->searchstr[0]) {
1054
LinkData *ld, *ldn, *ldc;
1056
/* free and rebuild if needed (i.e. if search-str changed) */
1057
if (strcmp(pld->searchstr, pld->searchold)) {
1058
/* free list of temporary search matches */
1059
BLI_freelistN(&pld->searchp);
1061
/* generate a new list of search matches */
1062
for (marker = pld->act->markers.first; marker; marker = marker->next) {
1063
/* does the name partially match?
1064
* - don't worry about case, to make it easier for users to quickly input a name (or
1065
* part of one), which is the whole point of this feature
1067
if (BLI_strcasestr(marker->name, pld->searchstr)) {
1068
/* make link-data to store reference to it */
1069
ld = MEM_callocN(sizeof(LinkData), "PoseMatch");
1071
BLI_addtail(&pld->searchp, ld);
1075
/* set current marker to NULL (so that we start from first) */
1079
/* check if any matches */
1080
if (pld->searchp.first == NULL) {
1085
/* find first match */
1086
for (ldc = pld->searchp.first; ldc; ldc = ldc->next) {
1087
if (ldc->data == pld->marker)
1091
ldc = pld->searchp.first;
1093
/* Loop through the matches in a cyclic fashion, incrementing/decrementing step as appropriate
1094
* until step == 0. At this point, marker should be the correct marker.
1097
for (ld = ldc; ld && step; ld = ldn, step--)
1098
ldn = (ld->next) ? ld->next : pld->searchp.first;
1101
for (ld = ldc; ld && step; ld = ldn, step++)
1102
ldn = (ld->prev) ? ld->prev : pld->searchp.last;
1107
pld->marker = ld->data;
1110
TimeMarker *marker, *next;
1112
/* if no marker, because we just ended searching, then set that to the start of the list */
1113
if (pld->marker == NULL)
1114
pld->marker = pld->act->markers.first;
1116
/* Loop through the markers in a cyclic fashion, incrementing/decrementing step as appropriate
1117
* until step == 0. At this point, marker should be the correct marker.
1120
for (marker = pld->marker; marker && step; marker = next, step--)
1121
next = (marker->next) ? marker->next : pld->act->markers.first;
1124
for (marker = pld->marker; marker && step; marker = next, step++)
1125
next = (marker->prev) ? marker->prev : pld->act->markers.last;
1128
/* it should be fairly impossible for marker to be NULL */
1130
pld->marker = marker;
1134
/* specially handle events for searching */
1135
static void poselib_preview_handle_search(tPoseLib_PreviewData *pld, unsigned short event, char ascii)
1137
/* try doing some form of string manipulation first */
1140
if (pld->searchstr[0] && pld->search_cursor) {
1141
short len = strlen(pld->searchstr);
1142
short index = pld->search_cursor;
1145
for (i = index; i <= len; i++)
1146
pld->searchstr[i - 1] = pld->searchstr[i];
1148
pld->search_cursor--;
1150
poselib_preview_get_next(pld, 1);
1151
pld->redraw = PL_PREVIEW_REDRAWALL;
1157
if (pld->searchstr[0] && pld->searchstr[1]) {
1158
short len = strlen(pld->searchstr);
1159
short index = pld->search_cursor;
1163
for (i = index; i < len; i++)
1164
pld->searchstr[i] = pld->searchstr[i + 1];
1166
poselib_preview_get_next(pld, 1);
1167
pld->redraw = PL_PREVIEW_REDRAWALL;
1175
/* character to add to the string */
1176
short index = pld->search_cursor;
1177
short len = (pld->searchstr[0]) ? strlen(pld->searchstr) : 0;
1181
for (i = len; i > index; i--)
1182
pld->searchstr[i] = pld->searchstr[i - 1];
1185
pld->searchstr[1] = 0;
1187
pld->searchstr[index] = ascii;
1188
pld->search_cursor++;
1190
poselib_preview_get_next(pld, 1);
1191
pld->redraw = PL_PREVIEW_REDRAWALL;
1195
/* handle events for poselib_preview_poses */
1196
static int poselib_preview_handle_event(bContext *UNUSED(C), wmOperator *op, wmEvent *event)
1198
tPoseLib_PreviewData *pld = op->customdata;
1199
int ret = OPERATOR_RUNNING_MODAL;
1201
/* only accept 'press' event, and ignore 'release', so that we don't get double actions */
1202
if (ELEM(event->val, KM_PRESS, KM_NOTHING) == 0) {
1203
//printf("PoseLib: skipping event with type '%s' and val %d\n", WM_key_event_string(event->type), event->val);
1207
/* backup stuff that needs to occur before every operation
1208
* - make a copy of searchstr, so that we know if cache needs to be rebuilt
1210
BLI_strncpy(pld->searchold, pld->searchstr, sizeof(pld->searchold));
1212
/* if we're currently showing the original pose, only certain events are handled */
1213
if (pld->flag & PL_PREVIEW_SHOWORIGINAL) {
1214
switch (event->type) {
1218
pld->state = PL_PREVIEW_CANCEL;
1221
/* exit - confirm */
1226
pld->state = PL_PREVIEW_CONFIRM;
1229
/* view manipulation */
1230
/* we add pass through here, so that the operators responsible for these can still run,
1231
* even though we still maintain control (as RUNNING_MODAL flag is still set too)
1233
case PAD0: case PAD1: case PAD2: case PAD3: case PAD4:
1234
case PAD5: case PAD6: case PAD7: case PAD8: case PAD9:
1235
case PADPLUSKEY: case PADMINUS:
1236
case MIDDLEMOUSE: case MOUSEMOVE:
1237
//pld->redraw = PL_PREVIEW_REDRAWHEADER;
1238
ret = OPERATOR_PASS_THROUGH;
1241
/* quicky compare to original */
1243
pld->flag &= ~PL_PREVIEW_SHOWORIGINAL;
1244
pld->redraw = PL_PREVIEW_REDRAWALL;
1252
/* NORMAL EVENT HANDLING... */
1253
/* searching takes priority over normal activity */
1254
switch (event->type) {
1258
pld->state = PL_PREVIEW_CANCEL;
1261
/* exit - confirm */
1266
pld->state = PL_PREVIEW_CONFIRM;
1269
/* toggle between original pose and poselib pose*/
1271
pld->flag |= PL_PREVIEW_SHOWORIGINAL;
1272
pld->redraw = PL_PREVIEW_REDRAWALL;
1275
/* change to previous pose (cyclic) */
1278
poselib_preview_get_next(pld, -1);
1279
pld->redraw = PL_PREVIEW_REDRAWALL;
1282
/* change to next pose (cyclic) */
1284
case WHEELDOWNMOUSE:
1285
poselib_preview_get_next(pld, 1);
1286
pld->redraw = PL_PREVIEW_REDRAWALL;
1289
/* jump 5 poses (cyclic, back) */
1291
poselib_preview_get_next(pld, -5);
1292
pld->redraw = PL_PREVIEW_REDRAWALL;
1295
/* jump 5 poses (cyclic, forward) */
1297
poselib_preview_get_next(pld, 5);
1298
pld->redraw = PL_PREVIEW_REDRAWALL;
1301
/* change to next pose or searching cursor control */
1303
if (pld->searchstr[0]) {
1304
/* move text-cursor to the right */
1305
if (pld->search_cursor < strlen(pld->searchstr))
1306
pld->search_cursor++;
1307
pld->redraw = PL_PREVIEW_REDRAWHEADER;
1310
/* change to next pose (cyclic) */
1311
poselib_preview_get_next(pld, 1);
1312
pld->redraw = PL_PREVIEW_REDRAWALL;
1316
/* change to next pose or searching cursor control */
1318
if (pld->searchstr[0]) {
1319
/* move text-cursor to the left */
1320
if (pld->search_cursor)
1321
pld->search_cursor--;
1322
pld->redraw = PL_PREVIEW_REDRAWHEADER;
1325
/* change to previous pose (cyclic) */
1326
poselib_preview_get_next(pld, -1);
1327
pld->redraw = PL_PREVIEW_REDRAWALL;
1331
/* change to first pose or start of searching string */
1333
if (pld->searchstr[0]) {
1334
pld->search_cursor = 0;
1335
pld->redraw = PL_PREVIEW_REDRAWHEADER;
1338
/* change to first pose */
1339
pld->marker = pld->act->markers.first;
1340
pld->act->active_marker = 1;
1342
pld->redraw = PL_PREVIEW_REDRAWALL;
1346
/* change to last pose or start of searching string */
1348
if (pld->searchstr[0]) {
1349
pld->search_cursor = strlen(pld->searchstr);
1350
pld->redraw = PL_PREVIEW_REDRAWHEADER;
1353
/* change to last pose */
1354
pld->marker = pld->act->markers.last;
1355
pld->act->active_marker = BLI_countlist(&pld->act->markers);
1357
pld->redraw = PL_PREVIEW_REDRAWALL;
1361
/* view manipulation */
1362
/* we add pass through here, so that the operators responsible for these can still run,
1363
* even though we still maintain control (as RUNNING_MODAL flag is still set too)
1365
case MIDDLEMOUSE: case MOUSEMOVE:
1366
//pld->redraw = PL_PREVIEW_REDRAWHEADER;
1367
ret = OPERATOR_PASS_THROUGH;
1370
/* view manipulation, or searching */
1371
case PAD0: case PAD1: case PAD2: case PAD3: case PAD4:
1372
case PAD5: case PAD6: case PAD7: case PAD8: case PAD9:
1373
case PADPLUSKEY: case PADMINUS:
1374
if (pld->searchstr[0]) {
1376
poselib_preview_handle_search(pld, event->type, event->ascii);
1379
/* view manipulation (see above) */
1380
//pld->redraw = PL_PREVIEW_REDRAWHEADER;
1381
ret = OPERATOR_PASS_THROUGH;
1385
/* otherwise, assume that searching might be able to handle it */
1387
poselib_preview_handle_search(pld, event->type, event->ascii);
1394
/* ---------------------------- */
1396
/* Init PoseLib Previewing data */
1397
static void poselib_preview_init_data(bContext *C, wmOperator *op)
1399
tPoseLib_PreviewData *pld;
1400
Object *ob = get_poselib_object(C);
1401
int pose_index = RNA_int_get(op->ptr, "pose_index");
1403
/* set up preview state info */
1404
op->customdata = pld = MEM_callocN(sizeof(tPoseLib_PreviewData), "PoseLib Preview Data");
1406
/* get basic data */
1408
pld->arm = (ob) ? (ob->data) : NULL;
1409
pld->pose = (ob) ? (ob->pose) : NULL;
1410
pld->act = (ob) ? (ob->poselib) : NULL;
1412
pld->scene = CTX_data_scene(C);
1413
pld->sa = CTX_wm_area(C);
1415
/* get starting pose based on RNA-props for this operator */
1416
if (pose_index == -1)
1417
pld->marker = poselib_get_active_pose(pld->act);
1418
else if (pose_index == -2)
1419
pld->flag |= PL_PREVIEW_SHOWORIGINAL;
1421
pld->marker = (pld->act) ? BLI_findlink(&pld->act->markers, pose_index) : NULL;
1423
/* check if valid poselib */
1424
if (ELEM3(NULL, pld->ob, pld->pose, pld->arm)) {
1425
BKE_report(op->reports, RPT_ERROR, "Pose lib is only for armatures in pose mode");
1426
pld->state = PL_PREVIEW_ERROR;
1429
if (pld->act == NULL) {
1430
BKE_report(op->reports, RPT_ERROR, "Object does not have a valid pose lib");
1431
pld->state = PL_PREVIEW_ERROR;
1434
if (pld->marker == NULL) {
1435
if (pld->act->markers.first) {
1436
/* just use first one then... */
1437
pld->marker = pld->act->markers.first;
1438
if (pose_index > -2)
1439
BKE_report(op->reports, RPT_WARNING, "Pose lib had no active pose");
1442
BKE_report(op->reports, RPT_ERROR, "Pose lib has no poses to preview/apply");
1443
pld->state = PL_PREVIEW_ERROR;
1448
/* get ID pointer for applying poses */
1449
RNA_id_pointer_create(&ob->id, &pld->rna_ptr);
1451
/* make backups for restoring pose */
1452
poselib_backup_posecopy(pld);
1454
/* set flags for running */
1455
pld->state = PL_PREVIEW_RUNNING;
1456
pld->redraw = PL_PREVIEW_REDRAWALL;
1457
pld->flag |= PL_PREVIEW_FIRSTTIME;
1459
/* set depsgraph flags */
1460
/* make sure the lock is set OK, unlock can be accidentally saved? */
1461
pld->pose->flag |= POSE_LOCKED;
1462
pld->pose->flag &= ~POSE_DO_UNLOCK;
1464
/* clear strings + search */
1465
pld->headerstr[0] = pld->searchstr[0] = pld->searchold[0] = '\0';
1466
pld->search_cursor = 0;
1469
/* After previewing poses */
1470
static void poselib_preview_cleanup(bContext *C, wmOperator *op)
1472
tPoseLib_PreviewData *pld = (tPoseLib_PreviewData *)op->customdata;
1473
Scene *scene = pld->scene;
1474
Object *ob = pld->ob;
1475
bPose *pose = pld->pose;
1476
bArmature *arm = pld->arm;
1477
bAction *act = pld->act;
1478
TimeMarker *marker = pld->marker;
1480
/* redraw the header so that it doesn't show any of our stuff anymore */
1481
ED_area_headerprint(pld->sa, NULL);
1483
/* this signal does one recalc on pose, then unlocks, so ESC or edit will work */
1484
pose->flag |= POSE_DO_UNLOCK;
1486
/* clear pose if canceled */
1487
if (pld->state == PL_PREVIEW_CANCEL) {
1488
poselib_backup_restore(pld);
1490
/* old optimize trick... this enforces to bypass the depgraph
1491
* - note: code copied from transform_generics.c -> recalcData()
1493
if ((arm->flag & ARM_DELAYDEFORM) == 0)
1494
DAG_id_tag_update(&ob->id, OB_RECALC_DATA); /* sets recalc flags */
1496
BKE_pose_where_is(scene, ob);
1499
else if (pld->state == PL_PREVIEW_CONFIRM) {
1500
/* tag poses as appropriate */
1501
poselib_keytag_pose(C, scene, pld);
1503
/* change active pose setting */
1504
act->active_marker = BLI_findindex(&act->markers, marker) + 1;
1505
action_set_activemarker(act, marker, NULL);
1507
/* Update event for pose and deformation children */
1508
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
1511
if (IS_AUTOKEY_MODE(scene, NORMAL)) {
1512
//remake_action_ipos(ob->action);
1515
BKE_pose_where_is(scene, ob);
1518
/* free memory used for backups and searching */
1519
poselib_backup_free_data(pld);
1520
BLI_freelistN(&pld->searchp);
1522
/* free temp data for operator */
1524
op->customdata = NULL;
1527
/* End previewing operation */
1528
static int poselib_preview_exit(bContext *C, wmOperator *op)
1530
tPoseLib_PreviewData *pld = op->customdata;
1531
int exit_state = pld->state;
1534
poselib_preview_cleanup(C, op);
1536
if (ELEM(exit_state, PL_PREVIEW_CANCEL, PL_PREVIEW_ERROR))
1537
return OPERATOR_CANCELLED;
1539
return OPERATOR_FINISHED;
1542
/* Cancel previewing operation (called when exiting Blender) */
1543
static int poselib_preview_cancel(bContext *C, wmOperator *op)
1545
poselib_preview_exit(C, op);
1546
return OPERATOR_CANCELLED;
1549
/* main modal status check */
1550
static int poselib_preview_modal(bContext *C, wmOperator *op, wmEvent *event)
1552
tPoseLib_PreviewData *pld = op->customdata;
1555
/* 1) check state to see if we're still running */
1556
if (pld->state != PL_PREVIEW_RUNNING)
1557
return poselib_preview_exit(C, op);
1559
/* 2) handle events */
1560
ret = poselib_preview_handle_event(C, op, event);
1562
/* 3) apply changes and redraw, otherwise, confirming goes wrong */
1564
poselib_preview_apply(C, op);
1569
/* Modal Operator init */
1570
static int poselib_preview_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1572
tPoseLib_PreviewData *pld;
1574
/* check if everything is ok, and init settings for modal operator */
1575
poselib_preview_init_data(C, op);
1576
pld = (tPoseLib_PreviewData *)op->customdata;
1578
if (pld->state == PL_PREVIEW_ERROR) {
1579
/* an error occurred, so free temp mem used */
1580
poselib_preview_cleanup(C, op);
1581
return OPERATOR_CANCELLED;
1584
/* do initial apply to have something to look at */
1585
poselib_preview_apply(C, op);
1587
/* add temp handler if we're running as a modal operator */
1588
WM_event_add_modal_handler(C, op);
1590
return OPERATOR_RUNNING_MODAL;
1593
/* Repeat operator */
1594
static int poselib_preview_exec(bContext *C, wmOperator *op)
1596
tPoseLib_PreviewData *pld;
1598
/* check if everything is ok, and init settings for modal operator */
1599
poselib_preview_init_data(C, op);
1600
pld = (tPoseLib_PreviewData *)op->customdata;
1602
if (pld->state == PL_PREVIEW_ERROR) {
1603
/* an error occurred, so free temp mem used */
1604
poselib_preview_cleanup(C, op);
1605
return OPERATOR_CANCELLED;
1608
/* the exec() callback is effectively a 'run-once' scenario, so set the state to that
1609
* so that everything draws correctly
1611
pld->state = PL_PREVIEW_RUNONCE;
1613
/* apply the active pose */
1614
poselib_preview_apply(C, op);
1616
/* now, set the status to exit */
1617
pld->state = PL_PREVIEW_CONFIRM;
1620
return poselib_preview_exit(C, op);
1623
void POSELIB_OT_browse_interactive(wmOperatorType *ot)
1626
ot->name = "PoseLib Browse Poses";
1627
ot->idname = "POSELIB_OT_browse_interactive";
1628
ot->description = "Interactively browse poses in 3D-View";
1631
ot->invoke = poselib_preview_invoke;
1632
ot->modal = poselib_preview_modal;
1633
ot->cancel = poselib_preview_cancel;
1634
ot->exec = poselib_preview_exec;
1635
ot->poll = has_poselib_pose_data_poll;
1638
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
1641
// TODO: make the pose_index into a proper enum instead of a cryptic int...
1642
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);
1644
// XXX: percentage vs factor?
1646
/* 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); */
1649
void POSELIB_OT_apply_pose(wmOperatorType *ot)
1652
ot->name = "Apply Pose Library Pose";
1653
ot->idname = "POSELIB_OT_apply_pose";
1654
ot->description = "Apply specified Pose Library pose to the rig";
1657
ot->exec = poselib_preview_exec;
1658
ot->poll = has_poselib_pose_data_poll;
1661
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1664
/* TODO: make the pose_index into a proper enum instead of a cryptic int... */
1665
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);