Animato: Added 'experimental' grouping schemes for F-Curves

When inserting keyframes on previous un-animated Objects/bones, F-Curves will be added into Action Groups into either "Object Transform" or <PoseChannel Name>. Ob->Material settings are not grouped for now to illustrate what's possible.

Old files are currently not patched to use do this, as it's still not clear whether this will be ideal.
This commit is contained in:
2009-02-09 10:04:11 +00:00
parent b9063b27a9
commit 59736af8fc
11 changed files with 296 additions and 66 deletions

View File

@@ -36,11 +36,10 @@
#include "DNA_listBase.h"
/**
* The following structures are defined in DNA_action_types.h, and DNA_anim_types.h
*/
/* The following structures are defined in DNA_action_types.h, and DNA_anim_types.h */
struct bAction;
struct bActionGroup;
struct FCurve;
struct bPose;
struct bPoseChannel;
struct Object;
@@ -52,28 +51,40 @@ struct ID;
extern "C" {
#endif
struct bAction *add_empty_action(const char name[]);
/**
* Allocate a new bAction on the heap and copy
* the contents of src into it. If src is NULL NULL is returned.
*/
/* Action API ----------------- */
/* Allocate a new bAction with the given name */
struct bAction *add_empty_action(const char name[]);
/* Allocate a copy of the given Action and all its data */
struct bAction *copy_action(struct bAction *src);
/**
* Deallocate the action's channels including constraint channels.
* does not free the action structure.
*/
/* Deallocate all of the Action's data, but not the Action itself */
void free_action(struct bAction *act);
// XXX is this needed?
void make_local_action(struct bAction *act);
/**
* Some kind of bounding box operation on the action.
*/
/* Some kind of bounding box operation on the action */
// XXX depreceated..
void calc_action_range(const struct bAction *act, float *start, float *end, int incl_hidden);
/* Action Groups API ----------------- */
/* Make the given Action Group the active one */
void set_active_action_group(struct bAction *act, struct bActionGroup *agrp, short select);
/* Add given channel into (active) group */
void action_groups_add_channel(struct bAction *act, struct bActionGroup *agrp, struct FCurve *fcurve);
/* Remove the given channel from all groups */
void action_groups_remove_channel(struct bAction *act, struct FCurve *fcu);
/* Find a group with the given name */
struct bActionGroup *action_groups_find_named(struct bAction *act, const char name[]);
/* Pose API ----------------- */
/**
* Removes and deallocates all channels from a pose.

View File

@@ -188,6 +188,192 @@ bAction *copy_action (bAction *src)
}
/* Get the active action-group for an Action */
bActionGroup *get_active_actiongroup (bAction *act)
{
bActionGroup *agrp= NULL;
if (act && act->groups.first) {
for (agrp= act->groups.first; agrp; agrp= agrp->next) {
if (agrp->flag & AGRP_ACTIVE)
break;
}
}
return agrp;
}
/* Make the given Action-Group the active one */
void set_active_action_group (bAction *act, bActionGroup *agrp, short select)
{
bActionGroup *grp;
/* sanity checks */
if (act == NULL)
return;
/* Deactive all others */
for (grp= act->groups.first; grp; grp= grp->next) {
if ((grp==agrp) && (select))
grp->flag |= AGRP_ACTIVE;
else
grp->flag &= ~AGRP_ACTIVE;
}
}
/* Add given channel into (active) group
* - assumes that channel is not linked to anything anymore
* - always adds at the end of the group
*/
void action_groups_add_channel (bAction *act, bActionGroup *agrp, FCurve *fcurve)
{
FCurve *fcu;
short done=0;
/* sanity checks */
if (ELEM3(NULL, act, agrp, fcurve))
return;
/* if no channels, just add to two lists at the same time */
if (act->curves.first == NULL) {
fcurve->next = fcurve->prev = NULL;
agrp->channels.first = agrp->channels.last = fcurve;
act->curves.first = act->curves.last = fcurve;
fcurve->grp= agrp;
return;
}
/* try to find a channel to slot this in before/after */
for (fcu= act->curves.first; fcu; fcu= fcu->next) {
/* if channel has no group, then we have ungrouped channels, which should always occur after groups */
if (fcu->grp == NULL) {
BLI_insertlinkbefore(&act->curves, fcu, fcurve);
if (agrp->channels.first == NULL)
agrp->channels.first= fcurve;
agrp->channels.last= fcurve;
done= 1;
break;
}
/* if channel has group after current, we can now insert (otherwise we have gone too far) */
else if (fcu->grp == agrp->next) {
BLI_insertlinkbefore(&act->curves, fcu, fcurve);
if (agrp->channels.first == NULL)
agrp->channels.first= fcurve;
agrp->channels.last= fcurve;
done= 1;
break;
}
/* if channel has group we're targeting, check whether it is the last one of these */
else if (fcu->grp == agrp) {
if ((fcu->next) && (fcu->next->grp != agrp)) {
BLI_insertlinkafter(&act->curves, fcu, fcurve);
agrp->channels.last= fcurve;
done= 1;
break;
}
else if (fcu->next == NULL) {
BLI_addtail(&act->curves, fcurve);
agrp->channels.last= fcurve;
done= 1;
break;
}
}
/* if channel has group before target, check whether the next one is something after target */
else if (fcu->grp == agrp->prev) {
if (fcu->next) {
if ((fcu->next->grp != fcu->grp) && (fcu->next->grp != agrp)) {
BLI_insertlinkafter(&act->curves, fcu, fcurve);
agrp->channels.first= fcurve;
agrp->channels.last= fcurve;
done= 1;
break;
}
}
else {
BLI_insertlinkafter(&act->curves, fcu, fcurve);
agrp->channels.first= fcurve;
agrp->channels.last= fcurve;
done= 1;
break;
}
}
}
/* only if added, set channel as belonging to this group */
if (done)
fcurve->grp= agrp;
else
printf("Error: FCurve '%s' couldn't be added to Group '%s' \n", fcurve->rna_path, agrp->name);
}
/* Remove the given channel from all groups */
void action_groups_remove_channel (bAction *act, FCurve *fcu)
{
/* sanity checks */
if (ELEM(NULL, act, fcu))
return;
/* check if any group used this directly */
if (fcu->grp) {
bActionGroup *agrp= fcu->grp;
if (agrp->channels.first == agrp->channels.last) {
if (agrp->channels.first == fcu) {
agrp->channels.first= NULL;
agrp->channels.last= NULL;
}
}
else if (agrp->channels.first == fcu) {
if ((fcu->next) && (fcu->next->grp==agrp))
agrp->channels.first= fcu->next;
else
agrp->channels.first= NULL;
}
else if (agrp->channels.last == fcu) {
if ((fcu->prev) && (fcu->prev->grp==agrp))
agrp->channels.last= fcu->prev;
else
agrp->channels.last= NULL;
}
fcu->grp= NULL;
}
/* now just remove from list */
BLI_remlink(&act->curves, fcu);
}
/* Find a group with the given name */
bActionGroup *action_groups_find_named (bAction *act, const char name[])
{
bActionGroup *grp;
/* sanity checks */
if (ELEM3(NULL, act, act->groups.first, name) || (name[0] == 0))
return NULL;
/* do string comparisons */
for (grp= act->groups.first; grp; grp= grp->next) {
if (strcmp(grp->name, name) == 0)
return grp;
}
/* not found */
return NULL;
}
/* ************************ Pose channels *************** */

View File

@@ -5525,7 +5525,7 @@ static void area_add_window_regions(ScrArea *sa, SpaceLink *sl, ListBase *lb)
/* we totally reinit the view for the Action Editor, as some old instances had some weird cruft set */
ar->v2d.tot.xmin= -20.0f;
ar->v2d.tot.ymin= (float)(-sa->winy);
ar->v2d.tot.xmax= (float)(sa->winx);
ar->v2d.tot.xmax= (float)((sa->winx > 120)? (sa->winx) : 120);
ar->v2d.tot.ymax= 0.0f;
ar->v2d.cur= ar->v2d.tot;

View File

@@ -1075,7 +1075,7 @@ static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, s
case ANIMTYPE_GROUP:
{
bActionGroup *agrp= (bActionGroup *)ale->data;
short offset= (ac->datatype == ANIMCONT_DOPESHEET)? 21 : 0;
short offset= (ac->datatype == ANIMCONT_DOPESHEET)? 18 : 0;
if ((x < (offset+17)) && (agrp->channels.first)) {
/* toggle expand */

View File

@@ -3,6 +3,7 @@
*/
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <math.h>
#include <float.h>
@@ -95,13 +96,13 @@ typedef struct bKeyingContext {
/* Animation Data Validation */
/* Get (or add relevant data to be able to do so) F-Curve from the Active Action,
* for the given Animation Data block
* for the given Animation Data block. This assumes that all the destinations are valid.
*/
// TODO: should we check if path is valid? For now, assume that it's already set OK by caller...
FCurve *verify_fcurve (ID *id, const char rna_path[], const int array_index, short add)
FCurve *verify_fcurve (ID *id, const char group[], const char rna_path[], const int array_index, short add)
{
AnimData *adt;
bAction *act;
bActionGroup *grp;
FCurve *fcu;
/* sanity checks */
@@ -133,7 +134,7 @@ FCurve *verify_fcurve (ID *id, const char rna_path[], const int array_index, sho
fcu= NULL;
if ((fcu == NULL) && (add)) {
/* use default settings */
/* use default settings to make a F-Curve */
fcu= MEM_callocN(sizeof(FCurve), "FCurve");
fcu->flag |= (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES);
@@ -144,8 +145,33 @@ FCurve *verify_fcurve (ID *id, const char rna_path[], const int array_index, sho
fcu->rna_path= BLI_strdupn(rna_path, strlen(rna_path));
fcu->array_index= array_index;
/* add curve */
BLI_addtail(&act->curves, fcu); // XXX it might be better to add this in order, for easier UI coding...
/* if a group name has been provided, try to add or find a group, then add F-Curve to it */
if (group) {
/* try to find group */
grp= action_groups_find_named(act, group);
/* no matching groups, so add one */
if (grp == NULL) {
/* Add a new group, and make it active */
grp= MEM_callocN(sizeof(bActionGroup), "bActionGroup");
grp->flag |= (AGRP_ACTIVE|AGRP_SELECTED|AGRP_EXPANDED);
BLI_snprintf(grp->name, 64, group);
BLI_addtail(&act->groups, grp);
BLI_uniquename(&act->groups, grp, "Group", offsetof(bActionGroup, name), 64);
set_active_action_group(act, grp, 1);
}
/* add F-Curve to group */
action_groups_add_channel(act, grp, fcu);
}
else {
/* just add F-Curve to end of Action's list */
BLI_addtail(&act->curves, fcu);
}
}
/* return the F-Curve */
@@ -711,7 +737,7 @@ static float visualkey_get_value (PointerRNA *ptr, PropertyRNA *prop, int array_
* the keyframe insertion. These include the 'visual' keyframing modes, quick refresh,
* and extra keyframe filtering.
*/
short insertkey (ID *id, const char rna_path[], int array_index, float cfra, short flag)
short insertkey (ID *id, const char group[], const char rna_path[], int array_index, float cfra, short flag)
{
PointerRNA id_ptr, ptr;
PropertyRNA *prop;
@@ -725,7 +751,7 @@ short insertkey (ID *id, const char rna_path[], int array_index, float cfra, sho
}
/* get F-Curve */
fcu= verify_fcurve(id, rna_path, array_index, 1);
fcu= verify_fcurve(id, group, rna_path, array_index, 1);
/* only continue if we have an F-Curve to add keyframe to */
if (fcu) {
@@ -809,7 +835,7 @@ short insertkey (ID *id, const char rna_path[], int array_index, float cfra, sho
* The flag argument is used for special settings that alter the behaviour of
* the keyframe deletion. These include the quick refresh options.
*/
short deletekey (ID *id, const char rna_path[], int array_index, float cfra, short flag)
short deletekey (ID *id, const char group[], const char rna_path[], int array_index, float cfra, short flag)
{
AnimData *adt;
FCurve *fcu;
@@ -819,7 +845,7 @@ short deletekey (ID *id, const char rna_path[], int array_index, float cfra, sho
* so 'add' var must be 0
*/
// XXX we don't check the validity of the path here yet, but it should be ok...
fcu= verify_fcurve(id, rna_path, array_index, 0);
fcu= verify_fcurve(id, group, rna_path, array_index, 0);
adt= BKE_animdata_from_id(id);
/* only continue if we have an ipo-curve to remove keyframes from */
@@ -2049,24 +2075,25 @@ static int insert_key_exec (bContext *C, wmOperator *op)
switch (mode) {
case 3: /* color of active material (only for geometry...) */
// NOTE: this is just a demo... but ideally we'd go through materials instead of active one only so reference stays same
success+= insertkey(id, "active_material.diffuse_color", 0, cfra, 0);
success+= insertkey(id, "active_material.diffuse_color", 1, cfra, 0);
success+= insertkey(id, "active_material.diffuse_color", 2, cfra, 0);
// XXX no group for now
success+= insertkey(id, NULL, "active_material.diffuse_color", 0, cfra, 0);
success+= insertkey(id, NULL, "active_material.diffuse_color", 1, cfra, 0);
success+= insertkey(id, NULL, "active_material.diffuse_color", 2, cfra, 0);
break;
case 2: /* object scale */
success+= insertkey(id, "scale", 0, cfra, 0);
success+= insertkey(id, "scale", 1, cfra, 0);
success+= insertkey(id, "scale", 2, cfra, 0);
success+= insertkey(id, "Object Transforms", "scale", 0, cfra, 0);
success+= insertkey(id, "Object Transforms", "scale", 1, cfra, 0);
success+= insertkey(id, "Object Transforms", "scale", 2, cfra, 0);
break;
case 1: /* object rotation */
success+= insertkey(id, "rotation", 0, cfra, 0);
success+= insertkey(id, "rotation", 1, cfra, 0);
success+= insertkey(id, "rotation", 2, cfra, 0);
success+= insertkey(id, "Object Transforms", "rotation", 0, cfra, 0);
success+= insertkey(id, "Object Transforms", "rotation", 1, cfra, 0);
success+= insertkey(id, "Object Transforms", "rotation", 2, cfra, 0);
break;
default: /* object location */
success+= insertkey(id, "location", 0, cfra, 0);
success+= insertkey(id, "location", 1, cfra, 0);
success+= insertkey(id, "location", 2, cfra, 0);
success+= insertkey(id, "Object Transforms", "location", 0, cfra, 0);
success+= insertkey(id, "Object Transforms", "location", 1, cfra, 0);
success+= insertkey(id, "Object Transforms", "location", 2, cfra, 0);
break;
}
@@ -2084,22 +2111,30 @@ static int insert_key_exec (bContext *C, wmOperator *op)
switch (mode) {
case 6: /* pchan scale */
sprintf(buf, "pose.pose_channels[\"%s\"].scale", pchan->name);
success+= insertkey(id, buf, 0, cfra, 0);
success+= insertkey(id, buf, 1, cfra, 0);
success+= insertkey(id, buf, 2, cfra, 0);
success+= insertkey(id, pchan->name, buf, 0, cfra, 0);
success+= insertkey(id, pchan->name, buf, 1, cfra, 0);
success+= insertkey(id, pchan->name, buf, 2, cfra, 0);
break;
case 5: /* pchan rotation */
sprintf(buf, "pose.pose_channels[\"%s\"].rotation", pchan->name);
success+= insertkey(id, buf, 0, cfra, 0);
success+= insertkey(id, buf, 1, cfra, 0);
success+= insertkey(id, buf, 2, cfra, 0);
success+= insertkey(id, buf, 3, cfra, 0);
if (pchan->rotmode == PCHAN_ROT_QUAT) {
sprintf(buf, "pose.pose_channels[\"%s\"].rotation", pchan->name);
success+= insertkey(id, pchan->name, buf, 0, cfra, 0);
success+= insertkey(id, pchan->name, buf, 1, cfra, 0);
success+= insertkey(id, pchan->name, buf, 2, cfra, 0);
success+= insertkey(id, pchan->name, buf, 3, cfra, 0);
}
else {
sprintf(buf, "pose.pose_channels[\"%s\"].euler_rotation", pchan->name);
success+= insertkey(id, pchan->name, buf, 0, cfra, 0);
success+= insertkey(id, pchan->name, buf, 1, cfra, 0);
success+= insertkey(id, pchan->name, buf, 2, cfra, 0);
}
break;
default: /* pchan location */
sprintf(buf, "pose.pose_channels[\"%s\"].location", pchan->name);
success+= insertkey(id, buf, 0, cfra, 0);
success+= insertkey(id, buf, 1, cfra, 0);
success+= insertkey(id, buf, 2, cfra, 0);
success+= insertkey(id, pchan->name, buf, 0, cfra, 0);
success+= insertkey(id, pchan->name, buf, 1, cfra, 0);
success+= insertkey(id, pchan->name, buf, 2, cfra, 0);
break;
}
}
@@ -2172,7 +2207,7 @@ static int delete_key_exec (bContext *C, wmOperator *op)
for (fcu= act->curves.first; fcu; fcu= fcn) {
fcn= fcu->next;
success+= deletekey(id, fcu->rna_path, fcu->array_index, cfra, 0);
success+= deletekey(id, NULL, fcu->rna_path, fcu->array_index, cfra, 0);
}
}

View File

@@ -73,12 +73,12 @@ enum {
* Use this to create any necessary animation data, and then insert a keyframe
* using the current value being keyframed, in the relevant place. Returns success.
*/
short insertkey(struct ID *id, const char rna_path[], int array_index, float cfra, short flag);
short insertkey(struct ID *id, const char group[], const char rna_path[], int array_index, float cfra, short flag);
/* Main Keyframing API call:
* Use this to delete keyframe on current frame for relevant channel. Will perform checks just in case.
*/
short deletekey(struct ID *id, const char rna_path[], int array_index, float cfra, short flag);
short deletekey(struct ID *id, const char group[], const char rna_path[], int array_index, float cfra, short flag);
/* Main Keyframe Management operators:

View File

@@ -594,7 +594,7 @@ void draw_channel_names(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
indent= 0;
special= -1;
offset= (ale->id) ? 21 : 0;
offset= (ale->id) ? 18 : 0;
/* only show expand if there are any channels */
if (agrp->channels.first) {
@@ -619,8 +619,8 @@ void draw_channel_names(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
indent = 0;
//group= (ale->grp) ? 1 : 0;
//grp= ale->grp;
group= (fcu->grp) ? 1 : 0;
grp= fcu->grp;
switch (ale->ownertype) {
case ANIMTYPE_NONE: /* no owner */
@@ -650,9 +650,7 @@ void draw_channel_names(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
sel = SEL_FCU(fcu);
// for now, we just print the full path... this needs more work!
getname_anim_fcurve(name, ale->id, fcu);
//sprintf(name, "%s[%d]", fcu->rna_path, fcu->array_index);
}
break;

View File

@@ -299,6 +299,7 @@ static void action_channel_area_listener(ARegion *ar, wmNotifier *wmn)
switch(wmn->data) {
case ND_BONE_ACTIVE:
case ND_BONE_SELECT:
case ND_KEYS:
ED_region_tag_redraw(ar);
break;
}

View File

@@ -875,7 +875,7 @@ void graph_draw_channel_names(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar)
indent= 0;
special= -1;
offset= (ale->id) ? 21 : 0;
offset= (ale->id) ? 18 : 0;
/* only show expand if there are any channels */
if (agrp->channels.first) {
@@ -900,8 +900,8 @@ void graph_draw_channel_names(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar)
indent = 0;
//group= (ale->grp) ? 1 : 0;
//grp= ale->grp;
group= (fcu->grp) ? 1 : 0;
grp= fcu->grp;
// XXX include some UI element to allow toggling of visibility

View File

@@ -122,7 +122,6 @@ static void get_keyframe_extents (bAnimContext *ac, float *xmin, float *xmax, fl
/* get range and apply necessary scaling before */
calc_fcurve_range(fcu, &tmin, &tmax);
tmin= tmax= 0.0f; // xxx
if (nob) {
tmin= get_action_frame_inv(nob, tmin);

View File

@@ -100,7 +100,7 @@ static SpaceLink *graph_new(const bContext *C)
ar->regiontype= RGN_TYPE_WINDOW;
ar->v2d.tot.xmin= 0.0f;
ar->v2d.tot.ymin= -10.0f;
ar->v2d.tot.ymin= (float)scene->r.sfra - 10.0f;
ar->v2d.tot.xmax= (float)scene->r.efra;
ar->v2d.tot.ymax= 10.0f;