2.5 - Pose Enhancement Tools
This commit restores the 'Relax Pose' tool, and also introduces two others: 'Push Pose' and 'Pose Breakdowner'. Be aware that this commit is just the initial starting point, with some parts yet to be done. A short description of these tools follows: * Relax Pose (Alt-E) - makes the current pose more like the poses on either side of it * Push Pose (Ctrl-E) - exaggerates the current pose * Breakdowner (Shift-E)[not working yet] - when this works, it will allow for interactive selection of a good in-between pose to act as a breakdown. Todo's: * Connect up the 'percentage' slider in the operator settings to allow these effects to be dialed in/out, exaggerating/relaxing/moveing-between-keyframes by varying degrees until the desired effect is reached. * Allow these effects to be interactively dialed in/out. The idea is to use the mouse to interactively set the percentage slider value initially, then use the percentage slider to tweak later. * Figure out why breakdown breaks down
This commit is contained in:
@@ -153,6 +153,11 @@ void copy_fcurves(ListBase *dst, ListBase *src);
|
||||
/* find matching F-Curve in the given list of F-Curves */
|
||||
struct FCurve *list_find_fcurve(ListBase *list, const char rna_path[], const int array_index);
|
||||
|
||||
/* Binary search algorithm for finding where to 'insert' BezTriple with given frame number.
|
||||
* Returns the index to insert at (data already at that index will be offset if replace is 0)
|
||||
*/
|
||||
int binarysearch_bezt_index(struct BezTriple array[], float frame, int arraylen, short *replace);
|
||||
|
||||
/* get the time extents for F-Curve */
|
||||
void calc_fcurve_range(struct FCurve *fcu, float *min, float *max);
|
||||
|
||||
|
||||
@@ -200,6 +200,85 @@ FCurve *list_find_fcurve (ListBase *list, const char rna_path[], const int array
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* threshold for binary-searching keyframes - threshold here should be good enough for now, but should become userpref */
|
||||
#define BEZT_BINARYSEARCH_THRESH 0.00001f
|
||||
|
||||
/* Binary search algorithm for finding where to insert BezTriple. (for use by insert_bezt_fcurve)
|
||||
* Returns the index to insert at (data already at that index will be offset if replace is 0)
|
||||
*/
|
||||
int binarysearch_bezt_index (BezTriple array[], float frame, int arraylen, short *replace)
|
||||
{
|
||||
int start=0, end=arraylen;
|
||||
int loopbreaker= 0, maxloop= arraylen * 2;
|
||||
|
||||
/* initialise replace-flag first */
|
||||
*replace= 0;
|
||||
|
||||
/* sneaky optimisations (don't go through searching process if...):
|
||||
* - keyframe to be added is to be added out of current bounds
|
||||
* - keyframe to be added would replace one of the existing ones on bounds
|
||||
*/
|
||||
if ((arraylen <= 0) || (array == NULL)) {
|
||||
printf("Warning: binarysearch_bezt_index() encountered invalid array \n");
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
/* check whether to add before/after/on */
|
||||
float framenum;
|
||||
|
||||
/* 'First' Keyframe (when only one keyframe, this case is used) */
|
||||
framenum= array[0].vec[1][0];
|
||||
if (IS_EQT(frame, framenum, BEZT_BINARYSEARCH_THRESH)) {
|
||||
*replace = 1;
|
||||
return 0;
|
||||
}
|
||||
else if (frame < framenum)
|
||||
return 0;
|
||||
|
||||
/* 'Last' Keyframe */
|
||||
framenum= array[(arraylen-1)].vec[1][0];
|
||||
if (IS_EQT(frame, framenum, BEZT_BINARYSEARCH_THRESH)) {
|
||||
*replace= 1;
|
||||
return (arraylen - 1);
|
||||
}
|
||||
else if (frame > framenum)
|
||||
return arraylen;
|
||||
}
|
||||
|
||||
|
||||
/* most of the time, this loop is just to find where to put it
|
||||
* 'loopbreaker' is just here to prevent infinite loops
|
||||
*/
|
||||
for (loopbreaker=0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) {
|
||||
/* compute and get midpoint */
|
||||
int mid = start + ((end - start) / 2); /* we calculate the midpoint this way to avoid int overflows... */
|
||||
float midfra= array[mid].vec[1][0];
|
||||
|
||||
/* check if exactly equal to midpoint */
|
||||
if (IS_EQT(frame, midfra, BEZT_BINARYSEARCH_THRESH)) {
|
||||
*replace = 1;
|
||||
return mid;
|
||||
}
|
||||
|
||||
/* repeat in upper/lower half */
|
||||
if (frame > midfra)
|
||||
start= mid + 1;
|
||||
else if (frame < midfra)
|
||||
end= mid - 1;
|
||||
}
|
||||
|
||||
/* print error if loop-limit exceeded */
|
||||
if (loopbreaker == (maxloop-1)) {
|
||||
printf("Error: binarysearch_bezt_index() was taking too long \n");
|
||||
|
||||
// include debug info
|
||||
printf("\tround = %d: start = %d, end = %d, arraylen = %d \n", loopbreaker, start, end, arraylen);
|
||||
}
|
||||
|
||||
/* not found, so return where to place it */
|
||||
return start;
|
||||
}
|
||||
|
||||
/* Calculate the extents of F-Curve's data */
|
||||
void calc_fcurve_bounds (FCurve *fcu, float *xmin, float *xmax, float *ymin, float *ymax)
|
||||
{
|
||||
|
||||
@@ -316,7 +316,7 @@ static void set_touched_actkeyblock (ActKeyBlock *ab)
|
||||
/* *************************** Keyframe Drawing *************************** */
|
||||
|
||||
/* helper function - find actkeycolumn that occurs on cframe */
|
||||
static ActKeyColumn *cfra_find_actkeycolumn (ActKeyColumn *ak, float cframe)
|
||||
ActKeyColumn *cfra_find_actkeycolumn (ActKeyColumn *ak, float cframe)
|
||||
{
|
||||
/* sanity checks */
|
||||
if (ak == NULL)
|
||||
@@ -331,6 +331,28 @@ static ActKeyColumn *cfra_find_actkeycolumn (ActKeyColumn *ak, float cframe)
|
||||
return ak; /* match */
|
||||
}
|
||||
|
||||
/* helper function - find actkeycolumn that occurs on cframe, or the nearest one if not found */
|
||||
ActKeyColumn *cfra_find_nearest_next_ak (ActKeyColumn *ak, float cframe, short next)
|
||||
{
|
||||
ActKeyColumn *akn= NULL;
|
||||
|
||||
/* sanity checks */
|
||||
if (ak == NULL)
|
||||
return NULL;
|
||||
|
||||
/* check if this is a match, or whether it is in some subtree */
|
||||
if (cframe < ak->cfra)
|
||||
akn= cfra_find_nearest_next_ak(ak->left, cframe, next);
|
||||
else if (cframe > ak->cfra)
|
||||
akn= cfra_find_nearest_next_ak(ak->right, cframe, next);
|
||||
|
||||
/* if no match found (or found match), just use the current one */
|
||||
if (akn == NULL)
|
||||
return ak;
|
||||
else
|
||||
return akn;
|
||||
}
|
||||
|
||||
/* -------- */
|
||||
|
||||
/* coordinates for diamond shape */
|
||||
|
||||
@@ -176,85 +176,6 @@ FCurve *verify_fcurve (bAction *act, const char group[], const char rna_path[],
|
||||
|
||||
/* -------------- BezTriple Insertion -------------------- */
|
||||
|
||||
/* threshold for inserting keyframes - threshold here should be good enough for now, but should become userpref */
|
||||
#define BEZT_INSERT_THRESH 0.00001f
|
||||
|
||||
/* Binary search algorithm for finding where to insert BezTriple. (for use by insert_bezt_icu)
|
||||
* Returns the index to insert at (data already at that index will be offset if replace is 0)
|
||||
*/
|
||||
static int binarysearch_bezt_index (BezTriple array[], float frame, int arraylen, short *replace)
|
||||
{
|
||||
int start=0, end=arraylen;
|
||||
int loopbreaker= 0, maxloop= arraylen * 2;
|
||||
|
||||
/* initialise replace-flag first */
|
||||
*replace= 0;
|
||||
|
||||
/* sneaky optimisations (don't go through searching process if...):
|
||||
* - keyframe to be added is to be added out of current bounds
|
||||
* - keyframe to be added would replace one of the existing ones on bounds
|
||||
*/
|
||||
if ((arraylen <= 0) || (array == NULL)) {
|
||||
printf("Warning: binarysearch_bezt_index() encountered invalid array \n");
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
/* check whether to add before/after/on */
|
||||
float framenum;
|
||||
|
||||
/* 'First' Keyframe (when only one keyframe, this case is used) */
|
||||
framenum= array[0].vec[1][0];
|
||||
if (IS_EQT(frame, framenum, BEZT_INSERT_THRESH)) {
|
||||
*replace = 1;
|
||||
return 0;
|
||||
}
|
||||
else if (frame < framenum)
|
||||
return 0;
|
||||
|
||||
/* 'Last' Keyframe */
|
||||
framenum= array[(arraylen-1)].vec[1][0];
|
||||
if (IS_EQT(frame, framenum, BEZT_INSERT_THRESH)) {
|
||||
*replace= 1;
|
||||
return (arraylen - 1);
|
||||
}
|
||||
else if (frame > framenum)
|
||||
return arraylen;
|
||||
}
|
||||
|
||||
|
||||
/* most of the time, this loop is just to find where to put it
|
||||
* 'loopbreaker' is just here to prevent infinite loops
|
||||
*/
|
||||
for (loopbreaker=0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) {
|
||||
/* compute and get midpoint */
|
||||
int mid = start + ((end - start) / 2); /* we calculate the midpoint this way to avoid int overflows... */
|
||||
float midfra= array[mid].vec[1][0];
|
||||
|
||||
/* check if exactly equal to midpoint */
|
||||
if (IS_EQT(frame, midfra, BEZT_INSERT_THRESH)) {
|
||||
*replace = 1;
|
||||
return mid;
|
||||
}
|
||||
|
||||
/* repeat in upper/lower half */
|
||||
if (frame > midfra)
|
||||
start= mid + 1;
|
||||
else if (frame < midfra)
|
||||
end= mid - 1;
|
||||
}
|
||||
|
||||
/* print error if loop-limit exceeded */
|
||||
if (loopbreaker == (maxloop-1)) {
|
||||
printf("Error: binarysearch_bezt_index() was taking too long \n");
|
||||
|
||||
// include debug info
|
||||
printf("\tround = %d: start = %d, end = %d, arraylen = %d \n", loopbreaker, start, end, arraylen);
|
||||
}
|
||||
|
||||
/* not found, so return where to place it */
|
||||
return start;
|
||||
}
|
||||
|
||||
/* This function adds a given BezTriple to an F-Curve. It will allocate
|
||||
* memory for the array if needed, and will insert the BezTriple into a
|
||||
* suitable place in chronological order.
|
||||
|
||||
@@ -118,11 +118,19 @@ void SKETCH_OT_select(struct wmOperatorType *ot);
|
||||
|
||||
/* ******************************************************* */
|
||||
/* PoseLib */
|
||||
|
||||
void POSELIB_OT_pose_add(struct wmOperatorType *ot);
|
||||
void POSELIB_OT_pose_remove(struct wmOperatorType *ot);
|
||||
void POSELIB_OT_pose_rename(struct wmOperatorType *ot);
|
||||
void POSELIB_OT_browse_interactive(struct wmOperatorType *ot);
|
||||
|
||||
/* ******************************************************* */
|
||||
/* Pose Sliding Tools */
|
||||
|
||||
void POSE_OT_push(struct wmOperatorType *ot);
|
||||
void POSE_OT_relax(struct wmOperatorType *ot);
|
||||
void POSE_OT_breakdown(struct wmOperatorType *ot);
|
||||
|
||||
/* ******************************************************* */
|
||||
/* editarmature.c */
|
||||
struct bArmature;
|
||||
|
||||
@@ -196,6 +196,11 @@ void ED_operatortypes_armature(void)
|
||||
WM_operatortype_append(POSELIB_OT_pose_remove);
|
||||
WM_operatortype_append(POSELIB_OT_pose_rename);
|
||||
|
||||
/* POSE SLIDING */
|
||||
WM_operatortype_append(POSE_OT_push);
|
||||
WM_operatortype_append(POSE_OT_relax);
|
||||
WM_operatortype_append(POSE_OT_breakdown);
|
||||
|
||||
/* TESTS */
|
||||
WM_operatortype_append(ARMATURE_OT_test); // XXX temp test for context iterators... to be removed
|
||||
}
|
||||
@@ -365,5 +370,11 @@ void ED_keymap_armature(wmWindowManager *wm)
|
||||
WM_keymap_add_item(keymap, "POSELIB_OT_pose_add", LKEY, KM_PRESS, KM_SHIFT, 0);
|
||||
WM_keymap_add_item(keymap, "POSELIB_OT_pose_remove", LKEY, KM_PRESS, KM_ALT, 0);
|
||||
WM_keymap_add_item(keymap, "POSELIB_OT_pose_rename", LKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
|
||||
|
||||
/* Pose -> Pose Sliding ------------- */
|
||||
/* only set in posemode, by space_view3d listener */
|
||||
WM_keymap_add_item(keymap, "POSE_OT_push", EKEY, KM_PRESS, KM_CTRL, 0);
|
||||
WM_keymap_add_item(keymap, "POSE_OT_relax", EKEY, KM_PRESS, KM_ALT, 0);
|
||||
WM_keymap_add_item(keymap, "POSE_OT_breakdown", EKEY, KM_PRESS, KM_SHIFT, 0);
|
||||
}
|
||||
|
||||
|
||||
722
source/blender/editors/armature/poseSlide.c
Normal file
722
source/blender/editors/armature/poseSlide.c
Normal file
@@ -0,0 +1,722 @@
|
||||
/**
|
||||
* $Id: poseSlide.c 23179 2009-09-13 12:34:00Z aligorith $
|
||||
*
|
||||
* ***** 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,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* 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 *****
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_arithb.h"
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_dynstr.h"
|
||||
#include "BLI_dlrbTree.h"
|
||||
|
||||
#include "DNA_listBase.h"
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_action_types.h"
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_curve_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_object_force.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_userdef_types.h"
|
||||
|
||||
#include "BKE_animsys.h"
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_armature.h"
|
||||
#include "BKE_depsgraph.h"
|
||||
#include "BKE_fcurve.h"
|
||||
#include "BKE_object.h"
|
||||
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_utildefines.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_define.h"
|
||||
#include "RNA_types.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
#include "UI_resources.h"
|
||||
|
||||
#include "BIF_gl.h"
|
||||
|
||||
#include "ED_anim_api.h"
|
||||
#include "ED_armature.h"
|
||||
#include "ED_keyframes_draw.h"
|
||||
#include "ED_keyframing.h"
|
||||
#include "ED_keyframes_edit.h"
|
||||
#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.
|
||||
*
|
||||
* B) Pose Sculpting
|
||||
* 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 */
|
||||
|
||||
ListBase pfLinks; /* links between posechannels and f-curves */
|
||||
DLRBT_Tree keys; /* binary tree for quicker searching for keyframes (when applicable) */
|
||||
|
||||
KeyingSet *ks_loc; /* builtin KeyingSet for keyframing locations */
|
||||
KeyingSet *ks_rot; /* builtin KeyingSet for keyframing rotations */
|
||||
KeyingSet *ks_scale;/* builtin KeyingSet for keyframing scale */
|
||||
|
||||
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;
|
||||
|
||||
/* Temporary data linking PoseChannels with the F-Curves they affect */
|
||||
typedef struct tPChanFCurveLink {
|
||||
struct tPChanFCurveLink *next, *prev;
|
||||
|
||||
ListBase fcurves; /* F-Curves for this PoseChannel */
|
||||
bPoseChannel *pchan; /* Pose Channel which data is attached to */
|
||||
char *pchan_path; /* RNA Path to this Pose Channel (needs to be freed when we're done) */
|
||||
} tPChanFCurveLink;
|
||||
|
||||
/* ------------------------------------ */
|
||||
|
||||
/* 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);
|
||||
pso->ob= CTX_data_active_object(C);
|
||||
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 */
|
||||
if (ELEM3(NULL, pso->ob, pso->ob->adt, pso->ob->adt->action))
|
||||
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...
|
||||
*/
|
||||
CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pchans)
|
||||
{
|
||||
ListBase curves = {NULL, NULL};
|
||||
int transFlags = action_get_item_transforms(act, pso->ob, pchan, &curves);
|
||||
|
||||
pchan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE);
|
||||
|
||||
/* check if any transforms found... */
|
||||
if (transFlags) {
|
||||
/* make new linkage data */
|
||||
tPChanFCurveLink *pfl= MEM_callocN(sizeof(tPChanFCurveLink), "tPChanFCurveLink");
|
||||
PointerRNA ptr;
|
||||
|
||||
pfl->fcurves= curves;
|
||||
pfl->pchan= pchan;
|
||||
|
||||
/* get the RNA path to this pchan - this needs to be freed! */
|
||||
RNA_pointer_create((ID *)pso->ob, &RNA_PoseChannel, pchan, &ptr);
|
||||
pfl->pchan_path= RNA_path_from_ID_to_struct(&ptr);
|
||||
|
||||
/* add linkage data to operator data */
|
||||
BLI_addtail(&pso->pfLinks, pfl);
|
||||
|
||||
/* set pchan's transform flags */
|
||||
if (transFlags & ACT_TRANS_LOC)
|
||||
pchan->flag |= POSE_LOC;
|
||||
if (transFlags & ACT_TRANS_ROT)
|
||||
pchan->flag |= POSE_ROT;
|
||||
if (transFlags & ACT_TRANS_SCALE)
|
||||
pchan->flag |= POSE_SIZE;
|
||||
}
|
||||
}
|
||||
CTX_DATA_END;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* get builtin KeyingSets */
|
||||
pso->ks_loc= ANIM_builtin_keyingset_get_named(NULL, "Location");
|
||||
pso->ks_rot= ANIM_builtin_keyingset_get_named(NULL, "Rotation");
|
||||
pso->ks_scale= ANIM_builtin_keyingset_get_named(NULL, "Scale");
|
||||
|
||||
/* return status is whether we've got all the data we were requested to get */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* exiting the operator - free data */
|
||||
static void pose_slide_exit (bContext *C, wmOperator *op)
|
||||
{
|
||||
tPoseSlideOp *pso= op->customdata;
|
||||
|
||||
/* if data exists, clear its data and exit */
|
||||
if (pso) {
|
||||
tPChanFCurveLink *pfl, *pfln=NULL;
|
||||
|
||||
/* free the temp pchan links and their data */
|
||||
for (pfl= pso->pfLinks.first; pfl; pfl= pfln) {
|
||||
pfln= pfl->next;
|
||||
|
||||
/* free list of F-Curve reference links */
|
||||
BLI_freelistN(&pfl->fcurves);
|
||||
|
||||
/* free pchan RNA Path */
|
||||
MEM_freeN(pfl->pchan_path);
|
||||
|
||||
/* free link itself */
|
||||
BLI_freelinkN(&pso->pfLinks, pfl);
|
||||
}
|
||||
|
||||
/* free RB-BST for keyframes (if it contained data) */
|
||||
BLI_dlrbTree_free(&pso->keys);
|
||||
|
||||
/* free data itself */
|
||||
MEM_freeN(pso);
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
op->customdata= NULL;
|
||||
}
|
||||
|
||||
/* ------------------------------------ */
|
||||
|
||||
/* helper for apply() callabcks - find the next F-Curve with matching path... */
|
||||
static LinkData *find_next_fcurve_link (ListBase *fcuLinks, LinkData *prev, char *path)
|
||||
{
|
||||
LinkData *first= (prev)? prev->next : (fcuLinks)? fcuLinks->first : NULL;
|
||||
LinkData *ld;
|
||||
|
||||
/* check each link to see if the linked F-Curve has a matching path */
|
||||
for (ld= first; ld; ld= ld->next) {
|
||||
FCurve *fcu= (FCurve *)ld->data;
|
||||
|
||||
/* check if paths match */
|
||||
if (strcmp(path, fcu->rna_path) == 0)
|
||||
return ld;
|
||||
}
|
||||
|
||||
/* none found */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* helper for apply() - perform sliding for some 3-element vector */
|
||||
static void pose_slide_apply_vec3 (tPoseSlideOp *pso, tPChanFCurveLink *pfl, float vec[3], char *propName)
|
||||
{
|
||||
LinkData *ld=NULL;
|
||||
char *path=NULL;
|
||||
float cframe;
|
||||
|
||||
/* get the path to use... */
|
||||
path= BLI_sprintfN("%s.%s", pfl->pchan_path, propName);
|
||||
|
||||
/* get the current frame number */
|
||||
cframe= (float)pso->cframe;
|
||||
|
||||
/* using this path, find each matching F-Curve for the variables we're interested in */
|
||||
while ( (ld= find_next_fcurve_link(&pfl->fcurves, ld, path)) ) {
|
||||
FCurve *fcu= (FCurve *)ld->data;
|
||||
float w1, w2, wtot, ctrl, ictrl;
|
||||
float sVal, eVal;
|
||||
int ch;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* get channel index */
|
||||
ch= fcu->array_index;
|
||||
|
||||
/* get the influence of the control */
|
||||
ctrl= pso->percentage;
|
||||
ictrl= 1.0f - pso->percentage;
|
||||
|
||||
/* calculate the relative weights of the endpoints
|
||||
* - these weights are derived from the relative distance of these
|
||||
* poses from the current frame
|
||||
* - they then get normalised, with the results of these normalised
|
||||
*/
|
||||
w1 = cframe - (float)pso->prevFrame;
|
||||
w2 = (float)pso->nextFrame - cframe;
|
||||
|
||||
wtot = w1 + w2;
|
||||
w1 = w1/wtot;
|
||||
w2 = w2/wtot;
|
||||
|
||||
/* depending on the mode, */
|
||||
switch (pso->mode) {
|
||||
case POSESLIDE_PUSH: /* make the current pose more pronounced */
|
||||
// TODO: this is not interactively modifiable!
|
||||
vec[ch]= ( -((sVal * w2) + (eVal * w1)) + (vec[ch] * 6.0f) ) / 5.0f;
|
||||
break;
|
||||
|
||||
case POSESLIDE_RELAX: /* make the current pose more like its surrounding ones */
|
||||
/* apply the value with a hard coded 6th */
|
||||
// TODO: this is not interactively modifiable!
|
||||
vec[ch]= ( ((sVal * w2) + (eVal * w1)) + (vec[ch] * 5.0f) ) / 6.0f;
|
||||
break;
|
||||
|
||||
case POSESLIDE_BREAKDOWN: /* make the current pose slide around between the endpoints */
|
||||
// NOTE: just linear interpolation for now, but could add small component of our key if necessary...
|
||||
// TODO: this doesn't work at all
|
||||
w2= 1.0f - w1;
|
||||
vec[ch]= ((sVal * w1) + (eVal * w2));
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* free the temp path we got */
|
||||
MEM_freeN(path);
|
||||
}
|
||||
|
||||
/* helper for apply() - perform sliding for quaternion rotations (using quat blending) */
|
||||
static void pose_slide_apply_quat (tPoseSlideOp *pso, tPChanFCurveLink *pfl)
|
||||
{
|
||||
// TODO: this is quite evil stuff...
|
||||
#if 0 // XXX port...
|
||||
/* get 2 quats */
|
||||
quat_prev[0] = eval_icu(icu_w, frame_prev);
|
||||
quat_prev[1] = eval_icu(icu_x, frame_prev);
|
||||
quat_prev[2] = eval_icu(icu_y, frame_prev);
|
||||
quat_prev[3] = eval_icu(icu_z, frame_prev);
|
||||
|
||||
quat_next[0] = eval_icu(icu_w, frame_next);
|
||||
quat_next[1] = eval_icu(icu_x, frame_next);
|
||||
quat_next[2] = eval_icu(icu_y, frame_next);
|
||||
quat_next[3] = eval_icu(icu_z, frame_next);
|
||||
|
||||
#if 0
|
||||
/* apply the setting, completely smooth */
|
||||
QuatInterpol(pchan->quat, quat_prev, quat_next, (framef-frame_prev) / (frame_next-frame_prev) );
|
||||
#else
|
||||
/* tricky interpolation */
|
||||
QuatInterpol(quat_interp, quat_prev, quat_next, (framef-frame_prev) / (frame_next-frame_prev) );
|
||||
QUATCOPY(quat_orig, pchan->quat);
|
||||
QuatInterpol(pchan->quat, quat_orig, quat_interp, 1.0f/6.0f);
|
||||
/* done */
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/* helper for apply() - perform autokeyframing */
|
||||
static void pose_slide_autoKeyframe (bContext *C, tPoseSlideOp *pso, bPoseChannel *pchan, KeyingSet *ks)
|
||||
{
|
||||
/* insert keyframes as necessary if autokeyframing */
|
||||
if (autokeyframe_cfra_can_key(pso->scene, &pso->ob->id)) {
|
||||
bCommonKeySrc cks;
|
||||
ListBase dsources = {&cks, &cks};
|
||||
|
||||
/* init common-key-source for use by KeyingSets */
|
||||
// TODO: for now, we don't clear it out, since it should be safe to do so...
|
||||
//memset(&cks, 0, sizeof(bCommonKeySrc));
|
||||
cks.id= &pso->ob->id;
|
||||
|
||||
/* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */
|
||||
cks.pchan= pchan;
|
||||
|
||||
/* insert keyframes */
|
||||
modify_keyframes(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)pso->cframe);
|
||||
}
|
||||
}
|
||||
|
||||
/* apply() - perform the pose sliding based on weighting various poses */
|
||||
static void pose_slide_apply (bContext *C, wmOperator *op, tPoseSlideOp *pso)
|
||||
{
|
||||
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");
|
||||
/* insert keyframes if needed */
|
||||
pose_slide_autoKeyframe(C, pso, pchan, pso->ks_loc);
|
||||
}
|
||||
|
||||
if (pchan->flag & POSE_SIZE) {
|
||||
/* calculate these for the 'scale' vector, and use scale curves */
|
||||
pose_slide_apply_vec3(pso, pfl, pchan->size, "scale");
|
||||
/* insert keyframes if needed */
|
||||
pose_slide_autoKeyframe(C, pso, pchan, pso->ks_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 */
|
||||
pose_slide_apply_vec3(pso, pfl, pchan->eul, "euler_rotation");
|
||||
}
|
||||
else if (pchan->rotmode == PCHAN_ROT_AXISANGLE) {
|
||||
// TODO: need to figure out how to do this!
|
||||
}
|
||||
else {
|
||||
/* quaternions - use quaternion blending */
|
||||
pose_slide_apply_quat(pso, pfl);
|
||||
}
|
||||
|
||||
/* insert keyframes if needed */
|
||||
pose_slide_autoKeyframe(C, pso, pchan, pso->ks_rot);
|
||||
}
|
||||
}
|
||||
|
||||
/* funky depsgraph flags - are these still needed? */
|
||||
pso->ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
|
||||
|
||||
/* do depsgraph flush */
|
||||
DAG_id_flush_update(&pso->ob->id, OB_RECALC_DATA);
|
||||
|
||||
/* note, notifier might evolve */
|
||||
//WM_event_add_notifier(C, NC_OBJECT|ND_POSE, pso->ob);
|
||||
WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, pso->ob);
|
||||
}
|
||||
|
||||
/* ------------------------------------ */
|
||||
|
||||
/* common code for invoke() methods */
|
||||
static int pose_slide_invoke_common (bContext *C, wmOperator *op, tPoseSlideOp *pso)
|
||||
{
|
||||
tPChanFCurveLink *pfl;
|
||||
AnimData *adt= pso->ob->adt;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* cancel if no keyframes found... */
|
||||
if (pso->keys.root) {
|
||||
ActKeyColumn *ak;
|
||||
|
||||
/* firstly, check if the current frame is a keyframe... */
|
||||
ak= cfra_find_actkeycolumn(pso->keys.root, pso->cframe);
|
||||
|
||||
if (ak == NULL) {
|
||||
/* current frame is not a keyframe, so search */
|
||||
/* prev frame */
|
||||
ak= cfra_find_nearest_next_ak(pso->keys.root, pso->cframe, 0);
|
||||
pso->prevFrame= (ak)? (ak->cfra) : (pso->cframe - 1);
|
||||
RNA_int_set(op->ptr, "prev_frame", pso->prevFrame);
|
||||
/* next frame */
|
||||
ak= cfra_find_nearest_next_ak(pso->keys.root, pso->cframe, 1);
|
||||
pso->nextFrame= (ak)? (ak->cfra) : (pso->cframe + 1);
|
||||
RNA_int_set(op->ptr, "next_frame", pso->prevFrame);
|
||||
}
|
||||
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.");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
|
||||
// TODO -----------------------------------
|
||||
// from here on, we should just invoke the modal operator, but for now, just do static...
|
||||
|
||||
/* temp static operator code... */
|
||||
pose_slide_apply(C, op, pso);
|
||||
pose_slide_exit(C, op);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
// TODO: common modal + cancel
|
||||
|
||||
|
||||
/* 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! */
|
||||
pose_slide_apply(C, op, pso);
|
||||
|
||||
/* cleanup and done */
|
||||
pose_slide_exit(C, op);
|
||||
|
||||
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 */
|
||||
static int pose_slide_push_invoke (bContext *C, wmOperator *op, wmEvent *evt)
|
||||
{
|
||||
tPoseSlideOp *pso;
|
||||
|
||||
/* initialise data */
|
||||
if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) {
|
||||
pose_slide_exit(C, op);
|
||||
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) {
|
||||
pose_slide_exit(C, op);
|
||||
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;
|
||||
//ot->modal= pose_slide_modal;
|
||||
//ot->cancel= pose_slide_cancel;
|
||||
ot->poll= ED_operator_posemode;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;//|OPTYPE_BLOCKING;
|
||||
|
||||
/* Properties */
|
||||
pose_slide_opdef_properties(ot);
|
||||
}
|
||||
|
||||
/* ........................ */
|
||||
|
||||
/* invoke() - for 'relax' mode */
|
||||
static int pose_slide_relax_invoke (bContext *C, wmOperator *op, wmEvent *evt)
|
||||
{
|
||||
tPoseSlideOp *pso;
|
||||
|
||||
/* initialise data */
|
||||
if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) {
|
||||
pose_slide_exit(C, op);
|
||||
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) {
|
||||
pose_slide_exit(C, op);
|
||||
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";
|
||||
ot->description= "Make the current pose more similar to its surrounding ones.";
|
||||
|
||||
/* callbacks */
|
||||
ot->exec= pose_slide_relax_exec;
|
||||
ot->invoke= pose_slide_relax_invoke;
|
||||
//ot->modal= pose_slide_modal;
|
||||
//ot->cancel= pose_slide_cancel;
|
||||
ot->poll= ED_operator_posemode;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;//|OPTYPE_BLOCKING;
|
||||
|
||||
/* Properties */
|
||||
pose_slide_opdef_properties(ot);
|
||||
}
|
||||
|
||||
/* ........................ */
|
||||
|
||||
/* invoke() - for 'breakdown' mode */
|
||||
static int pose_slide_breakdown_invoke (bContext *C, wmOperator *op, wmEvent *evt)
|
||||
{
|
||||
tPoseSlideOp *pso;
|
||||
|
||||
/* initialise data */
|
||||
if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) {
|
||||
pose_slide_exit(C, op);
|
||||
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) {
|
||||
pose_slide_exit(C, op);
|
||||
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";
|
||||
ot->description= "Create a suitable breakdown pose on the current frame.";
|
||||
|
||||
/* callbacks */
|
||||
ot->exec= pose_slide_breakdown_exec;
|
||||
ot->invoke= pose_slide_breakdown_invoke;
|
||||
//ot->modal= pose_slide_modal;
|
||||
//ot->cancel= pose_slide_cancel;
|
||||
ot->poll= ED_operator_posemode;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;//|OPTYPE_BLOCKING;
|
||||
|
||||
/* Properties */
|
||||
pose_slide_opdef_properties(ot);
|
||||
}
|
||||
|
||||
/* **************************************************** */
|
||||
@@ -44,7 +44,6 @@
|
||||
#include "DNA_action_types.h"
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_curve_types.h"
|
||||
#include "DNA_ipo_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_object_force.h"
|
||||
#include "DNA_scene_types.h"
|
||||
@@ -62,8 +61,6 @@
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_utildefines.h"
|
||||
|
||||
#include "PIL_time.h" /* sleep */
|
||||
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_define.h"
|
||||
#include "RNA_types.h"
|
||||
@@ -769,6 +766,10 @@ static void poselib_keytag_pose (bContext *C, Scene *scene, tPoseLib_PreviewData
|
||||
if (poselib_ks_locrotscale == NULL)
|
||||
poselib_ks_locrotscale= ANIM_builtin_keyingset_get_named(NULL, "LocRotScale");
|
||||
|
||||
/* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */
|
||||
cks.pchan= pchan;
|
||||
|
||||
/* now insert the keyframe */
|
||||
modify_keyframes(C, &dsources, NULL, poselib_ks_locrotscale, MODIFYKEY_MODE_INSERT, (float)CFRA);
|
||||
|
||||
/* clear any unkeyed tags */
|
||||
|
||||
@@ -1084,6 +1084,9 @@ static int pose_paste_exec (bContext *C, wmOperator *op)
|
||||
if (posePaste_ks_locrotscale == NULL)
|
||||
posePaste_ks_locrotscale= ANIM_builtin_keyingset_get_named(NULL, "LocRotScale");
|
||||
|
||||
/* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */
|
||||
cks.pchan= pchan;
|
||||
|
||||
modify_keyframes(C, &dsources, NULL, posePaste_ks_locrotscale, MODIFYKEY_MODE_INSERT, (float)CFRA);
|
||||
|
||||
/* clear any unkeyed tags */
|
||||
@@ -1983,175 +1986,6 @@ void ARMATURE_OT_bone_layers (wmOperatorType *ot)
|
||||
|
||||
/* ********************************************** */
|
||||
|
||||
#if 0
|
||||
// XXX old sys
|
||||
/* for use with pose_relax only */
|
||||
static int pose_relax_icu(struct IpoCurve *icu, float framef, float *val, float *frame_prev, float *frame_next)
|
||||
{
|
||||
if (!icu) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
BezTriple *bezt = icu->bezt;
|
||||
|
||||
BezTriple *bezt_prev=NULL, *bezt_next=NULL;
|
||||
float w1, w2, wtot;
|
||||
int i;
|
||||
|
||||
for (i=0; i < icu->totvert; i++, bezt++) {
|
||||
if (bezt->vec[1][0] < framef - 0.5) {
|
||||
bezt_prev = bezt;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bezt_prev==NULL) return 0;
|
||||
|
||||
/* advance to the next, dont need to advance i */
|
||||
bezt = bezt_prev+1;
|
||||
|
||||
for (; i < icu->totvert; i++, bezt++) {
|
||||
if (bezt->vec[1][0] > framef + 0.5) {
|
||||
bezt_next = bezt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bezt_next==NULL) return 0;
|
||||
|
||||
if (val) {
|
||||
w1 = framef - bezt_prev->vec[1][0];
|
||||
w2 = bezt_next->vec[1][0] - framef;
|
||||
wtot = w1 + w2;
|
||||
w1=w1/wtot;
|
||||
w2=w2/wtot;
|
||||
#if 0
|
||||
val = (bezt_prev->vec[1][1] * w2) + (bezt_next->vec[1][1] * w1);
|
||||
#else
|
||||
/* apply the value with a hard coded 6th */
|
||||
*val = (((bezt_prev->vec[1][1] * w2) + (bezt_next->vec[1][1] * w1)) + (*val * 5.0f)) / 6.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (frame_prev) *frame_prev = bezt_prev->vec[1][0];
|
||||
if (frame_next) *frame_next = bezt_next->vec[1][0];
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void pose_relax(Scene *scene)
|
||||
{
|
||||
Object *ob = OBACT;
|
||||
bPose *pose;
|
||||
bAction *act;
|
||||
bArmature *arm;
|
||||
|
||||
// IpoCurve *icu_w, *icu_x, *icu_y, *icu_z;
|
||||
|
||||
bPoseChannel *pchan;
|
||||
// bActionChannel *achan;
|
||||
// float framef = F_CFRA;
|
||||
// float frame_prev, frame_next;
|
||||
// float quat_prev[4], quat_next[4], quat_interp[4], quat_orig[4];
|
||||
|
||||
int do_scale = 0;
|
||||
int do_loc = 0;
|
||||
int do_quat = 0;
|
||||
int flag = 0;
|
||||
// int do_x, do_y, do_z;
|
||||
|
||||
if (!ob) return;
|
||||
|
||||
pose = ob->pose;
|
||||
act = ob->action;
|
||||
arm = (bArmature *)ob->data;
|
||||
|
||||
if (!pose || !act || !arm) return;
|
||||
|
||||
for (pchan=pose->chanbase.first; pchan; pchan= pchan->next) {
|
||||
|
||||
pchan->bone->flag &= ~BONE_TRANSFORM;
|
||||
|
||||
if (pchan->bone->layer & arm->layer) {
|
||||
if (pchan->bone->flag & BONE_SELECTED) {
|
||||
/* do we have an ipo curve? */
|
||||
#if 0 // XXX old animation system
|
||||
achan= get_action_channel(act, pchan->name);
|
||||
|
||||
if (achan && achan->ipo) {
|
||||
/*calc_ipo(achan->ipo, ctime);*/
|
||||
|
||||
do_x = pose_relax_icu(find_ipocurve(achan->ipo, AC_LOC_X), framef, &pchan->loc[0], NULL, NULL);
|
||||
do_y = pose_relax_icu(find_ipocurve(achan->ipo, AC_LOC_Y), framef, &pchan->loc[1], NULL, NULL);
|
||||
do_z = pose_relax_icu(find_ipocurve(achan->ipo, AC_LOC_Z), framef, &pchan->loc[2], NULL, NULL);
|
||||
do_loc += do_x + do_y + do_z;
|
||||
|
||||
do_x = pose_relax_icu(find_ipocurve(achan->ipo, AC_SIZE_X), framef, &pchan->size[0], NULL, NULL);
|
||||
do_y = pose_relax_icu(find_ipocurve(achan->ipo, AC_SIZE_Y), framef, &pchan->size[1], NULL, NULL);
|
||||
do_z = pose_relax_icu(find_ipocurve(achan->ipo, AC_SIZE_Z), framef, &pchan->size[2], NULL, NULL);
|
||||
do_scale += do_x + do_y + do_z;
|
||||
|
||||
if( ((icu_w = find_ipocurve(achan->ipo, AC_QUAT_W))) &&
|
||||
((icu_x = find_ipocurve(achan->ipo, AC_QUAT_X))) &&
|
||||
((icu_y = find_ipocurve(achan->ipo, AC_QUAT_Y))) &&
|
||||
((icu_z = find_ipocurve(achan->ipo, AC_QUAT_Z))) )
|
||||
{
|
||||
/* use the quatw keyframe as a basis for others */
|
||||
if (pose_relax_icu(icu_w, framef, NULL, &frame_prev, &frame_next)) {
|
||||
/* get 2 quats */
|
||||
quat_prev[0] = eval_icu(icu_w, frame_prev);
|
||||
quat_prev[1] = eval_icu(icu_x, frame_prev);
|
||||
quat_prev[2] = eval_icu(icu_y, frame_prev);
|
||||
quat_prev[3] = eval_icu(icu_z, frame_prev);
|
||||
|
||||
quat_next[0] = eval_icu(icu_w, frame_next);
|
||||
quat_next[1] = eval_icu(icu_x, frame_next);
|
||||
quat_next[2] = eval_icu(icu_y, frame_next);
|
||||
quat_next[3] = eval_icu(icu_z, frame_next);
|
||||
|
||||
#if 0
|
||||
/* apply the setting, completely smooth */
|
||||
QuatInterpol(pchan->quat, quat_prev, quat_next, (framef-frame_prev) / (frame_next-frame_prev) );
|
||||
#else
|
||||
/* tricky interpolation */
|
||||
QuatInterpol(quat_interp, quat_prev, quat_next, (framef-frame_prev) / (frame_next-frame_prev) );
|
||||
QUATCOPY(quat_orig, pchan->quat);
|
||||
QuatInterpol(pchan->quat, quat_orig, quat_interp, 1.0f/6.0f);
|
||||
/* done */
|
||||
#endif
|
||||
do_quat++;
|
||||
}
|
||||
}
|
||||
|
||||
/* apply BONE_TRANSFORM tag so that autokeying will pick it up */
|
||||
pchan->bone->flag |= BONE_TRANSFORM;
|
||||
}
|
||||
|
||||
#endif // XXX old animation system
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
|
||||
|
||||
/* do auto-keying */
|
||||
if (do_loc) flag |= TFM_TRANSLATION;
|
||||
if (do_scale) flag |= TFM_RESIZE;
|
||||
if (do_quat) flag |= TFM_ROTATION;
|
||||
autokeyframe_pose_cb_func(ob, flag, 0);
|
||||
|
||||
/* clear BONE_TRANSFORM flags */
|
||||
for (pchan=pose->chanbase.first; pchan; pchan= pchan->next)
|
||||
pchan->bone->flag &= ~ BONE_TRANSFORM;
|
||||
|
||||
/* do depsgraph flush */
|
||||
DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
|
||||
BIF_undo_push("Relax Pose");
|
||||
}
|
||||
|
||||
/* for use in insertkey, ensure rotation goes other way around */
|
||||
void pose_flipquats(Scene *scene)
|
||||
{
|
||||
|
||||
@@ -119,5 +119,9 @@ void ob_to_keylist(struct bDopeSheet *ads, struct Object *ob, struct DLRBT_Tree
|
||||
void scene_to_keylist(struct bDopeSheet *ads, struct Scene *sce, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
|
||||
void gpl_to_keylist(struct bDopeSheet *ads, struct bGPDlayer *gpl, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
|
||||
|
||||
/* Keyframe Finding */
|
||||
ActKeyColumn *cfra_find_actkeycolumn(ActKeyColumn *ak, float cframe);
|
||||
ActKeyColumn *cfra_find_nearest_next_ak(ActKeyColumn *ak, float cframe, short next);
|
||||
|
||||
#endif /* ED_KEYFRAMES_DRAW_H */
|
||||
|
||||
|
||||
@@ -1444,29 +1444,6 @@ static void SCREEN_OT_frame_jump(wmOperatorType *ot)
|
||||
|
||||
/* ************** jump to keyframe operator ***************************** */
|
||||
|
||||
/* helper function - find actkeycolumn that occurs on cframe, or the nearest one if not found */
|
||||
// TODO: make this an API func?
|
||||
static ActKeyColumn *cfra_find_nearest_next_ak (ActKeyColumn *ak, float cframe, short next)
|
||||
{
|
||||
ActKeyColumn *akn= NULL;
|
||||
|
||||
/* sanity checks */
|
||||
if (ak == NULL)
|
||||
return NULL;
|
||||
|
||||
/* check if this is a match, or whether it is in some subtree */
|
||||
if (cframe < ak->cfra)
|
||||
akn= cfra_find_nearest_next_ak(ak->left, cframe, next);
|
||||
else if (cframe > ak->cfra)
|
||||
akn= cfra_find_nearest_next_ak(ak->right, cframe, next);
|
||||
|
||||
/* if no match found (or found match), just use the current one */
|
||||
if (akn == NULL)
|
||||
return ak;
|
||||
else
|
||||
return akn;
|
||||
}
|
||||
|
||||
/* function to be called outside UI context, or for redo */
|
||||
static int keyframe_jump_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user