== PoseLib - Quick Search for Preview ==

Now, when Previewing/Browsing poses with Ctrl-L, it is possible to type in part of a name to limit the poses which can get chosen to hone in on the poses you wish to apply more quickly. 
* The search is case insensitive, and doesn't look for complete matches (it will 'match' if the whole search-string is found). 
* Only basic text manipulation capabilities are available for editing the search string (i.e.  backspace, del, home, end, move text-cursor forward ->, move text-cursor backwards <-).
* Pose browsing using the Scroll-Wheel and Page up/down can be used to browse through the matches
* View manipulation is only possible with MMB, as numpad keys are used for search-string input.

In the process, I've recoded the preview function to be more modular. It's now split up more, like the Transform core.
This commit is contained in:
Joshua Leung
2008-01-05 10:54:33 +00:00
parent 264aaddcb4
commit fc2ea439b0

View File

@@ -515,6 +515,49 @@ void poselib_rename_pose (Object *ob)
/* ************************************************************* */
/* Simple struct for storing settings/data for use during PoseLib preview */
typedef struct tPoseLib_PreviewData {
ListBase backups; /* tPoseLib_Backup structs for restoring poses */
ListBase searchp; /* LinkData structs storing list of poses which match the current search-string */
Object *ob; /* object to work on */
bArmature *arm; /* object's armature data */
bPose *pose; /* object's pose */
bAction *act; /* poselib to use */
TimeMarker *marker; /* 'active' pose */
short state; /* state of main loop */
short redraw; /* redraw/update settings during main loop */
short firsttime; /* first loop... (no restore) */
int selcount; /* number of selected elements to work on */
int totcount; /* total number of elements to work on */
char headerstr[200]; /* Info-text to print in header */
char searchstr[64]; /* (Part of) Name to search for to filter poses that get shown */
char searchold[64]; /* Previously set searchstr (from last loop run), so that we can detected when to rebuild searchp */
short search_cursor; /* position of cursor in searchstr (cursor occurs before the item at the nominated index) */
} tPoseLib_PreviewData;
/* defines for tPoseLib_PreviewData->state values */
enum {
PL_PREVIEW_ERROR = -1,
PL_PREVIEW_RUNNING,
PL_PREVIEW_CONFIRM,
PL_PREVIEW_CANCEL,
PL_PREVIEW_RUNONCE
};
/* defines for tPoseLib_PreviewData->redraw values */
enum {
PL_PREVIEW_NOREDRAW = 0,
PL_PREVIEW_REDRAWALL,
PL_PREVIEW_REDRAWHEADER,
};
/* ---------------------------- */
/* simple struct for storing backup info */
typedef struct tPoseLib_Backup {
struct tPoseLib_Backup *next, *prev;
@@ -524,41 +567,46 @@ typedef struct tPoseLib_Backup {
} tPoseLib_Backup;
/* Makes a copy of the current pose for restoration purposes - doesn't do constraints currently */
static void poselib_backup_posecopy (ListBase *backups, bPose *pose, bAction *act)
static void poselib_backup_posecopy (tPoseLib_PreviewData *pld)
{
bActionChannel *achan;
bPoseChannel *pchan;
/* for each posechannel that has an actionchannel in */
for (achan= act->chanbase.first; achan; achan= achan->next) {
for (achan= pld->act->chanbase.first; achan; achan= achan->next) {
/* try to find posechannel */
pchan= get_pose_channel(pose, achan->name);
pchan= get_pose_channel(pld->pose, achan->name);
/* backup data if available */
if (pchan) {
tPoseLib_Backup *plb;
/* store backup */
plb= MEM_callocN(sizeof(tPoseLib_Backup), "tPoseLib_Backup");
plb->pchan= pchan;
memcpy(&plb->olddata, plb->pchan, sizeof(bPoseChannel));
BLI_addtail(backups, plb);
BLI_addtail(&pld->backups, plb);
/* mark as being affected */
if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED))
pld->selcount++;
pld->totcount++;
}
}
}
/* Restores original pose - doesn't do constraints currently */
static void poselib_backup_restore (ListBase *backups)
static void poselib_backup_restore (tPoseLib_PreviewData *pld)
{
tPoseLib_Backup *plb;
for (plb= backups->first; plb; plb= plb->next) {
for (plb= pld->backups.first; plb; plb= plb->next) {
memcpy(plb->pchan, &plb->olddata, sizeof(bPoseChannel));
}
}
/* ---------------------------- */
/* Applies the appropriate stored pose from the pose-library to the current pose
@@ -566,14 +614,19 @@ static void poselib_backup_restore (ListBase *backups)
* - gets the string to print in the header
* - this code is based on the code for extract_pose_from_action in blenkernel/action.c
*/
static void poselib_apply_pose (Object *ob, TimeMarker *marker, char headerstr[])
static void poselib_apply_pose (tPoseLib_PreviewData *pld)
{
bPose *pose= ob->pose;
bPose *pose= pld->pose;
bPoseChannel *pchan;
bAction *act= ob->poselib;
bAction *act= pld->act;
bActionChannel *achan;
IpoCurve *icu;
int frame= marker->frame;
int frame;
if (pld->marker)
frame= pld->marker->frame;
else
return;
/* start applying - only those channels which have a key at this point in time! */
for (achan= act->chanbase.first; achan; achan= achan->next) {
@@ -600,13 +653,18 @@ static void poselib_apply_pose (Object *ob, TimeMarker *marker, char headerstr[]
if (found) {
pchan= get_pose_channel(pose, achan->name);
if ( (pchan) && (pchan->bone) &&
(pchan->bone->flag & (BONE_SELECTED|BONE_ACTIVE)) )
{
/* Evaluates and sets the internal ipo values */
calc_ipo(achan->ipo, frame);
/* This call also sets the pchan flags */
execute_action_ipo(achan, pchan);
if (pchan) {
short ok;
ok= (pchan->bone) ? (pchan->bone->flag & (BONE_SELECTED|BONE_ACTIVE)) : 0;
ok= (ok || pld->selcount) ? 1 : 0;
if (ok) {
/* Evaluates and sets the internal ipo values */
calc_ipo(achan->ipo, frame);
/* This call also sets the pchan flags */
execute_action_ipo(achan, pchan);
}
}
}
}
@@ -620,21 +678,22 @@ static void poselib_apply_pose (Object *ob, TimeMarker *marker, char headerstr[]
}
/* Auto-keys/tags bones affected by the pose used from the poselib */
static void poselib_keytag_pose (Object *ob)
static void poselib_keytag_pose (tPoseLib_PreviewData *pld)
{
bPose *pose= pld->pose;
bPoseChannel *pchan;
bAction *act= ob->poselib;
bAction *act= pld->act;
bActionChannel *achan;
/* start tagging/keying */
for (achan= act->chanbase.first; achan; achan= achan->next) {
/* only for selected action channels */
if (achan->flag & ACHAN_SELECTED) {
pchan= get_pose_channel(ob->pose, achan->name);
pchan= get_pose_channel(pose, achan->name);
if (pchan) {
if (G.flags & G_RECORDKEYS) {
ID *id= &ob->id;
ID *id= &pld->ob->id;
/* Set keys on pose */
if (pchan->flag & POSE_ROT) {
@@ -673,216 +732,361 @@ static void poselib_keytag_pose (Object *ob)
/* This helper function is called during poselib_preview_poses to find the
* pose to preview next (after a change event)
*/
static TimeMarker *poselib_preview_get_next (bAction *act, TimeMarker *current, int step)
static void poselib_preview_get_next (tPoseLib_PreviewData *pld, int step)
{
if (step) {
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=current; marker && step; marker=next, step--)
next= (marker->next) ? marker->next : act->markers.first;
if ((pld->marker) && (step)) {
/* 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);
/* 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 marker */
if (ld)
pld->marker= ld->data;
}
else {
for (marker=current; marker && step; marker=next, step++)
next= (marker->prev) ? marker->prev : act->markers.last;
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;
}
/* don't go anywhere if for some reason an error occurred */
return (marker) ? marker : current;
}
else
return current;
}
/* specially handle events for searching */
static void poselib_preview_handle_search (tPoseLib_PreviewData *pld, unsigned short event, char ascii)
{
if (ascii) {
/* character to add to the string */
short index= pld->search_cursor;
short len= (pld->searchstr[0]) ? strlen(pld->searchstr) : 0;
short i;
if (len) {
for (i = len; i > index; i--)
pld->searchstr[i]= pld->searchstr[i-1];
}
else
pld->searchstr[1]= 0;
pld->searchstr[index]= ascii;
pld->search_cursor++;
poselib_preview_get_next(pld, 1);
pld->redraw = PL_PREVIEW_REDRAWALL;
}
else {
/* some form of string manipulation */
switch (event) {
case BACKSPACEKEY:
if (pld->searchstr[0] && pld->search_cursor) {
short len= strlen(pld->searchstr);
short index= pld->search_cursor;
short i;
for (i = index; i <= len; i++)
pld->searchstr[i-1] = pld->searchstr[i];
pld->search_cursor--;
poselib_preview_get_next(pld, 1);
pld->redraw = PL_PREVIEW_REDRAWALL;
}
break;
case DELKEY:
if (pld->searchstr[0] && pld->searchstr[1]) {
short len= strlen(pld->searchstr);
short index= pld->search_cursor;
int i;
if (index < len) {
for (i = index; i < len; i++)
pld->searchstr[i] = pld->searchstr[i+1];
poselib_preview_get_next(pld, 1);
pld->redraw = PL_PREVIEW_REDRAWALL;
}
}
break;
}
}
}
/* handle events for poselib_preview_poses */
static void poselib_preview_handle_event (tPoseLib_PreviewData *pld, unsigned short event, char ascii)
{
/* backup stuff that needs to occur before every operation
* - make a copy of searchstr, so that we know if cache needs to be rebuilt
*/
strcpy(pld->searchold, pld->searchstr);
/* searching takes priority over normal activity */
switch (event) {
/* exit - cancel */
case ESCKEY:
case RIGHTMOUSE:
pld->state= PL_PREVIEW_CANCEL;
break;
/* exit - confirm */
case LEFTMOUSE:
case RETKEY:
case PADENTER:
case SPACEKEY:
pld->state= PL_PREVIEW_CONFIRM;
break;
/* change to previous pose (cyclic) */
case PAGEUPKEY:
case WHEELUPMOUSE:
poselib_preview_get_next(pld, -1);
pld->redraw= PL_PREVIEW_REDRAWALL;
break;
/* change to next pose (cyclic) */
case PAGEDOWNKEY:
case WHEELDOWNMOUSE:
poselib_preview_get_next(pld, 1);
pld->redraw= PL_PREVIEW_REDRAWALL;
break;
/* jump 5 poses (cyclic, back) */
case DOWNARROWKEY:
poselib_preview_get_next(pld, -5);
pld->redraw= PL_PREVIEW_REDRAWALL;
break;
/* jump 5 poses (cyclic, forward) */
case UPARROWKEY:
poselib_preview_get_next(pld, 5);
pld->redraw= PL_PREVIEW_REDRAWALL;
break;
/* change to previous pose or searching cursor control */
case RIGHTARROWKEY:
if (pld->searchstr[0]) {
/* move text-cursor to the right */
if (pld->search_cursor < strlen(pld->searchstr))
pld->search_cursor++;
pld->redraw= PL_PREVIEW_REDRAWHEADER;
}
else {
/* change to previous pose (cyclic) */
poselib_preview_get_next(pld, -1);
pld->redraw= PL_PREVIEW_REDRAWALL;
}
break;
/* change to next pose or searching cursor control */
case LEFTARROWKEY:
if (pld->searchstr[0]) {
/* move text-cursor to the left */
if (pld->search_cursor)
pld->search_cursor--;
pld->redraw= PL_PREVIEW_REDRAWHEADER;
}
else {
/* change to next pose (cyclic) */
poselib_preview_get_next(pld, 1);
pld->redraw= PL_PREVIEW_REDRAWALL;
}
break;
/* change to first pose or start of searching string */
case HOMEKEY:
if (pld->searchstr[0]) {
pld->search_cursor= 0;
pld->redraw= PL_PREVIEW_REDRAWHEADER;
}
else {
/* change to first pose */
pld->marker= pld->act->markers.first;
pld->act->active_marker= 1;
pld->redraw= PL_PREVIEW_REDRAWALL;
}
break;
/* change to last pose or start of searching string */
case ENDKEY:
if (pld->searchstr[0]) {
pld->search_cursor= strlen(pld->searchstr);
pld->redraw= PL_PREVIEW_REDRAWHEADER;
}
else {
/* change to last pose */
pld->marker= pld->act->markers.last;
pld->act->active_marker= BLI_countlist(&pld->act->markers);
pld->redraw= PL_PREVIEW_REDRAWALL;
}
break;
/* view manipulation */
case MIDDLEMOUSE:
// there's a little bug here that causes the normal header to get drawn while view is manipulated
handle_view_middlemouse();
pld->redraw= PL_PREVIEW_REDRAWHEADER;
break;
/* view manipulation, or searching */
case PAD0: case PAD1: case PAD2: case PAD3: case PAD4:
case PAD5: case PAD6: case PAD7: case PAD8: case PAD9:
case PADPLUSKEY: case PADMINUS:
if (pld->searchstr[0]) {
poselib_preview_handle_search(pld, event, ascii);
}
else {
persptoetsen(event);
pld->redraw= PL_PREVIEW_REDRAWHEADER;
}
break;
/* otherwise, assume that searching might be able to handle it */
default:
poselib_preview_handle_search(pld, event, ascii);
break;
}
}
/* ---------------------------- */
/* defines for poselib_preview_poses --> ret_val values */
enum {
PL_PREVIEW_RUNNING = 0,
PL_PREVIEW_CONFIRM,
PL_PREVIEW_CANCEL,
PL_PREVIEW_RUNONCE
};
/* defines for poselib_preview_poses --> redraw values */
enum {
PL_PREVIEW_NOREDRAW = 0,
PL_PREVIEW_REDRAWALL,
PL_PREVIEW_REDRAWHEADER,
};
/* This tool allows users to preview the pose from the pose-lib using the mouse-scrollwheel/pageupdown
* It is also used to apply the active poselib pose only
*/
void poselib_preview_poses (Object *ob, short apply_active)
/* Init PoseLib Previewing data */
static void poselib_preview_init_data (tPoseLib_PreviewData *pld, Object *ob, short apply_active)
{
ListBase backups = {NULL, NULL};
/* clear pld first as it resides on the stack */
memset(pld, 0, sizeof(tPoseLib_PreviewData));
bPose *pose= (ob) ? (ob->pose) : NULL;
bArmature *arm= (ob) ? (ob->data) : NULL;
bAction *act= (ob) ? (ob->poselib) : NULL;
TimeMarker *marker= poselib_get_active_pose(act);
Base *base;
short ret_val= (apply_active) ? PL_PREVIEW_RUNONCE : PL_PREVIEW_RUNNING;
short val=0, redraw=1, firsttime=1;
unsigned short event;
char headerstr[200];
/* get basic data */
pld->ob= ob;
pld->arm= (ob) ? (ob->data) : NULL;
pld->pose= (ob) ? (ob->pose) : NULL;
pld->act= (ob) ? (ob->poselib) : NULL;
pld->marker= poselib_get_active_pose(pld->act);
/* check if valid poselib */
if (ELEM3(NULL, ob, pose, arm)) {
if (ELEM3(NULL, pld->ob, pld->pose, pld->arm)) {
error("PoseLib is only for Armatures in PoseMode");
pld->state= PL_PREVIEW_ERROR;
return;
}
if (act == NULL) {
if (pld->act == NULL) {
error("Object doesn't have a valid PoseLib");
pld->state= PL_PREVIEW_ERROR;
return;
}
if (marker == NULL) {
error("PoseLib has no poses to preview/apply");
return;
if (pld->marker == NULL) {
if ((apply_active==0) || (pld->act->markers.first)) {
/* just use first one then... */
pld->marker= pld->act->markers.first;
printf("PoseLib had no active pose\n");
}
else {
error("PoseLib has no poses to preview/apply");
pld->state= PL_PREVIEW_ERROR;
return;
}
}
/* make backup of current pose for restoring pose */
poselib_backup_posecopy(&backups, pose, act);
/* make backups for restoring pose */
poselib_backup_posecopy(pld);
/* set flags for running */
pld->state= (apply_active) ? PL_PREVIEW_RUNONCE : PL_PREVIEW_RUNNING;
pld->redraw= PL_PREVIEW_REDRAWALL;
pld->firsttime= 1;
/* set depsgraph flags */
/* make sure the lock is set OK, unlock can be accidentally saved? */
pose->flag |= POSE_LOCKED;
pose->flag &= ~POSE_DO_UNLOCK;
pld->pose->flag |= POSE_LOCKED;
pld->pose->flag &= ~POSE_DO_UNLOCK;
/* start preview loop */
while (ELEM(ret_val, PL_PREVIEW_RUNNING, PL_PREVIEW_RUNONCE)) {
/* preview a pose */
if (redraw) {
/* only recalc pose (and its dependencies) if pose has changed */
if (redraw == PL_PREVIEW_REDRAWALL) {
/* don't clear pose if firsttime */
if (firsttime == 0)
poselib_backup_restore(&backups);
else
firsttime = 0;
/* pose should be the right one to draw */
poselib_apply_pose(ob, marker, headerstr);
/* old optimize trick... this enforces to bypass the depgraph
* - note: code copied from transform_generics.c -> recalcData()
*/
if ((arm->flag & ARM_DELAYDEFORM)==0) {
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); /* sets recalc flags */
/* bah, softbody exception... recalcdata doesnt reset */
for (base= FIRSTBASE; base; base= base->next) {
if (base->object->recalc & OB_RECALC_DATA)
if (modifiers_isSoftbodyEnabled(base->object)) {
base->object->softflag |= OB_SB_REDO;
}
}
}
else
where_is_pose(ob);
}
/* do header print - if interactively previewing */
if (ret_val == PL_PREVIEW_RUNNING) {
sprintf(headerstr, "PoseLib Previewing Pose: \"%s\" | Use ScrollWheel or PageUp/Down to change", marker->name);
headerprint(headerstr);
}
/* force drawing of view + clear redraw flag */
force_draw(0);
redraw= PL_PREVIEW_NOREDRAW;
}
/* stop now if only running once */
if (ret_val == PL_PREVIEW_RUNONCE) {
ret_val = PL_PREVIEW_CONFIRM;
break;
}
/* essential for idling subloop */
if (qtest() == 0)
PIL_sleep_ms(2);
/* emptying queue and reading events */
while ( qtest() ) {
event= extern_qread(&val);
/* event processing */
if (val) {
switch (event) {
/* exit - cancel */
case ESCKEY:
case RIGHTMOUSE:
ret_val= PL_PREVIEW_CANCEL;
break;
/* exit - confirm */
case LEFTMOUSE:
case RETKEY:
case SPACEKEY:
ret_val= PL_PREVIEW_CONFIRM;
break;
/* change to previous pose (cyclic) */
case PAGEUPKEY:
case WHEELUPMOUSE:
case RIGHTARROWKEY:
marker= poselib_preview_get_next(act, marker, -1);
redraw= PL_PREVIEW_REDRAWALL;
break;
/* change to next pose (cyclic) */
case PAGEDOWNKEY:
case WHEELDOWNMOUSE:
case LEFTARROWKEY:
marker= poselib_preview_get_next(act, marker, 1);
redraw= PL_PREVIEW_REDRAWALL;
break;
/* jump 5 poses (cyclic, back) */
case DOWNARROWKEY:
marker= poselib_preview_get_next(act, marker, -5);
redraw= PL_PREVIEW_REDRAWALL;
break;
/* jump 5 poses (cyclic, forward) */
case UPARROWKEY:
marker= poselib_preview_get_next(act, marker, 5);
redraw= PL_PREVIEW_REDRAWALL;
break;
/* view manipulation */
case MIDDLEMOUSE:
// there's a little bug here that causes the normal header to get drawn while view is manipulated
handle_view_middlemouse();
redraw= PL_PREVIEW_REDRAWHEADER;
break;
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 PADENTER:
persptoetsen(event);
redraw= PL_PREVIEW_REDRAWHEADER;
break;
}
}
}
}
/* clear strings + search */
strcpy(pld->headerstr, "");
strcpy(pld->searchstr, "");
strcpy(pld->searchold, "");
pld->search_cursor= 0;
}
/* After previewing poses */
static void poselib_preview_cleanup (tPoseLib_PreviewData *pld)
{
Base *base;
Object *ob= pld->ob;
bPose *pose= pld->pose;
bArmature *arm= pld->arm;
bAction *act= pld->act;
TimeMarker *marker= pld->marker;
/* this signal does one recalc on pose, then unlocks, so ESC or edit will work */
pose->flag |= POSE_DO_UNLOCK;
/* clear pose if cancelled */
if (ret_val == PL_PREVIEW_CANCEL) {
poselib_backup_restore(&backups);
if (pld->state == PL_PREVIEW_CANCEL) {
poselib_backup_restore(pld);
/* old optimize trick... this enforces to bypass the depgraph
* - note: code copied from transform_generics.c -> recalcData()
@@ -902,13 +1106,15 @@ void poselib_preview_poses (Object *ob, short apply_active)
where_is_pose(ob);
allqueue(REDRAWVIEW3D, 0);
allqueue(REDRAWBUTSEDIT, 0);
}
else if (ret_val == PL_PREVIEW_CONFIRM) {
else if (pld->state == PL_PREVIEW_CONFIRM) {
/* tag poses as appropriate */
poselib_keytag_pose(ob);
poselib_keytag_pose(pld);
/* change active pose setting */
act->active_marker= BLI_findindex(&act->markers, marker) + 1;
action_set_activemarker(act, marker, 0);
/* Update event for pose and deformation children */
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
@@ -932,8 +1138,121 @@ void poselib_preview_poses (Object *ob, short apply_active)
allqueue(REDRAWBUTSEDIT, 0);
}
}
/* free memory used for backups */
BLI_freelistN(&backups);
BLI_freelistN(&pld->backups);
BLI_freelistN(&pld->searchp);
}
/* This tool allows users to preview the pose from the pose-lib using the mouse-scrollwheel/pageupdown
* It is also used to apply the active poselib pose only
*/
void poselib_preview_poses (Object *ob, short apply_active)
{
tPoseLib_PreviewData pld;
Base *base;
unsigned short event;
short val=0;
char ascii;
/* check if valid poselib */
poselib_preview_init_data(&pld, ob, apply_active);
if (pld.state == PL_PREVIEW_ERROR)
return;
/* start preview loop */
while (ELEM(pld.state, PL_PREVIEW_RUNNING, PL_PREVIEW_RUNONCE)) {
/* preview a pose */
if (pld.redraw) {
/* only recalc pose (and its dependencies) if pose has changed */
if (pld.redraw == PL_PREVIEW_REDRAWALL) {
/* don't clear pose if firsttime */
if (pld.firsttime == 0)
poselib_backup_restore(&pld);
else
pld.firsttime = 0;
/* pose should be the right one to draw */
poselib_apply_pose(&pld);
/* old optimize trick... this enforces to bypass the depgraph
* - note: code copied from transform_generics.c -> recalcData()
*/
if ((pld.arm->flag & ARM_DELAYDEFORM)==0) {
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); /* sets recalc flags */
/* bah, softbody exception... recalcdata doesnt reset */
for (base= FIRSTBASE; base; base= base->next) {
if (base->object->recalc & OB_RECALC_DATA)
if (modifiers_isSoftbodyEnabled(base->object)) {
base->object->softflag |= OB_SB_REDO;
}
}
}
else
where_is_pose(ob);
}
/* do header print - if interactively previewing */
if (pld.state == PL_PREVIEW_RUNNING) {
if (pld.searchstr[0]) {
char tempstr[65];
char markern[64];
short index;
/* get search-string */
index= pld.search_cursor;
memcpy(&tempstr[0], &pld.searchstr[0], index);
tempstr[index]= '|';
memcpy(&tempstr[index+1], &pld.searchstr[index], 64-index);
/* get marker name */
if (pld.marker)
strcpy(markern, pld.marker->name);
else
strcpy(markern, "No Matches");
sprintf(pld.headerstr, "PoseLib Previewing Pose: Filter - [%s] | Current Pose - \"%s\" | Use ScrollWheel or PageUp/Down to change", tempstr, markern);
headerprint(pld.headerstr);
}
else {
sprintf(pld.headerstr, "PoseLib Previewing Pose: \"%s\" | Use ScrollWheel or PageUp/Down to change", pld.marker->name);
headerprint(pld.headerstr);
}
}
/* force drawing of view + clear redraw flag */
force_draw(0);
pld.redraw= PL_PREVIEW_NOREDRAW;
}
/* stop now if only running once */
if (pld.state == PL_PREVIEW_RUNONCE) {
pld.state = PL_PREVIEW_CONFIRM;
break;
}
/* essential for idling subloop */
if (qtest() == 0)
PIL_sleep_ms(2);
/* emptying queue and reading events */
while ( qtest() ) {
event= extern_qread_ext(&val, &ascii);
/* event processing */
if (val) {
poselib_preview_handle_event(&pld, event, ascii);
}
}
}
/* finish up */
poselib_preview_cleanup(&pld);
BIF_undo_push("PoseLib Apply Pose");
}