== Action Editor - 'Long' Keyframes ==

When animating, it is often useful to be able to visually see where the
'pauses' are between keyframes. Long keyframes do this - linking two
keyframes in the same channel together.

Long keyframes are only drawn when the two keyframes have the exact
same values. This has to happen for every ipo-curve represented by the
keyframes shown for a long keyframe to be drawn.

I've added two new theme colours for the action editor. They are for
the selected and deselected colours of the long keyframes (currently
defaulted to be the same as the NLA strip selection colours).
This commit is contained in:
2006-12-15 05:51:53 +00:00
parent e4340d1b58
commit c43b064895
5 changed files with 202 additions and 165 deletions

View File

@@ -35,16 +35,39 @@
struct BezTriple; struct BezTriple;
struct Ipo; struct Ipo;
struct IpoCurve;
struct gla2DDrawInfo; struct gla2DDrawInfo;
struct bAction; struct bAction;
struct Object; struct Object;
struct ListBase;
/* 'Long Keyframe' Struct */
typedef struct ActKeyBlock {
struct ActKeyBlock *next, *prev;
short sel, handle_type;
float val;
float start, end;
/* only while drawing - used to determine if block needs to be drawn */
short modified;
short incurve, totcurve;
} ActKeyBlock;
/*Action Generics */
void draw_cfra_action(void); void draw_cfra_action(void);
void draw_ipo_channel(struct gla2DDrawInfo *di, struct Ipo *ipo, int flags, float ypos); int count_action_levels (struct bAction *act);
void draw_action_channel(struct gla2DDrawInfo *di, struct bAction *act, int flags, float ypos);
void draw_object_channel(struct gla2DDrawInfo *di, struct Object *ob, int flags, float ypos);
int count_action_levels (bAction *act); /* Channel Drawing */
void draw_icu_channel(struct gla2DDrawInfo *di, IpoCurve *icu, float ypos);
void draw_ipo_channel(struct gla2DDrawInfo *di, Ipo *ipo, float ypos);
void draw_action_channel(struct gla2DDrawInfo *di, bAction *act, float ypos);
void draw_object_channel(struct gla2DDrawInfo *di, Object *ob, float ypos);
/* Keydata Generation */
void icu_to_keylist(struct IpoCurve *icu, ListBase *keys, ListBase *blocks);
void ipo_to_keylist(struct Ipo *ipo, ListBase *keys, ListBase *blocks);
void action_to_keylist(bAction *act, ListBase *keys, ListBase *blocks);
void ob_to_keylist(Object *ob, ListBase *keys, ListBase *blocks);
#endif /* BDR_DRAWACTION_H */ #endif /* BDR_DRAWACTION_H */

View File

@@ -91,14 +91,6 @@
#include "mydevice.h" #include "mydevice.h"
/* local functions ----------------------------------------------------- */
static ListBase *ipo_to_keylist(Ipo *ipo, int flags);
static ListBase *action_to_keylist(bAction *act, int flags);
static ListBase *ob_to_keylist(Object *ob, int flags);
static ListBase *icu_to_keylist(IpoCurve *icu, int flags);
void draw_icu_channel(gla2DDrawInfo *di, IpoCurve *icu, int flags, float ypos);
static void meshactionbuts(SpaceAction *saction, Object *ob, Key *key) static void meshactionbuts(SpaceAction *saction, Object *ob, Key *key)
{ {
int i; int i;
@@ -484,12 +476,12 @@ static void draw_channel_strips(SpaceAction *saction)
for (chan=act->chanbase.first; chan; chan=chan->next){ for (chan=act->chanbase.first; chan; chan=chan->next){
if((chan->flag & ACHAN_HIDDEN)==0) { if((chan->flag & ACHAN_HIDDEN)==0) {
draw_ipo_channel(di, chan->ipo, 0, y); draw_ipo_channel(di, chan->ipo, y);
y-=CHANNELHEIGHT+CHANNELSKIP; y-=CHANNELHEIGHT+CHANNELSKIP;
/* Draw constraint channels */ /* Draw constraint channels */
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){ for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
draw_ipo_channel(di, conchan->ipo, 0, y); draw_ipo_channel(di, conchan->ipo, y);
y-=CHANNELHEIGHT+CHANNELSKIP; y-=CHANNELHEIGHT+CHANNELSKIP;
} }
} }
@@ -559,7 +551,7 @@ static void draw_mesh_strips(SpaceAction *saction, Key *key)
/* draw the little squares /* draw the little squares
*/ */
draw_icu_channel(di, icu, 0, y); draw_icu_channel(di, icu, y);
} }
glaEnd2DDraw(di); glaEnd2DDraw(di);
@@ -747,67 +739,42 @@ void drawactionspace(ScrArea *sa, void *spacedata)
curarea->win_swap= WIN_BACK_OK; curarea->win_swap= WIN_BACK_OK;
} }
#if 0 static void draw_keylist(gla2DDrawInfo *di, ListBase *keys, ListBase *blocks, float ypos)
/** Draw a nicely beveled diamond shape (in screen space) */
static void draw_key_but(int x, int y, int w, int h, int sel)
{
int xmin= x, ymin= y;
int xmax= x+w-1, ymax= y+h-1;
int xc= (xmin+xmax)/2, yc= (ymin+ymax)/2;
/* interior */
if (sel) glColor3ub(0xF1, 0xCA, 0x13);
else glColor3ub(0xAC, 0xAC, 0xAC);
glBegin(GL_QUADS);
glVertex2i(xc, ymin);
glVertex2i(xmax, yc);
glVertex2i(xc, ymax);
glVertex2i(xmin, yc);
glEnd();
/* bevel */
glBegin(GL_LINE_LOOP);
if (sel) glColor3ub(0xD0, 0x7E, 0x06);
else glColor3ub(0x8C, 0x8C, 0x8C);
/* under */
glVertex2i(xc, ymin+1);
glVertex2i(xmax-1, yc);
if (sel) glColor3ub(0xF4, 0xEE, 0x8E);
else glColor3ub(0xDF, 0xDF, 0xDF);
/* top */
glVertex2i(xc, ymax-1);
glVertex2i(xmin+1, yc);
glEnd();
/* outline */
glColor3ub(0,0,0);
glBegin(GL_LINE_LOOP);
glVertex2i(xc, ymin);
glVertex2i(xmax, yc);
glVertex2i(xc, ymax);
glVertex2i(xmin, yc);
glEnd();
}
#endif
static void draw_keylist(gla2DDrawInfo *di, ListBase *elems, float ypos)
{ {
CfraElem *ce; CfraElem *ce;
ActKeyBlock *ab;
if (!elems) if ((keys==NULL) || (blocks==NULL))
return; return;
glEnable(GL_BLEND); glEnable(GL_BLEND);
for (ce= elems->first; ce; ce= ce->next){ /* draw keyblocks */
for (ab= blocks->first; ab; ab= ab->next) {
/* only draw keyblock if it appears in all curves sampled */
if (ab->incurve == ab->totcurve) {
int sc_xa, sc_ya;
int sc_xb, sc_yb;
/* get co-ordinates of block */
gla2DDrawTranslatePt(di, ab->start, ypos, &sc_xa, &sc_ya);
gla2DDrawTranslatePt(di, ab->end, ypos, &sc_xb, &sc_yb);
/* draw block */
if (ab->sel & 1)
BIF_ThemeColor4(TH_STRIP_SELECT);
else
BIF_ThemeColor4(TH_STRIP);
glRectf(sc_xa, sc_ya-3, sc_xb, sc_yb+5);
}
}
/* draw keys */
for (ce= keys->first; ce; ce= ce->next) {
int sc_x, sc_y; int sc_x, sc_y;
/* get co-ordinate to draw at */
gla2DDrawTranslatePt(di, ce->cfra, ypos, &sc_x, &sc_y); gla2DDrawTranslatePt(di, ce->cfra, ypos, &sc_x, &sc_y);
// draw_key_but(sc_x-5, sc_y-6, 13, 13, (ce->sel & 1));
if(ce->sel & 1) BIF_icon_draw_aspect(sc_x-7, sc_y-6, ICON_SPACE2, 1.0f); if(ce->sel & 1) BIF_icon_draw_aspect(sc_x-7, sc_y-6, ICON_SPACE2, 1.0f);
else BIF_icon_draw_aspect(sc_x-7, sc_y-6, ICON_SPACE3, 1.0f); else BIF_icon_draw_aspect(sc_x-7, sc_y-6, ICON_SPACE3, 1.0f);
@@ -816,157 +783,189 @@ static void draw_keylist(gla2DDrawInfo *di, ListBase *elems, float ypos)
glDisable(GL_BLEND); glDisable(GL_BLEND);
} }
void draw_object_channel(gla2DDrawInfo *di, Object *ob, int flags, float ypos) void draw_object_channel(gla2DDrawInfo *di, Object *ob, float ypos)
{ {
ListBase *elems; ListBase keys = {0, 0};
ListBase blocks = {0, 0};
elems = ob_to_keylist(ob, flags); ob_to_keylist(ob, &keys, &blocks);
if (elems){ draw_keylist(di, &keys, &blocks, ypos);
draw_keylist(di, elems, ypos);
BLI_freelistN(elems); BLI_freelistN(&keys);
MEM_freeN(elems); BLI_freelistN(&blocks);
}
} }
void draw_ipo_channel(gla2DDrawInfo *di, Ipo *ipo, int flags, float ypos) void draw_ipo_channel(gla2DDrawInfo *di, Ipo *ipo, float ypos)
{ {
ListBase *elems; ListBase keys = {0, 0};
ListBase blocks = {0, 0};
elems = ipo_to_keylist(ipo, flags); ipo_to_keylist(ipo, &keys, &blocks);
if (elems){ draw_keylist(di, &keys, &blocks, ypos);
draw_keylist(di, elems, ypos);
BLI_freelistN(elems); BLI_freelistN(&keys);
MEM_freeN(elems); BLI_freelistN(&blocks);
}
} }
void draw_icu_channel(gla2DDrawInfo *di, IpoCurve *icu, int flags, float ypos) void draw_icu_channel(gla2DDrawInfo *di, IpoCurve *icu, float ypos)
{ {
/* draw the keys for an IpoCurve ListBase keys = {0, 0};
ListBase blocks = {0, 0};
icu_to_keylist(icu, &keys, &blocks);
draw_keylist(di, &keys, &blocks, ypos);
BLI_freelistN(&keys);
BLI_freelistN(&blocks);
}
void draw_action_channel(gla2DDrawInfo *di, bAction *act, float ypos)
{
ListBase keys = {0, 0};
ListBase blocks = {0, 0};
action_to_keylist(act, &keys, &blocks);
/* Keyblocks need to be freed here, otherwise,
* they will draw in the nla editor as keyframes
* for the active strip. We don't want this as
* it could get confusing...
*/ */
ListBase *elems; BLI_freelistN(&blocks);
elems = icu_to_keylist(icu, flags); draw_keylist(di, &keys, &blocks, ypos);
if (elems){ BLI_freelistN(&keys);
draw_keylist(di, elems, ypos);
BLI_freelistN(elems);
MEM_freeN(elems);
}
} }
void draw_action_channel(gla2DDrawInfo *di, bAction *act, int flags, float ypos) static void add_bezt_to_keyblockslist(BezTriple *bezt, BezTriple *prev, ListBase *blocks)
{ {
ListBase *elems; /* The equivilant of add_to_cfra_elem except this version
* makes ActKeyBlocks - one of the two datatypes required
* for action editor drawing.
*/
ActKeyBlock *ab, *abn;
elems = action_to_keylist(act, flags); /* check if block needed */
if (bezt->vec[1][1] != prev->vec[1][1])
return;
if (elems){ /* try to find a keyblock that starts on the previous beztriple */
draw_keylist(di, elems, ypos); for (ab= blocks->first; ab; ab= ab->next) {
/* check if alter existing block or add new block */
if (ab->start == prev->vec[1][0]) {
/* replace end frame if end frame is less than current beztriple */
if (ab->end < bezt->vec[1][0])
ab->end= bezt->vec[1][0];
BLI_freelistN(elems); /* set selection status and 'touched' status */
MEM_freeN(elems); if (BEZSELECTED(bezt)) ab->sel = SELECT;
ab->modified += 1;
return;
} }
else if (ab->start > prev->vec[1][0]) break;
}
/* add new block */
abn= MEM_callocN(sizeof(ActKeyBlock), "add_bezt_to_keyblockslist");
if (ab) BLI_insertlinkbefore(blocks, ab, abn);
else BLI_addtail(blocks, abn);
abn->start= prev->vec[1][0];
abn->end= bezt->vec[1][0];
abn->val= bezt->vec[1][1];
if (BEZSELECTED(prev) || BEZSELECTED(bezt))
abn->sel = SELECT;
else
abn->sel = 0;
abn->modified += 1;
} }
static ListBase *ob_to_keylist(Object *ob, int flags) void ob_to_keylist(Object *ob, ListBase *keys, ListBase *blocks)
{ {
bConstraintChannel *conchan; bConstraintChannel *conchan;
ListBase *elems = NULL;
if (ob) { if (ob) {
/* allocate memory for list */
elems = MEM_callocN(sizeof(ListBase), "ObKeylist");
/* Add object keyframes */ /* Add object keyframes */
if (ob->ipo) { if (ob->ipo) {
make_cfra_list(ob->ipo, elems); ipo_to_keylist(ob->ipo, keys, blocks);
} }
/* Add constraint keyframes */ /* Add constraint keyframes */
for (conchan=ob->constraintChannels.first; conchan; conchan=conchan->next){ for (conchan=ob->constraintChannels.first; conchan; conchan=conchan->next){
if(conchan->ipo) { if(conchan->ipo) {
make_cfra_list(conchan->ipo, elems); ipo_to_keylist(conchan->ipo, keys, blocks);
} }
} }
/* Add object data keyframes */ /* Add object data keyframes */
// TODO?? // TODO??
} }
/* return pointer to listbase */
return elems;
} }
static ListBase *icu_to_keylist(IpoCurve *icu, int flags) void icu_to_keylist(IpoCurve *icu, ListBase *keys, ListBase *blocks)
{ {
/* compile a list of all bezier triples in an BezTriple *bezt, *prev;
* IpoCurve. ActKeyBlock *ab, *abn;
*/
ListBase *elems = NULL;
BezTriple *bezt;
int v; int v;
if (icu && icu->totvert){ if (icu && icu->totvert){
elems = MEM_callocN(sizeof(ListBase), "IpoCurveKeylist"); /* loop through beztriples, making ActKeys and ActKeyBlocks */
/* loop through beztriples, making CfraElems */
bezt= icu->bezt; bezt= icu->bezt;
prev= NULL;
for (v=0; v<icu->totvert; v++, bezt++) { for (v=0; v<icu->totvert; v++, bezt++) {
add_to_cfra_elem(elems, bezt); add_to_cfra_elem(keys, bezt);
} if (v) add_bezt_to_keyblockslist(bezt, prev, blocks);
prev= bezt;
} }
/* return pointer to listbase */ /* update the number of curves the blocks have appeared in */
return elems; for (ab= blocks->first; ab; ab= abn) {
abn= ab->next;
if (ab->modified) {
ab->modified = 0;
ab->incurve += 1;
}
ab->totcurve += 1;
}
}
} }
static ListBase *ipo_to_keylist(Ipo *ipo, int flags) void ipo_to_keylist(Ipo *ipo, ListBase *keys, ListBase *blocks)
{ {
ListBase *elems = NULL; IpoCurve *icu;
if (ipo) { if (ipo) {
/* allocate memory for list of keys */ for (icu= ipo->curve.first; icu; icu= icu->next) {
elems= MEM_callocN(sizeof(ListBase), "IpoKeylist"); icu_to_keylist(icu, keys, blocks);
}
/* make list */
make_cfra_list(ipo, elems);
} }
/* return pointer to listbase */
return elems;
} }
static ListBase *action_to_keylist(bAction *act, int flags) void action_to_keylist(bAction *act, ListBase *keys, ListBase *blocks)
{ {
bActionChannel *achan; bActionChannel *achan;
bConstraintChannel *conchan; bConstraintChannel *conchan;
ListBase *elems = NULL;
if (act) { if (act) {
/* allocate memory for list of keys */
elems= MEM_callocN(sizeof(ListBase), "ActionKeylist");
/* loop through action channels */ /* loop through action channels */
for (achan= act->chanbase.first; achan; achan= achan->next) { for (achan= act->chanbase.first; achan; achan= achan->next) {
/* firstly, add keys from action channel's ipo block */ /* firstly, add keys from action channel's ipo block */
if (achan->ipo) { if (achan->ipo) {
make_cfra_list(achan->ipo, elems); ipo_to_keylist(achan->ipo, keys, blocks);
} }
/* then, add keys from constraint channels */ /* then, add keys from constraint channels */
for (conchan= achan->constraintChannels.first; conchan; conchan= conchan->next) { for (conchan= achan->constraintChannels.first; conchan; conchan= conchan->next) {
if (conchan->ipo) { if (conchan->ipo) {
make_cfra_list(conchan->ipo, elems); ipo_to_keylist(achan->ipo, keys, blocks);
} }
} }
} }
} }
/* return pointer to listbase */
return elems;
} }

View File

@@ -280,7 +280,7 @@ static void draw_nla_strips_keys(SpaceNla *snla)
glDisable (GL_BLEND); glDisable (GL_BLEND);
/* Draw the ipo keys */ /* Draw the ipo keys */
draw_object_channel(di, ob, 0, y); draw_object_channel(di, ob, y);
y-=NLACHANNELHEIGHT+NLACHANNELSKIP; y-=NLACHANNELHEIGHT+NLACHANNELSKIP;
@@ -312,7 +312,7 @@ static void draw_nla_strips_keys(SpaceNla *snla)
/* Draw the action keys, optionally corrected for active strip */ /* Draw the action keys, optionally corrected for active strip */
map_active_strip(di, ob, 0); map_active_strip(di, ob, 0);
draw_action_channel(di, ob->action, 0, y); draw_action_channel(di, ob->action, y);
map_active_strip(di, ob, 1); map_active_strip(di, ob, 1);
y-=NLACHANNELHEIGHT+NLACHANNELSKIP; y-=NLACHANNELHEIGHT+NLACHANNELSKIP;

View File

@@ -612,6 +612,8 @@ char *BIF_ThemeColorsPup(int spacetype)
str += sprintf(str, "View Sliders %%x%d|", TH_SHADE1); str += sprintf(str, "View Sliders %%x%d|", TH_SHADE1);
str += sprintf(str, "Channels %%x%d|", TH_SHADE2); str += sprintf(str, "Channels %%x%d|", TH_SHADE2);
str += sprintf(str, "Channels Selected %%x%d|", TH_HILITE); str += sprintf(str, "Channels Selected %%x%d|", TH_HILITE);
str += sprintf(str, "Long Key %%x%d|", TH_STRIP);
str += sprintf(str, "Long Key selected %%x%d|", TH_STRIP_SELECT);
break; break;
case SPACE_IMAGE: case SPACE_IMAGE:
str += sprintf(str, "%%l|"); str += sprintf(str, "%%l|");

View File

@@ -304,10 +304,12 @@ static void init_userdef_file(void)
SETCOL(btheme->tnode.syntaxv, 142, 138, 145, 255); /* generator */ SETCOL(btheme->tnode.syntaxv, 142, 138, 145, 255); /* generator */
SETCOL(btheme->tnode.syntaxc, 120, 145, 120, 255); /* group */ SETCOL(btheme->tnode.syntaxc, 120, 145, 120, 255); /* group */
} }
/* Group theme colours */
if(btheme->tv3d.group[3]==0) { if(btheme->tv3d.group[3]==0) {
SETCOL(btheme->tv3d.group, 0x10, 0x40, 0x10, 255); SETCOL(btheme->tv3d.group, 0x10, 0x40, 0x10, 255);
SETCOL(btheme->tv3d.group_active, 0x66, 0xFF, 0x66, 255); SETCOL(btheme->tv3d.group_active, 0x66, 0xFF, 0x66, 255);
} }
/* Sequence editor theme*/
if(btheme->tseq.movie[3]==0) { if(btheme->tseq.movie[3]==0) {
SETCOL(btheme->tseq.movie, 81, 105, 135, 255); SETCOL(btheme->tseq.movie, 81, 105, 135, 255);
SETCOL(btheme->tseq.image, 109, 88, 129, 255); SETCOL(btheme->tseq.image, 109, 88, 129, 255);
@@ -329,6 +331,17 @@ static void init_userdef_file(void)
} }
} }
if (G.main->versionfile <= 242) {
bTheme *btheme;
/* long keyframe colour */
for(btheme= U.themes.first; btheme; btheme= btheme->next) {
/* check for alpha==0 is safe, then color was never set */
if(btheme->tact.strip[3]==0) {
SETCOL(btheme->tact.strip_select, 0xff, 0xff, 0xaa, 204);
SETCOL(btheme->tact.strip, 0xe4, 0x9c, 0xc6, 204);
}
}
}
if (U.undosteps==0) U.undosteps=32; if (U.undosteps==0) U.undosteps=32;