== Action Editor - Long Keyframes ==
authorJoshua Leung <aligorith@gmail.com>
Tue, 19 Jun 2007 09:46:52 +0000 (09:46 +0000)
committerJoshua Leung <aligorith@gmail.com>
Tue, 19 Jun 2007 09:46:52 +0000 (09:46 +0000)
I've recoded the way long keyframes work a bit, so that more cases are handled accurately. Now, it takes into account the number of IPO-curves that have keyframes in them on the start/end frame of the long-keyframe, instead of just taking the total number of IPO-curves present for the channel being drawn.

source/blender/include/BDR_drawaction.h
source/blender/src/drawaction.c

index fdbd710c59fa0dccc304f17e618d9cef49d1ed50..821d8ea6b79be567617013214854946634f7e2a3 100644 (file)
@@ -41,6 +41,19 @@ struct bAction;
 struct Object;
 struct ListBase;
 
+/* ****************************** Base Structs ****************************** */
+
+/* Keyframe Column Struct */
+typedef struct ActKeyColumn {
+       struct ActKeyColumn *next, *prev;
+       short sel, handle_type;
+       float cfra;
+       
+       /* only while drawing - used to determine if long-keyframe needs to be drawn */
+       short modified;
+       short totcurve;
+} ActKeyColumn;
+
 /* 'Long Keyframe' Struct */
 typedef struct ActKeyBlock {
        struct ActKeyBlock *next, *prev;
@@ -53,7 +66,10 @@ typedef struct ActKeyBlock {
        short totcurve; 
 } ActKeyBlock;
 
-/*Action Generics */
+
+/* ******************************* Methods ****************************** */
+
+/* Action Generics */
 void draw_cfra_action(void);
 int count_action_levels (struct bAction *act);
 
@@ -65,9 +81,9 @@ void draw_object_channel(struct gla2DDrawInfo *di, Object *ob, float ypos);
 
 /* Keydata Generation */
 void icu_to_keylist(struct IpoCurve *icu, ListBase *keys, ListBase *blocks);
-int ipo_to_keylist(struct Ipo *ipo, ListBase *keys, ListBase *blocks);
-int action_to_keylist(bAction *act, ListBase *keys, ListBase *blocks);
-int ob_to_keylist(Object *ob, 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 */
 
index 6576dac1d2cee54339b8ea7806d946a336a0eb7a..f1aba5903586dd7173f1768a43941f5aa928af00 100644 (file)
@@ -926,6 +926,8 @@ static void action_blockhandlers(ScrArea *sa)
        uiDrawBlocksPanels(sa, 0);
 }
 
+/* ************************* Action Editor Space ***************************** */
+
 void drawactionspace(ScrArea *sa, void *spacedata)
 {
        short ofsx = 0, ofsy = 0;
@@ -1077,9 +1079,131 @@ void drawactionspace(ScrArea *sa, void *spacedata)
        curarea->win_swap= WIN_BACK_OK;
 }
 
-static void draw_keylist(gla2DDrawInfo *di, ListBase *keys, ListBase *blocks, float ypos, int totcurve)
+/* *************************** Keyframe Drawing *************************** */
+
+static void add_bezt_to_keycolumnslist(ListBase *keys, BezTriple *bezt)
+{
+       /* The equivilant of add_to_cfra_elem except this version 
+        * makes ActKeyColumns - one of the two datatypes required
+        * for action editor drawing.
+        */
+       ActKeyColumn *ak, *akn;
+       
+       if (!(keys) || !(bezt)) return;
+       
+       /* try to find a keyblock that starts on the previous beztriple */
+       for (ak= keys->first; ak; ak= ak->next) {
+               /* do because of double keys */
+               if (ak->cfra == bezt->vec[1][0]) {                      
+                       /* set selection status and 'touched' status */
+                       if (BEZSELECTED(bezt)) ak->sel = SELECT;
+                       ak->modified += 1;
+                       
+                       return;
+               }
+               else if (ak->cfra > bezt->vec[1][0]) break;
+       }
+       
+       /* add new block */
+       akn= MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumn");
+       if (ak) BLI_insertlinkbefore(keys, ak, akn);
+       else BLI_addtail(keys, akn);
+       
+       akn->cfra= bezt->vec[1][0];
+       akn->modified += 1;
+       
+       // TODO: handle type = bezt->h1 or bezt->h2
+       akn->handle_type= 0; 
+       
+       if (BEZSELECTED(bezt))
+               akn->sel = SELECT;
+       else
+               akn->sel = 0;
+}
+
+static void add_bezt_to_keyblockslist(ListBase *blocks, IpoCurve *icu, int index)
+{
+       /* 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;
+       BezTriple *beztn=NULL, *prev=NULL;
+       BezTriple *bezt;
+       int v;
+       
+       /* get beztriples */
+       beztn= (icu->bezt + index);
+       
+       for (v=0, bezt=icu->bezt; v<icu->totvert; v++, bezt++) {
+               /* skip if beztriple is current */
+               if (v != index) {
+                       /* check if beztriple is immediately before */
+                       if (beztn->vec[1][0] > bezt->vec[1][0]) {
+                               /* check if closer than previous was */
+                               if (prev) {
+                                       if (prev->vec[1][0] < bezt->vec[1][0])
+                                               prev= bezt;
+                               }
+                               else {
+                                       prev= bezt;
+                               }
+                       }
+               }
+       }
+       
+       /* check if block needed - same value? */
+       if ((!prev) || (!beztn))
+               return;
+       if (beztn->vec[1][1] != prev->vec[1][1])
+               return;
+       
+       /* try to find a keyblock that starts on the previous beztriple */
+       for (ab= blocks->first; ab; ab= ab->next) {
+               /* check if alter existing block or add new block */
+               if (ab->start == prev->vec[1][0]) {                     
+                       /* set selection status and 'touched' status */
+                       if (BEZSELECTED(beztn)) ab->sel = SELECT;
+                       ab->modified += 1;
+                       
+                       return;
+               }
+               else if (ab->start > prev->vec[1][0]) break;
+       }
+       
+       /* add new block */
+       abn= MEM_callocN(sizeof(ActKeyBlock), "ActKeyBlock");
+       if (ab) BLI_insertlinkbefore(blocks, ab, abn);
+       else BLI_addtail(blocks, abn);
+       
+       abn->start= prev->vec[1][0];
+       abn->end= beztn->vec[1][0];
+       abn->val= beztn->vec[1][1];
+       
+       if (BEZSELECTED(prev) || BEZSELECTED(beztn))
+               abn->sel = SELECT;
+       abn->modified = 1;
+}
+
+/* helper function - find actkeycolumn that occurs on cframe */
+static ActKeyColumn *cfra_find_actkeycolumn (ListBase *keys, float cframe)
 {
-       CfraElem *ce;
+       ActKeyColumn *ak;
+       
+       if (keys==NULL) 
+               return NULL;
+        
+       for (ak= keys->first; ak; ak= ak->next) {
+               if (ak->cfra == cframe)
+                       return ak;
+       }
+       
+       return NULL;
+}
+
+static void draw_keylist(gla2DDrawInfo *di, ListBase *keys, ListBase *blocks, float ypos)
+{
+       ActKeyColumn *ak;
        ActKeyBlock *ab;
        
        glEnable(GL_BLEND);
@@ -1087,8 +1211,22 @@ static void draw_keylist(gla2DDrawInfo *di, ListBase *keys, ListBase *blocks, fl
        /* draw keyblocks */
        if (blocks) {
                for (ab= blocks->first; ab; ab= ab->next) {
-                       /* only draw keyblock if it appears in all curves sampled */
-                       if (ab->totcurve == totcurve) {
+                       short startCurves, endCurves, totCurves;
+                       
+                       /* 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;
                                
@@ -1108,13 +1246,13 @@ static void draw_keylist(gla2DDrawInfo *di, ListBase *keys, ListBase *blocks, fl
        
        /* draw keys */
        if (keys) {
-               for (ce= keys->first; ce; ce= ce->next) {
+               for (ak= keys->first; ak; ak= ak->next) {
                        int sc_x, sc_y;
                        
                        /* get co-ordinate to draw at */
-                       gla2DDrawTranslatePt(di, ce->cfra, ypos, &sc_x, &sc_y);
+                       gla2DDrawTranslatePt(di, ak->cfra, ypos, &sc_x, &sc_y);
                        
-                       if(ce->sel & 1) BIF_icon_draw_aspect(sc_x-7, sc_y-6, ICON_SPACE2, 1.0f);
+                       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);
                }       
        }
@@ -1126,10 +1264,9 @@ void draw_object_channel(gla2DDrawInfo *di, Object *ob, float ypos)
 {
        ListBase keys = {0, 0};
        ListBase blocks = {0, 0};
-       int totcurve;
 
-       totcurve= ob_to_keylist(ob, &keys, &blocks);
-       draw_keylist(di, &keys, &blocks, ypos, totcurve);
+       ob_to_keylist(ob, &keys, &blocks);
+       draw_keylist(di, &keys, &blocks, ypos);
        
        BLI_freelistN(&keys);
        BLI_freelistN(&blocks);
@@ -1139,10 +1276,9 @@ void draw_ipo_channel(gla2DDrawInfo *di, Ipo *ipo, float ypos)
 {
        ListBase keys = {0, 0};
        ListBase blocks = {0, 0};
-       int totcurve;
 
-       totcurve= ipo_to_keylist(ipo, &keys, &blocks);
-       draw_keylist(di, &keys, &blocks, ypos, totcurve);
+       ipo_to_keylist(ipo, &keys, &blocks);
+       draw_keylist(di, &keys, &blocks, ypos);
        
        BLI_freelistN(&keys);
        BLI_freelistN(&blocks);
@@ -1154,7 +1290,7 @@ void draw_icu_channel(gla2DDrawInfo *di, IpoCurve *icu, float ypos)
        ListBase blocks = {0, 0};
 
        icu_to_keylist(icu, &keys, &blocks);
-       draw_keylist(di, &keys, &blocks, ypos, 1);
+       draw_keylist(di, &keys, &blocks, ypos);
        
        BLI_freelistN(&keys);
        BLI_freelistN(&blocks);
@@ -1165,116 +1301,35 @@ void draw_action_channel(gla2DDrawInfo *di, bAction *act, float ypos)
        ListBase keys = {0, 0};
 
        action_to_keylist(act, &keys, NULL);
-       draw_keylist(di, &keys, NULL, ypos, 0);
+       draw_keylist(di, &keys, NULL, ypos);
        BLI_freelistN(&keys);
 }
 
-static void add_bezt_to_keyblockslist(ListBase *blocks, IpoCurve *icu, int index)
-{
-       /* 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;
-       BezTriple *beztn=NULL, *prev=NULL;
-       BezTriple *bezt;
-       int v;
-       
-       /* get beztriples */
-       beztn= (icu->bezt + index);
-       /* The following search for previous beztriple doesn't work
-        * that great on actions with a large amount of keys. There
-        * are a few commented out shortcuts for these cases, which will
-        * remain so until the definitive point where slowdown starts to
-        * bite is determined.
-        */
-       //if (icu->totvert > 3500) {
-       //      if (index >= 1) 
-       //              prev= (icu->bezt + (index - 1));
-       //}
-       //else {
-               for (v=0, bezt=icu->bezt; v<icu->totvert; v++, bezt++) {
-                       /* skip if beztriple is current */
-                       if (v != index) {
-                               /* check if beztriple is immediately before */
-                               if (beztn->vec[1][0] > bezt->vec[1][0]) {
-                                       /* check if closer than previous was */
-                                       if (prev) {
-                                               if (prev->vec[1][0] < bezt->vec[1][0])
-                                                       prev= bezt;
-                                       }
-                                       else {
-                                               prev= bezt;
-                                       }
-                               }
-                       }
-               }
-       //}
-       
-       /* check if block needed - same value? */
-       if ((!prev) || (!beztn))
-               return;
-       if (beztn->vec[1][1] != prev->vec[1][1])
-               return;
-       
-       /* try to find a keyblock that starts on the previous beztriple */
-       for (ab= blocks->first; ab; ab= ab->next) {
-               /* check if alter existing block or add new block */
-               if (ab->start == prev->vec[1][0]) {                     
-                       /* set selection status and 'touched' status */
-                       if (BEZSELECTED(beztn)) 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= beztn->vec[1][0];
-       abn->val= beztn->vec[1][1];
-       
-       if (BEZSELECTED(prev) || BEZSELECTED(beztn))
-               abn->sel = SELECT;
-       else
-               abn->sel = 0;
-       abn->modified += 1;
-}
-
-int ob_to_keylist(Object *ob, ListBase *keys, ListBase *blocks)
+void ob_to_keylist(Object *ob, ListBase *keys, ListBase *blocks)
 {
        bConstraintChannel *conchan;
-       int totcurve = 0;
 
        if (ob) {
                /* Add object keyframes */
-               if (ob->ipo) {
-                       totcurve += ipo_to_keylist(ob->ipo, keys, blocks);
-               }
+               if (ob->ipo)
+                       ipo_to_keylist(ob->ipo, keys, blocks);
                
                /* Add constraint keyframes */
                for (conchan=ob->constraintChannels.first; conchan; conchan=conchan->next){
-                       if(conchan->ipo) {
-                               totcurve += ipo_to_keylist(conchan->ipo, keys, blocks);
-                       }                               
+                       if(conchan->ipo)
+                               ipo_to_keylist(conchan->ipo, keys, blocks);             
                }
                        
                /* Add object data keyframes */
                //              TODO??
        }
-       
-       return totcurve;
 }
 
 void icu_to_keylist(IpoCurve *icu, ListBase *keys, ListBase *blocks)
 {
        BezTriple *bezt;
-       ActKeyBlock *ab, *abn;
+       ActKeyColumn *ak;
+       ActKeyBlock *ab;
        int v;
        
        if (icu && icu->totvert) {
@@ -1282,15 +1337,21 @@ void icu_to_keylist(IpoCurve *icu, ListBase *keys, ListBase *blocks)
                bezt= icu->bezt;
                
                for (v=0; v<icu->totvert; v++, bezt++) {
-                       add_to_cfra_elem(keys, bezt);
+                       add_bezt_to_keycolumnslist(keys, bezt);
                        if (blocks) add_bezt_to_keyblockslist(blocks, icu, v);
                }
                
-               /* update the number of curves the blocks have appeared in */
+               /* update the number of curves that elements have appeared in  */
+               if (keys) {
+                       for (ak= keys->first; ak; ak= ak->next) {
+                               if (ak->modified) {
+                                       ak->modified = 0;
+                                       ak->totcurve += 1;
+                               }
+                       }
+               }
                if (blocks) {
-                       for (ab= blocks->first; ab; ab= abn) {
-                               abn= ab->next;
-                               
+                       for (ab= blocks->first; ab; ab= ab->next) {
                                if (ab->modified) {
                                        ab->modified = 0;
                                        ab->totcurve += 1;
@@ -1300,44 +1361,34 @@ void icu_to_keylist(IpoCurve *icu, ListBase *keys, ListBase *blocks)
        }
 }
 
-int ipo_to_keylist(Ipo *ipo, ListBase *keys, ListBase *blocks)
+void ipo_to_keylist(Ipo *ipo, ListBase *keys, ListBase *blocks)
 {
        IpoCurve *icu;
-       int totcurve = 0;
        
        if (ipo) {
-               for (icu= ipo->curve.first; icu; icu= icu->next) {
+               for (icu= ipo->curve.first; icu; icu= icu->next)
                        icu_to_keylist(icu, keys, blocks);
-                       totcurve++;
-               }
        }
-       
-       return totcurve;
 }
 
-int action_to_keylist(bAction *act, ListBase *keys, ListBase *blocks)
+void action_to_keylist(bAction *act, ListBase *keys, ListBase *blocks)
 {
        bActionChannel *achan;
        bConstraintChannel *conchan;
-       int totcurve = 0;
 
        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) {
-                               totcurve+= ipo_to_keylist(achan->ipo, keys, blocks);
-                       }
+                       if (achan->ipo)
+                               ipo_to_keylist(achan->ipo, keys, blocks);
                        
                        /* then, add keys from constraint channels */
                        for (conchan= achan->constraintChannels.first; conchan; conchan= conchan->next) {
-                               if (conchan->ipo) {
-                                       totcurve+= ipo_to_keylist(achan->ipo, keys, blocks);
-                               }
+                               if (conchan->ipo)
+                                       ipo_to_keylist(achan->ipo, keys, blocks);
                        }
                }
        }
-       
-       return totcurve;
 }