Index: source/blender/src/drawaction.c =================================================================== --- source/blender/src/drawaction.c (revision 13599) +++ source/blender/src/drawaction.c (working copy) @@ -98,6 +98,8 @@ #include "interface.h" #include "mydevice.h" +#include + /********************************** Slider Stuff **************************** */ /* sliders for shapekeys */ @@ -1194,197 +1196,288 @@ abn->modified = 1; } -/* helper function - find actkeycolumn that occurs on cframe */ -static ActKeyColumn *cfra_find_actkeycolumn (ListBase *keys, float cframe) +static ActKeysInc *init_aki_data() { - ActKeyColumn *ak; + static ActKeysInc aki; - if (keys==NULL) + /* init data of static struct here */ + if ((curarea->spacetype == SPACE_ACTION) && NLA_ACTION_SCALED) + aki.ob= OBACT; + else if (curarea->spacetype == SPACE_NLA) + aki.ob= NULL; // FIXME + else + aki.ob= NULL; + + aki.start= G.v2d->cur.xmin - 10; + aki.end= G.v2d->cur.xmax + 10; + + /* only pass pointer for Action Editor if enabled (for now) */ + if ((curarea->spacetype == SPACE_ACTION) && (G.saction->flag & SACTION_HORIZOPTIMISEON)) + return &aki; + else return NULL; - - for (ak= keys->first; ak; ak= ak->next) { - if (ak->cfra == cframe) - return ak; +} + +static short bezt_in_aki_range (ActKeysInc *aki, BezTriple *bezt) +{ + /* when aki == NULL, we don't care about range */ + if (aki == NULL) + return 1; + + /* if nla-scaling is in effect, apply appropriate scaling adjustments */ + if (aki->ob) { + float frame= get_action_frame_inv(aki->ob, bezt->vec[1][0]); + return IN_RANGE(frame, aki->start, aki->end); } - - return NULL; + else { + /* check if in range */ + return IN_RANGE(bezt->vec[1][0], aki->start, aki->end); + } } -/* Draw a simple diamond shape with a filled in center (in screen space) */ -static void draw_key_but(int x, int y, short w, short h, int sel) +void draw_object_channel(gla2DDrawInfo *di, Object *ob, float ypos) { - int xmin= x, ymin= y; - int xmax= x+w-1, ymax= y+h-1; - int xc= (xmin+xmax)/2, yc= (ymin+ymax)/2; + bConstraintChannel *conchan; + + if (ob) { + /* draw object keyframes */ + if (ob->ipo) + draw_ipo_channel(di, ob->ipo, ypos); + + /* draw constraint keyframes */ + for (conchan=ob->constraintChannels.first; conchan; conchan=conchan->next) { + if (conchan->ipo) + draw_ipo_channel(di, conchan->ipo, ypos); + } + } +} + +/* finds the first key before t using a binary search */ +int find_key(IpoCurve* icu, float t) +{ + int lbound = 0; + int ubound = icu->totvert; + int idx = 0; + int diff; - /* interior - hardcoded colours (for selected and unselected only) */ - if (sel) glColor3ub(0xF1, 0xCA, 0x13); - else glColor3ub(0xE9, 0xE9, 0xE9); + /* handle common trivial scenarios */ + if (t < icu->bezt[idx].vec[1][0]) { + return 0; + } + if (t > icu->bezt[icu->totvert - 1].vec[1][0]) { + return icu->totvert - 1; + } - glBegin(GL_QUADS); - glVertex2i(xc, ymin); - glVertex2i(xmax, yc); - glVertex2i(xc, ymax); - glVertex2i(xmin, yc); - glEnd(); + while (ubound - lbound > 1) { + diff = (ubound - lbound) / 2; + idx = lbound + diff; + + if (icu->bezt[idx].vec[1][0] < t) { + lbound += diff; + } else { + ubound = lbound + diff; + } + } - - /* outline */ - glColor3ub(0, 0, 0); - - glBegin(GL_LINE_LOOP); - glVertex2i(xc, ymin); - glVertex2i(xmax, yc); - glVertex2i(xc, ymax); - glVertex2i(xmin, yc); - glEnd(); + return idx; } -static void draw_keylist(gla2DDrawInfo *di, ListBase *keys, ListBase *blocks, float ypos) +/* batch draw all of the keyframes in an ipo curve using GL_QUADS */ +void draw_icu_keyframes(gla2DDrawInfo *di, ActKeysInc *aki, IpoCurve* icu, float ypos, int selected) { - ActKeyColumn *ak; - ActKeyBlock *ab; + BezTriple *bezt; + int v; + int sc_x, sc_y; + int last_sc_x = -1; + int start, end; + const int keysize = 4; + const int bordsize = keysize + 1; + + if (!icu || !icu->totvert) { + return; + } - glEnable(GL_BLEND); + /* find the first visible start key and the last visible end key */ + if (aki == NULL) { + start = 0; + end = icu->totvert - 1; + } else if (aki->ob) { + start = find_key(icu, get_action_frame(aki->ob, aki->start)); + end = find_key(icu, get_action_frame(aki->ob, aki->end)); + } else { + start = find_key(icu, aki->start); + end = find_key(icu, aki->end); + } - /* draw keyblocks */ - if (blocks) { - for (ab= blocks->first; ab; ab= ab->next) { - short startCurves, endCurves, totCurves; + gla2DDrawTranslatePt(di, icu->bezt[start].vec[1][0], ypos, &sc_x, &sc_y); + last_sc_x = sc_x - 2; + + /* for efficiency we need to batch draw the all the keyframe borders first */ + glColor3ub(0, 0, 0); + glBegin(GL_QUADS); + for (v=start; v<= end; v++) { + bezt = &icu->bezt[v]; + if(BEZSELECTED(bezt) == selected) { + gla2DDrawTranslatePt(di, bezt->vec[1][0], ypos, &sc_x, &sc_y); - /* find out how many curves occur at each keyframe */ - ak= cfra_find_actkeycolumn(keys, ab->start); - startCurves = (ak)? ak->totcurve: 0; - - ak= cfra_find_actkeycolumn(keys, ab->end); - endCurves = (ak)? ak->totcurve: 0; - - /* only draw keyblock if it appears in at all of the keyframes at lowest end */ - if (!startCurves && !endCurves) - continue; - else - totCurves = (startCurves>endCurves)? endCurves: startCurves; - - if (ab->totcurve >= totCurves) { - 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) - BIF_ThemeColor4(TH_STRIP_SELECT); - else - BIF_ThemeColor4(TH_STRIP); - glRectf(sc_xa, sc_ya-3, sc_xb, sc_yb+5); + /* avoid redrawing over the same pixels */ + if (sc_x - last_sc_x > 1) { + glVertex2i(sc_x, sc_y - bordsize); + glVertex2i(sc_x + bordsize, sc_y); + glVertex2i(sc_x, sc_y + bordsize); + glVertex2i(sc_x - bordsize, sc_y); + last_sc_x = sc_x; } } } + glEnd(); - /* draw keys */ - if (keys) { - for (ak= keys->first; ak; ak= ak->next) { - int sc_x, sc_y; + gla2DDrawTranslatePt(di, icu->bezt[start].vec[1][0], ypos, &sc_x, &sc_y); + last_sc_x = sc_x - 2; + + if (selected) { + glColor3ub(0xF1, 0xCA, 0x13); + } else { + glColor3ub(0xE9, 0xE9, 0xE9); + } + + /* draw the yellow keyframe cores */ + glBegin(GL_QUADS); + for (v = start; v <= end; v++) { + bezt = &icu->bezt[v]; + if(BEZSELECTED(bezt) == selected) { + gla2DDrawTranslatePt(di, bezt->vec[1][0], ypos, &sc_x, &sc_y); - /* get co-ordinate to draw at */ - gla2DDrawTranslatePt(di, ak->cfra, ypos, &sc_x, &sc_y); - - /* draw using icons - old way which is slower but more proven */ - //if(ak->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); - - /* draw using OpenGL - slightly uglier but faster */ - draw_key_but(sc_x-5, sc_y-4, 11, 11, (ak->sel & SELECT)); - } + if (sc_x - last_sc_x > 1) { + glVertex2i(sc_x, sc_y - keysize); + glVertex2i(sc_x + keysize, sc_y); + glVertex2i(sc_x, sc_y + keysize); + glVertex2i(sc_x - keysize, sc_y); + last_sc_x = sc_x; + } + } } - - glDisable(GL_BLEND); + glEnd(); } - -static ActKeysInc *init_aki_data() +void draw_block(gla2DDrawInfo *di, float tstart, float tend, float ypos, int selected) { - static ActKeysInc aki; + int sc_xa, sc_ya; + int sc_xb, sc_yb; + gla2DDrawTranslatePt(di, tstart, ypos, &sc_xa, &sc_ya); + gla2DDrawTranslatePt(di, tend, ypos, &sc_xb, &sc_yb); - /* init data of static struct here */ - if ((curarea->spacetype == SPACE_ACTION) && NLA_ACTION_SCALED) - aki.ob= OBACT; - else if (curarea->spacetype == SPACE_NLA) - aki.ob= NULL; // FIXME - else - aki.ob= NULL; - - aki.start= G.v2d->cur.xmin - 10; - aki.end= G.v2d->cur.xmax + 10; - - /* only pass pointer for Action Editor if enabled (for now) */ - if ((curarea->spacetype == SPACE_ACTION) && (G.saction->flag & SACTION_HORIZOPTIMISEON)) - return &aki; - else - return NULL; + if (selected) { + BIF_ThemeColor4(TH_STRIP_SELECT); + } else { + BIF_ThemeColor4(TH_STRIP); + } + glRectf(sc_xa + 1, sc_ya-2, sc_xb - 1, sc_yb+2); } -void draw_object_channel(gla2DDrawInfo *di, Object *ob, float ypos) +void draw_icu_keyblocks(gla2DDrawInfo *di, ActKeysInc *aki, IpoCurve* icu, float ypos) { - ListBase keys = {0, 0}; - ListBase blocks = {0, 0}; - ActKeysInc *aki = init_aki_data(); - - ob_to_keylist(ob, &keys, &blocks, aki); - draw_keylist(di, &keys, &blocks, ypos); + BezTriple *bezt = icu->bezt; + BezTriple *kbstart, *kbend, *prev; + int v; + int selected = 0; - BLI_freelistN(&keys); - BLI_freelistN(&blocks); + kbstart = kbend = bezt; + bezt++; + for (v=1; vtotvert + 1; v++, bezt++) { + kbend = bezt; + prev = kbend - 1; + + if (BEZSELECTED(prev)) { + selected = 1; + } + + if (v == icu->totvert || + IS_EQ(kbend->vec[1][1], prev->vec[1][1]) == 0 || + IS_EQ(kbend->vec[1][1], kbend->vec[0][1]) == 0 || + IS_EQ(prev->vec[1][1], prev->vec[2][1]) == 0 + ) { + + if (kbstart < prev) { + draw_block(di, kbstart->vec[1][0], prev->vec[1][0], ypos, selected); + } + + kbstart = kbend = bezt; + selected = 0; + } + } } -void draw_ipo_channel(gla2DDrawInfo *di, Ipo *ipo, float ypos) +void draw_icu_channel(gla2DDrawInfo *di, IpoCurve *icu, float ypos) { - ListBase keys = {0, 0}; - ListBase blocks = {0, 0}; ActKeysInc *aki = init_aki_data(); - ipo_to_keylist(ipo, &keys, &blocks, aki); - draw_keylist(di, &keys, &blocks, ypos); - - BLI_freelistN(&keys); - BLI_freelistN(&blocks); + draw_icu_keyblocks(di, aki, icu, ypos); + draw_icu_keyframes(di, aki, icu, ypos, 0); + draw_icu_keyframes(di, aki, icu, ypos, 1); } -void draw_icu_channel(gla2DDrawInfo *di, IpoCurve *icu, float ypos) +void draw_ipo_channel(gla2DDrawInfo *di, Ipo *ipo, float ypos) { - ListBase keys = {0, 0}; - ListBase blocks = {0, 0}; + IpoCurve *icu; ActKeysInc *aki = init_aki_data(); - - icu_to_keylist(icu, &keys, &blocks, aki); - draw_keylist(di, &keys, &blocks, ypos); - BLI_freelistN(&keys); - BLI_freelistN(&blocks); + if (ipo) { + /* draw blocks */ + for (icu= ipo->curve.first; icu; icu= icu->next) { + draw_icu_keyblocks(di, aki, icu, ypos); + } + /* draw unselected */ + for (icu= ipo->curve.first; icu; icu= icu->next) { + draw_icu_keyframes(di, aki, icu, ypos, 0); + } + /* draw selected */ + for (icu= ipo->curve.first; icu; icu= icu->next) { + draw_icu_keyframes(di, aki, icu, ypos, 1); + } + } } void draw_agroup_channel(gla2DDrawInfo *di, bActionGroup *agrp, float ypos) -{ - ListBase keys = {0, 0}; - ListBase blocks = {0, 0}; - ActKeysInc *aki = init_aki_data(); +{ + bActionChannel *achan; + bConstraintChannel *conchan; - agroup_to_keylist(agrp, &keys, &blocks, aki); - draw_keylist(di, &keys, &blocks, ypos); - BLI_freelistN(&keys); - BLI_freelistN(&blocks); + if (agrp) { + /* loop through action channels */ + for (achan= agrp->channels.first; achan && achan->grp==agrp; achan= achan->next) { + /* firstly, add keys from action channel's ipo block */ + if (achan->ipo) + draw_ipo_channel(di, achan->ipo, ypos); + + /* then, add keys from constraint channels */ + for (conchan= achan->constraintChannels.first; conchan; conchan= conchan->next) { + if (conchan->ipo) + draw_ipo_channel(di, conchan->ipo, ypos); + } + } + } } void draw_action_channel(gla2DDrawInfo *di, bAction *act, float ypos) { - ListBase keys = {0, 0}; - ActKeysInc *aki = init_aki_data(); + bActionChannel *achan; + bConstraintChannel *conchan; - action_to_keylist(act, &keys, NULL, aki); - draw_keylist(di, &keys, NULL, ypos); - BLI_freelistN(&keys); + if (act) { + /* loop through action channels */ + for (achan= act->chanbase.first; achan; achan= achan->next) { + /* firstly, add keys from action channel's ipo block */ + if (achan->ipo) + draw_ipo_channel(di, achan->ipo, ypos); + + /* then, add keys from constraint channels */ + for (conchan= achan->constraintChannels.first; conchan; conchan= conchan->next) { + if (conchan->ipo) + draw_ipo_channel(di, conchan->ipo, ypos); + } + } + } } /* --------------- Conversion: data -> keyframe list ------------------ */ @@ -1409,23 +1502,6 @@ } } -static short bezt_in_aki_range (ActKeysInc *aki, BezTriple *bezt) -{ - /* when aki == NULL, we don't care about range */ - if (aki == NULL) - return 1; - - /* if nla-scaling is in effect, apply appropriate scaling adjustments */ - if (aki->ob) { - float frame= get_action_frame_inv(aki->ob, bezt->vec[1][0]); - return IN_RANGE(frame, aki->start, aki->end); - } - else { - /* check if in range */ - return IN_RANGE(bezt->vec[1][0], aki->start, aki->end); - } -} - void icu_to_keylist(IpoCurve *icu, ListBase *keys, ListBase *blocks, ActKeysInc *aki) { BezTriple *bezt;