Page Menu
Home
Search
Configure Global Search
Log In
Files
F5353
actnlaperf2-2.patch
Public
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Authored By
Adriano Macchietto (macchiea)
Nov 13 2013, 1:22 PM
Size
15 KB
Subscribers
None
actnlaperf2-2.patch
View Options
Index: source/blender/src/drawaction.c
===================================================================
--- source/blender/src/drawaction.c (revision 13600)
+++ source/blender/src/drawaction.c (working copy)
@@ -35,7 +35,10 @@
#include <math.h>
#include <stdlib.h>
+#include <string.h>
+#include <GL/gl.h>
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -1194,6 +1197,62 @@
abn->modified = 1;
}
+static ActKeysInc *init_aki_data()
+{
+ static ActKeysInc aki;
+
+ /* 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;
+}
+
+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 draw_object_channel(gla2DDrawInfo *di, Object *ob, float ypos)
+{
+ 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);
+ }
+ }
+}
+
/* helper function - find actkeycolumn that occurs on cframe */
static ActKeyColumn *cfra_find_actkeycolumn (ListBase *keys, float cframe)
{
@@ -1210,6 +1269,7 @@
return NULL;
}
+
/* 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)
{
@@ -1304,87 +1364,470 @@
}
-static ActKeysInc *init_aki_data()
+void insertsort_icu_keys(BezTriple* bezt, int totvert)
{
- static ActKeysInc aki;
+ int i, j;
+ BezTriple tmp;
- /* 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;
+ if (!bezt) {
+ return;
+ }
+
+ for (i = 1; i < totvert; ++i) {
+ for (j = i - 1; j >= 0; --j) {
+ if (bezt[j + 1].vec[1][0] < bezt[j].vec[1][0]) {
+ tmp = bezt[j];
+ bezt[j] = bezt[j + 1];
+ bezt[j + 1] = tmp;
+ } else {
+ break;
+ }
+ }
+ }
+}
+
+void insertsort_ipo_keys(Ipo* ipo)
+{
+ IpoCurve* cu;
+
+ if (!ipo)
+ return;
+
+ for (cu = ipo->curve.first; cu; cu = cu->next) {
+ insertsort_icu_keys(cu->bezt, cu->totvert);
+ }
+}
+
+/* find the key immediately before time t using a binary search */
+BezTriple* find_key(IpoCurve* icu, BezTriple* bezt, float t)
+{
+ int lbound = bezt - icu->bezt;
+ int ubound = icu->totvert;
+ int idx;
+ int diff;
+
+ if (!bezt) {
+ return NULL;
+ }
+
+ /* handle common trivial scenarios */
+ if (bezt->vec[1][0] > t) {
+ return NULL;
+ }
+ if (t > icu->bezt[icu->totvert - 1].vec[1][0]) {
+ return &icu->bezt[icu->totvert - 1];
+ }
+
+ while (ubound - lbound > 1) {
+ diff = (ubound - lbound) / 2;
+ idx = lbound + diff;
- aki.start= G.v2d->cur.xmin - 10;
- aki.end= G.v2d->cur.xmax + 10;
+ if (icu->bezt[idx].vec[1][0] < t) {
+ lbound += diff;
+ } else {
+ ubound = lbound + diff;
+ }
+ }
- /* 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;
+ return &icu->bezt[lbound];
}
-void draw_object_channel(gla2DDrawInfo *di, Object *ob, float ypos)
+void find_unculled_key_range(IpoCurve *icu, ActKeysInc *aki, BezTriple **start, BezTriple **end)
{
- ListBase keys = {0, 0};
- ListBase blocks = {0, 0};
- ActKeysInc *aki = init_aki_data();
+ if (!icu || icu->totvert == 0) {
+ *start = *end = NULL;
+ return;
+ }
+
+ if (!aki) {
+ *start = icu->bezt;
+ *end = &icu->bezt[icu->totvert - 1];
+ return;
+ }
+
+ if (aki->ob) {
+ *start = find_key(icu, icu->bezt, get_action_frame(aki->ob, aki->start));
+ *end = find_key(icu, icu->bezt, get_action_frame(aki->ob, aki->end));
+ } else {
+ *start = find_key(icu, icu->bezt, aki->start);
+ *end = find_key(icu, icu->bezt, aki->end);
+ }
+
+ if (!(*start)) {
+ *start = icu->bezt;
+ }
+}
- ob_to_keylist(ob, &keys, &blocks, aki);
- draw_keylist(di, &keys, &blocks, 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)
+{
+ BezTriple *bezt;
+ BezTriple *start, *end;
+ int sc_x, sc_y;
+ int last_sc_x = -1;
+ const int keysize = 4;
+ const int bordsize = keysize + 1;
+
+ if (!icu || !icu->totvert) {
+ return;
+ }
- BLI_freelistN(&keys);
- BLI_freelistN(&blocks);
+ /* find the first visible start key and the last visible end key */
+ find_unculled_key_range(icu, aki, &start, &end);
+
+ gla2DDrawTranslatePt(di, start->vec[1][0], ypos, &sc_x, &sc_y);
+ last_sc_x = sc_x - 3;
+
+ /* for efficiency we need to batch draw the all the keyframe borders first */
+ glColor3ub(0, 0, 0);
+ glBegin(GL_QUADS);
+ for (bezt=start; bezt <= end; ++bezt) {
+ if(BEZSELECTED(bezt) == selected) {
+ gla2DDrawTranslatePt(di, bezt->vec[1][0], ypos, &sc_x, &sc_y);
+
+ /* avoid redrawing over the same pixels */
+ if (abs(sc_x - last_sc_x) > 2) {
+ 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();
+
+ gla2DDrawTranslatePt(di, start->vec[1][0], ypos, &sc_x, &sc_y);
+ last_sc_x = sc_x - 3;
+
+ if (selected) {
+ glColor3ub(0xF1, 0xCA, 0x13);
+ } else {
+ glColor3ub(0xE9, 0xE9, 0xE9);
+ }
+
+ /* draw the yellow keyframe cores */
+ glBegin(GL_QUADS);
+ for (bezt=start; bezt <= end; ++bezt) {
+ if(BEZSELECTED(bezt) == selected) {
+ gla2DDrawTranslatePt(di, bezt->vec[1][0], ypos, &sc_x, &sc_y);
+
+ if (abs(sc_x - last_sc_x) > 2) {
+ 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;
+ }
+ }
+ }
+ glEnd();
}
-void draw_ipo_channel(gla2DDrawInfo *di, Ipo *ipo, float ypos)
+void draw_block(gla2DDrawInfo *di, float tstart, float tend, float ypos, int selected)
{
- ListBase keys = {0, 0};
- ListBase blocks = {0, 0};
- ActKeysInc *aki = init_aki_data();
+ int sc_xa, sc_ya;
+ int sc_xb, sc_yb;
+ const int halfheight = 3;
+
+ gla2DDrawTranslatePt(di, tstart, ypos, &sc_xa, &sc_ya);
+ gla2DDrawTranslatePt(di, tend, ypos, &sc_xb, &sc_yb);
+
+ if (selected) {
+ BIF_ThemeColor4(TH_STRIP_SELECT);
+ } else {
+ BIF_ThemeColor4(TH_STRIP);
+ }
+
+ if (sc_xa - sc_xb < 1) {
+ glRectf(sc_xa + 1, sc_ya - halfheight, sc_xb - 1, sc_yb + halfheight);
+ }
+}
- ipo_to_keylist(ipo, &keys, &blocks, aki);
- draw_keylist(di, &keys, &blocks, ypos);
+/* find the next key block starting at or after cur */
+void find_next_keyblock(
+ IpoCurve *icu, BezTriple *cur, BezTriple **kbstart, BezTriple **kbend, int *selected
+ )
+{
+ int v;
+ *selected = 0;
- BLI_freelistN(&keys);
- BLI_freelistN(&blocks);
+ if (cur == NULL) {
+ *kbstart = *kbend = NULL;
+ return;
+ }
+
+ if (cur - icu->bezt >= icu->totvert) {
+ *kbstart = *kbend = NULL;
+ return;
+ }
+
+ for (v = cur - icu->bezt; v < icu->totvert - 1; v++) {
+ *kbstart = &(icu->bezt[v]);
+ *kbend = *kbstart + 1;
+
+ if (
+ IS_EQ((*kbend)->vec[1][1], (*kbstart)->vec[1][1]) &&
+ IS_EQ((*kbend)->vec[1][1], (*kbend)->vec[0][1]) &&
+ IS_EQ((*kbstart)->vec[1][1], (*kbstart)->vec[2][1])
+ ) {
+ if (selected && (BEZSELECTED(*kbstart) || BEZSELECTED(*kbend))) {
+ *selected = 1;
+ }
+
+ return;
+ }
+ }
+
+ *kbstart = *kbend = NULL;
}
+/* find a keyblock starting on or after cur which begins at start and ends at end */
+int find_keyblock_time(IpoCurve *icu, BezTriple *cur, float start, float end, int *selected)
+{
+ BezTriple *kbstart, *kbend;
+
+ if (cur == NULL) {
+ return 0;
+ }
+
+ do {
+ find_next_keyblock(icu, cur, &kbstart, &kbend, selected);
+
+ if (kbstart == NULL || kbend == NULL) { /* no block exists */
+ return 0;
+ } else if (kbstart->vec[1][0] > start || kbend->vec[1][0] > end) { /* no aligned block */
+ return 0;
+ } else if (IS_EQ(kbstart->vec[1][0], start) && IS_EQ(kbend->vec[1][0], end)) { /* block exists */
+ return 1;
+ }
+
+ cur = kbend;
+ } while (1);
+
+ return 0;
+}
+
+void draw_ipo_keyblocks(gla2DDrawInfo *di, ActKeysInc *aki, Ipo* ipo, float ypos)
+{
+ BezTriple **acur; /* array of BezTriple* to help speedup drawing */
+ BezTriple **bezcopy, **bezorig; /* sorted copy and original keyframes */
+
+ IpoCurve *mincu;
+ BezTriple *minbeztcur, *minbeztstart, *minbeztend;
+ int minvert;
+
+ IpoCurve *cu;
+ BezTriple *kbstart, *kbend;
+
+ int selected;
+ int ncu;
+ int v;
+
+ if (!ipo->curve.first) {
+ return;
+ }
+
+ ncu = 0;
+ for (cu = ipo->curve.first; cu; cu = cu->next) {
+ ++ncu;
+ }
+
+ acur = MEM_mallocN(ncu * sizeof(BezTriple*), "draw_ipo_keyblocks");
+ bezcopy = MEM_mallocN(ncu * sizeof(BezTriple*), "draw_ipo_keyblocks");
+ bezorig = MEM_mallocN(ncu * sizeof(BezTriple*), "draw_ipo_keyblocks");
+
+ /* create copies of each ipo curve for sorting */
+ v = 0;
+ for (cu = ipo->curve.first; cu; cu = cu->next, ++v) {
+ bezcopy[v] = (BezTriple*)MEM_mallocN(cu->totvert * sizeof(BezTriple), "draw_ipo_keyblocks");
+ memcpy((void*)bezcopy[v], (void*)cu->bezt, cu->totvert * sizeof(BezTriple));
+ bezorig[v] = cu->bezt;
+ cu->bezt = bezcopy[v];
+
+ acur[v] = cu->bezt;
+ }
+
+ /* insertion sort the keys (the keys should be already sorted, for the most part) */
+ insertsort_ipo_keys(ipo);
+
+ /* find the curve with the minimum number of keyframes for efficiency */
+ cu = ipo->curve.first;
+ minvert = cu->totvert;
+ mincu = cu;
+ for (cu = cu->next; cu; cu = cu->next) {
+ if (cu->totvert < minvert) {
+ minvert = cu->totvert;
+ mincu = cu;
+ }
+ }
+
+ find_unculled_key_range(mincu, aki, &minbeztstart, &minbeztend);
+ minbeztcur = minbeztstart;
+ do {
+ int hasblock = 1;
+ find_next_keyblock(mincu, minbeztcur, &kbstart, &kbend, &selected);
+
+ /* no keyblock at or past cur exists */
+ if (kbstart == NULL || kbend == NULL) {
+ break;
+ }
+
+ /* the beginning of the next keyblock is outside of our visible range */
+ if (kbstart->vec[1][0] > minbeztend->vec[1][0]) {
+ break;
+ }
+
+ /* check if all other IPO curves have a block that begins and ends at the current block */
+ v = 0;
+ for (cu = ipo->curve.first; cu; cu = cu->next, ++v) {
+
+ /* the last block for one of the curves has been exceeded (no further blocks will match up) */
+ if (!acur[v]) {
+ //hasblock = 0;
+ break;
+ }
+
+ /* set the keyframe to continue searching from to the one right before our block */
+ acur[v] = find_key(cu, acur[v], kbstart->vec[1][0]);
+
+ /* see if we can find the block */
+ hasblock = find_keyblock_time(cu, acur[v], kbstart->vec[1][0], kbend->vec[1][0], &selected);
+
+ /* one curve does not match, so we will not draw a long keyframe */
+ if (!hasblock) {
+ break;
+ }
+ }
+
+ if (!acur[v]) {
+ break;
+ }
+
+ if (hasblock) {
+ draw_block(di, kbstart->vec[1][0], kbend->vec[1][0], ypos, selected);
+ }
+
+ minbeztcur = kbend;
+ } while (1);
+
+
+ /* cleanup */
+ v = 0;
+ for (cu = ipo->curve.first; cu; cu = cu->next, ++v) {
+ cu->bezt = bezorig[v];
+ MEM_freeN(bezcopy[v]);
+ }
+ MEM_freeN(bezcopy);
+ MEM_freeN(bezorig);
+ MEM_freeN(acur);
+}
+
+void draw_icu_keyblocks(gla2DDrawInfo *di, ActKeysInc *aki, IpoCurve* icu, float ypos)
+{
+ BezTriple *kbstart, *kbend; /* keyblock start and end */
+ BezTriple *culregstart, *culregend; /* region of keys not culled */
+ BezTriple *bezcopy, *bezorig; /* sorted copy and original IpoCurve keys */
+
+ BezTriple *cur;
+ int selected;
+
+ if (!icu->bezt) {
+ return;
+ }
+
+ /* make a sorted copy of the bezier triples to make drawing quick and easy */
+ bezcopy = MEM_mallocN(sizeof(BezTriple) * icu->totvert, "draw_icu_keyblocks");
+ memcpy(bezcopy, icu->bezt, sizeof(BezTriple) * icu->totvert);
+ bezorig = icu->bezt;
+ icu->bezt = bezcopy;
+
+ /* sort */
+ insertsort_icu_keys(bezcopy, icu->totvert);
+
+ /* find the visible region of keys */
+ find_unculled_key_range(icu, aki, &culregstart, &culregend);
+ cur = culregstart;
+
+ find_next_keyblock(icu, cur, &kbstart, &kbend, &selected);
+ cur = kbend;
+ while (kbstart != NULL && kbend != NULL) {
+ draw_block(di, kbstart->vec[1][0], kbend->vec[1][0], ypos, selected);
+
+ if (kbstart->vec[1][0] > culregend->vec[1][0]) {
+ break;
+ }
+
+ find_next_keyblock(icu, cur, &kbstart, &kbend, &selected);
+ cur = kbend;
+ }
+
+ /* cleanup */
+ icu->bezt = bezorig;
+ MEM_freeN(bezcopy);
+}
+
void draw_icu_channel(gla2DDrawInfo *di, IpoCurve *icu, float ypos)
{
- ListBase keys = {0, 0};
- ListBase blocks = {0, 0};
ActKeysInc *aki = init_aki_data();
- icu_to_keylist(icu, &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_agroup_channel(gla2DDrawInfo *di, bActionGroup *agrp, 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();
+
+ if (ipo) {
+ /* draw blocks */
+ draw_ipo_keyblocks(di, aki, ipo, 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);
+ }
+ }
+}
- agroup_to_keylist(agrp, &keys, &blocks, aki);
- draw_keylist(di, &keys, &blocks, ypos);
- BLI_freelistN(&keys);
- BLI_freelistN(&blocks);
+void draw_agroup_channel(gla2DDrawInfo *di, bActionGroup *agrp, float ypos)
+{
+ bActionChannel *achan;
+ bConstraintChannel *conchan;
+
+ 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};
+ ListBase blocks = {0, 0};
ActKeysInc *aki = init_aki_data();
- action_to_keylist(act, &keys, NULL, aki);
- draw_keylist(di, &keys, NULL, ypos);
+ action_to_keylist(act, &keys, &blocks, aki);
+ draw_keylist(di, &keys, &blocks, ypos);
+
BLI_freelistN(&keys);
+ BLI_freelistN(&blocks);
}
/* --------------- Conversion: data -> keyframe list ------------------ */
@@ -1409,23 +1852,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;
File Metadata
Details
Mime Type
text/x-diff
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
e4/a1/84fd82513c142ec691852423eccb
Event Timeline
Log In to Comment