2.5 - Restored Bone Paths Operators

* A number-counter cursor is now used while sampling the curve
* Fixed some of the drawing errors with the paths. Unfortunately, when the armature is rotated, the path text is drawn in the wrong places still...
This commit is contained in:
Joshua Leung 2009-07-24 12:27:42 +00:00
parent bd628d9c0c
commit 1844fc7057
5 changed files with 234 additions and 137 deletions

@ -67,6 +67,9 @@ void POSE_OT_scale_clear(struct wmOperatorType *ot);
void POSE_OT_copy(struct wmOperatorType *ot);
void POSE_OT_paste(struct wmOperatorType *ot);
void POSE_OT_paths_calculate(struct wmOperatorType *ot);
void POSE_OT_paths_clear(struct wmOperatorType *ot);
void POSE_OT_select_all_toggle(struct wmOperatorType *ot);
void POSE_OT_select_inverse(struct wmOperatorType *ot);
void POSE_OT_select_parent(struct wmOperatorType *ot);

@ -150,6 +150,9 @@ void ED_operatortypes_armature(void)
WM_operatortype_append(POSE_OT_copy);
WM_operatortype_append(POSE_OT_paste);
WM_operatortype_append(POSE_OT_paths_calculate);
WM_operatortype_append(POSE_OT_paths_clear);
WM_operatortype_append(POSE_OT_select_all_toggle);
WM_operatortype_append(POSE_OT_select_inverse);

@ -21,6 +21,7 @@
* All rights reserved.
*
* Contributor(s): Ton Roosendaal, Blender Foundation '05, full recode.
* Joshua Leung
*
* ***** END GPL LICENSE BLOCK *****
* support for animation modes - Reevan McKay
@ -50,6 +51,7 @@
#include "DNA_view3d_types.h"
#include "DNA_userdef_types.h"
#include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_blender.h"
@ -89,7 +91,6 @@
/* ************* XXX *************** */
static int movetolayer_short_buts() {return 1;}
static int pupmenu() {return 0;}
static void waitcursor() {};
static void error() {};
static void BIF_undo_push() {}
static void countall() {}
@ -201,104 +202,12 @@ int ED_pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan)
/* ********************************************** */
/* For the object with pose/action: create path curves for selected bones
* This recalculates the WHOLE path within the pchan->pathsf and pchan->pathef range
*/
void pose_calculate_path(bContext *C, Scene *scene, Object *ob)
{
bArmature *arm;
bPoseChannel *pchan;
Base *base;
float *fp;
int cfra;
int sfra, efra;
if (ob==NULL || ob->pose==NULL)
return;
arm= ob->data;
/* version patch for older files here (do_versions patch too complicated) */
if ((arm->pathsf == 0) || (arm->pathef == 0)) {
arm->pathsf = SFRA;
arm->pathef = EFRA;
}
if (arm->pathsize == 0) {
arm->pathsize = 1;
}
/* set frame values */
cfra= CFRA;
sfra = arm->pathsf;
efra = arm->pathef;
if (efra <= sfra) {
error("Can't calculate paths when pathlen <= 0");
return;
}
waitcursor(1);
/* hack: for unsaved files, set OB_RECALC so that paths can get calculated */
if ((ob->recalc & OB_RECALC)==0) {
ob->recalc |= OB_RECALC;
ED_anim_object_flush_update(C, ob);
}
else
ED_anim_object_flush_update(C, ob);
/* malloc the path blocks */
for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) {
if (arm->layer & pchan->bone->layer) {
pchan->pathlen= efra-sfra+1;
pchan->pathsf= sfra;
pchan->pathef= efra+1;
if (pchan->path)
MEM_freeN(pchan->path);
pchan->path= MEM_callocN(3*pchan->pathlen*sizeof(float), "pchan path");
}
}
}
for (CFRA=sfra; CFRA<=efra; CFRA++) {
/* do all updates */
for (base= FIRSTBASE; base; base= base->next) {
if (base->object->recalc) {
int temp= base->object->recalc;
object_handle_update(scene, base->object);
base->object->recalc= temp;
}
}
for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) {
if (arm->layer & pchan->bone->layer) {
if (pchan->path) {
fp= pchan->path+3*(CFRA-sfra);
if (arm->pathflag & ARM_PATH_HEADS) {
VECCOPY(fp, pchan->pose_head);
}
else {
VECCOPY(fp, pchan->pose_tail);
}
Mat4MulVecfl(ob->obmat, fp);
}
}
}
}
}
waitcursor(0);
CFRA= cfra;
}
/* For the object with pose/action: update paths for those that have got them
* This should selectively update paths that exist...
*
* To be called from various tools that do incremental updates
*/
void pose_recalculate_paths(bContext *C, Scene *scene, Object *ob)
void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob)
{
bArmature *arm;
bPoseChannel *pchan;
@ -307,7 +216,8 @@ void pose_recalculate_paths(bContext *C, Scene *scene, Object *ob)
int cfra;
int sfra, efra;
if (ob==NULL || ob->pose==NULL)
/* sanity checks */
if ELEM(NULL, ob, ob->pose)
return;
arm= ob->data;
@ -329,8 +239,6 @@ void pose_recalculate_paths(bContext *C, Scene *scene, Object *ob)
}
if (efra <= sfra) return;
waitcursor(1);
/* hack: for unsaved files, set OB_RECALC so that paths can get calculated */
if ((ob->recalc & OB_RECALC)==0) {
ob->recalc |= OB_RECALC;
@ -339,11 +247,17 @@ void pose_recalculate_paths(bContext *C, Scene *scene, Object *ob)
else
ED_anim_object_flush_update(C, ob);
/* calculate path over requested range */
for (CFRA=sfra; CFRA<=efra; CFRA++) {
/* do all updates */
for (base= FIRSTBASE; base; base= base->next) {
if (base->object->recalc) {
int temp= base->object->recalc;
if (base->object->adt)
BKE_animsys_evaluate_animdata(&base->object->id, base->object->adt, (float)CFRA, ADT_RECALC_ALL);
/* update object */
object_handle_update(scene, base->object);
base->object->recalc= temp;
}
@ -373,18 +287,181 @@ void pose_recalculate_paths(bContext *C, Scene *scene, Object *ob)
}
}
waitcursor(0);
/* reset flags */
CFRA= cfra;
ob->pose->flag &= ~POSE_RECALCPATHS;
/* flush one final time - to restore to the original state */
for (base= FIRSTBASE; base; base= base->next) {
if (base->object->recalc) {
int temp= base->object->recalc;
if (base->object->adt)
BKE_animsys_evaluate_animdata(&base->object->id, base->object->adt, (float)CFRA, ADT_RECALC_ALL);
object_handle_update(scene, base->object);
base->object->recalc= temp;
}
}
}
/* --------- */
/* For the object with pose/action: create path curves for selected bones
* This recalculates the WHOLE path within the pchan->pathsf and pchan->pathef range
*/
static int pose_calculate_paths_exec (bContext *C, wmOperator *op)
{
wmWindow *win= CTX_wm_window(C);
ScrArea *sa= CTX_wm_area(C);
Scene *scene= CTX_data_scene(C);
Object *ob;
bArmature *arm;
bPoseChannel *pchan;
Base *base;
float *fp;
int cfra;
int sfra, efra;
/* since this call may also be used from the buttons window, we need to check for where to get the object */
if (sa->spacetype == SPACE_BUTS)
ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
else
ob= CTX_data_active_object(C);
/* only continue if there's an object */
if ELEM(NULL, ob, ob->pose)
return OPERATOR_CANCELLED;
arm= ob->data;
/* version patch for older files here (do_versions patch too complicated) */
if ((arm->pathsf == 0) || (arm->pathef == 0)) {
arm->pathsf = SFRA;
arm->pathef = EFRA;
}
if (arm->pathsize == 0) {
arm->pathsize = 1;
}
/* get frame values to use */
cfra= CFRA;
sfra = arm->pathsf;
efra = arm->pathef;
if (efra <= sfra) {
BKE_report(op->reports, RPT_ERROR, "Can't calculate paths when pathlen <= 0");
return OPERATOR_CANCELLED;
}
/* hack: for unsaved files, set OB_RECALC so that paths can get calculated */
if ((ob->recalc & OB_RECALC)==0) {
ob->recalc |= OB_RECALC;
ED_anim_object_flush_update(C, ob);
}
else
ED_anim_object_flush_update(C, ob);
/* alloc the path cache arrays */
for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) {
if (arm->layer & pchan->bone->layer) {
pchan->pathlen= efra-sfra+1;
pchan->pathsf= sfra;
pchan->pathef= efra+1;
if (pchan->path)
MEM_freeN(pchan->path);
pchan->path= MEM_callocN(3*pchan->pathlen*sizeof(float), "pchan path");
}
}
}
/* step through frame range sampling the values */
for (CFRA=sfra; CFRA<=efra; CFRA++) {
/* for each frame we calculate, update time-cursor... (may be too slow) */
WM_timecursor(win, CFRA);
/* do all updates */
for (base= FIRSTBASE; base; base= base->next) {
if (base->object->recalc) {
int temp= base->object->recalc;
if (base->object->adt)
BKE_animsys_evaluate_animdata(&base->object->id, base->object->adt, (float)CFRA, ADT_RECALC_ALL);
object_handle_update(scene, base->object);
base->object->recalc= temp;
}
}
for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) {
if (arm->layer & pchan->bone->layer) {
if (pchan->path) {
fp= pchan->path+3*(CFRA-sfra);
if (arm->pathflag & ARM_PATH_HEADS) {
VECCOPY(fp, pchan->pose_head);
}
else {
VECCOPY(fp, pchan->pose_tail);
}
Mat4MulVecfl(ob->obmat, fp);
}
}
}
}
}
/* restore original cursor */
WM_cursor_restore(win);
/* reset current frame, and clear flags */
CFRA= cfra;
ob->pose->flag &= ~POSE_RECALCPATHS;
/* flush one final time - to restore to the original state */
for (base= FIRSTBASE; base; base= base->next) {
if (base->object->recalc) {
int temp= base->object->recalc;
if (base->object->adt)
BKE_animsys_evaluate_animdata(&base->object->id, base->object->adt, (float)CFRA, ADT_RECALC_ALL);
object_handle_update(scene, base->object);
base->object->recalc= temp;
}
}
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
return OPERATOR_FINISHED;
}
void POSE_OT_paths_calculate (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Calculate Bone Paths";
ot->idname= "POSE_OT_paths_calculate";
ot->description= "Calculate paths for the selected bones.";
/* api callbacks */
ot->exec= pose_calculate_paths_exec;
ot->poll= ED_operator_posemode;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
/* --------- */
/* for the object with pose/action: clear path curves for selected bones only */
void pose_clear_paths(Object *ob)
void ED_pose_clear_paths(Object *ob)
{
bPoseChannel *pchan;
if (ob==NULL || ob->pose==NULL)
if ELEM(NULL, ob, ob->pose)
return;
/* free the path blocks */
@ -396,9 +473,49 @@ void pose_clear_paths(Object *ob)
}
}
}
}
/* operator callback for this */
static int pose_clear_paths_exec (bContext *C, wmOperator *op)
{
ScrArea *sa= CTX_wm_area(C);
Object *ob;
/* since this call may also be used from the buttons window, we need to check for where to get the object */
if (sa->spacetype == SPACE_BUTS)
ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
else
ob= CTX_data_active_object(C);
/* only continue if there's an object */
if ELEM(NULL, ob, ob->pose)
return OPERATOR_CANCELLED;
/* for now, just call the API function for this (which is shared with backend functions) */
ED_pose_clear_paths(ob);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
return OPERATOR_FINISHED;
}
void POSE_OT_paths_clear (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Clear Bone Paths";
ot->idname= "POSE_OT_paths_clear";
ot->description= "Clear path caches for selected bones.";
/* api callbacks */
ot->exec= pose_clear_paths_exec;
ot->poll= ED_operator_posemode;
/* flags */
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
}
/* ******************* Select Constraint Target Operator ************* */
// XXX this function is to be removed when the other stuff is recoded
void pose_select_constraint_target(Scene *scene)

@ -2154,12 +2154,12 @@ static void draw_pose_paths(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec
/* only draw framenum if several consecutive highlighted points don't occur on same point */
if (a == 0) {
sprintf(str, " %d\n", (a+sfra));
sprintf(str, "%d", (a+sfra));
view3d_object_text_draw_add(fp[0], fp[1], fp[2], str, 0);
}
else if ((a > stepsize) && (a < len-stepsize)) {
if ((VecEqual(fp, fp-(stepsize*3))==0) || (VecEqual(fp, fp+(stepsize*3))==0)) {
sprintf(str, " %d\n", (a+sfra));
sprintf(str, "%d", (a+sfra));
view3d_object_text_draw_add(fp[0], fp[1], fp[2], str, 0);
}
}
@ -2201,7 +2201,7 @@ static void draw_pose_paths(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec
if (ak->cfra == (a+sfra)) {
char str[32];
sprintf(str, " %d\n", (a+sfra));
sprintf(str, "%d", (a+sfra));
view3d_object_text_draw_add(fp[0], fp[1], fp[2], str, 0);
}
}

@ -3051,37 +3051,11 @@ static void view3d_pose_armature_groupmenu(bContext *C, uiLayout *layout, void *
uiItemO(layout, "Remove Active Group", 0, "POSE_OT_group_remove");
}
#if 0
static void do_view3d_pose_armature_motionpathsmenu(bContext *C, void *arg, int event)
static void view3d_pose_armature_motionpathsmenu(bContext *C, uiLayout *layout, void *arg_unused)
{
switch(event) {
case 1:
pose_calculate_path(OBACT);
break;
case 2:
pose_clear_paths(OBACT);
break;
uiItemO(layout, NULL, 0, "POSE_OT_paths_calculate");
uiItemO(layout, NULL, 0, "POSE_OT_paths_clear");
}
}
static uiBlock *view3d_pose_armature_motionpathsmenu(bContext *C, ARegion *ar, void *arg_unused)
{
uiBlock *block;
short yco = 20, menuwidth = 120;
block= uiBeginBlock(C, ar, "view3d_pose_armature_motionpathsmenu", UI_EMBOSSP);
uiBlockSetButmFunc(block, do_view3d_pose_armature_motionpathsmenu, NULL);
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Calculate Paths|W", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear All Paths|W", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
uiBlockSetDirection(block, UI_RIGHT);
uiTextBoundsBlock(block, 60);
return block;
}
#endif
static void view3d_pose_armature_poselibmenu(bContext *C, uiLayout *layout, void *arg_unused)
{
@ -3184,7 +3158,7 @@ static void view3d_pose_armaturemenu(bContext *C, uiLayout *layout, void *arg_un
uiItemS(layout);
uiItemMenuF(layout, "Pose Library", 0, view3d_pose_armature_poselibmenu);
//uiItemMenuF(layout, "Motion Paths", 0, view3d_pose_armature_motionpathsmenu);
uiItemMenuF(layout, "Motion Paths", 0, view3d_pose_armature_motionpathsmenu);
uiItemMenuF(layout, "Bone Groups", 0, view3d_pose_armature_groupmenu);
uiItemS(layout);