2011-02-23 10:52:22 +00:00
/*
2009-09-22 19:09:04 +00:00
* $ Id $
2009-09-19 00:18:42 +00:00
*
* * * * * * BEGIN GPL LICENSE BLOCK * * * * *
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software Foundation ,
2010-02-12 13:34:04 +00:00
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
2009-09-19 00:18:42 +00:00
*
* The Original Code is Copyright ( C ) 2009 , Blender Foundation , Joshua Leung
* This is a new part of Blender
*
* Contributor ( s ) : Joshua Leung
*
* * * * * * END GPL LICENSE BLOCK * * * * *
*/
2011-02-27 20:29:51 +00:00
/** \file blender/editors/armature/poseSlide.c
* \ ingroup edarmature
*/
2009-09-19 00:18:42 +00:00
# include <stdlib.h>
# include <stdio.h>
# include <stddef.h>
# include <string.h>
# include <math.h>
# include <float.h>
# include "MEM_guardedalloc.h"
2009-11-10 20:43:45 +00:00
# include "BLI_math.h"
2009-09-19 00:18:42 +00:00
# include "BLI_blenlib.h"
# include "BLI_dynstr.h"
# include "BLI_dlrbTree.h"
2011-01-07 18:36:47 +00:00
# include "BLI_utildefines.h"
2009-09-19 00:18:42 +00:00
# include "DNA_anim_types.h"
# include "DNA_armature_types.h"
# include "DNA_object_types.h"
# include "DNA_scene_types.h"
# include "BKE_fcurve.h"
# include "BKE_context.h"
# include "BKE_report.h"
# include "RNA_access.h"
# include "RNA_define.h"
# include "WM_api.h"
# include "WM_types.h"
# include "ED_armature.h"
# include "ED_keyframes_draw.h"
2011-03-31 01:37:42 +00:00
# include "ED_markers.h"
2009-09-19 00:18:42 +00:00
# include "ED_screen.h"
# include "armature_intern.h"
/* **************************************************** */
/* == POSE 'SLIDING' TOOLS ==
*
* A ) Push & Relax , Breakdowner
* These tools provide the animator with various capabilities
* for interactively controlling the spacing of poses , but also
* for ' pushing ' and / or ' relaxing ' extremes as they see fit .
*
2011-03-24 03:02:34 +00:00
* B ) Propagate
* This tool copies elements of the selected pose to successive
* keyframes , allowing the animator to go back and modify the poses
* for some " static " pose controls , without having to repeatedly
* doing a " next paste " dance .
*
* C ) Pose Sculpting
2009-09-19 00:18:42 +00:00
* This is yet to be implemented , but the idea here is to use
* sculpting techniques to make it easier to pose rigs by allowing
* rigs to be manipulated using a familiar paint - based interface .
*/
/* **************************************************** */
/* A) Push & Relax, Breakdowner */
/* Temporary data shared between these operators */
typedef struct tPoseSlideOp {
Scene * scene ; /* current scene */
ARegion * ar ; /* region that we're operating in (needed for */
Object * ob ; /* active object that Pose Info comes from */
2009-09-19 11:59:23 +00:00
bArmature * arm ; /* armature for pose */
2009-09-19 00:18:42 +00:00
ListBase pfLinks ; /* links between posechannels and f-curves */
DLRBT_Tree keys ; /* binary tree for quicker searching for keyframes (when applicable) */
int cframe ; /* current frame number */
int prevFrame ; /* frame before current frame (blend-from) */
int nextFrame ; /* frame after current frame (blend-to) */
int mode ; /* sliding mode (ePoseSlide_Modes) */
int flag ; // unused for now, but can later get used for storing runtime settings....
float percentage ; /* 0-1 value for determining the influence of whatever is relevant */
} tPoseSlideOp ;
/* Pose Sliding Modes */
typedef enum ePoseSlide_Modes {
POSESLIDE_PUSH = 0 , /* exaggerate the pose... */
POSESLIDE_RELAX , /* soften the pose... */
POSESLIDE_BREAKDOWN , /* slide between the endpoint poses, finding a 'soft' spot */
} ePoseSlide_Modes ;
/* ------------------------------------ */
/* operator init */
static int pose_slide_init ( bContext * C , wmOperator * op , short mode )
{
tPoseSlideOp * pso ;
bAction * act = NULL ;
/* init slide-op data */
pso = op - > customdata = MEM_callocN ( sizeof ( tPoseSlideOp ) , " tPoseSlideOp " ) ;
/* get info from context */
pso - > scene = CTX_data_scene ( C ) ;
2010-10-07 23:17:14 +00:00
pso - > ob = ED_object_pose_armature ( CTX_data_active_object ( C ) ) ;
2009-09-19 11:59:23 +00:00
pso - > arm = ( pso - > ob ) ? pso - > ob - > data : NULL ;
2009-09-19 00:18:42 +00:00
pso - > ar = CTX_wm_region ( C ) ; /* only really needed when doing modal() */
pso - > cframe = pso - > scene - > r . cfra ;
pso - > mode = mode ;
/* set range info from property values - these may get overridden for the invoke() */
pso - > percentage = RNA_float_get ( op - > ptr , " percentage " ) ;
pso - > prevFrame = RNA_int_get ( op - > ptr , " prev_frame " ) ;
pso - > nextFrame = RNA_int_get ( op - > ptr , " next_frame " ) ;
/* check the settings from the context */
2009-09-19 11:59:23 +00:00
if ( ELEM4 ( NULL , pso - > ob , pso - > arm , pso - > ob - > adt , pso - > ob - > adt - > action ) )
2009-09-19 00:18:42 +00:00
return 0 ;
else
act = pso - > ob - > adt - > action ;
/* for each Pose-Channel which gets affected, get the F-Curves for that channel
* and set the relevant transform flags . . .
*/
2010-02-19 11:42:21 +00:00
poseAnim_mapping_get ( C , & pso - > pfLinks , pso - > ob , act ) ;
2009-09-19 00:18:42 +00:00
2009-09-19 11:59:23 +00:00
/* set depsgraph flags */
/* make sure the lock is set OK, unlock can be accidentally saved? */
pso - > ob - > pose - > flag | = POSE_LOCKED ;
pso - > ob - > pose - > flag & = ~ POSE_DO_UNLOCK ;
2009-09-19 00:18:42 +00:00
/* do basic initialise of RB-BST used for finding keyframes, but leave the filling of it up
* to the caller of this ( usually only invoke ( ) will do it , to make things more efficient ) .
*/
BLI_dlrbTree_init ( & pso - > keys ) ;
/* return status is whether we've got all the data we were requested to get */
return 1 ;
}
/* exiting the operator - free data */
2010-10-16 02:40:31 +00:00
static void pose_slide_exit ( wmOperator * op )
2009-09-19 00:18:42 +00:00
{
tPoseSlideOp * pso = op - > customdata ;
/* if data exists, clear its data and exit */
if ( pso ) {
/* free the temp pchan links and their data */
2010-02-19 11:42:21 +00:00
poseAnim_mapping_free ( & pso - > pfLinks ) ;
2009-09-19 00:18:42 +00:00
/* free RB-BST for keyframes (if it contained data) */
BLI_dlrbTree_free ( & pso - > keys ) ;
/* free data itself */
MEM_freeN ( pso ) ;
}
/* cleanup */
op - > customdata = NULL ;
}
/* ------------------------------------ */
2009-09-20 05:05:16 +00:00
/* helper for apply() / reset() - refresh the data */
static void pose_slide_refresh ( bContext * C , tPoseSlideOp * pso )
{
2010-02-19 11:42:21 +00:00
/* wrapper around the generic version, allowing us to add some custom stuff later still */
poseAnim_mapping_refresh ( C , pso - > scene , pso - > ob ) ;
2009-09-19 00:18:42 +00:00
}
2011-03-13 12:22:57 +00:00
/* helper for apply() - perform sliding for some value */
2011-03-13 12:26:53 +00:00
static void pose_slide_apply_val ( tPoseSlideOp * pso , FCurve * fcu , float * val )
2011-03-13 12:22:57 +00:00
{
float cframe = ( float ) pso - > cframe ;
float sVal , eVal ;
float w1 , w2 ;
/* get keyframe values for endpoint poses to blend with */
/* previous/start */
sVal = evaluate_fcurve ( fcu , ( float ) pso - > prevFrame ) ;
/* next/end */
eVal = evaluate_fcurve ( fcu , ( float ) pso - > nextFrame ) ;
/* calculate the relative weights of the endpoints */
if ( pso - > mode = = POSESLIDE_BREAKDOWN ) {
/* get weights from the percentage control */
w1 = pso - > percentage ; /* this must come second */
w2 = 1.0f - w1 ; /* this must come first */
}
else {
/* - these weights are derived from the relative distance of these
* poses from the current frame
* - they then get normalised so that they only sum up to 1
*/
float wtot ;
w1 = cframe - ( float ) pso - > prevFrame ;
w2 = ( float ) pso - > nextFrame - cframe ;
wtot = w1 + w2 ;
w1 = ( w1 / wtot ) ;
w2 = ( w2 / wtot ) ;
}
/* depending on the mode, calculate the new value
* - in all of these , the start + end values are multiplied by w2 and w1 ( respectively ) ,
* since multiplication in another order would decrease the value the current frame is closer to
*/
switch ( pso - > mode ) {
case POSESLIDE_PUSH : /* make the current pose more pronounced */
{
/* perform a weighted average here, favouring the middle pose
* - numerator should be larger than denominator to ' expand ' the result
* - perform this weighting a number of times given by the percentage . . .
*/
int iters = ( int ) ceil ( 10.0f * pso - > percentage ) ; // TODO: maybe a sensitivity ctrl on top of this is needed
while ( iters - - > 0 ) {
( * val ) = ( - ( ( sVal * w2 ) + ( eVal * w1 ) ) + ( ( * val ) * 6.0f ) ) / 5.0f ;
}
}
break ;
case POSESLIDE_RELAX : /* make the current pose more like its surrounding ones */
{
/* perform a weighted average here, favouring the middle pose
* - numerator should be smaller than denominator to ' relax ' the result
* - perform this weighting a number of times given by the percentage . . .
*/
int iters = ( int ) ceil ( 10.0f * pso - > percentage ) ; // TODO: maybe a sensitivity ctrl on top of this is needed
while ( iters - - > 0 ) {
( * val ) = ( ( ( sVal * w2 ) + ( eVal * w1 ) ) + ( ( * val ) * 5.0f ) ) / 6.0f ;
}
}
break ;
case POSESLIDE_BREAKDOWN : /* make the current pose slide around between the endpoints */
{
/* perform simple linear interpolation - coefficient for start must come from pso->percentage... */
// TODO: make this use some kind of spline interpolation instead?
( * val ) = ( ( sVal * w2 ) + ( eVal * w1 ) ) ;
}
break ;
}
}
2009-09-19 00:18:42 +00:00
/* helper for apply() - perform sliding for some 3-element vector */
2011-03-13 12:22:57 +00:00
static void pose_slide_apply_vec3 ( tPoseSlideOp * pso , tPChanFCurveLink * pfl , float vec [ 3 ] , const char propName [ ] )
2009-09-19 00:18:42 +00:00
{
LinkData * ld = NULL ;
char * path = NULL ;
/* get the path to use... */
path = BLI_sprintfN ( " %s.%s " , pfl - > pchan_path , propName ) ;
/* using this path, find each matching F-Curve for the variables we're interested in */
2010-02-19 11:42:21 +00:00
while ( ( ld = poseAnim_mapping_getNextFCurve ( & pfl - > fcurves , ld , path ) ) ) {
2009-09-19 00:18:42 +00:00
FCurve * fcu = ( FCurve * ) ld - > data ;
2011-03-13 12:22:57 +00:00
/* just work on these channels one by one... there's no interaction between values */
2011-03-13 12:26:53 +00:00
pose_slide_apply_val ( pso , fcu , & vec [ fcu - > array_index ] ) ;
2011-03-13 12:22:57 +00:00
}
/* free the temp path we got */
MEM_freeN ( path ) ;
}
/* helper for apply() - perform sliding for custom properties */
static void pose_slide_apply_props ( tPoseSlideOp * pso , tPChanFCurveLink * pfl )
{
PointerRNA ptr = { { NULL } } ;
LinkData * ld ;
int len = strlen ( pfl - > pchan_path ) ;
/* setup pointer RNA for resolving paths */
RNA_pointer_create ( NULL , & RNA_PoseBone , pfl - > pchan , & ptr ) ;
/* custom properties are just denoted using ["..."][etc.] after the end of the base path,
* so just check for opening pair after the end of the path
*/
for ( ld = pfl - > fcurves . first ; ld ; ld = ld - > next ) {
FCurve * fcu = ( FCurve * ) ld - > data ;
char * bPtr , * pPtr ;
2009-09-19 00:18:42 +00:00
2011-03-13 12:22:57 +00:00
if ( fcu - > rna_path = = NULL )
continue ;
2009-09-19 00:18:42 +00:00
2011-03-13 12:22:57 +00:00
/* do we have a match?
* - bPtr is the RNA Path with the standard part chopped off
* - pPtr is the chunk of the path which is left over
*/
bPtr = strstr ( fcu - > rna_path , pfl - > pchan_path ) + len ;
pPtr = strstr ( bPtr , " [ \" " ) ; /* dummy " for texteditor bugs */
if ( pPtr ) {
/* use RNA to try and get a handle on this property, then, assuming that it is just
* numerical , try and grab the value as a float for temp editing before setting back
2009-09-19 11:59:23 +00:00
*/
2011-03-13 12:22:57 +00:00
PropertyRNA * prop = RNA_struct_find_property ( & ptr , pPtr ) ;
2009-09-19 11:59:23 +00:00
2011-03-13 12:22:57 +00:00
if ( prop ) {
2011-03-13 12:26:53 +00:00
switch ( RNA_property_type ( prop ) ) {
case PROP_FLOAT :
{
float tval = RNA_property_float_get ( & ptr , prop ) ;
pose_slide_apply_val ( pso , fcu , & tval ) ;
RNA_property_float_set ( & ptr , prop , tval ) ;
}
break ;
case PROP_BOOLEAN :
case PROP_ENUM :
case PROP_INT :
{
float tval = ( float ) RNA_property_int_get ( & ptr , prop ) ;
pose_slide_apply_val ( pso , fcu , & tval ) ;
RNA_property_int_set ( & ptr , prop , ( int ) tval ) ;
}
break ;
default :
/* cannot handle */
//printf("Cannot Pose Slide non-numerical property\n");
break ;
}
2009-09-20 05:05:16 +00:00
}
2009-09-19 00:18:42 +00:00
}
}
}
/* helper for apply() - perform sliding for quaternion rotations (using quat blending) */
static void pose_slide_apply_quat ( tPoseSlideOp * pso , tPChanFCurveLink * pfl )
{
2009-09-20 12:54:30 +00:00
FCurve * fcu_w = NULL , * fcu_x = NULL , * fcu_y = NULL , * fcu_z = NULL ;
bPoseChannel * pchan = pfl - > pchan ;
LinkData * ld = NULL ;
char * path = NULL ;
float cframe ;
/* get the path to use - this should be quaternion rotations only (needs care) */
2009-12-29 23:25:46 +00:00
path = BLI_sprintfN ( " %s.%s " , pfl - > pchan_path , " rotation_quaternion " ) ;
2009-09-20 12:54:30 +00:00
/* get the current frame number */
cframe = ( float ) pso - > cframe ;
/* using this path, find each matching F-Curve for the variables we're interested in */
2010-02-19 11:42:21 +00:00
while ( ( ld = poseAnim_mapping_getNextFCurve ( & pfl - > fcurves , ld , path ) ) ) {
2009-09-20 12:54:30 +00:00
FCurve * fcu = ( FCurve * ) ld - > data ;
/* assign this F-Curve to one of the relevant pointers... */
switch ( fcu - > array_index ) {
case 3 : /* z */
fcu_z = fcu ;
break ;
case 2 : /* y */
fcu_y = fcu ;
break ;
case 1 : /* x */
fcu_x = fcu ;
break ;
case 0 : /* w */
fcu_w = fcu ;
break ;
}
}
/* only if all channels exist, proceed */
if ( fcu_w & & fcu_x & & fcu_y & & fcu_z ) {
float quat_prev [ 4 ] , quat_next [ 4 ] ;
/* get 2 quats */
quat_prev [ 0 ] = evaluate_fcurve ( fcu_w , pso - > prevFrame ) ;
quat_prev [ 1 ] = evaluate_fcurve ( fcu_x , pso - > prevFrame ) ;
quat_prev [ 2 ] = evaluate_fcurve ( fcu_y , pso - > prevFrame ) ;
quat_prev [ 3 ] = evaluate_fcurve ( fcu_z , pso - > prevFrame ) ;
quat_next [ 0 ] = evaluate_fcurve ( fcu_w , pso - > nextFrame ) ;
quat_next [ 1 ] = evaluate_fcurve ( fcu_x , pso - > nextFrame ) ;
quat_next [ 2 ] = evaluate_fcurve ( fcu_y , pso - > nextFrame ) ;
quat_next [ 3 ] = evaluate_fcurve ( fcu_z , pso - > nextFrame ) ;
/* perform blending */
if ( pso - > mode = = POSESLIDE_BREAKDOWN ) {
/* just perform the interpol between quat_prev and quat_next using pso->percentage as a guide */
2009-11-10 20:43:45 +00:00
interp_qt_qtqt ( pchan - > quat , quat_prev , quat_next , pso - > percentage ) ;
2009-09-20 12:54:30 +00:00
}
2009-12-29 23:25:46 +00:00
else if ( pso - > mode = = POSESLIDE_PUSH ) {
float quat_diff [ 4 ] , quat_orig [ 4 ] ;
/* calculate the delta transform from the previous to the current */
// TODO: investigate ways to favour one transform more?
sub_qt_qtqt ( quat_diff , pchan - > quat , quat_prev ) ;
/* make a copy of the original rotation */
QUATCOPY ( quat_orig , pchan - > quat ) ;
/* increase the original by the delta transform, by an amount determined by percentage */
add_qt_qtqt ( pchan - > quat , quat_orig , quat_diff , pso - > percentage ) ;
}
2009-09-20 12:54:30 +00:00
else {
float quat_interp [ 4 ] , quat_orig [ 4 ] ;
int iters = ( int ) ceil ( 10.0f * pso - > percentage ) ; // TODO: maybe a sensitivity ctrl on top of this is needed
/* perform this blending several times until a satisfactory result is reached */
while ( iters - - > 0 ) {
/* calculate the interpolation between the endpoints */
2009-11-10 20:43:45 +00:00
interp_qt_qtqt ( quat_interp , quat_prev , quat_next , ( cframe - pso - > prevFrame ) / ( pso - > nextFrame - pso - > prevFrame ) ) ;
2009-09-20 12:54:30 +00:00
/* make a copy of the original rotation */
QUATCOPY ( quat_orig , pchan - > quat ) ;
2009-12-29 23:25:46 +00:00
/* tricky interpolations - blending between original and new */
interp_qt_qtqt ( pchan - > quat , quat_orig , quat_interp , 1.0f / 6.0f ) ;
2009-09-20 12:54:30 +00:00
}
}
}
/* free the path now */
MEM_freeN ( path ) ;
2009-09-19 00:18:42 +00:00
}
/* apply() - perform the pose sliding based on weighting various poses */
2010-10-16 02:40:31 +00:00
static void pose_slide_apply ( bContext * C , tPoseSlideOp * pso )
2009-09-19 00:18:42 +00:00
{
tPChanFCurveLink * pfl ;
/* sanitise the frame ranges */
if ( pso - > prevFrame = = pso - > nextFrame ) {
/* move out one step either side */
pso - > prevFrame - - ;
pso - > nextFrame + + ;
}
/* for each link, handle each set of transforms */
for ( pfl = pso - > pfLinks . first ; pfl ; pfl = pfl - > next ) {
/* valid transforms for each PoseChannel should have been noted already
* - sliding the pose should be a straightforward exercise for location + rotation ,
* but rotations get more complicated since we may want to use quaternion blending
* for quaternions instead . . .
*/
bPoseChannel * pchan = pfl - > pchan ;
if ( pchan - > flag & POSE_LOC ) {
/* calculate these for the 'location' vector, and use location curves */
pose_slide_apply_vec3 ( pso , pfl , pchan - > loc , " location " ) ;
}
if ( pchan - > flag & POSE_SIZE ) {
/* calculate these for the 'scale' vector, and use scale curves */
pose_slide_apply_vec3 ( pso , pfl , pchan - > size , " scale " ) ;
}
if ( pchan - > flag & POSE_ROT ) {
/* everything depends on the rotation mode */
if ( pchan - > rotmode > 0 ) {
/* eulers - so calculate these for the 'eul' vector, and use euler_rotation curves */
2009-09-28 10:19:20 +00:00
pose_slide_apply_vec3 ( pso , pfl , pchan - > eul , " rotation_euler " ) ;
2009-09-19 00:18:42 +00:00
}
2009-09-28 10:19:20 +00:00
else if ( pchan - > rotmode = = ROT_MODE_AXISANGLE ) {
2009-09-19 00:18:42 +00:00
// TODO: need to figure out how to do this!
}
else {
/* quaternions - use quaternion blending */
pose_slide_apply_quat ( pso , pfl ) ;
}
}
2011-03-13 12:22:57 +00:00
if ( pfl - > oldprops ) {
/* not strictly a transform, but contributes to the pose produced in many rigs */
pose_slide_apply_props ( pso , pfl ) ;
}
2009-09-19 00:18:42 +00:00
}
2009-09-20 05:05:16 +00:00
/* depsgraph updates + redraws */
pose_slide_refresh ( C , pso ) ;
}
/* perform autokeyframing after changes were made + confirmed */
static void pose_slide_autoKeyframe ( bContext * C , tPoseSlideOp * pso )
{
2010-02-19 11:42:21 +00:00
/* wrapper around the generic call */
poseAnim_mapping_autoKeyframe ( C , pso - > scene , pso - > ob , & pso - > pfLinks , ( float ) pso - > cframe ) ;
2009-09-20 05:05:16 +00:00
}
/* reset changes made to current pose */
2010-10-16 02:40:31 +00:00
static void pose_slide_reset ( tPoseSlideOp * pso )
2009-09-20 05:05:16 +00:00
{
2010-02-19 11:42:21 +00:00
/* wrapper around the generic call, so that custom stuff can be added later */
poseAnim_mapping_reset ( & pso - > pfLinks ) ;
2009-09-19 00:18:42 +00:00
}
/* ------------------------------------ */
/* common code for invoke() methods */
static int pose_slide_invoke_common ( bContext * C , wmOperator * op , tPoseSlideOp * pso )
{
tPChanFCurveLink * pfl ;
AnimData * adt = pso - > ob - > adt ;
2009-09-19 12:36:22 +00:00
wmWindow * win = CTX_wm_window ( C ) ;
2009-09-19 00:18:42 +00:00
/* for each link, add all its keyframes to the search tree */
for ( pfl = pso - > pfLinks . first ; pfl ; pfl = pfl - > next ) {
LinkData * ld ;
/* do this for each F-Curve */
for ( ld = pfl - > fcurves . first ; ld ; ld = ld - > next ) {
FCurve * fcu = ( FCurve * ) ld - > data ;
fcurve_to_keylist ( adt , fcu , & pso - > keys , NULL ) ;
}
}
/* consolidate these keyframes, and figure out the nearest ones */
BLI_dlrbTree_linkedlist_sync ( & pso - > keys ) ;
2009-09-19 11:59:23 +00:00
/* cancel if no keyframes found... */
2009-09-19 00:18:42 +00:00
if ( pso - > keys . root ) {
ActKeyColumn * ak ;
2009-12-29 23:25:46 +00:00
float cframe = ( float ) pso - > cframe ;
2009-09-19 00:18:42 +00:00
/* firstly, check if the current frame is a keyframe... */
2009-12-29 23:25:46 +00:00
ak = ( ActKeyColumn * ) BLI_dlrbTree_search_exact ( & pso - > keys , compare_ak_cfraPtr , & cframe ) ;
2009-09-19 00:18:42 +00:00
if ( ak = = NULL ) {
/* current frame is not a keyframe, so search */
2009-12-29 23:25:46 +00:00
ActKeyColumn * pk = ( ActKeyColumn * ) BLI_dlrbTree_search_prev ( & pso - > keys , compare_ak_cfraPtr , & cframe ) ;
ActKeyColumn * nk = ( ActKeyColumn * ) BLI_dlrbTree_search_next ( & pso - > keys , compare_ak_cfraPtr , & cframe ) ;
2009-09-19 11:59:23 +00:00
/* new set the frames */
2009-09-19 00:18:42 +00:00
/* prev frame */
2009-09-19 11:59:23 +00:00
pso - > prevFrame = ( pk ) ? ( pk - > cfra ) : ( pso - > cframe - 1 ) ;
2009-09-19 00:18:42 +00:00
RNA_int_set ( op - > ptr , " prev_frame " , pso - > prevFrame ) ;
/* next frame */
2009-09-19 11:59:23 +00:00
pso - > nextFrame = ( nk ) ? ( nk - > cfra ) : ( pso - > cframe + 1 ) ;
RNA_int_set ( op - > ptr , " next_frame " , pso - > nextFrame ) ;
2009-09-19 00:18:42 +00:00
}
else {
/* current frame itself is a keyframe, so just take keyframes on either side */
/* prev frame */
pso - > prevFrame = ( ak - > prev ) ? ( ak - > prev - > cfra ) : ( pso - > cframe - 1 ) ;
RNA_int_set ( op - > ptr , " prev_frame " , pso - > prevFrame ) ;
/* next frame */
pso - > nextFrame = ( ak - > next ) ? ( ak - > next - > cfra ) : ( pso - > cframe + 1 ) ;
RNA_int_set ( op - > ptr , " next_frame " , pso - > nextFrame ) ;
}
}
else {
BKE_report ( op - > reports , RPT_ERROR , " No keyframes to slide between. " ) ;
2011-03-13 12:22:57 +00:00
pose_slide_exit ( op ) ;
2009-09-19 00:18:42 +00:00
return OPERATOR_CANCELLED ;
}
2009-09-20 05:05:16 +00:00
/* initial apply for operator... */
// TODO: need to calculate percentage for initial round too...
2010-10-16 02:40:31 +00:00
pose_slide_apply ( C , pso ) ;
2009-09-20 05:05:16 +00:00
/* depsgraph updates + redraws */
pose_slide_refresh ( C , pso ) ;
/* set cursor to indicate modal */
WM_cursor_modal ( win , BC_EW_SCROLLCURSOR ) ;
/* add a modal handler for this operator */
WM_event_add_modal_handler ( C , op ) ;
return OPERATOR_RUNNING_MODAL ;
2009-09-19 11:59:23 +00:00
}
/* common code for modal() */
static int pose_slide_modal ( bContext * C , wmOperator * op , wmEvent * evt )
{
tPoseSlideOp * pso = op - > customdata ;
2009-09-19 12:36:22 +00:00
wmWindow * win = CTX_wm_window ( C ) ;
2009-09-19 00:18:42 +00:00
2009-09-19 11:59:23 +00:00
switch ( evt - > type ) {
case LEFTMOUSE : /* confirm */
2009-09-20 05:05:16 +00:00
{
/* return to normal cursor */
2009-09-19 12:36:22 +00:00
WM_cursor_restore ( win ) ;
2009-09-20 05:05:16 +00:00
/* insert keyframes as required... */
pose_slide_autoKeyframe ( C , pso ) ;
2010-10-16 02:40:31 +00:00
pose_slide_exit ( op ) ;
2009-09-20 05:05:16 +00:00
/* done! */
2009-09-19 11:59:23 +00:00
return OPERATOR_FINISHED ;
2009-09-20 05:05:16 +00:00
}
2009-09-19 11:59:23 +00:00
case ESCKEY : /* cancel */
case RIGHTMOUSE :
2009-09-20 05:05:16 +00:00
{
/* return to normal cursor */
2009-09-19 12:36:22 +00:00
WM_cursor_restore ( win ) ;
2009-09-20 05:05:16 +00:00
/* reset transforms back to original state */
2010-10-16 02:40:31 +00:00
pose_slide_reset ( pso ) ;
2009-09-20 05:05:16 +00:00
/* depsgraph updates + redraws */
pose_slide_refresh ( C , pso ) ;
/* clean up temp data */
2010-10-16 02:40:31 +00:00
pose_slide_exit ( op ) ;
2009-09-20 05:05:16 +00:00
/* cancelled! */
2009-09-19 11:59:23 +00:00
return OPERATOR_CANCELLED ;
2009-09-20 05:05:16 +00:00
}
2009-09-19 11:59:23 +00:00
case MOUSEMOVE : /* calculate new position */
{
/* calculate percentage based on position of mouse (we only use x-axis for now.
* since this is more conveninent for users to do ) , and store new percentage value
*/
pso - > percentage = ( evt - > x - pso - > ar - > winrct . xmin ) / ( ( float ) pso - > ar - > winx ) ;
RNA_float_set ( op - > ptr , " percentage " , pso - > percentage ) ;
2009-09-20 05:05:16 +00:00
/* reset transforms (to avoid accumulation errors) */
2010-10-16 02:40:31 +00:00
pose_slide_reset ( pso ) ;
2009-09-20 05:05:16 +00:00
2009-09-19 11:59:23 +00:00
/* apply... */
2010-10-16 02:40:31 +00:00
pose_slide_apply ( C , pso ) ;
2009-09-19 11:59:23 +00:00
}
break ;
2009-09-23 07:28:26 +00:00
default : /* unhandled event (maybe it was some view manip? */
/* allow to pass through */
return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH ;
2009-09-19 11:59:23 +00:00
}
2009-09-19 00:18:42 +00:00
2009-09-19 11:59:23 +00:00
/* still running... */
return OPERATOR_RUNNING_MODAL ;
2009-09-19 00:18:42 +00:00
}
2009-09-19 11:59:23 +00:00
/* common code for cancel() */
2010-10-16 02:40:31 +00:00
static int pose_slide_cancel ( bContext * UNUSED ( C ) , wmOperator * op )
2009-09-19 11:59:23 +00:00
{
/* cleanup and done */
2010-10-16 02:40:31 +00:00
pose_slide_exit ( op ) ;
2009-09-19 11:59:23 +00:00
return OPERATOR_CANCELLED ;
}
2009-09-19 00:18:42 +00:00
/* common code for exec() methods */
static int pose_slide_exec_common ( bContext * C , wmOperator * op , tPoseSlideOp * pso )
{
/* settings should have been set up ok for applying, so just apply! */
2010-10-16 02:40:31 +00:00
pose_slide_apply ( C , pso ) ;
2009-09-19 00:18:42 +00:00
2009-09-20 05:05:16 +00:00
/* insert keyframes if needed */
pose_slide_autoKeyframe ( C , pso ) ;
2009-09-19 00:18:42 +00:00
/* cleanup and done */
2010-10-16 02:40:31 +00:00
pose_slide_exit ( op ) ;
2009-09-19 00:18:42 +00:00
return OPERATOR_FINISHED ;
}
/* common code for defining RNA properties */
static void pose_slide_opdef_properties ( wmOperatorType * ot )
{
RNA_def_int ( ot - > srna , " prev_frame " , 0 , MINAFRAME , MAXFRAME , " Previous Keyframe " , " Frame number of keyframe immediately before the current frame. " , 0 , 50 ) ;
RNA_def_int ( ot - > srna , " next_frame " , 0 , MINAFRAME , MAXFRAME , " Next Keyframe " , " Frame number of keyframe immediately after the current frame. " , 0 , 50 ) ;
RNA_def_float_percentage ( ot - > srna , " percentage " , 0.5f , 0.0f , 1.0f , " Percentage " , " Weighting factor for the sliding operation " , 0.3 , 0.7 ) ;
}
/* ------------------------------------ */
/* invoke() - for 'push' mode */
2010-10-15 01:36:14 +00:00
static int pose_slide_push_invoke ( bContext * C , wmOperator * op , wmEvent * UNUSED ( evt ) )
2009-09-19 00:18:42 +00:00
{
tPoseSlideOp * pso ;
/* initialise data */
if ( pose_slide_init ( C , op , POSESLIDE_PUSH ) = = 0 ) {
2010-10-16 02:40:31 +00:00
pose_slide_exit ( op ) ;
2009-09-19 00:18:42 +00:00
return OPERATOR_CANCELLED ;
}
else
pso = op - > customdata ;
/* do common setup work */
return pose_slide_invoke_common ( C , op , pso ) ;
}
/* exec() - for push */
static int pose_slide_push_exec ( bContext * C , wmOperator * op )
{
tPoseSlideOp * pso ;
/* initialise data (from RNA-props) */
if ( pose_slide_init ( C , op , POSESLIDE_PUSH ) = = 0 ) {
2010-10-16 02:40:31 +00:00
pose_slide_exit ( op ) ;
2009-09-19 00:18:42 +00:00
return OPERATOR_CANCELLED ;
}
else
pso = op - > customdata ;
/* do common exec work */
return pose_slide_exec_common ( C , op , pso ) ;
}
void POSE_OT_push ( wmOperatorType * ot )
{
/* identifiers */
ot - > name = " Push Pose " ;
ot - > idname = " POSE_OT_push " ;
ot - > description = " Exaggerate the current pose " ;
/* callbacks */
ot - > exec = pose_slide_push_exec ;
ot - > invoke = pose_slide_push_invoke ;
2009-09-20 05:05:16 +00:00
ot - > modal = pose_slide_modal ;
ot - > cancel = pose_slide_cancel ;
2009-09-19 00:18:42 +00:00
ot - > poll = ED_operator_posemode ;
/* flags */
2009-09-20 05:05:16 +00:00
ot - > flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING ;
2009-09-19 00:18:42 +00:00
/* Properties */
pose_slide_opdef_properties ( ot ) ;
}
/* ........................ */
/* invoke() - for 'relax' mode */
2010-10-15 01:36:14 +00:00
static int pose_slide_relax_invoke ( bContext * C , wmOperator * op , wmEvent * UNUSED ( evt ) )
2009-09-19 00:18:42 +00:00
{
tPoseSlideOp * pso ;
/* initialise data */
if ( pose_slide_init ( C , op , POSESLIDE_RELAX ) = = 0 ) {
2010-10-16 02:40:31 +00:00
pose_slide_exit ( op ) ;
2009-09-19 00:18:42 +00:00
return OPERATOR_CANCELLED ;
}
else
pso = op - > customdata ;
/* do common setup work */
return pose_slide_invoke_common ( C , op , pso ) ;
}
/* exec() - for relax */
static int pose_slide_relax_exec ( bContext * C , wmOperator * op )
{
tPoseSlideOp * pso ;
/* initialise data (from RNA-props) */
if ( pose_slide_init ( C , op , POSESLIDE_RELAX ) = = 0 ) {
2010-10-16 02:40:31 +00:00
pose_slide_exit ( op ) ;
2009-09-19 00:18:42 +00:00
return OPERATOR_CANCELLED ;
}
else
pso = op - > customdata ;
/* do common exec work */
return pose_slide_exec_common ( C , op , pso ) ;
}
void POSE_OT_relax ( wmOperatorType * ot )
{
/* identifiers */
ot - > name = " Relax Pose " ;
ot - > idname = " POSE_OT_relax " ;
2010-02-10 21:15:44 +00:00
ot - > description = " Make the current pose more similar to its surrounding ones " ;
2009-09-19 00:18:42 +00:00
/* callbacks */
ot - > exec = pose_slide_relax_exec ;
ot - > invoke = pose_slide_relax_invoke ;
2009-09-20 05:05:16 +00:00
ot - > modal = pose_slide_modal ;
ot - > cancel = pose_slide_cancel ;
2009-09-19 00:18:42 +00:00
ot - > poll = ED_operator_posemode ;
/* flags */
2009-09-20 05:05:16 +00:00
ot - > flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING ;
2009-09-19 00:18:42 +00:00
/* Properties */
pose_slide_opdef_properties ( ot ) ;
}
/* ........................ */
/* invoke() - for 'breakdown' mode */
2010-10-15 01:36:14 +00:00
static int pose_slide_breakdown_invoke ( bContext * C , wmOperator * op , wmEvent * UNUSED ( evt ) )
2009-09-19 00:18:42 +00:00
{
tPoseSlideOp * pso ;
/* initialise data */
if ( pose_slide_init ( C , op , POSESLIDE_BREAKDOWN ) = = 0 ) {
2010-10-16 02:40:31 +00:00
pose_slide_exit ( op ) ;
2009-09-19 00:18:42 +00:00
return OPERATOR_CANCELLED ;
}
else
pso = op - > customdata ;
/* do common setup work */
return pose_slide_invoke_common ( C , op , pso ) ;
}
/* exec() - for breakdown */
static int pose_slide_breakdown_exec ( bContext * C , wmOperator * op )
{
tPoseSlideOp * pso ;
/* initialise data (from RNA-props) */
if ( pose_slide_init ( C , op , POSESLIDE_BREAKDOWN ) = = 0 ) {
2010-10-16 02:40:31 +00:00
pose_slide_exit ( op ) ;
2009-09-19 00:18:42 +00:00
return OPERATOR_CANCELLED ;
}
else
pso = op - > customdata ;
/* do common exec work */
return pose_slide_exec_common ( C , op , pso ) ;
}
void POSE_OT_breakdown ( wmOperatorType * ot )
{
/* identifiers */
ot - > name = " Pose Breakdowner " ;
ot - > idname = " POSE_OT_breakdown " ;
2010-02-10 21:15:44 +00:00
ot - > description = " Create a suitable breakdown pose on the current frame " ;
2009-09-19 00:18:42 +00:00
/* callbacks */
ot - > exec = pose_slide_breakdown_exec ;
ot - > invoke = pose_slide_breakdown_invoke ;
2009-09-19 11:59:23 +00:00
ot - > modal = pose_slide_modal ;
ot - > cancel = pose_slide_cancel ;
2009-09-19 00:18:42 +00:00
ot - > poll = ED_operator_posemode ;
/* flags */
2009-09-19 11:59:23 +00:00
ot - > flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING ;
2009-09-19 00:18:42 +00:00
/* Properties */
pose_slide_opdef_properties ( ot ) ;
}
/* **************************************************** */
2011-03-24 03:02:34 +00:00
/* B) Pose Propagate */
/* "termination conditions" - i.e. when we stop */
typedef enum ePosePropagate_Termination {
2011-03-31 00:45:52 +00:00
/* stop after the current hold ends */
POSE_PROPAGATE_SMART_HOLDS = 0 ,
/* only do on the last keyframe */
POSE_PROPAGATE_LAST_KEY ,
2011-03-24 03:02:34 +00:00
/* stop after the next keyframe */
POSE_PROPAGATE_NEXT_KEY ,
/* stop after the specified frame */
POSE_PROPAGATE_BEFORE_FRAME ,
2011-03-31 00:45:52 +00:00
/* stop when we run out of keyframes */
2011-03-31 01:37:42 +00:00
POSE_PROPAGATE_BEFORE_END ,
/* only do on the frames where markers are selected */
POSE_PROPAGATE_SELECTED_MARKERS
2011-03-24 03:02:34 +00:00
} ePosePropagate_Termination ;
2011-03-31 01:37:42 +00:00
/* termination data needed for some modes - assumes only one of these entries will be needed at a time */
typedef union tPosePropagate_ModeData {
/* smart holds + before frame: frame number to stop on */
float end_frame ;
/* selected markers: listbase for CfraElem's marking these frames */
ListBase sel_markers ;
} tPosePropagate_ModeData ;
2011-03-24 03:02:34 +00:00
/* --------------------------------- */
/* get frame on which the "hold" for the bone ends
* XXX : this may not really work that well if a bone moves on some channels and not others
* if this happens to be a major issue , scrap this , and just make this happen
* independently per F - Curve
*/
static float pose_propagate_get_boneHoldEndFrame ( Object * ob , tPChanFCurveLink * pfl , float startFrame )
{
DLRBT_Tree keys , blocks ;
ActKeyBlock * ab ;
AnimData * adt = ob - > adt ;
LinkData * ld ;
float endFrame = startFrame ;
/* set up optimised data-structures for searching for relevant keyframes + holds */
BLI_dlrbTree_init ( & keys ) ;
BLI_dlrbTree_init ( & blocks ) ;
for ( ld = pfl - > fcurves . first ; ld ; ld = ld - > next ) {
FCurve * fcu = ( FCurve * ) ld - > data ;
fcurve_to_keylist ( adt , fcu , & keys , & blocks ) ;
}
BLI_dlrbTree_linkedlist_sync ( & keys ) ;
BLI_dlrbTree_linkedlist_sync ( & blocks ) ;
/* find the long keyframe (i.e. hold), and hence obtain the endFrame value
* - the best case would be one that starts on the frame itself
*/
ab = ( ActKeyBlock * ) BLI_dlrbTree_search_exact ( & blocks , compare_ab_cfraPtr , & startFrame ) ;
if ( actkeyblock_is_valid ( ab , & keys ) = = 0 ) {
/* There are only two cases for no-exact match:
* 1 ) the current frame is just before another key but not on a key itself
* 2 ) the current frame is on a key , but that key doesn ' t link to the next
*
* If we ' ve got the first case , then we can search for another block ,
* otherwise forget it , as we ' d be overwriting some valid data .
*/
if ( BLI_dlrbTree_search_exact ( & keys , compare_ak_cfraPtr , & startFrame ) = = NULL ) {
/* we've got case 1, so try the one after */
ab = ( ActKeyBlock * ) BLI_dlrbTree_search_next ( & blocks , compare_ab_cfraPtr , & startFrame ) ;
if ( actkeyblock_is_valid ( ab , & keys ) = = 0 ) {
/* try the block before this frame then as last resort */
ab = ( ActKeyBlock * ) BLI_dlrbTree_search_prev ( & blocks , compare_ab_cfraPtr , & startFrame ) ;
/* whatever happens, stop searching now... */
if ( actkeyblock_is_valid ( ab , & keys ) = = 0 ) {
/* restrict range to just the frame itself
* i . e . everything is in motion , so no holds to safely overwrite
*/
ab = NULL ;
}
}
}
else {
/* we've got case 2 - set ab to NULL just in case, since we shouldn't do anything in this case */
ab = NULL ;
}
}
/* check if we can go any further than we've already gone */
if ( ab ) {
/* go to next if it is also valid and meets "extension" criteria */
while ( ab - > next ) {
ActKeyBlock * abn = ( ActKeyBlock * ) ab - > next ;
/* must be valid */
if ( actkeyblock_is_valid ( abn , & keys ) = = 0 )
break ;
/* should start on the same frame that the last ended on */
if ( ab - > end ! = abn - > start )
break ;
/* should have the same number of curves */
if ( ab - > totcurve ! = abn - > totcurve )
break ;
/* should have the same value
* XXX : this may be a bit fuzzy on larger data sets , so be careful
*/
if ( ab - > val ! = abn - > val )
break ;
/* we can extend the bounds to the end of this "next" block now */
ab = abn ;
}
/* end frame can now take the value of the end of the block */
endFrame = ab - > end ;
}
/* free temp memory */
BLI_dlrbTree_free ( & keys ) ;
BLI_dlrbTree_free ( & blocks ) ;
/* return the end frame we've found */
return endFrame ;
}
/* get reference value from F-Curve using RNA */
static float pose_propagate_get_refVal ( Object * ob , FCurve * fcu )
{
PointerRNA id_ptr , ptr ;
PropertyRNA * prop ;
float value ;
/* base pointer is always the object -> id_ptr */
RNA_id_pointer_create ( & ob - > id , & id_ptr ) ;
/* resolve the property... */
if ( RNA_path_resolve ( & id_ptr , fcu - > rna_path , & ptr , & prop ) ) {
if ( RNA_property_array_check ( & ptr , prop ) ) {
/* array */
if ( fcu - > array_index < RNA_property_array_length ( & ptr , prop ) ) {
switch ( RNA_property_type ( prop ) ) {
case PROP_BOOLEAN :
value = ( float ) RNA_property_boolean_get_index ( & ptr , prop , fcu - > array_index ) ;
break ;
case PROP_INT :
value = ( float ) RNA_property_int_get_index ( & ptr , prop , fcu - > array_index ) ;
break ;
case PROP_FLOAT :
value = RNA_property_float_get_index ( & ptr , prop , fcu - > array_index ) ;
break ;
default :
break ;
}
}
}
else {
/* not an array */
switch ( RNA_property_type ( prop ) ) {
case PROP_BOOLEAN :
value = ( float ) RNA_property_boolean_get ( & ptr , prop ) ;
break ;
case PROP_INT :
value = ( float ) RNA_property_int_get ( & ptr , prop ) ;
break ;
case PROP_ENUM :
value = ( float ) RNA_property_enum_get ( & ptr , prop ) ;
break ;
case PROP_FLOAT :
value = RNA_property_float_get ( & ptr , prop ) ;
break ;
default :
break ;
}
}
}
return value ;
}
/* propagate just works along each F-Curve in turn */
2011-03-31 01:37:42 +00:00
static void pose_propagate_fcurve ( wmOperator * op , Object * ob , FCurve * fcu ,
float startFrame , tPosePropagate_ModeData modeData )
2011-03-24 03:02:34 +00:00
{
const int mode = RNA_enum_get ( op - > ptr , " mode " ) ;
BezTriple * bezt ;
float refVal = 0.0f ;
short keyExists ;
int i , match ;
short first = 1 ;
/* skip if no keyframes to edit */
if ( ( fcu - > bezt = = NULL ) | | ( fcu - > totvert < 2 ) )
return ;
/* find the reference value from bones directly, which means that the user
* doesn ' t need to firstly keyframe the pose ( though this doesn ' t mean that
* they can ' t either )
*/
refVal = pose_propagate_get_refVal ( ob , fcu ) ;
/* find the first keyframe to start propagating from
* - if there ' s a keyframe on the current frame , we probably want to save this value there too
* since it may be as of yet unkeyed
* - if starting before the starting frame , don ' t touch the key , as it may have had some valid
* values
*/
match = binarysearch_bezt_index ( fcu - > bezt , startFrame , fcu - > totvert , & keyExists ) ;
if ( fcu - > bezt [ match ] . vec [ 1 ] [ 0 ] < startFrame )
i = match + 1 ;
else
i = match ;
for ( bezt = & fcu - > bezt [ i ] ; i < fcu - > totvert ; i + + , bezt + + ) {
/* additional termination conditions based on the operator 'mode' property go here... */
if ( ELEM ( mode , POSE_PROPAGATE_BEFORE_FRAME , POSE_PROPAGATE_SMART_HOLDS ) ) {
/* stop if keyframe is outside the accepted range */
2011-03-31 01:37:42 +00:00
if ( bezt - > vec [ 1 ] [ 0 ] > modeData . end_frame )
2011-03-31 00:45:52 +00:00
break ;
2011-03-24 03:02:34 +00:00
}
else if ( mode = = POSE_PROPAGATE_NEXT_KEY ) {
/* stop after the first keyframe has been processed */
if ( first = = 0 )
break ;
}
2011-03-31 00:45:52 +00:00
else if ( mode = = POSE_PROPAGATE_LAST_KEY ) {
/* only affect this frame if it will be the last one */
if ( i ! = ( fcu - > totvert - 1 ) )
continue ;
}
2011-03-31 01:37:42 +00:00
else if ( mode = = POSE_PROPAGATE_SELECTED_MARKERS ) {
/* only allow if there's a marker on this frame */
CfraElem * ce = NULL ;
/* stop on matching marker if there is one */
for ( ce = modeData . sel_markers . first ; ce ; ce = ce - > next ) {
if ( ce - > cfra = = ( int ) ( floor ( bezt - > vec [ 1 ] [ 0 ] + 0.5f ) ) )
break ;
}
/* skip this keyframe if no marker */
if ( ce = = NULL )
continue ;
}
2011-03-24 03:02:34 +00:00
/* just flatten handles, since values will now be the same either side... */
// TODO: perhaps a fade-out modulation of the value is required here (optional once again)?
bezt - > vec [ 0 ] [ 1 ] = bezt - > vec [ 1 ] [ 1 ] = bezt - > vec [ 2 ] [ 1 ] = refVal ;
/* select keyframe to indicate that it's been changed */
bezt - > f2 | = SELECT ;
first = 0 ;
}
}
/* --------------------------------- */
static int pose_propagate_exec ( bContext * C , wmOperator * op )
{
Scene * scene = CTX_data_scene ( C ) ;
Object * ob = ED_object_pose_armature ( CTX_data_active_object ( C ) ) ;
bAction * act = ( ob & & ob - > adt ) ? ob - > adt - > action : NULL ;
ListBase pflinks = { NULL , NULL } ;
tPChanFCurveLink * pfl ;
2011-03-31 01:37:42 +00:00
tPosePropagate_ModeData modeData ;
2011-03-24 03:02:34 +00:00
const int mode = RNA_enum_get ( op - > ptr , " mode " ) ;
/* sanity checks */
if ( ob = = NULL ) {
BKE_report ( op - > reports , RPT_ERROR , " No object to propagate poses for " ) ;
return OPERATOR_CANCELLED ;
}
if ( act = = NULL ) {
BKE_report ( op - > reports , RPT_ERROR , " No keyframed poses to propagate to " ) ;
return OPERATOR_CANCELLED ;
}
/* isolate F-Curves related to the selected bones */
poseAnim_mapping_get ( C , & pflinks , ob , act ) ;
2011-03-31 01:37:42 +00:00
/* mode-specific data preprocessing (requiring no access to curves) */
if ( mode = = POSE_PROPAGATE_SELECTED_MARKERS ) {
/* get a list of selected markers */
ED_markers_make_cfra_list ( & scene - > markers , & modeData . sel_markers , SELECT ) ;
}
else {
/* assume everything else wants endFrame */
modeData . end_frame = RNA_float_get ( op - > ptr , " end_frame " ) ;
}
2011-03-24 03:02:34 +00:00
/* for each bone, perform the copying required */
for ( pfl = pflinks . first ; pfl ; pfl = pfl - > next ) {
LinkData * ld ;
/* mode-specific data preprocessing (requiring access to all curves) */
if ( mode = = POSE_PROPAGATE_SMART_HOLDS ) {
/* we store in endFrame the end frame of the "long keyframe" (i.e. a held value) starting
* from the keyframe that occurs after the current frame
*/
2011-03-31 01:37:42 +00:00
modeData . end_frame = pose_propagate_get_boneHoldEndFrame ( ob , pfl , ( float ) CFRA ) ;
2011-03-24 03:02:34 +00:00
}
/* go through propagating pose to keyframes, curve by curve */
for ( ld = pfl - > fcurves . first ; ld ; ld = ld - > next )
2011-03-31 01:37:42 +00:00
pose_propagate_fcurve ( op , ob , ( FCurve * ) ld - > data , ( float ) CFRA , modeData ) ;
2011-03-24 03:02:34 +00:00
}
/* free temp data */
poseAnim_mapping_free ( & pflinks ) ;
2011-03-31 01:37:42 +00:00
if ( mode = = POSE_PROPAGATE_SELECTED_MARKERS )
BLI_freelistN ( & modeData . sel_markers ) ;
2011-03-24 03:02:34 +00:00
/* updates + notifiers */
poseAnim_mapping_refresh ( C , scene , ob ) ;
return OPERATOR_FINISHED ;
}
/* --------------------------------- */
void POSE_OT_propagate ( wmOperatorType * ot )
{
static EnumPropertyItem terminate_items [ ] = {
{ POSE_PROPAGATE_SMART_HOLDS , " WHILE_HELD " , 0 , " While Held " , " Propagate pose to all keyframes after current frame that don't change (Default behaviour) " } ,
2011-03-31 00:45:52 +00:00
{ POSE_PROPAGATE_NEXT_KEY , " NEXT_KEY " , 0 , " To Next Keyframe " , " Propagate pose to first keyframe following the current frame only " } ,
{ POSE_PROPAGATE_LAST_KEY , " LAST_KEY " , 0 , " To Last Keyframe " , " Propagate pose to the last keyframe only (i.e. making action cyclic) " } ,
{ POSE_PROPAGATE_BEFORE_FRAME , " BEFORE_FRAME " , 0 , " Before Frame " , " Propagate pose to all keyframes between current frame and 'Frame' property " } ,
{ POSE_PROPAGATE_BEFORE_END , " BEFORE_END " , 0 , " Before Last Keyframe " , " Propagate pose to all keyframes from current frame until no more are found " } ,
2011-03-31 01:37:42 +00:00
{ POSE_PROPAGATE_SELECTED_MARKERS , " SELECTED_MARKERS " , 0 , " On Selected Markers " , " Propagate pose to all keyframes occurring on frames with Scene Markers after the current frame " } ,
2011-03-24 03:02:34 +00:00
{ 0 , NULL , 0 , NULL , NULL } } ;
/* identifiers */
ot - > name = " Propagate Pose " ;
ot - > idname = " POSE_OT_propagate " ;
ot - > description = " Copy selected aspects of the current pose to subsequent poses already keyframed " ;
/* callbacks */
ot - > exec = pose_propagate_exec ;
ot - > poll = ED_operator_posemode ; // XXX: needs selected bones!
/* flag */
ot - > flag = OPTYPE_REGISTER | OPTYPE_UNDO ;
/* properties */
// TODO: add "fade out" control for tapering off amount of propagation as time goes by?
ot - > prop = RNA_def_enum ( ot - > srna , " mode " , terminate_items , POSE_PROPAGATE_SMART_HOLDS , " Terminate Mode " , " Method used to determine when to stop propagating pose to keyframes " ) ;
2011-03-31 00:45:52 +00:00
RNA_def_float ( ot - > srna , " end_frame " , 250.0 , FLT_MIN , FLT_MAX , " End Frame " , " Frame to stop propagating frames to (for 'Before Frame' mode) " , 1.0 , 250.0 ) ;
2011-03-24 03:02:34 +00:00
}
/* **************************************************** */